diff --git a/src/base.cpp b/src/base.cpp index 745ac11..375911b 100755 --- a/src/base.cpp +++ b/src/base.cpp @@ -40,6 +40,22 @@ static Matrix identMat = { }; // lazy implementation +int +strcmp_ci(const char *s1, const char *s2) +{ + char c1, c2; + for(;;){ + c1 = tolower(*s1); + c2 = tolower(*s2); + if(c1 != c2) + return c1 - c2; + if(c1 == '\0') + return 0; + s1++; + s2++; + } +} + int strncmp_ci(const char *s1, const char *s2, int n) { diff --git a/src/matfx.cpp b/src/matfx.cpp index aa7a258..0035527 100755 --- a/src/matfx.cpp +++ b/src/matfx.cpp @@ -36,8 +36,9 @@ createAtomicMatFX(void *object, int32 offset, int32) static void* copyAtomicMatFX(void *dst, void *src, int32 offset, int32) { + // don't call seteffects, it will override the pipeline if(*PLUGINOFFSET(int32, src, offset)) - MatFX::enableEffects((Atomic*)dst); + *PLUGINOFFSET(int32, dst, offset) = 1; return dst; } @@ -170,6 +171,24 @@ MatFX::setBumpCoefficient(float32 coef) 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) { @@ -194,6 +213,34 @@ MatFX::setEnvCoefficient(float32 coef) this->fx[i].env.coefficient = coef; } +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; +} + + void MatFX::setDualTexture(Texture *t) { @@ -218,6 +265,56 @@ MatFX::setDualDestBlend(int32 blend) 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) { @@ -437,6 +534,19 @@ MatFX::enableEffects(Atomic *atomic) 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) { diff --git a/src/rwanim.h b/src/rwanim.h index dad4be7..c24786b 100644 --- a/src/rwanim.h +++ b/src/rwanim.h @@ -105,6 +105,16 @@ struct AnimInterpolator // UV anim // +struct UVAnimParamData +{ + float32 theta; // rotation + float32 s0; // scale x + float32 s1; // scale y + float32 skew; // skew + float32 x; // x pos + float32 y; // y pos +}; + struct UVAnimKeyFrame { UVAnimKeyFrame *prev; @@ -162,9 +172,15 @@ struct UVAnimDictionary extern UVAnimDictionary *currentUVAnimDictionary; +// Material plugin struct UVAnim { + Matrix *uv[2]; AnimInterpolator *interp[8]; + + static bool32 exists(Material *mat); + static void addTime(Material *mat, float32 t); + static void applyUpdate(Material *mat); }; extern int32 uvAnimOffset; diff --git a/src/rwbase.h b/src/rwbase.h index c35c89a..2a1577e 100644 --- a/src/rwbase.h +++ b/src/rwbase.h @@ -579,6 +579,7 @@ extern int32 platform; extern bool32 streamAppendFrames; extern char *debugFile; +int strcmp_ci(const char *s1, const char *s2); int strncmp_ci(const char *s1, const char *s2, int n); // 0x04000000 3.1 diff --git a/src/rwplugins.h b/src/rwplugins.h index d0edf9f..86075e1 100755 --- a/src/rwplugins.h +++ b/src/rwplugins.h @@ -112,11 +112,10 @@ struct MatFX int32 dstBlend; }; struct UVtransform { - float *baseTransform; - float *dualTransform; + Matrix *baseTransform; + Matrix *dualTransform; }; struct { -// uint32 foo[32]; uint32 type; union { Bump bump; @@ -131,16 +130,32 @@ struct MatFX static uint32 getEffects(Material *m); static MatFX *get(Material *m); int32 getEffectIndex(uint32 type); + // Bump void setBumpTexture(Texture *t); void setBumpCoefficient(float32 coef); + Texture *getBumpTexture(void); + float32 getBumpCoefficient(void); + // Env void setEnvTexture(Texture *t); void setEnvFrame(Frame *f); void setEnvCoefficient(float32 coef); + Texture *getEnvTexture(void); + Frame *getEnvFrame(void); + float32 getEnvCoefficient(void); + // Dual void setDualTexture(Texture *t); void setDualSrcBlend(int32 blend); void setDualDestBlend(int32 blend); + Texture *getDualTexture(void); + int32 getDualSrcBlend(void); + int32 getDualDestBlend(void); + // UV transform + void setUVTransformMatrices(Matrix *base, Matrix *dual); + void getUVTransformMatrices(Matrix **base, Matrix **dual); static void enableEffects(Atomic *atomic); + static void disableEffects(Atomic *atomic); + static bool32 getEffects(Atomic *atomic); }; struct MatFXGlobals diff --git a/src/uvanim.cpp b/src/uvanim.cpp index fba042c..05e2fba 100644 --- a/src/uvanim.cpp +++ b/src/uvanim.cpp @@ -168,18 +168,103 @@ uvAnimStreamGetSize(Animation *anim) return 4 + 32 + 8*4 + anim->numFrames*(4 + 6*4 + 4); } +static void +uvAnimLinearApplyCB(void *result, void *frame) +{ + Matrix *m = (Matrix*)result; + UVAnimInterpFrame *f = (UVAnimInterpFrame*)frame; + m->right.x = f->uv[0]; + m->right.y = f->uv[1]; + m->right.z = 0.0f; + m->up.x = f->uv[2]; + m->up.y = f->uv[3]; + m->up.z = 0.0f; + m->at.x = 0.0f; + m->at.y = 0.0f; + m->at.z = 0.0f; + m->pos.x = f->uv[4]; + m->pos.y = f->uv[5]; + m->pos.z = 0.0f; + m->update(); +} + +static void +uvAnimLinearInterpCB(void *out, void *in1, void *in2, float32 t, void *custom) +{ + UVAnimInterpFrame *intf = (UVAnimInterpFrame*)out; + UVAnimKeyFrame *kf1 = (UVAnimKeyFrame*)in1; + UVAnimKeyFrame *kf2 = (UVAnimKeyFrame*)in2; + float32 f = (t - kf1->time) / (kf2->time - kf1->time); + intf->uv[0] = (kf2->uv[0] - kf1->uv[0])*f + kf1->uv[0]; + intf->uv[1] = (kf2->uv[1] - kf1->uv[1])*f + kf1->uv[1]; + intf->uv[2] = (kf2->uv[2] - kf1->uv[2])*f + kf1->uv[2]; + intf->uv[3] = (kf2->uv[3] - kf1->uv[3])*f + kf1->uv[3]; + intf->uv[4] = (kf2->uv[4] - kf1->uv[4])*f + kf1->uv[4]; + intf->uv[5] = (kf2->uv[5] - kf1->uv[5])*f + kf1->uv[5]; +} + +static void +uvAnimParamApplyCB(void *result, void *frame) +{ + Matrix *m = (Matrix*)result; + UVAnimInterpFrame *f = (UVAnimInterpFrame*)frame; + UVAnimParamData *p = (UVAnimParamData*)f->uv; + + m->right.x = p->s0; + m->right.y = p->skew; + m->right.z = 0.0f; + m->up.x = 0.0f; + m->up.y = p->s1; + m->up.z = 0.0f; + m->at.x = 0.0f; + m->at.y = 0.0f; + m->at.z = 0.0f; + m->pos.x = p->x; + m->pos.y = p->y; + m->pos.z = 0.0f; + m->update(); + static V3d xlat1 = { -0.5f, -0.5f, 0.0f }; + static V3d xlat2 = { 0.5f, 0.5f, 0.0f }; + static V3d axis = { 0.0f, 0.0f, 1.0f }; + m->translate(&xlat1, COMBINEPOSTCONCAT); + m->rotate(&axis, p->theta*180.0f/M_PI, COMBINEPOSTCONCAT); + m->translate(&xlat2, COMBINEPOSTCONCAT); +} + +static void +uvAnimParamInterpCB(void *out, void *in1, void *in2, float32 t, void *custom) +{ + UVAnimInterpFrame *intf = (UVAnimInterpFrame*)out; + UVAnimKeyFrame *kf1 = (UVAnimKeyFrame*)in1; + UVAnimKeyFrame *kf2 = (UVAnimKeyFrame*)in2; + float32 f = (t - kf1->time) / (kf2->time - kf1->time); + + float32 a = kf2->uv[0] - kf1->uv[0]; + while(a < M_PI) a += 2*M_PI; + while(a > M_PI) a -= 2*M_PI; + intf->uv[0] = a*f + kf1->uv[0]; + intf->uv[1] = (kf2->uv[1] - kf1->uv[1])*f + kf1->uv[1]; + intf->uv[2] = (kf2->uv[2] - kf1->uv[2])*f + kf1->uv[2]; + intf->uv[3] = (kf2->uv[3] - kf1->uv[3])*f + kf1->uv[3]; + intf->uv[4] = (kf2->uv[4] - kf1->uv[4])*f + kf1->uv[4]; + intf->uv[5] = (kf2->uv[5] - kf1->uv[5])*f + kf1->uv[5]; +} + + static void registerUVAnimInterpolator(void) { + // TODO: implement this fully + // Linear AnimInterpolatorInfo *info = rwNewT(AnimInterpolatorInfo, 1, MEMDUR_GLOBAL | ID_UVANIMATION); info->id = 0x1C0; info->interpKeyFrameSize = sizeof(UVAnimInterpFrame); info->animKeyFrameSize = sizeof(UVAnimKeyFrame); info->customDataSize = sizeof(UVAnimCustomData); - info->applyCB = nil; + info->applyCB = uvAnimLinearApplyCB; info->blendCB = nil; - info->interpCB = nil; + info->interpCB = uvAnimLinearInterpCB; info->addCB = nil; info->mulRecipCB = nil; info->streamRead = uvAnimStreamRead; @@ -193,9 +278,9 @@ registerUVAnimInterpolator(void) info->interpKeyFrameSize = sizeof(UVAnimInterpFrame); info->animKeyFrameSize = sizeof(UVAnimKeyFrame); info->customDataSize = sizeof(UVAnimCustomData); - info->applyCB = nil; + info->applyCB = uvAnimParamApplyCB; info->blendCB = nil; - info->interpCB = nil; + info->interpCB = uvAnimParamInterpCB; info->addCB = nil; info->mulRecipCB = nil; info->streamRead = uvAnimStreamRead; @@ -303,6 +388,11 @@ readUVAnim(Stream *stream, int32, void *object, int32 offset, int32) } bit <<= 1; } + // TEMP + if(uvanim->uv[0] == nil) + uvanim->uv[0] = Matrix::create(); + if(uvanim->uv[1] == nil) + uvanim->uv[1] = Matrix::create(); return stream; } @@ -358,4 +448,55 @@ registerUVAnimPlugin(void) readUVAnim, writeUVAnim, getSizeUVAnim); } +bool32 +UVAnim::exists(Material *mat) +{ + int32 i; + UVAnim *uvanim = PLUGINOFFSET(UVAnim, mat, uvAnimOffset); + for(i = 0; i < 8; i++) + if(uvanim->interp[i]) + return 1; + return 0; +} + +void +UVAnim::addTime(Material *mat, float32 t) +{ + int32 i; + UVAnim *uvanim = PLUGINOFFSET(UVAnim, mat, uvAnimOffset); + for(i = 0; i < 8; i++) + if(uvanim->interp[i]) + uvanim->interp[i]->addTime(t); +} + +void +UVAnim::applyUpdate(Material *mat) +{ + int32 i, j; + int32 uv; + Matrix m; + UVAnim *uvanim = PLUGINOFFSET(UVAnim, mat, uvAnimOffset); + for(i = 0; i < 2; i++) + if(uvanim->uv[i]) + uvanim->uv[i]->setIdentity(); + m.setIdentity(); + + for(i = 0; i < 8; i++){ + AnimInterpolator *ip = uvanim->interp[i]; + if(ip == nil) + continue; + UVAnimCustomData *custom = UVAnimCustomData::get(ip->currentAnim); + for(j = 0; j < ip->numNodes; j++){ + InterpFrameHeader *f = ip->getInterpFrame(j); + uv = custom->nodeToUVChannel[j]; + if(uv < 2 && uvanim->uv[uv]){ + ip->applyCB(&m, f); + uvanim->uv[uv]->transform(&m, COMBINEPRECONCAT); + } + } + } + MatFX *mfx = MatFX::get(mat); + if(mfx) mfx->setUVTransformMatrices(uvanim->uv[0], uvanim->uv[1]); +} + }