diff options
| author | claude-bot <[email protected]> | 2026-07-13 12:40:03 +0000 |
|---|---|---|
| committer | claude-bot <[email protected]> | 2026-07-13 12:40:03 +0000 |
| commit | 847962910f0bff071f3bf07c9abb87764fb6cac3 (patch) | |
| tree | ddcd429e134c7fd5f72ddc97ced175de8d66fcd0 /src/matfx.cpp | |
| download | librw-master.tar.gz librw-master.zip | |
Snapshot for re3/reVC vendoring, per @lzcnt.
Source: https://github.com/aap/librw (master).
Diffstat (limited to 'src/matfx.cpp')
| -rw-r--r-- | src/matfx.cpp | 641 |
1 files changed, 641 insertions, 0 deletions
diff --git a/src/matfx.cpp b/src/matfx.cpp new file mode 100644 index 0000000..c143fc1 --- /dev/null +++ b/src/matfx.cpp @@ -0,0 +1,641 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#include "rwbase.h" +#include "rwerror.h" +#include "rwplg.h" +#include "rwpipeline.h" +#include "rwobjects.h" +#include "rwengine.h" +#include "rwanim.h" +#include "rwplugins.h" +#include "ps2/rwps2.h" +#include "ps2/rwps2plg.h" +#include "d3d/rwxbox.h" +#include "d3d/rwd3d8.h" +#include "d3d/rwd3d9.h" +#include "gl/rwwdgl.h" +#include "gl/rwgl3.h" +#include "gl/rwgl3plg.h" + +#define PLUGIN_ID ID_MATFX + +namespace rw { + +bool32 MatFX::envMapFlipU; +bool32 MatFX::envMapApplyLight; +bool32 MatFX::envMapUseMatColor; +RGBA MatFX::envMapColor = { 255, 255, 255, 255 }; + + +// Atomic + +static void* +createAtomicMatFX(void *object, int32 offset, int32) +{ + *PLUGINOFFSET(int32, object, offset) = 0; + return object; +} + +static void* +copyAtomicMatFX(void *dst, void *src, int32 offset, int32) +{ + // don't call seteffects, it will override the pipeline + if(*PLUGINOFFSET(int32, src, offset)) + *PLUGINOFFSET(int32, dst, offset) = 1; + return dst; +} + +static Stream* +readAtomicMatFX(Stream *stream, int32, void *object, int32, int32) +{ + if(stream->readI32()) + MatFX::enableEffects((Atomic*)object); + return stream; +} + +static Stream* +writeAtomicMatFX(Stream *stream, int32, void *object, int32 offset, int32) +{ + stream->writeI32(*PLUGINOFFSET(int32, object, offset)); + return stream; +} + +static int32 +getSizeAtomicMatFX(void *object, int32 offset, int32) +{ + int32 flag = *PLUGINOFFSET(int32, object, offset); + // TODO: not sure which version + return flag || rw::version < 0x34000 ? 4 : 0; +} + +// Material + +MatFXGlobals matFXGlobals = { 0, 0, { nil }, nil }; + +// TODO: Frames and Matrices? +static void +clearMatFX(MatFX *matfx) +{ + for(int i = 0; i < 2; i++) + switch(matfx->fx[i].type){ + case MatFX::BUMPMAP: + if(matfx->fx[i].bump.bumpedTex) + matfx->fx[i].bump.bumpedTex->destroy(); + if(matfx->fx[i].bump.tex) + matfx->fx[i].bump.tex->destroy(); + break; + + case MatFX::ENVMAP: + if(matfx->fx[i].env.tex) + matfx->fx[i].env.tex->destroy(); + break; + + case MatFX::DUAL: + if(matfx->fx[i].dual.tex) + matfx->fx[i].dual.tex->destroy(); + break; + } + memset(matfx, 0, sizeof(MatFX)); +} + +void +MatFX::setEffects(Material *mat, uint32 type) +{ + MatFX *matfx; + + matfx = MatFX::get(mat); + if(matfx == nil){ + matfx = rwNewT(MatFX, 1, MEMDUR_EVENT | ID_MATFX); + memset(matfx, 0, sizeof(MatFX)); + *PLUGINOFFSET(MatFX*, mat, matFXGlobals.materialOffset) = matfx; + } + + if(matfx->type != 0 && matfx->type != type) + clearMatFX(matfx); + matfx->type = type; + switch(type){ + case BUMPMAP: + case ENVMAP: + case DUAL: + case UVTRANSFORM: + matfx->fx[0].type = type; + matfx->fx[1].type = NOTHING; + break; + + case BUMPENVMAP: + matfx->fx[0].type = BUMPMAP; + matfx->fx[1].type = ENVMAP; + break; + + case DUALUVTRANSFORM: + matfx->fx[0].type = UVTRANSFORM; + matfx->fx[1].type = DUAL; + break; + } +} + +uint32 +MatFX::getEffects(const Material *m) +{ + MatFX *fx = *PLUGINOFFSET(MatFX*, m, matFXGlobals.materialOffset); + if(fx) + return fx->type; + return 0; +} + +MatFX* +MatFX::get(const Material *m) +{ + return *PLUGINOFFSET(MatFX*, m, matFXGlobals.materialOffset); +} + +int32 +MatFX::getEffectIndex(uint32 type) +{ + for(int i = 0; i < 2; i++) + if(this->fx[i].type == type) + return i; + return -1; +} + +void +MatFX::setBumpTexture(Texture *t) +{ + int32 i = this->getEffectIndex(BUMPMAP); + if(i >= 0){ + if(this->fx[i].bump.tex) + this->fx[i].bump.tex->destroy(); + this->fx[i].bump.tex = t; + if(t) + t->addRef(); + } +} + +void +MatFX::setBumpCoefficient(float32 coef) +{ + int32 i = this->getEffectIndex(BUMPMAP); + if(i >= 0) + this->fx[i].bump.coefficient = coef; +} + +Texture* +MatFX::getBumpTexture(void) +{ + int32 i = this->getEffectIndex(BUMPMAP); + if(i >= 0) + return this->fx[i].bump.tex; + return nil; +} + +float32 +MatFX::getBumpCoefficient(void) +{ + int32 i = this->getEffectIndex(BUMPMAP); + if(i >= 0) + return this->fx[i].bump.coefficient; + return 0.0f; +} + +void +MatFX::setEnvTexture(Texture *t) +{ + int32 i = this->getEffectIndex(ENVMAP); + if(i >= 0){ + if(this->fx[i].env.tex) + this->fx[i].env.tex->destroy(); + this->fx[i].env.tex = t; + if(t) + t->addRef(); + } +} + +void +MatFX::setEnvFrame(Frame *f) +{ + int32 i = this->getEffectIndex(ENVMAP); + if(i >= 0) + this->fx[i].env.frame = f; +} + +void +MatFX::setEnvCoefficient(float32 coef) +{ + int32 i = this->getEffectIndex(ENVMAP); + if(i >= 0) + this->fx[i].env.coefficient = coef; +} + +void +MatFX::setEnvFBAlpha(bool32 useFBAlpha) +{ + int32 i = this->getEffectIndex(ENVMAP); + if(i >= 0) + this->fx[i].env.fbAlpha = useFBAlpha; +} + +Texture* +MatFX::getEnvTexture(void) +{ + int32 i = this->getEffectIndex(ENVMAP); + if(i >= 0) + return this->fx[i].env.tex; + return nil; +} + +Frame* +MatFX::getEnvFrame(void) +{ + int32 i = this->getEffectIndex(ENVMAP); + if(i >= 0) + return this->fx[i].env.frame; + return nil; +} + +float32 +MatFX::getEnvCoefficient(void) +{ + int32 i = this->getEffectIndex(ENVMAP); + if(i >= 0) + return this->fx[i].env.coefficient; + return 0.0f; +} + +bool32 +MatFX::getEnvFBAlpha(void) +{ + int32 i = this->getEffectIndex(ENVMAP); + if(i >= 0) + return this->fx[i].env.fbAlpha; + return 0; +} + + +void +MatFX::setDualTexture(Texture *t) +{ + int32 i = this->getEffectIndex(DUAL); + if(i >= 0){ + if(this->fx[i].dual.tex) + this->fx[i].dual.tex->destroy(); + this->fx[i].dual.tex = t; + if(t) + t->addRef(); + } +} + +void +MatFX::setDualSrcBlend(int32 blend) +{ + int32 i = this->getEffectIndex(DUAL); + if(i >= 0) + this->fx[i].dual.srcBlend = blend; +} + +void +MatFX::setDualDestBlend(int32 blend) +{ + int32 i = this->getEffectIndex(DUAL); + if(i >= 0) + this->fx[i].dual.dstBlend = blend; +} + +Texture* +MatFX::getDualTexture(void) +{ + int32 i = this->getEffectIndex(DUAL); + if(i >= 0) + return this->fx[i].dual.tex; + return nil; +} + +int32 +MatFX::getDualSrcBlend(void) +{ + int32 i = this->getEffectIndex(DUAL); + if(i >= 0) + return this->fx[i].dual.srcBlend; + return 0; +} + +int32 +MatFX::getDualDestBlend(void) +{ + int32 i = this->getEffectIndex(DUAL); + if(i >= 0) + return this->fx[i].dual.dstBlend; + return 0; +} + +void +MatFX::setUVTransformMatrices(Matrix *base, Matrix *dual) +{ + int32 i = this->getEffectIndex(UVTRANSFORM); + if(i >= 0){ + this->fx[i].uvtransform.baseTransform = base; + this->fx[i].uvtransform.dualTransform = dual; + } +} + +void +MatFX::getUVTransformMatrices(Matrix **base, Matrix **dual) +{ + int32 i = this->getEffectIndex(UVTRANSFORM); + if(i >= 0){ + if(base) *base = this->fx[i].uvtransform.baseTransform; + if(dual) *dual = this->fx[i].uvtransform.dualTransform; + return; + } + if(base) *base = nil; + if(dual) *dual = nil; +} + +static void* +createMaterialMatFX(void *object, int32 offset, int32) +{ + *PLUGINOFFSET(MatFX*, object, offset) = nil; + return object; +} + +static void* +destroyMaterialMatFX(void *object, int32 offset, int32) +{ + MatFX *matfx = *PLUGINOFFSET(MatFX*, object, offset); + if(matfx){ + clearMatFX(matfx); + rwFree(matfx); + } + return object; +} + +static void* +copyMaterialMatFX(void *dst, void *src, int32 offset, int32) +{ + MatFX *srcfx = *PLUGINOFFSET(MatFX*, src, offset); + if(srcfx == nil) + return dst; + MatFX *dstfx = rwNewT(MatFX, 1, MEMDUR_EVENT | ID_MATFX); + *PLUGINOFFSET(MatFX*, dst, offset) = dstfx; + memcpy(dstfx, srcfx, sizeof(MatFX)); + for(int i = 0; i < 2; i++) + switch(dstfx->fx[i].type){ + case MatFX::BUMPMAP: + if(dstfx->fx[i].bump.bumpedTex) + dstfx->fx[i].bump.bumpedTex->addRef(); + if(dstfx->fx[i].bump.tex) + dstfx->fx[i].bump.tex->addRef(); + break; + + case MatFX::ENVMAP: + if(dstfx->fx[i].env.tex) + dstfx->fx[i].env.tex->addRef(); + break; + + case MatFX::DUAL: + if(dstfx->fx[i].dual.tex) + dstfx->fx[i].dual.tex->addRef(); + break; + } + return dst; +} + +static Stream* +readMaterialMatFX(Stream *stream, int32, void *object, int32 offset, int32) +{ + Material *mat; + MatFX *matfx; + Texture *tex, *bumpedTex; + float coefficient; + int32 fbAlpha; + int32 srcBlend, dstBlend; + int32 idx; + + mat = (Material*)object; + MatFX::setEffects(mat, stream->readU32()); + matfx = MatFX::get(mat); + + for(int i = 0; i < 2; i++){ + uint32 type = stream->readU32(); + switch(type){ + case MatFX::BUMPMAP: + coefficient = stream->readF32(); + bumpedTex = tex = nil; + if(stream->readI32()){ + if(!findChunk(stream, ID_TEXTURE, + nil, nil)){ + RWERROR((ERR_CHUNK, "TEXTURE")); + return nil; + } + bumpedTex = Texture::streamRead(stream); + } + if(stream->readI32()){ + if(!findChunk(stream, ID_TEXTURE, + nil, nil)){ + RWERROR((ERR_CHUNK, "TEXTURE")); + return nil; + } + tex = Texture::streamRead(stream); + } + idx = matfx->getEffectIndex(type); + assert(idx >= 0); + matfx->fx[idx].bump.bumpedTex = bumpedTex; + matfx->fx[idx].bump.tex = tex; + matfx->fx[idx].bump.coefficient = coefficient; + break; + + case MatFX::ENVMAP: + coefficient = stream->readF32(); + fbAlpha = stream->readI32(); + tex = nil; + if(stream->readI32()){ + if(!findChunk(stream, ID_TEXTURE, + nil, nil)){ + RWERROR((ERR_CHUNK, "TEXTURE")); + return nil; + } + tex = Texture::streamRead(stream); + } + idx = matfx->getEffectIndex(type); + assert(idx >= 0); + matfx->fx[idx].env.tex = tex; + matfx->fx[idx].env.fbAlpha = fbAlpha; + matfx->fx[idx].env.coefficient = coefficient; + break; + + case MatFX::DUAL: + srcBlend = stream->readI32(); + dstBlend = stream->readI32(); + tex = nil; + if(stream->readI32()){ + if(!findChunk(stream, ID_TEXTURE, + nil, nil)){ + RWERROR((ERR_CHUNK, "TEXTURE")); + return nil; + } + tex = Texture::streamRead(stream); + } + idx = matfx->getEffectIndex(type); + assert(idx >= 0); + matfx->fx[idx].dual.tex = tex; + matfx->fx[idx].dual.srcBlend = srcBlend; + matfx->fx[idx].dual.dstBlend = dstBlend; + break; + } + } + return stream; +} + +static Stream* +writeMaterialMatFX(Stream *stream, int32, void *object, int32 offset, int32) +{ + MatFX *matfx = *PLUGINOFFSET(MatFX*, object, offset); + + stream->writeU32(matfx->type); + for(int i = 0; i < 2; i++){ + stream->writeU32(matfx->fx[i].type); + switch(matfx->fx[i].type){ + case MatFX::BUMPMAP: + stream->writeF32(matfx->fx[i].bump.coefficient); + stream->writeI32(matfx->fx[i].bump.bumpedTex != nil); + if(matfx->fx[i].bump.bumpedTex) + matfx->fx[i].bump.bumpedTex->streamWrite(stream); + stream->writeI32(matfx->fx[i].bump.tex != nil); + if(matfx->fx[i].bump.tex) + matfx->fx[i].bump.tex->streamWrite(stream); + break; + + case MatFX::ENVMAP: + stream->writeF32(matfx->fx[i].env.coefficient); + stream->writeI32(matfx->fx[i].env.fbAlpha); + stream->writeI32(matfx->fx[i].env.tex != nil); + if(matfx->fx[i].env.tex) + matfx->fx[i].env.tex->streamWrite(stream); + break; + + case MatFX::DUAL: + stream->writeI32(matfx->fx[i].dual.srcBlend); + stream->writeI32(matfx->fx[i].dual.dstBlend); + stream->writeI32(matfx->fx[i].dual.tex != nil); + if(matfx->fx[i].dual.tex) + matfx->fx[i].dual.tex->streamWrite(stream); + break; + } + } + return stream; +} + +static int32 +getSizeMaterialMatFX(void *object, int32 offset, int32) +{ + MatFX *matfx = *PLUGINOFFSET(MatFX*, object, offset); + if(matfx == nil) + return -1; + int32 size = 4 + 4 + 4; + + for(int i = 0; i < 2; i++){ + switch(matfx->fx[i].type){ + case MatFX::BUMPMAP: + size += 4 + 4 + 4; + if(matfx->fx[i].bump.bumpedTex) + size += 12 + + matfx->fx[i].bump.bumpedTex->streamGetSize(); + if(matfx->fx[i].bump.tex) + size += 12 + + matfx->fx[i].bump.tex->streamGetSize(); + break; + + case MatFX::ENVMAP: + size += 4 + 4 + 4; + if(matfx->fx[i].env.tex) + size += 12 + + matfx->fx[i].env.tex->streamGetSize(); + break; + + case MatFX::DUAL: + size += 4 + 4 + 4; + if(matfx->fx[i].dual.tex) + size += 12 + + matfx->fx[i].dual.tex->streamGetSize(); + break; + } + } + return size; +} + +void +MatFX::enableEffects(Atomic *atomic) +{ + *PLUGINOFFSET(int32, atomic, matFXGlobals.atomicOffset) = 1; + atomic->pipeline = matFXGlobals.pipelines[rw::platform]; +} + +// This prevents setting the pipeline on clone +void +MatFX::disableEffects(Atomic *atomic) +{ + *PLUGINOFFSET(int32, atomic, matFXGlobals.atomicOffset) = 0; +} + +bool32 +MatFX::getEffects(Atomic *atomic) +{ + return *PLUGINOFFSET(int32, atomic, matFXGlobals.atomicOffset); +} + +static void* +matfxOpen(void *o, int32, int32) +{ + // init dummy pipelines + matFXGlobals.dummypipe = ObjPipeline::create(); + matFXGlobals.dummypipe->pluginID = 0; //ID_MATFX; + matFXGlobals.dummypipe->pluginData = 0; + for(uint i = 0; i < nelem(matFXGlobals.pipelines); i++) + matFXGlobals.pipelines[i] = matFXGlobals.dummypipe; + return o; +} + +static void* +matfxClose(void *o, int32, int32) +{ + for(uint i = 0; i < nelem(matFXGlobals.pipelines); i++) + if(matFXGlobals.pipelines[i] == matFXGlobals.dummypipe) + matFXGlobals.pipelines[i] = nil; + matFXGlobals.dummypipe->destroy(); + matFXGlobals.dummypipe = nil; + return o; +} + +void +registerMatFXPlugin(void) +{ + Driver::registerPlugin(PLATFORM_NULL, 0, ID_MATFX, + matfxOpen, matfxClose); + ps2::initMatFX(); + xbox::initMatFX(); + d3d8::initMatFX(); + d3d9::initMatFX(); + wdgl::initMatFX(); + gl3::initMatFX(); + + matFXGlobals.atomicOffset = + Atomic::registerPlugin(sizeof(int32), ID_MATFX, + createAtomicMatFX, nil, copyAtomicMatFX); + Atomic::registerPluginStream(ID_MATFX, + readAtomicMatFX, + writeAtomicMatFX, + getSizeAtomicMatFX); + + matFXGlobals.materialOffset = + Material::registerPlugin(sizeof(MatFX*), ID_MATFX, + createMaterialMatFX, destroyMaterialMatFX, + copyMaterialMatFX); + Material::registerPluginStream(ID_MATFX, + readMaterialMatFX, + writeMaterialMatFX, + getSizeMaterialMatFX); +} + +} |
