summaryrefslogtreecommitdiffstats
path: root/src/rw/RwMatFX.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/rw/RwMatFX.cpp')
-rw-r--r--src/rw/RwMatFX.cpp213
1 files changed, 213 insertions, 0 deletions
diff --git a/src/rw/RwMatFX.cpp b/src/rw/RwMatFX.cpp
new file mode 100644
index 00000000..ca9a633b
--- /dev/null
+++ b/src/rw/RwMatFX.cpp
@@ -0,0 +1,213 @@
+#define WITHD3D
+#include "common.h"
+#include "patcher.h"
+
+struct MatFXNothing { int pad[5]; int effect; };
+
+struct MatFXBump
+{
+ RwFrame *bumpFrame;
+ RwTexture *bumpedTex;
+ RwTexture *bumpTex;
+ float negBumpCoefficient;
+ int pad;
+ int effect;
+};
+
+struct MatFXEnv
+{
+ RwFrame *envFrame;
+ RwTexture *envTex;
+ float envCoeff;
+ int envFBalpha;
+ int pad;
+ int effect;
+};
+
+struct MatFXDual
+{
+ RwTexture *dualTex;
+ RwInt32 srcBlend;
+ RwInt32 dstBlend;
+};
+
+
+struct MatFX
+{
+ union {
+ MatFXNothing n;
+ MatFXBump b;
+ MatFXEnv e;
+ MatFXDual d;
+ } fx[2];
+ int effects;
+};
+
+int &MatFXMaterialDataOffset = *(int*)0x66188C;
+int &MatFXAtomicDataOffset = *(int*)0x66189C;
+
+#ifdef PS2_MATFX
+
+void
+_rpMatFXD3D8AtomicMatFXDefaultRender(RxD3D8InstanceData *inst, int flags, RwTexture *texture)
+{
+ if(flags & (rpGEOMETRYTEXTURED|rpGEOMETRYTEXTURED2) && texture)
+ RwD3D8SetTexture(texture, 0);
+ else
+ RwD3D8SetTexture(nil, 0);
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)(inst->vertexAlpha || inst->material->color.alpha != 0xFF));
+ RwD3D8SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, inst->vertexAlpha != 0);
+ RwD3D8SetPixelShader(0);
+ RwD3D8SetVertexShader(inst->vertexShader);
+ RwD3D8SetStreamSource(0, inst->vertexBuffer, inst->stride);
+
+ if(inst->indexBuffer){
+ RwD3D8SetIndices(inst->indexBuffer, inst->baseIndex);
+ RwD3D8DrawIndexedPrimitive(inst->primType, 0, inst->numVertices, 0, inst->numIndices);
+ }else
+ RwD3D8DrawPrimitive(inst->primType, inst->baseIndex, inst->numVertices);
+}
+
+// map [-1; -1] -> [0; 1], flip V
+static RwMatrix scalenormal = {
+ { 0.5f, 0.0f, 0.0f }, 0,
+ { 0.0f, -0.5f, 0.0f }, 0,
+ { 0.0f, 0.0f, 1.0f }, 0,
+ { 0.5f, 0.5f, 0.0f }, 0,
+
+};
+
+// flipped U for PS2
+static RwMatrix scalenormal_flipU = {
+ { -0.5f, 0.0f, 0.0f }, 0,
+ { 0.0f, -0.5f, 0.0f }, 0,
+ { 0.0f, 0.0f, 1.0f }, 0,
+ { 0.5f, 0.5f, 0.0f }, 0,
+
+};
+
+void
+ApplyEnvMapTextureMatrix(RwTexture *tex, int n, RwFrame *frame)
+{
+ RwD3D8SetTexture(tex, n);
+ RwD3D8SetTextureStageState(n, D3DRS_ALPHAREF, 2);
+ RwD3D8SetTextureStageState(n, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACENORMAL);
+ if(frame){
+ RwMatrix *envframemat = RwMatrixCreate();
+ RwMatrix *tmpmat = RwMatrixCreate();
+ RwMatrix *envmat = RwMatrixCreate();
+
+ RwMatrixInvert(envframemat, RwFrameGetLTM(frame));
+ // PS2
+ // can this be simplified?
+ *tmpmat = *RwFrameGetLTM(RwCameraGetFrame((RwCamera*)RWSRCGLOBAL(curCamera)));
+ RwV3dNegate(&tmpmat->right, &tmpmat->right);
+ tmpmat->flags = 0;
+ tmpmat->pos.x = 0.0f;
+ tmpmat->pos.y = 0.0f;
+ tmpmat->pos.z = 0.0f;
+ RwMatrixMultiply(envmat, tmpmat, envframemat);
+ *tmpmat = *envmat;
+ // important because envframemat can have a translation that we don't like
+ tmpmat->pos.x = 0.0f;
+ tmpmat->pos.y = 0.0f;
+ tmpmat->pos.z = 0.0f;
+ // for some reason we flip in U as well
+ RwMatrixMultiply(envmat, tmpmat, &scalenormal_flipU);
+
+ RwD3D8SetTransform(D3DTS_TEXTURE0+n, envmat);
+
+ RwMatrixDestroy(envmat);
+ RwMatrixDestroy(tmpmat);
+ RwMatrixDestroy(envframemat);
+ }else
+ RwD3D8SetTransform(D3DTS_TEXTURE0+n, &scalenormal);
+}
+
+void
+_rpMatFXD3D8AtomicMatFXEnvRender_ps2(RxD3D8InstanceData *inst, int flags, int sel, RwTexture *texture, RwTexture *envMap)
+{
+ MatFX *matfx = *RWPLUGINOFFSET(MatFX*, inst->material, MatFXMaterialDataOffset);
+ MatFXEnv *env = &matfx->fx[sel].e;
+
+ uint8 intens = (uint8)(env->envCoeff*255.0f);
+
+ if(intens == 0 || envMap == nil){
+ if(sel == 0)
+ _rpMatFXD3D8AtomicMatFXDefaultRender(inst, flags, texture);
+ return;
+ }
+
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)(inst->vertexAlpha || inst->material->color.alpha != 0xFF));
+ if(flags & (rpGEOMETRYTEXTURED|rpGEOMETRYTEXTURED2) && texture)
+ RwD3D8SetTexture(texture, 0);
+ else
+ RwD3D8SetTexture(nil, 0);
+ RwD3D8SetPixelShader(0);
+ RwD3D8SetVertexShader(inst->vertexShader);
+ RwD3D8SetStreamSource(0, inst->vertexBuffer, inst->stride);
+ RwD3D8SetIndices(inst->indexBuffer, inst->baseIndex);
+ if(inst->indexBuffer)
+ RwD3D8DrawIndexedPrimitive(inst->primType, 0, inst->numVertices, 0, inst->numIndices);
+ else
+ RwD3D8DrawPrimitive(inst->primType, inst->baseIndex, inst->numVertices);
+
+ // Effect pass
+
+ ApplyEnvMapTextureMatrix(envMap, 0, env->envFrame);
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+ RwUInt32 src, dst, lighting, zwrite, fog, fogcol;
+ RwRenderStateGet(rwRENDERSTATESRCBLEND, &src);
+ RwRenderStateGet(rwRENDERSTATEDESTBLEND, &dst);
+
+ // This is of course not using framebuffer alpha,
+ // but if the diffuse texture had no alpha, the result should actually be rather the same
+ if(env->envFBalpha)
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
+ else
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE);
+ RwD3D8GetRenderState(D3DRS_LIGHTING, &lighting);
+ RwD3D8GetRenderState(D3DRS_ZWRITEENABLE, &zwrite);
+ RwD3D8GetRenderState(D3DRS_FOGENABLE, &fog);
+ RwD3D8SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
+ if(fog){
+ RwD3D8GetRenderState(D3DRS_FOGCOLOR, &fogcol);
+ RwD3D8SetRenderState(D3DRS_FOGCOLOR, 0);
+ }
+
+ D3DCOLOR texfactor = D3DCOLOR_RGBA(intens, intens, intens, intens);
+ RwD3D8SetRenderState(D3DRS_TEXTUREFACTOR, texfactor);
+ RwD3D8SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE);
+ RwD3D8SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_CURRENT);
+ RwD3D8SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_TFACTOR);
+ // alpha unused
+ //RwD3D8SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
+ //RwD3D8SetTextureStageState(1, D3DTSS_ALPHAARG1, D3DTA_CURRENT);
+ //RwD3D8SetTextureStageState(1, D3DTSS_ALPHAARG2, D3DTA_TFACTOR);
+
+ if(inst->indexBuffer)
+ RwD3D8DrawIndexedPrimitive(inst->primType, 0, inst->numVertices, 0, inst->numIndices);
+ else
+ RwD3D8DrawPrimitive(inst->primType, inst->baseIndex, inst->numVertices);
+
+ // Reset states
+
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)src);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)dst);
+ RwD3D8SetRenderState(D3DRS_LIGHTING, lighting);
+ RwD3D8SetRenderState(D3DRS_ZWRITEENABLE, zwrite);
+ if(fog)
+ RwD3D8SetRenderState(D3DRS_FOGCOLOR, fogcol);
+ RwD3D8SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
+ RwD3D8SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
+ RwD3D8SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, 0);
+ RwD3D8SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0);
+}
+
+STARTPATCHES
+ InjectHook(0x5CF6C0, _rpMatFXD3D8AtomicMatFXEnvRender_ps2, PATCH_JUMP);
+ENDPATCHES
+
+#endif