diff --git a/src/RwHelper.cpp b/src/RwHelper.cpp index c8782f9e..2634cfd6 100644 --- a/src/RwHelper.cpp +++ b/src/RwHelper.cpp @@ -1,5 +1,31 @@ +#define WITHD3D #include "common.h" +#include "TimeCycle.h" +void +DefinedState(void) +{ + RwRenderStateSet(rwRENDERSTATETEXTUREADDRESS, (void*)rwTEXTUREADDRESSWRAP); + RwRenderStateSet(rwRENDERSTATETEXTUREPERSPECTIVE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATESHADEMODE, (void*)rwSHADEMODEGOURAUD); + RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); + RwRenderStateSet(rwRENDERSTATEALPHAPRIMITIVEBUFFER, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATEBORDERCOLOR, (void*)RWRGBALONG(0, 0, 0, 255)); + RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATEFOGCOLOR, + (void*)RWRGBALONG(CTimeCycle::GetFogRed(), CTimeCycle::GetFogGreen(), CTimeCycle::GetFogBlue(), 255)); + RwRenderStateSet(rwRENDERSTATEFOGTYPE, (void*)rwFOGTYPELINEAR); + RwRenderStateSet(rwRENDERSTATECULLMODE, (void*)rwCULLMODECULLNONE); + + // D3D stuff + RwD3D8SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER); + RwD3D8SetRenderState(D3DRS_ALPHAREF, 2); +} RwObject* GetFirstObjectCallback(RwObject *object, void *data) diff --git a/src/RwHelper.h b/src/RwHelper.h index 90852b08..49292449 100644 --- a/src/RwHelper.h +++ b/src/RwHelper.h @@ -1,3 +1,4 @@ #pragma once +void DefinedState(void); RwObject *GetFirstObject(RwFrame *frame); diff --git a/src/Timecycle.h b/src/Timecycle.h index 6946cc7c..2f9e4f2f 100644 --- a/src/Timecycle.h +++ b/src/Timecycle.h @@ -107,5 +107,8 @@ public: static int GetFluffyCloudsBottomRed(void) { return m_nCurrentFluffyCloudsBottomRed; } static int GetFluffyCloudsBottomGreen(void) { return m_nCurrentFluffyCloudsBottomGreen; } static int GetFluffyCloudsBottomBlue(void) { return m_nCurrentFluffyCloudsBottomBlue; } + static int GetFogRed(void) { return m_nCurrentFogColourRed; } + static int GetFogGreen(void) { return m_nCurrentFogColourGreen; } + static int GetFogBlue(void) { return m_nCurrentFogColourBlue; } }; diff --git a/src/common.h b/src/common.h index 34214d42..a82e4c7f 100644 --- a/src/common.h +++ b/src/common.h @@ -13,6 +13,11 @@ #include #include +#ifdef WITHD3D +#include +#include +#endif + #include #include diff --git a/src/main.cpp b/src/main.cpp index 955b33ed..4f125098 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -25,17 +25,12 @@ void operator delete(void *ptr) noexcept { gtadelete(ptr); } unsigned __int64 myrand_seed = 1; int -myps2rand(void) +myrand(void) { myrand_seed = 0x5851F42D4C957F2D * myrand_seed + 1; return ((myrand_seed >> 32) & 0x7FFFFFFF); } -int myrand(void) -{ - return myps2rand(); -} - void mysrand(unsigned int seed) { diff --git a/src/render/Draw.cpp b/src/render/Draw.cpp index f26f2ada..6244c3fa 100644 --- a/src/render/Draw.cpp +++ b/src/render/Draw.cpp @@ -1,6 +1,34 @@ #include "common.h" +#include "patcher.h" #include "Draw.h" float &CDraw::ms_fNearClipZ = *(float*)0x8E2DC4; float &CDraw::ms_fFarClipZ = *(float*)0x9434F0; float &CDraw::ms_fFOV = *(float*)0x5FBC6C; + +static float hFov2vFov(float hfov) +{ + float w = SCREENW; + float h = SCREENH; + + // => tan(hFOV/2) = tan(vFOV/2)*aspectRatio + // => tan(vFOV/2) = tan(hFOV/2)/aspectRatio + float ar1 = 4.0/3.0; + float ar2 = w/h; + hfov = DEGTORAD(hfov); + float vfov = atan(tan(hfov/2) / ar1) *2; + hfov = atan(tan(vfov/2) * ar2) *2; + return RADTODEG(hfov); +} + +void +CDraw::SetFOV(float fov) +{ +// TODO: fix FOV here or somewhere else? +// ms_fFOV = hFov2vFov(fov); + ms_fFOV = fov; +} + +STARTPATCHES + InjectHook(0x4FE7B0, CDraw::SetFOV, PATCH_JUMP); +ENDPATCHES diff --git a/src/render/Draw.h b/src/render/Draw.h index 62fe5193..84ec7ed3 100644 --- a/src/render/Draw.h +++ b/src/render/Draw.h @@ -11,6 +11,6 @@ public: static float GetNearClipZ(void) { return ms_fNearClipZ; } static void SetFarClipZ(float farclip) { ms_fFarClipZ = farclip; } static float GetFarClipZ(void) { return ms_fFarClipZ; } - static void SetFOV(float fov) { ms_fFOV = fov; } + static void SetFOV(float fov); static float GetFOV(void) { return ms_fFOV; } }; diff --git a/src/render/MBlur.cpp b/src/render/MBlur.cpp new file mode 100644 index 00000000..b7a65adc --- /dev/null +++ b/src/render/MBlur.cpp @@ -0,0 +1,221 @@ +#include "common.h" +#include "patcher.h" +#include "RwHelper.h" +#include "MBlur.h" + +RwRaster *&CMBlur::pFrontBuffer = *(RwRaster**)0x8E2C48; +bool &CMBlur::ms_bJustInitialised = *(bool*)0x95CDAB; +bool &CMBlur::BlurOn = *(bool*)0x95CDAD; + +static RwIm2DVertex Vertex[4]; +//static RwIm2DVertex *Vertex = (RwIm2DVertex*)0x62F780; +static RwImVertexIndex Index[6] = { 0, 1, 2, 0, 2, 3 }; + +void +CMBlur::MotionBlurOpen(RwCamera *cam) +{ + // TODO. this is simplified + + RwRect rect = { 0, 0, 0, 0 }; + + if(pFrontBuffer) + MotionBlurClose(); + + if(BlurOn){ + for(rect.w = 1; rect.w < RwRasterGetWidth(RwCameraGetRaster(cam)); rect.w *= 2); + for(rect.h = 1; rect.h < RwRasterGetHeight(RwCameraGetRaster(cam)); rect.h *= 2); + pFrontBuffer = RwRasterCreate(rect.w, rect.h, RwRasterGetDepth(RwCameraGetRaster(cam)), rwRASTERTYPECAMERATEXTURE); + if(pFrontBuffer) + ms_bJustInitialised = true; + else{ + debug("MBlurOpen can't create raster."); + BlurOn = false; + rect.w = RwRasterGetWidth(RwCameraGetRaster(cam)); + rect.h = RwRasterGetHeight(RwCameraGetRaster(cam)); + } + CreateImmediateModeData(cam, &rect); + }else{ + rect.w = RwRasterGetWidth(RwCameraGetRaster(cam)); + rect.h = RwRasterGetHeight(RwCameraGetRaster(cam)); + CreateImmediateModeData(cam, &rect); + } +} + +void +CMBlur::MotionBlurClose(void) +{ + if(pFrontBuffer){ + RwRasterDestroy(pFrontBuffer); + pFrontBuffer = nil; + } +} + +void +CMBlur::CreateImmediateModeData(RwCamera *cam, RwRect *rect) +{ + float zero, xmax, ymax; + + if(RwRasterGetDepth(RwCameraGetRaster(cam)) == 16){ + zero = 0.5f; + xmax = rect->w + 0.5f; + ymax = rect->h + 0.5f; + }else{ + zero = -0.5f; + xmax = rect->w - 0.5f; + ymax = rect->h - 0.5f; + } + + RwIm2DVertexSetScreenX(&Vertex[0], zero); + RwIm2DVertexSetScreenY(&Vertex[0], zero); + RwIm2DVertexSetScreenZ(&Vertex[0], RwIm2DGetNearScreenZ()); + RwIm2DVertexSetCameraZ(&Vertex[0], RwCameraGetNearClipPlane(cam)); + RwIm2DVertexSetRecipCameraZ(&Vertex[0], 1.0f/RwCameraGetNearClipPlane(cam)); + RwIm2DVertexSetU(&Vertex[0], 0.0f, 1.0f/RwCameraGetNearClipPlane(cam)); + RwIm2DVertexSetV(&Vertex[0], 0.0f, 1.0f/RwCameraGetNearClipPlane(cam)); + RwIm2DVertexSetIntRGBA(&Vertex[0], 255, 255, 255, 255); + + RwIm2DVertexSetScreenX(&Vertex[1], zero); + RwIm2DVertexSetScreenY(&Vertex[1], ymax); + RwIm2DVertexSetScreenZ(&Vertex[1], RwIm2DGetNearScreenZ()); + RwIm2DVertexSetCameraZ(&Vertex[1], RwCameraGetNearClipPlane(cam)); + RwIm2DVertexSetRecipCameraZ(&Vertex[1], 1.0f/RwCameraGetNearClipPlane(cam)); + RwIm2DVertexSetU(&Vertex[1], 0.0f, 1.0f/RwCameraGetNearClipPlane(cam)); + RwIm2DVertexSetV(&Vertex[1], 1.0f, 1.0f/RwCameraGetNearClipPlane(cam)); + RwIm2DVertexSetIntRGBA(&Vertex[1], 255, 255, 255, 255); + + RwIm2DVertexSetScreenX(&Vertex[2], xmax); + RwIm2DVertexSetScreenY(&Vertex[2], ymax); + RwIm2DVertexSetScreenZ(&Vertex[2], RwIm2DGetNearScreenZ()); + RwIm2DVertexSetCameraZ(&Vertex[2], RwCameraGetNearClipPlane(cam)); + RwIm2DVertexSetRecipCameraZ(&Vertex[2], 1.0f/RwCameraGetNearClipPlane(cam)); + RwIm2DVertexSetU(&Vertex[2], 1.0f, 1.0f/RwCameraGetNearClipPlane(cam)); + RwIm2DVertexSetV(&Vertex[2], 1.0f, 1.0f/RwCameraGetNearClipPlane(cam)); + RwIm2DVertexSetIntRGBA(&Vertex[2], 255, 255, 255, 255); + + RwIm2DVertexSetScreenX(&Vertex[3], xmax); + RwIm2DVertexSetScreenY(&Vertex[3], zero); + RwIm2DVertexSetScreenZ(&Vertex[3], RwIm2DGetNearScreenZ()); + RwIm2DVertexSetCameraZ(&Vertex[3], RwCameraGetNearClipPlane(cam)); + RwIm2DVertexSetRecipCameraZ(&Vertex[3], 1.0f/RwCameraGetNearClipPlane(cam)); + RwIm2DVertexSetU(&Vertex[3], 1.0f, 1.0f/RwCameraGetNearClipPlane(cam)); + RwIm2DVertexSetV(&Vertex[3], 0.0f, 1.0f/RwCameraGetNearClipPlane(cam)); + RwIm2DVertexSetIntRGBA(&Vertex[3], 255, 255, 255, 255); + +} + +void +CMBlur::MotionBlurRender(RwCamera *cam, uint32 red, uint32 green, uint32 blue, uint32 alpha, int32 type, uint32 bluralpha) +{ + RwRGBA color = { red, green, blue, alpha }; + if(BlurOn){ + if(pFrontBuffer){ + if(ms_bJustInitialised) + ms_bJustInitialised = false; + else + OverlayRender(cam, pFrontBuffer, color, type, bluralpha); + } + RwRasterPushContext(pFrontBuffer); + RwRasterRenderFast(RwCameraGetRaster(cam), 0, 0); + RwRasterPopContext(); + }else{ + OverlayRender(cam, nil, color, type, bluralpha); + } +} + +void +CMBlur::OverlayRender(RwCamera *cam, RwRaster *raster, RwRGBA color, int32 type, uint32 bluralpha) +{ + int r, g, b, a; + + r = color.red; + g = color.green; + b = color.blue; + a = color.alpha; + + DefinedState(); + + switch(type){ + case 3: + r = 0; + g = 255; + b = 0; + a = 128; + break; + case 5: + r = 100; + g = 220; + b = 230; + a = 158; + break; + case 6: + r = 80; + g = 255; + b = 230; + a = 138; + break; + case 8: + r = 255; + g = 60; + b = 60; + a = 200; + break; + case 9: + r = 255; + g = 180; + b = 180; + a = 128; + break; + } + + if(!BlurOn){ + r *= 0.6f; + g *= 0.6f; + b *= 0.6f; + if(type != 1) + a *= 0.6f; + // game clamps to 255 here, but why? + } + RwIm2DVertexSetIntRGBA(&Vertex[0], r, g, b, a); + RwIm2DVertexSetIntRGBA(&Vertex[1], r, g, b, a); + RwIm2DVertexSetIntRGBA(&Vertex[2], r, g, b, a); + RwIm2DVertexSetIntRGBA(&Vertex[3], r, g, b, a); + + RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERNEAREST); + RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE); + + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, BlurOn ? raster : nil); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); + RwIm2DRenderIndexedPrimitive(rwPRIMTYPETRILIST, Vertex, 4, Index, 6); + + a = bluralpha/2; + if(a < 30) + a = 30; + + if(BlurOn && a != 0){ // the second condition should always be true + RwIm2DVertexSetIntRGBA(&Vertex[0], 255, 255, 255, a); + RwIm2DVertexSetIntRGBA(&Vertex[1], 255, 255, 255, a); + RwIm2DVertexSetIntRGBA(&Vertex[2], 255, 255, 255, a); + RwIm2DVertexSetIntRGBA(&Vertex[3], 255, 255, 255, a); + RwIm2DRenderIndexedPrimitive(rwPRIMTYPETRILIST, Vertex, 4, Index, 6); + } + + RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); +} + +STARTPATCHES + InjectHook(0x50AE40, CMBlur::MotionBlurOpen, PATCH_JUMP); + InjectHook(0x50B170, CMBlur::MotionBlurClose, PATCH_JUMP); + InjectHook(0x50A800, CMBlur::CreateImmediateModeData, PATCH_JUMP); + InjectHook(0x50AD70, CMBlur::MotionBlurRender, PATCH_JUMP); + InjectHook(0x50A9C0, CMBlur::OverlayRender, PATCH_JUMP); +ENDPATCHES diff --git a/src/render/MBlur.h b/src/render/MBlur.h new file mode 100644 index 00000000..67ed658f --- /dev/null +++ b/src/render/MBlur.h @@ -0,0 +1,15 @@ +#pragma once + +class CMBlur +{ + static RwRaster *&pFrontBuffer; + static bool &ms_bJustInitialised; + static bool &BlurOn; + +public: + static void MotionBlurOpen(RwCamera *cam); + static void MotionBlurClose(void); + static void CreateImmediateModeData(RwCamera *cam, RwRect *rect); + static void MotionBlurRender(RwCamera *cam, uint32 red, uint32 green, uint32 blue, uint32 alpha, int32 type, uint32 bluralpha); + static void OverlayRender(RwCamera *cam, RwRaster *raster, RwRGBA color, int32 type, uint32 bluralpha); +};