#include #include #include #include #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); } }