#define WITHWINDOWS #define WITH_D3D #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_NORMAL; bool CPostFX::MotionBlurOn = false; static RwIm2DVertex Vertex[4]; static RwIm2DVertex Vertex2[4]; static RwImVertexIndex Index[6] = { 0, 1, 2, 0, 2, 3 }; #ifdef RW_D3D9 void *colourfilterIII_PS; void *contrast_PS; #endif #ifdef RW_OPENGL int32 u_blurcolor; int32 u_contrastAdd; int32 u_contrastMult; rw::gl3::Shader *colourFilterIII; 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/colourfilterIII_PS.inc" colourfilterIII_PS = rw::d3d::createPixelShader(colourfilterIII_PS_cso); #include "shaders/contrastPS.inc" contrast_PS = rw::d3d::createPixelShader(contrastPS_cso); #endif #ifdef RW_OPENGL using namespace rw::gl3; { #include "shaders/im2d_gl.inc" #include "shaders/colourfilterIII_fs_gl.inc" const char *vs[] = { shaderDecl, header_vert_src, im2d_vert_src, nil }; const char *fs[] = { shaderDecl, header_frag_src, colourfilterIII_frag_src, nil }; colourFilterIII = Shader::create(vs, fs); assert(colourFilterIII); } { #include "shaders/im2d_gl.inc" #include "shaders/contrast_fs_gl.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(colourfilterIII_PS){ rw::d3d::destroyPixelShader(colourfilterIII_PS); colourfilterIII_PS = nil; } if(contrast_PS){ rw::d3d::destroyPixelShader(contrast_PS); contrast_PS = nil; } #endif #ifdef RW_OPENGL if(colourFilterIII){ colourFilterIII->destroy(); colourFilterIII = nil; } if(contrast){ contrast->destroy(); contrast = nil; } #endif } void CPostFX::RenderOverlayBlur(RwCamera *cam, int32 r, int32 g, int32 b, int32 a) { RwRenderStateSet(rwRENDERSTATETEXTURERASTER, pFrontBuffer); RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); 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(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); RwIm2DRenderIndexedPrimitive(rwPRIMTYPETRILIST, Vertex, 4, Index, 6); } void CPostFX::RenderOverlaySimple(RwCamera *cam, int32 r, int32 g, int32 b, int32 a) { RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil); RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); r *= 0.6f; g *= 0.6f; b *= 0.6f; a *= 0.6f; 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(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); RwIm2DRenderIndexedPrimitive(rwPRIMTYPETRILIST, 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)/384.0f + 1.14f; mult[1] = (g-64)/384.0f + 1.14f; mult[2] = (b-64)/384.0f + 1.14f; add[0] = r/1536.f; add[1] = g/1536.f; add[2] = b/1536.f; #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/255.0f; blurcolors[1] = g/255.0f; blurcolors[2] = b/255.0f; blurcolors[3] = a*f/255.0f; #ifdef RW_D3D9 rw::d3d::d3ddevice->SetPixelShaderConstantF(10, blurcolors, 1); rw::d3d::im2dOverridePS = colourfilterIII_PS; #endif #ifdef RW_OPENGL rw::gl3::im2dOverrideShader = colourFilterIII; colourFilterIII->use(); glUniform4fv(colourFilterIII->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: // no actual rendering here return false; case POSTFX_SIMPLE: return false; case POSTFX_NORMAL: if(MotionBlurOn) return false; else return true; 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::Render(RwCamera *cam, uint32 red, uint32 green, uint32 blue, uint32 blur, int32 type, uint32 bluralpha) { switch(type) { case MOTION_BLUR_SECURITY_CAM: red = 0; green = 255; blue = 0; blur = 128; break; case MOTION_BLUR_INTRO: red = 100; green = 220; blue = 230; blur = 158; break; case MOTION_BLUR_INTRO2: red = 80; green = 255; blue = 230; blur = 138; break; case MOTION_BLUR_INTRO3: red = 255; green = 60; blue = 60; blur = 200; break; case MOTION_BLUR_INTRO4: red = 255; green = 180; blue = 180; blur = 128; break; } if(pFrontBuffer == nil) Open(cam); assert(pFrontBuffer); assert(pBackBuffer); if(NeedBackBuffer()){ RwRasterPushContext(pBackBuffer); RwRasterRenderFast(RwCameraGetRaster(cam), 0, 0); RwRasterPopContext(); } DefinedState(); RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE); RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERNEAREST); RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE); RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE); if(type == MOTION_BLUR_SNIPER){ if(!bJustInitialised) RenderOverlaySniper(cam, red, green, blue, blur); }else switch(EffectSwitch){ case POSTFX_OFF: // no actual rendering here break; case POSTFX_SIMPLE: RenderOverlaySimple(cam, red, green, blue, blur); break; case POSTFX_NORMAL: if(MotionBlurOn){ if(!bJustInitialised) RenderOverlayBlur(cam, red, green, blue, blur); }else{ RenderOverlayShader(cam, red, green, blue, blur); } break; case POSTFX_MOBILE: RenderOverlayShader(cam, red, green, blue, blur); break; } // TODO? maybe we want this even without motion blur on sometimes? 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; } #endif