From 9f61c9e6ac6b1ac5692cf6352d2ebbd47a31a686 Mon Sep 17 00:00:00 2001 From: claude-bot Date: Mon, 13 Jul 2026 12:27:07 +0000 Subject: Import Cai1Hsu/re3 @ miami (reVC / GTA:VC decompilation) Snapshot import (no upstream history) into git.ancap.in.ua/claude, per @lzcnt. Source: https://github.com/Cai1Hsu/re3 branch miami. --- src/rw/RwMatFX.cpp | 312 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 312 insertions(+) create mode 100644 src/rw/RwMatFX.cpp (limited to 'src/rw/RwMatFX.cpp') diff --git a/src/rw/RwMatFX.cpp b/src/rw/RwMatFX.cpp new file mode 100644 index 0000000..c8384b0 --- /dev/null +++ b/src/rw/RwMatFX.cpp @@ -0,0 +1,312 @@ +#ifndef LIBRW + +#define WITHD3D +#include "common.h" +#include "rpmatfx.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; +}; + +extern "C" { + extern int MatFXMaterialDataOffset; + extern int MatFXAtomicDataOffset; + + void _rpMatFXD3D8AtomicMatFXEnvRender(RxD3D8InstanceData* inst, int flags, int sel, RwTexture* texture, RwTexture* envMap); + void _rpMatFXD3D8AtomicMatFXRenderBlack(RxD3D8InstanceData *inst); + void _rpMatFXD3D8AtomicMatFXBumpMapRender(RxD3D8InstanceData *inst, int flags, RwTexture *texture, RwTexture *bumpMap, RwTexture *envMap); + void _rpMatFXD3D8AtomicMatFXDualPassRender(RxD3D8InstanceData *inst, int flags, RwTexture *texture, RwTexture *dualTexture); +} + + +#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); +} + +void +_rwD3D8EnableClippingIfNeeded(void *object, RwUInt8 type) +{ + int clip; + if (type == rpATOMIC) + clip = !RwD3D8CameraIsSphereFullyInsideFrustum(RwCameraGetCurrentCameraMacro(), RpAtomicGetWorldBoundingSphere((RpAtomic *)object)); + else + clip = !RwD3D8CameraIsBBoxFullyInsideFrustum(RwCameraGetCurrentCameraMacro(), &((RpWorldSector *)object)->tightBoundingBox); + RwD3D8SetRenderState(D3DRS_CLIPPING, clip); +} + +void +_rwD3D8AtomicMatFXRenderCallback(RwResEntry *repEntry, void *object, RwUInt8 type, RwUInt32 flags) +{ + RwBool lighting; + RwBool forceBlack; + RxD3D8ResEntryHeader *header; + RxD3D8InstanceData *inst; + RwInt32 i; + + if (flags & rpGEOMETRYPRELIT) { + RwD3D8SetRenderState(D3DRS_COLORVERTEX, 1); + RwD3D8SetRenderState(D3DRS_EMISSIVEMATERIALSOURCE, D3DMCS_COLOR1); + } else { + RwD3D8SetRenderState(D3DRS_COLORVERTEX, 0); + RwD3D8SetRenderState(D3DRS_EMISSIVEMATERIALSOURCE, D3DMCS_MATERIAL); + } + + _rwD3D8EnableClippingIfNeeded(object, type); + + RwD3D8GetRenderState(D3DRS_LIGHTING, &lighting); + if (lighting || flags & rpGEOMETRYPRELIT) { + forceBlack = FALSE; + } else { + forceBlack = TRUE; + RwD3D8SetTexture(nil, 0); + RwD3D8SetRenderState(D3DRS_TEXTUREFACTOR, D3DCOLOR_RGBA(0, 0, 0, 255)); + RwD3D8SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG2); + RwD3D8SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_TFACTOR); + } + + header = (RxD3D8ResEntryHeader *)(repEntry + 1); + inst = (RxD3D8InstanceData *)(header + 1); + for (i = 0; i < header->numMeshes; i++) { + if (forceBlack) + _rpMatFXD3D8AtomicMatFXRenderBlack(inst); + else { + if (lighting) + RwD3D8SetSurfaceProperties(&inst->material->color, &inst->material->surfaceProps, flags & rpGEOMETRYMODULATEMATERIALCOLOR); + MatFX *matfx = *RWPLUGINOFFSET(MatFX *, inst->material, MatFXMaterialDataOffset); + int effect = matfx ? matfx->effects : rpMATFXEFFECTNULL; + switch (effect) { + case rpMATFXEFFECTNULL: + default: + _rpMatFXD3D8AtomicMatFXDefaultRender(inst, flags, inst->material->texture); + break; + case rpMATFXEFFECTBUMPMAP: + _rpMatFXD3D8AtomicMatFXBumpMapRender(inst, flags, inst->material->texture, matfx->fx[0].b.bumpedTex, nil); + break; + case rpMATFXEFFECTENVMAP: + { + // TODO: matfx switch in the settings + //_rpMatFXD3D8AtomicMatFXEnvRender(inst, flags, 0, inst->material->texture, matfx->fx[0].e.envTex); + _rpMatFXD3D8AtomicMatFXEnvRender_ps2(inst, flags, 0, inst->material->texture, matfx->fx[0].e.envTex); + break; + } + case rpMATFXEFFECTBUMPENVMAP: + _rpMatFXD3D8AtomicMatFXBumpMapRender(inst, flags, inst->material->texture, matfx->fx[0].b.bumpedTex, matfx->fx[1].e.envTex); + break; + case rpMATFXEFFECTDUAL: + _rpMatFXD3D8AtomicMatFXDualPassRender(inst, flags, inst->material->texture, matfx->fx[0].d.dualTex); + break; + } + } + inst++; + } + + if (forceBlack) { + RwD3D8SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG2); + RwD3D8SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + } +} + +void +ReplaceMatFxCallback() +{ + RxD3D8AllInOneSetRenderCallBack( + RxPipelineFindNodeByName(RpMatFXGetD3D8Pipeline(rpMATFXD3D8ATOMICPIPELINE), RxNodeDefinitionGetD3D8AtomicAllInOne()->name, nil, nil), + _rwD3D8AtomicMatFXRenderCallback); + +} +#endif // PS2_MATFX + +#endif // !LIBRW -- cgit v1.2.3