#define WITHD3D #include "common.h" #ifdef EXTENDED_COLOURFILTER #ifndef LIBRW #error "Need librw for EXTENDED_COLOURFILTER" #endif #include "RwHelper.h" #include "Camera.h" #include "MBlur.h" #include "postfx.h" RwRaster *CPostFX::pFrontBuffer; RwRaster *CPostFX::pBackBuffer; bool CPostFX::bJustInitialised; int CPostFX::EffectSwitch = POSTFX_PS2; bool CPostFX::BlurOn = false; bool CPostFX::MotionBlurOn = false; static RwIm2DVertex Vertex[4]; static RwIm2DVertex Vertex2[4]; static RwImVertexIndex Index[6] = { 0, 1, 2, 0, 2, 3 }; static RwIm2DVertex BlurVertex[12]; static RwImVertexIndex BlurIndex[18] = { 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, 8, 9, 10, 8, 10, 11 }; #ifdef RW_D3D9 void *colourfilterLCS_PS; void *contrast_PS; #endif #ifdef RW_OPENGL int32 u_blurcolor; int32 u_contrastAdd; int32 u_contrastMult; rw::gl3::Shader *colourFilterLCS; rw::gl3::Shader *contrast; #endif void CPostFX::InitOnce(void) { #ifdef RW_OPENGL u_blurcolor = rw::gl3::registerUniform("u_blurcolor"); u_contrastAdd = rw::gl3::registerUniform("u_contrastAdd"); u_contrastMult = rw::gl3::registerUniform("u_contrastMult"); #endif } void CPostFX::Open(RwCamera *cam) { uint32 width = Pow(2.0f, int32(log2(RwRasterGetWidth (RwCameraGetRaster(cam))))+1); uint32 height = Pow(2.0f, int32(log2(RwRasterGetHeight(RwCameraGetRaster(cam))))+1); uint32 depth = RwRasterGetDepth(RwCameraGetRaster(cam)); pFrontBuffer = RwRasterCreate(width, height, depth, rwRASTERTYPECAMERATEXTURE); pBackBuffer = RwRasterCreate(width, height, depth, rwRASTERTYPECAMERATEXTURE); bJustInitialised = true; float zero, xmax, ymax; if(RwRasterGetDepth(RwCameraGetRaster(cam)) == 16){ zero = HALFPX; xmax = width + HALFPX; ymax = height + HALFPX; }else{ zero = -HALFPX; xmax = width - HALFPX; ymax = height - HALFPX; } 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); RwIm2DVertexSetScreenX(&Vertex2[0], zero + 2.0f); RwIm2DVertexSetScreenY(&Vertex2[0], zero + 2.0f); RwIm2DVertexSetScreenZ(&Vertex2[0], RwIm2DGetNearScreenZ()); RwIm2DVertexSetCameraZ(&Vertex2[0], RwCameraGetNearClipPlane(cam)); RwIm2DVertexSetRecipCameraZ(&Vertex2[0], 1.0f/RwCameraGetNearClipPlane(cam)); RwIm2DVertexSetU(&Vertex2[0], 0.0f, 1.0f/RwCameraGetNearClipPlane(cam)); RwIm2DVertexSetV(&Vertex2[0], 0.0f, 1.0f/RwCameraGetNearClipPlane(cam)); RwIm2DVertexSetIntRGBA(&Vertex2[0], 255, 255, 255, 255); RwIm2DVertexSetScreenX(&Vertex2[1], 2.0f); RwIm2DVertexSetScreenY(&Vertex2[1], ymax + 2.0f); RwIm2DVertexSetScreenZ(&Vertex2[1], RwIm2DGetNearScreenZ()); RwIm2DVertexSetCameraZ(&Vertex2[1], RwCameraGetNearClipPlane(cam)); RwIm2DVertexSetRecipCameraZ(&Vertex2[1], 1.0f/RwCameraGetNearClipPlane(cam)); RwIm2DVertexSetU(&Vertex2[1], 0.0f, 1.0f/RwCameraGetNearClipPlane(cam)); RwIm2DVertexSetV(&Vertex2[1], 1.0f, 1.0f/RwCameraGetNearClipPlane(cam)); RwIm2DVertexSetIntRGBA(&Vertex2[1], 255, 255, 255, 255); RwIm2DVertexSetScreenX(&Vertex2[2], xmax + 2.0f); RwIm2DVertexSetScreenY(&Vertex2[2], ymax + 2.0f); RwIm2DVertexSetScreenZ(&Vertex2[2], RwIm2DGetNearScreenZ()); RwIm2DVertexSetCameraZ(&Vertex2[2], RwCameraGetNearClipPlane(cam)); RwIm2DVertexSetRecipCameraZ(&Vertex2[2], 1.0f/RwCameraGetNearClipPlane(cam)); RwIm2DVertexSetU(&Vertex2[2], 1.0f, 1.0f/RwCameraGetNearClipPlane(cam)); RwIm2DVertexSetV(&Vertex2[2], 1.0f, 1.0f/RwCameraGetNearClipPlane(cam)); RwIm2DVertexSetIntRGBA(&Vertex2[2], 255, 255, 255, 255); RwIm2DVertexSetScreenX(&Vertex2[3], xmax + 2.0f); RwIm2DVertexSetScreenY(&Vertex2[3], zero + 2.0f); RwIm2DVertexSetScreenZ(&Vertex2[3], RwIm2DGetNearScreenZ()); RwIm2DVertexSetCameraZ(&Vertex2[3], RwCameraGetNearClipPlane(cam)); RwIm2DVertexSetRecipCameraZ(&Vertex2[3], 1.0f/RwCameraGetNearClipPlane(cam)); RwIm2DVertexSetU(&Vertex2[3], 1.0f, 1.0f/RwCameraGetNearClipPlane(cam)); RwIm2DVertexSetV(&Vertex2[3], 0.0f, 1.0f/RwCameraGetNearClipPlane(cam)); RwIm2DVertexSetIntRGBA(&Vertex2[3], 255, 255, 255, 255); #ifdef RW_D3D9 #include "shaders/obj/colourfilterLCS_PS.inc" colourfilterLCS_PS = rw::d3d::createPixelShader(colourfilterLCS_PS_cso); #include "shaders/obj/contrastPS.inc" contrast_PS = rw::d3d::createPixelShader(contrastPS_cso); #endif #ifdef RW_OPENGL using namespace rw::gl3; { #include "shaders/obj/im2d_vert.inc" #include "shaders/obj/colourfilterLCS_frag.inc" const char *vs[] = { shaderDecl, header_vert_src, im2d_vert_src, nil }; const char *fs[] = { shaderDecl, header_frag_src, colourfilterLCS_frag_src, nil }; colourFilterLCS = Shader::create(vs, fs); assert(colourFilterLCS); } { #include "shaders/obj/im2d_vert.inc" #include "shaders/obj/contrast_frag.inc" const char *vs[] = { shaderDecl, header_vert_src, im2d_vert_src, nil }; const char *fs[] = { shaderDecl, header_frag_src, contrast_frag_src, nil }; contrast = Shader::create(vs, fs); assert(contrast); } #endif } void CPostFX::Close(void) { if(pFrontBuffer){ RwRasterDestroy(pFrontBuffer); pFrontBuffer = nil; } if(pBackBuffer){ RwRasterDestroy(pBackBuffer); pBackBuffer = nil; } #ifdef RW_D3D9 if(colourfilterLCS_PS){ rw::d3d::destroyPixelShader(colourfilterLCS_PS); colourfilterLCS_PS = nil; } if(contrast_PS){ rw::d3d::destroyPixelShader(contrast_PS); contrast_PS = nil; } #endif #ifdef RW_OPENGL if(colourFilterLCS){ colourFilterLCS->destroy(); colourFilterLCS = nil; } if(contrast){ contrast->destroy(); contrast = nil; } #endif } static float blurOffset = 0.6f;//3.0f/16.0f; // not quite sure sure about this static float blurIntensity = 0.25f; void CPostFX::RenderOverlayBlur(RwCamera *cam, int32 r, int32 g, int32 b, int32 a) { memcpy(BlurVertex, Vertex, sizeof(Vertex)); memcpy(BlurVertex+4, Vertex, sizeof(Vertex)); memcpy(BlurVertex+8, Vertex, sizeof(Vertex)); int intensity = 255*blurIntensity; int i; for(i = 0; i < 4; i++){ RwIm2DVertexSetScreenX(&BlurVertex[i], RwIm2DVertexGetScreenX(&BlurVertex[i]) + blurOffset); RwIm2DVertexSetIntRGBA(&BlurVertex[i], 255, 255, 255, intensity); } for(i = 4; i < 8; i++){ RwIm2DVertexSetScreenX(&BlurVertex[i], RwIm2DVertexGetScreenX(&BlurVertex[i]) + blurOffset); RwIm2DVertexSetScreenY(&BlurVertex[i], RwIm2DVertexGetScreenY(&BlurVertex[i]) + blurOffset); RwIm2DVertexSetIntRGBA(&BlurVertex[i], 255, 255, 255, intensity); } for(i = 8; i < 12; i++){ RwIm2DVertexSetScreenY(&BlurVertex[i], RwIm2DVertexGetScreenY(&BlurVertex[i]) + blurOffset); RwIm2DVertexSetIntRGBA(&BlurVertex[i], 255, 255, 255, intensity); } RwRenderStateSet(rwRENDERSTATETEXTURERASTER, pBackBuffer); RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR); RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); RwIm2DRenderIndexedPrimitive(rwPRIMTYPETRILIST, BlurVertex, 12, BlurIndex, 18); // this sucks: should render colourfilter with blending instead // but can't change equation to subtraction for PSP here GetBackBuffer(cam); /* the old way RwRenderStateSet(rwRENDERSTATETEXTURERASTER, pFrontBuffer); RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); RwIm2DVertexSetIntRGBA(&Vertex[0], r*2, g*2, b*2, 30); RwIm2DVertexSetIntRGBA(&Vertex[1], r*2, g*2, b*2, 30); RwIm2DVertexSetIntRGBA(&Vertex[2], r*2, g*2, b*2, 30); RwIm2DVertexSetIntRGBA(&Vertex[3], r*2, g*2, b*2, 30); RwIm2DVertexSetIntRGBA(&Vertex2[0], r*2, g*2, b*2, 30); RwIm2DVertexSetIntRGBA(&Vertex2[1], r*2, g*2, b*2, 30); RwIm2DVertexSetIntRGBA(&Vertex2[2], r*2, g*2, b*2, 30); RwIm2DVertexSetIntRGBA(&Vertex2[3], r*2, g*2, b*2, 30); RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); RwIm2DRenderIndexedPrimitive(rwPRIMTYPETRILIST, BlurOn ? Vertex2 : Vertex, 4, Index, 6); RwIm2DVertexSetIntRGBA(&Vertex2[0], r, g, b, a); RwIm2DVertexSetIntRGBA(&Vertex[0], r, g, b, a); RwIm2DVertexSetIntRGBA(&Vertex2[1], r, g, b, a); RwIm2DVertexSetIntRGBA(&Vertex[1], r, g, b, a); RwIm2DVertexSetIntRGBA(&Vertex2[2], r, g, b, a); RwIm2DVertexSetIntRGBA(&Vertex[2], r, g, b, a); RwIm2DVertexSetIntRGBA(&Vertex2[3], r, g, b, a); RwIm2DVertexSetIntRGBA(&Vertex[3], r, g, b, a); RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE); RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE); RwIm2DRenderIndexedPrimitive(rwPRIMTYPETRILIST, Vertex, 4, Index, 6); RwIm2DRenderIndexedPrimitive(rwPRIMTYPETRILIST, BlurOn ? Vertex2 : Vertex, 4, Index, 6); */ } void CPostFX::RenderOverlaySniper(RwCamera *cam, int32 r, int32 g, int32 b, int32 a) { RwRenderStateSet(rwRENDERSTATETEXTURERASTER, pFrontBuffer); RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); RwIm2DVertexSetIntRGBA(&Vertex[0], r, g, b, 80); RwIm2DVertexSetIntRGBA(&Vertex[1], r, g, b, 80); RwIm2DVertexSetIntRGBA(&Vertex[2], r, g, b, 80); RwIm2DVertexSetIntRGBA(&Vertex[3], r, g, b, 80); RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); RwIm2DRenderIndexedPrimitive(rwPRIMTYPETRILIST, Vertex, 4, Index, 6); } float CPostFX::Intensity = 1.0f; void CPostFX::RenderOverlayShader(RwCamera *cam, int32 r, int32 g, int32 b, int32 a) { RwRenderStateSet(rwRENDERSTATETEXTURERASTER, pBackBuffer); if(EffectSwitch == POSTFX_MOBILE){ float mult[3], add[3]; mult[0] = (r-64)/256.0f + 1.4f; mult[1] = (g-64)/256.0f + 1.4f; mult[2] = (b-64)/256.0f + 1.4f; add[0] = r/1536.f - 0.05f; add[1] = g/1536.f - 0.05f; add[2] = b/1536.f - 0.05f; #ifdef RW_D3D9 rw::d3d::d3ddevice->SetPixelShaderConstantF(10, mult, 1); rw::d3d::d3ddevice->SetPixelShaderConstantF(11, add, 1); rw::d3d::im2dOverridePS = contrast_PS; #endif #ifdef RW_OPENGL rw::gl3::im2dOverrideShader = contrast; contrast->use(); glUniform3fv(contrast->uniformLocations[u_contrastMult], 1, mult); glUniform3fv(contrast->uniformLocations[u_contrastAdd], 1, add); #endif }else{ float f = Intensity; float blurcolors[4]; blurcolors[0] = r*f/255.0f; blurcolors[1] = g*f/255.0f; blurcolors[2] = b*f/255.0f; blurcolors[3] = EffectSwitch == POSTFX_PSP ? -1.0f : 1.0f; #ifdef RW_D3D9 rw::d3d::d3ddevice->SetPixelShaderConstantF(10, blurcolors, 1); rw::d3d::im2dOverridePS = colourfilterLCS_PS; #endif #ifdef RW_OPENGL rw::gl3::im2dOverrideShader = colourFilterLCS; colourFilterLCS->use(); glUniform4fv(colourFilterLCS->uniformLocations[u_blurcolor], 1, blurcolors); #endif } RwIm2DRenderIndexedPrimitive(rwPRIMTYPETRILIST, Vertex, 4, Index, 6); #ifdef RW_D3D9 rw::d3d::im2dOverridePS = nil; #endif #ifdef RW_OPENGL rw::gl3::im2dOverrideShader = nil; #endif } void CPostFX::RenderMotionBlur(RwCamera *cam, uint32 blur) { if(blur == 0) return; RwRenderStateSet(rwRENDERSTATETEXTURERASTER, pFrontBuffer); RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); RwIm2DVertexSetIntRGBA(&Vertex[0], 255, 255, 255, blur); RwIm2DVertexSetIntRGBA(&Vertex[1], 255, 255, 255, blur); RwIm2DVertexSetIntRGBA(&Vertex[2], 255, 255, 255, blur); RwIm2DVertexSetIntRGBA(&Vertex[3], 255, 255, 255, blur); RwIm2DRenderIndexedPrimitive(rwPRIMTYPETRILIST, Vertex, 4, Index, 6); } bool CPostFX::NeedBackBuffer(void) { // Current frame -- needed for non-blur effect switch(EffectSwitch){ case POSTFX_OFF: case POSTFX_SIMPLE: // no actual rendering here return false; case POSTFX_PSP: case POSTFX_PS2: case POSTFX_MOBILE: return true; } return false; } bool CPostFX::NeedFrontBuffer(int32 type) { // Last frame -- needed for motion blur if(MotionBlurOn) return true; if(type == MOTION_BLUR_SNIPER) return true; return false; } void CPostFX::GetBackBuffer(RwCamera *cam) { RwRasterPushContext(pBackBuffer); RwRasterRenderFast(RwCameraGetRaster(cam), 0, 0); RwRasterPopContext(); } void CPostFX::Render(RwCamera *cam, uint32 red, uint32 green, uint32 blue, uint32 blur, int32 type, uint32 bluralpha) { // LCS PS2 blur is drawn in three passes: // blend frame with current frame 3 times to blur a bit // blend one more time with colour filter // motion blur like normal if(pFrontBuffer == nil) Open(cam); assert(pFrontBuffer); assert(pBackBuffer); /* // LCS: don't need that anymore if(type == MOTION_BLUR_LIGHT_SCENE){ SmoothColor(red, green, blue, blur); red = AvgRed; green = AvgGreen; blue = AvgBlue; blur = AvgAlpha; } */ if(NeedBackBuffer()) GetBackBuffer(cam); DefinedState(); RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE); RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE); RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE); if(BlurOn) RenderOverlayBlur(cam, 0, 0, 0, 0); RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERNEAREST); // TODO(LCS): check this out if(type == MOTION_BLUR_SNIPER){ if(!bJustInitialised) RenderOverlaySniper(cam, red, green, blue, blur); }else switch(EffectSwitch){ case POSTFX_OFF: case POSTFX_SIMPLE: // no actual rendering here break; case POSTFX_PSP: case POSTFX_PS2: case POSTFX_MOBILE: RenderOverlayShader(cam, red, green, blue, blur); break; } if(MotionBlurOn) if(!bJustInitialised) RenderMotionBlur(cam, bluralpha); RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE); RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil); RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE); RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); if(NeedFrontBuffer(type)){ RwRasterPushContext(pFrontBuffer); RwRasterRenderFast(RwCameraGetRaster(cam), 0, 0); RwRasterPopContext(); bJustInitialised = false; }else bJustInitialised = true; } int CPostFX::PrevRed[NUMAVERAGE], CPostFX::AvgRed; int CPostFX::PrevGreen[NUMAVERAGE], CPostFX::AvgGreen; int CPostFX::PrevBlue[NUMAVERAGE], CPostFX::AvgBlue; int CPostFX::PrevAlpha[NUMAVERAGE], CPostFX::AvgAlpha; int CPostFX::Next; int CPostFX::NumValues; // This is rather annoying...the blur color can flicker slightly // which becomes very visible when amplified by the shader void CPostFX::SmoothColor(uint32 red, uint32 green, uint32 blue, uint32 alpha) { PrevRed[Next] = red; PrevGreen[Next] = green; PrevBlue[Next] = blue; PrevAlpha[Next] = alpha; Next = (Next+1) % NUMAVERAGE; NumValues = Min(NumValues+1, NUMAVERAGE); AvgRed = 0; AvgGreen = 0; AvgBlue = 0; AvgAlpha = 0; for(int i = 0; i < NumValues; i++){ AvgRed += PrevRed[i]; AvgGreen += PrevGreen[i]; AvgBlue += PrevBlue[i]; AvgAlpha += PrevAlpha[i]; } AvgRed /= NumValues; AvgGreen /= NumValues; AvgBlue /= NumValues; AvgAlpha /= NumValues; } #endif