#include "common.h" #include "patcher.h" #include "RwHelper.h" #include "Camera.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 blur, int32 type, uint32 addalpha) { RwRGBA color = { (RwUInt8)red, (RwUInt8)green, (RwUInt8)blue, (RwUInt8)blur }; if(BlurOn){ if(pFrontBuffer){ if(ms_bJustInitialised) ms_bJustInitialised = false; else OverlayRender(cam, pFrontBuffer, color, type, addalpha); } RwRasterPushContext(pFrontBuffer); RwRasterRenderFast(RwCameraGetRaster(cam), 0, 0); RwRasterPopContext(); }else{ OverlayRender(cam, nil, color, type, addalpha); } } void CMBlur::OverlayRender(RwCamera *cam, RwRaster *raster, RwRGBA color, int32 type, uint32 addalpha) { int r, g, b, a; r = color.red; g = color.green; b = color.blue; a = color.alpha; DefinedState(); switch(type){ case MBLUR_INTRO1: r = 0; g = 255; b = 0; a = 128; break; case MBLUR_INTRO3: r = 100; g = 220; b = 230; a = 158; break; case MBLUR_INTRO4: r = 80; g = 255; b = 230; a = 138; break; case MBLUR_INTRO6: r = 255; g = 60; b = 60; a = 200; break; case MBLUR_UNUSED: 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 = addalpha/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