/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "watchmaker/ll/ll_mesh.h" #include "watchmaker/types.h" #include "watchmaker/t3d.h" #include "watchmaker/3d/math/llmath.h" #include "watchmaker/3d/geometry.h" #include "watchmaker/windows_hacks.h" #include "watchmaker/define.h" #include "watchmaker/globvar.h" #include "watchmaker/ll/ll_util.h" #include "watchmaker/3d/animation.h" #include "watchmaker/utils.h" #include "watchmaker/ll/ll_mouse.h" #include "watchmaker/walk/walkutil.h" #include "watchmaker/walk/walk.h" #include "watchmaker/ll/ll_system.h" namespace Watchmaker { // locals struct t3dHEADMOVE { t3dV3F OldPos, DestAng, CurAng; }; t3dHEADMOVE HeadMove[T3D_MAX_CHARACTERS]; t3dF32 OldArrowLen, OldExplosionScale; uint32 **SavedBodyLight; uint8 LastLightChar, LastLightRoom; /* -----------------14/04/99 18.24------------------- * t3dUpdateArrow * --------------------------------------------------*/ void t3dUpdateArrow(t3dMESH *m, t3dF32 len) { uint32 i; if (!m) return; m->VBptr = m->VertexBuffer; for (i = 0; i < m->NumVerts; i++) if (fabs(m->VBptr[i].z) > 1.0f) m->VBptr[i].z += (-len + OldArrowLen); m->Flags |= T3D_MESH_UPDATEVB; m->VBptr = nullptr; OldArrowLen = len; } /* -----------------27/04/99 10.52------------------- * t3dLightRoom * --------------------------------------------------*/ void t3dLightRoom(Init &init, t3dBODY *b, t3dV3F *p, t3dF32 NearRange, t3dF32 FarRange, t3dF32 IperRange) { uint32 i, j, k, rr, gg, bb, aa, cr, cb, cg, *sbl; uint32 addr = 110; uint32 addg = 95; uint32 addb = 80; t3dMESH *m; t3dF32 dist; t3dV3F tmp; gVertex *gv; if (!b || !p) return; FarRange *= FarRange; NearRange *= NearRange; IperRange *= IperRange; if (!SavedBodyLight) { if (!(SavedBodyLight = (uint32 **)t3dMalloc(sizeof(uint32 *) * b->NumMeshes()))) return ; m = &b->MeshTable[0]; for (j = 0; j < b->NumMeshes(); j++, m++) { if (!m) continue; if (!(SavedBodyLight[j] = (uint32 *)t3dMalloc(sizeof(uint32) * m->NumVerts * 4))) continue; gv = m->VBptr; m->VBptr = m->VertexBuffer; for (i = 0; i < m->NumVerts; i++, gv++) { SavedBodyLight[j][i * 4 + 0] = RGBA_GETRED(gv->diffuse); SavedBodyLight[j][i * 4 + 1] = RGBA_GETGREEN(gv->diffuse); SavedBodyLight[j][i * 4 + 2] = RGBA_GETBLUE(gv->diffuse); SavedBodyLight[j][i * 4 + 3] = RGBA_GETALPHA(gv->diffuse); } m->VBptr = nullptr; } } LastLightRoom = (LastLightRoom + 1) > 3 ? 0 : LastLightRoom + 1; m = &b->MeshTable[0]; for (j = 0; j < b->NumMeshes(); j++, m++) { if (!m) continue; if (m->name.equalsIgnoreCase("p50-cielo") || m->name.equalsIgnoreCase("p50-stelle") || m->name.equalsIgnoreCase("p50-luna")) continue; if (!(m->Flags & T3D_MESH_VISIBLE) && !(m->Flags & T3D_MESH_HIDDEN)) { m->Flags &= ~T3D_MESH_HIDDEN; continue; } m->Flags &= ~T3D_MESH_HIDDEN; // if( (j%4) != LastLightRoom ) continue; sbl = (uint32 *)&SavedBodyLight[j][0]; for (k = 0; k < MAX_OBJ_MESHLINKS ; k++) { if (((!init.Obj[oNEXTPORTAL].meshLinkIsEmpty(k)) && (m->name.equalsIgnoreCase(init.Obj[oNEXTPORTAL].getMeshLink(k)))) || m->name.equalsIgnoreCase("p50-sentierini01") || m->name.equalsIgnoreCase("p50-sentierini02") || m->name.equalsIgnoreCase("p50-sentierini03") || m->name.equalsIgnoreCase("p50-sentierini04") || m->name.equalsIgnoreCase("p50-sentierini05") || m->name.equalsIgnoreCase("p50-sentierini06")) { tmp.x = m->Pos.x - p->x; tmp.z = m->Pos.z - p->z; gv = m->VBptr; m->VBptr = m->VertexBuffer; if ((dist = tmp.x * tmp.x + tmp.z * tmp.z) > (FarRange + m->Radius * m->Radius * 1.3f)) { if ((bGolfMode == 0) || (bGolfMode == 1)) if (dist > (FarRange + m->Radius * m->Radius) * 2.5f) m->Flags |= T3D_MESH_HIDDEN; for (i = 0; i < m->NumVerts; i++, gv++) { rr = *sbl++; gg = *sbl++; bb = *sbl++; aa = *sbl++; gv->diffuse = RGBA_MAKE(rr, gg, bb, aa); } } else { for (i = 0; i < m->NumVerts; i++, gv++) { tmp.x = gv->x - p->x; tmp.z = gv->z - p->z; if ((dist = tmp.x * tmp.x + tmp.z * tmp.z) < IperRange) { rr = *sbl++ + addr * 2; gg = *sbl++ + addg * 2; bb = *sbl++ + addb * 2; } else if (dist < NearRange) { rr = *sbl++ + addr; gg = *sbl++ + addg; bb = *sbl++ + addb; } else if (dist < FarRange) { dist = 1.0f - (dist - NearRange) / (FarRange - NearRange); rr = *sbl++ + (uint32)((t3dF32)(addr) * dist); gg = *sbl++ + (uint32)((t3dF32)(addg) * dist); bb = *sbl++ + (uint32)((t3dF32)(addb) * dist); } else { rr = *sbl++; gg = *sbl++; bb = *sbl++; } aa = *sbl++; if (rr > 255) rr = 255; if (gg > 255) gg = 255; if (bb > 255) bb = 255; gv->diffuse = RGBA_MAKE(rr, gg, bb, aa); } } m->Flags |= T3D_MESH_UPDATEVB; m->VBptr = nullptr; break; } } if (k < MAX_OBJ_MESHLINKS) continue; tmp.x = m->Pos.x - p->x + m->Trasl.x; tmp.z = m->Pos.z - p->z + m->Trasl.z; if ((dist = tmp.x * tmp.x + tmp.z * tmp.z) < IperRange) { cr = addr * 2; cg = addg * 2; cb = addb * 2; } else if (dist < NearRange) { cr = addr; cg = addg; cb = addb; } else if (dist < FarRange) { dist = 1.0f - (dist - NearRange) / (FarRange - NearRange); cr = (uint32)((t3dF32)(addr) * dist); cg = (uint32)((t3dF32)(addg) * dist); cb = (uint32)((t3dF32)(addb) * dist); } else { if ((bGolfMode == 0) || (bGolfMode == 1)) if (dist > (FarRange + m->Radius * m->Radius) * 2.5f) m->Flags |= T3D_MESH_HIDDEN; cr = 0; cg = 0; cb = 0; } gv = m->VBptr; m->VBptr = m->VertexBuffer; for (i = 0; i < m->NumVerts; i++, gv++) { rr = cr + *sbl++; gg = cg + *sbl++; bb = cb + *sbl++; aa = *sbl++; if (rr > 255) rr = 255; if (gg > 255) gg = 255; if (bb > 255) bb = 255; gv->diffuse = RGBA_MAKE(rr, gg, bb, aa); } m->Flags |= T3D_MESH_UPDATEVB; m->VBptr = nullptr; } } /* -----------------27/04/99 15.35------------------- * t3dLightChar * --------------------------------------------------*/ void t3dLightChar(t3dMESH *mesh, t3dV3F *p) { #if 0 int16 df; uint32 j, rr, gg, bb, cr, cb, cg; t3dF32 addr = 110 + 60; t3dF32 addg = 95 + 75; t3dF32 addb = 80 + 90; t3dF32 nlight; t3dV3F ppos, l, *normal; gVertex *gv; if (!mesh || !p) return; t3dVectAdd(&ppos, &mesh->Trasl, &mesh->Pos); gv = mesh->VBptr = mesh->VertexBuffer; cr = (t3dU32)t3dCurRoom->AmbientLight.x + 20; cg = (t3dU32)t3dCurRoom->AmbientLight.y + 20; cb = (t3dU32)t3dCurRoom->AmbientLight.z + 20; df = RGBA_MAKE(cr, cg, cb, 255); for (j = 0; j < mesh->NumVerts; j++, gv++) gv->diffuse = df; t3dVectSub(&l, p, &ppos); t3dVectTransformInv(&l, &l, &mesh->Matrix); t3dVectNormalize(&l); gv = mesh->VBptr; for (j = 0; j < mesh->NumVerts; j++, gv++) { normal = &mesh->NList[j]->n; nlight = t3dVectDot(normal, &l); // if( (nlight=t3dVectDot(normal,&l)) >= 0 ) { rr = cr + t3dFloatToInt((addr * nlight)); gg = cg + t3dFloatToInt((addg * nlight)); bb = cb + t3dFloatToInt((addb * nlight)); if (rr > 255) rr = 255; if (gg > 255) gg = 255; if (bb > 255) bb = 255; gv->diffuse = RGBA_MAKE(rr, gg, bb, 255); } } mesh->Flags |= T3D_MESH_UPDATEVB; mesh->VBptr = nullptr; #endif } /* -----------------12/04/99 12.11------------------- * t3dVectMeshInters * --------------------------------------------------*/ uint8 t3dVectMeshInters(t3dMESH *m, t3dV3F start, t3dV3F end, t3dV3F *inters) { t3dV3F v1, v2, v3; if (!m) return 0; if (!t3dVectPlaneIntersection(inters, start, end, m->BBoxNormal[3])) return 0; m->VBptr = m->VertexBuffer; for (uint32 j = 0; j < m->NumFaces(); j++) { t3dFACE &f = m->FList[j]; if (!f.n) continue; v1.x = m->VBptr[f.VertexIndex[0]].x; v1.y = m->VBptr[f.VertexIndex[0]].y; v1.z = m->VBptr[f.VertexIndex[0]].z; v2.x = m->VBptr[f.VertexIndex[1]].x; v2.y = m->VBptr[f.VertexIndex[1]].y; v2.z = m->VBptr[f.VertexIndex[1]].z; v3.x = m->VBptr[f.VertexIndex[2]].x; v3.y = m->VBptr[f.VertexIndex[2]].y; v3.z = m->VBptr[f.VertexIndex[2]].z; if (t3dVectTriangleIntersection(inters, start, end, v1, v2, v3, *f.n)) { m->VBptr = nullptr; return 1; } } m->VBptr = nullptr; return 0; } /* -----------------19/05/00 12.43------------------- * t3dMoveAndCheck1stCamera * --------------------------------------------------*/ bool t3dMoveAndCheck1stCamera(t3dBODY *rr, t3dCAMERA *cc, t3dV3F *mm) { t3dWALK *w; t3dV3F tmp; int32 i, j; if (!Character[ocCURPLAYER]) return FALSE; w = &Character[ocCURPLAYER]->Walk; t3dVectAdd(&tmp, &cc->Source, mm); // Controlla che non sia dentro un Bounding Box for (i = 0; i < (int32)rr->NumMeshes(); i++) { t3dMESH &mesh = rr->MeshTable[i]; if (!(mesh.Flags & T3D_MESH_HIDDEN)) { // Se il punto di destinazione e' dentro il bound box (allargato dell'altezza del ginocchio) for (j = 0; j < 6; j++) if (t3dVectPlaneDistance(tmp, mesh.BBoxNormal[j]) < -KNEE_HEIGHT) break; if (j >= 6) { // Prima controlla che non sia dentro i bounds for (j = 0; j < w->PanelNum; j++) { if (PointInside(ocCURPLAYER, j, (double)tmp.x, (double)tmp.z) != 0) { warning("Inters %s", mesh.name.c_str()); // TODO: Debug return FALSE; } } warning("Saved by bounds"); // TODO: Debug } } } // evito che si entri nell'altro personaggio giocante i = (CurPlayer ^ 1); if (Character[i + ocDARRELL] && Character[i + ocDARRELL]->Mesh && t3dCurRoom->name.equalsIgnoreCase(PlayerStand[i].roomName)) { // Used to be stricmp t3dF32 d = t3dVectDistance(&tmp, &Character[i + ocDARRELL]->Mesh->Trasl); if (d < 435.f) return FALSE; } t3dVectAdd(&cc->Source, &cc->Source, mm); t3dVectAdd(&cc->Target, &cc->Target, mm); return TRUE; } /* -----------------03/05/99 15.24------------------- * t3dClipToSurface * --------------------------------------------------*/ uint8 t3dClipToSurface(Init &init, t3dV3F *pt) { t3dV3F tmp, start, end; int32 i; t3dMESH *m; t3dVectCopy(&start, pt); start.y = 260000.0f; t3dVectCopy(&end, pt); end.y = -130000.0f; for (i = 0; i < 6; i++) { if ((m = LinkMeshToStr(init, init.Obj[oNEXTPORTAL].getMeshLink(i))) && (t3dVectMeshInters(m, start, end, &tmp))) { pt->y = tmp.y; return true; } } return false; } /* -----------------03/05/99 16.44------------------- * t3dUpdateExplosion * --------------------------------------------------*/ void t3dUpdateExplosion(t3dMESH *m, t3dF32 scale) { // t3dU32 i; if (!m) return; m->Matrix.M[0] = scale; m->Matrix.M[4] = scale; m->Matrix.M[8] = scale; /* m->VBptr=m->VertexBuffer; for (i=0; iNumVerts; i++ ) { m->VBptr[i].x *= (scale/OldExplosionScale); m->VBptr[i].y *= (scale/OldExplosionScale); m->VBptr[i].z *= (scale/OldExplosionScale); } m->Flags |= T3D_MESH_UPDATEVB; m->VBptr = NULL; */ OldExplosionScale = scale; } /* -----------------03/09/98 17.42------------------- * UpdateBoundingBox * --------------------------------------------------*/ void UpdateBoundingBox(t3dMESH *mesh) { t3dBONEANIM *db; t3dBONE *bone; t3dV3F Appov; int32 i, frame; if (!mesh || (mesh->Flags & T3D_MESH_NOBOUNDBOX))return; // DebugFile("Update Bounding Box %s",mesh->Name); if (mesh->Flags & T3D_MESH_DEFAULTANIM) db = &mesh->DefaultAnim; else db = &mesh->Anim; frame = mesh->CurFrame; bone = db->BoneTable; for (i = 0; i < db->NumBones; i++, bone++) { if (!bone || !bone->Trasl || !bone->Matrix || (bone->ModVertices.size() > mesh->NumVerts)) continue; if ((!bone->ModVertices.empty()) && !(mesh->Flags & T3D_MESH_CHARACTER)) { for (i = 0; i < 8; i++) { t3dVectSub(&Appov, &mesh->BBox[i].p, &bone->Trasl[1]); t3dVectTransform(&Appov, &Appov, &bone->Matrix[1]); t3dVectTransformInv(&Appov, &Appov, &bone->Matrix[frame]); t3dVectAdd(&mesh->BBox[i].p, &Appov, &bone->Trasl[frame]); } t3dPlaneNormal(&mesh->BBoxNormal[0], &mesh->BBox[0].p, &mesh->BBox[2].p, &mesh->BBox[1].p); //front t3dPlaneNormal(&mesh->BBoxNormal[1], &mesh->BBox[4].p, &mesh->BBox[5].p, &mesh->BBox[6].p); //back t3dPlaneNormal(&mesh->BBoxNormal[2], &mesh->BBox[4].p, &mesh->BBox[0].p, &mesh->BBox[5].p); //Up t3dPlaneNormal(&mesh->BBoxNormal[3], &mesh->BBox[6].p, &mesh->BBox[7].p, &mesh->BBox[2].p); //Down t3dPlaneNormal(&mesh->BBoxNormal[4], &mesh->BBox[4].p, &mesh->BBox[6].p, &mesh->BBox[0].p); //Left t3dPlaneNormal(&mesh->BBoxNormal[5], &mesh->BBox[5].p, &mesh->BBox[1].p, &mesh->BBox[7].p); //Right return ; } } } /* -----------------08/06/00 14.51------------------- * t3dSetSpecialAnimFrame * --------------------------------------------------*/ bool t3dSetSpecialAnimFrame(WGame &game, const char *name, t3dMESH *mesh, int32 nf) { if (!name || !mesh) return false; if (t3dLoadAnimation(game, name, mesh, T3D_MESH_DEFAULTANIM) <= 0) return false; mesh->Flags |= (T3D_MESH_ABS_ANIM | T3D_MESH_DEFAULTANIM); FixupAnim(mesh, 0, ""); if (nf < 0) nf = mesh->DefaultAnim.NumFrames - 1; mesh->CurFrame = nf; mesh->LastFrame = -1; mesh->BlendPercent = 255; mesh->LastBlendPercent = 0; return true; } void MeshModifiers::modifyMesh(WGame &game, t3dMESH *mesh) { struct SMeshModifier *mm; int16 i; if (!mesh || (mesh->Flags & T3D_MESH_CHARACTER)) return; // Check if there is a modifier for this mesh mm = &MMList[0]; for (i = 0; i < MAX_MODIFIED_MESH; i++, mm++) if ((!mm->meshName.empty()) && (mm->meshName.equalsIgnoreCase(mesh->name))) break; // If there are no modifiers for this mesh or they refer to a body if ((i >= MAX_MODIFIED_MESH) || (mm->getFlags() & (MM_SET_BND_LEVEL | MM_SET_HALOES))) return; mm->modifyMesh(game, mesh); } void SMeshModifier::modifyMesh(WGame &game, t3dMESH *mesh) { warning("MM %s: addflags %X, removeflags %X, anim |%s|", mesh->name.c_str(), this->AddFlags, this->RemoveFlags, this->animName.c_str()); // Update Flags if (this->Flags & MM_REMOVE_FLAGS) mesh->Flags &= ~this->RemoveFlags; if (this->Flags & MM_ADD_FLAGS) mesh->Flags |= this->AddFlags; // Update Materials if (this->Flags & MM_REMOVE_MAT_FLAGS) mesh->FList[0].getMaterial()->Flags &= ~this->RemoveMatFlags; if (this->Flags & MM_ADD_MAT_FLAGS) mesh->FList[0].getMaterial()->Flags |= this->AddMatFlags; if (this->Flags & MM_SET_MAT_FRAME) mesh->setMovieFrame(this->MatFrame); // This did NOT check for existing face/material before setting before. // Update Anim if ((this->Flags & MM_ANIM_BLOCK) && (!this->animName.empty()) && (!mesh->CurFrame)) { t3dSetSpecialAnimFrame(game, this->animName.c_str(), mesh, -1); t3dCalcMeshBones(mesh, 1); UpdateBoundingBox(mesh); } } /* -----------------15/09/98 12.04------------------- * AddMeshModifier * --------------------------------------------------*/ void MeshModifiers::addMeshModifier(const Common::String &name, int16 com, void *p) { struct SMeshModifier *mm; int16 i; warning("Not sure this is right"); // Used to check for nullptr, not 0 length. if (name.empty() || !p) return; // DebugLogFile("AddMM |%s| %d",name,com); // Check if a modifier already exists for this mesh mm = &MMList[0]; for (i = 0; i < MAX_MODIFIED_MESH; i++, mm++) if ((!mm->meshName.empty()) && mm->meshName.equalsIgnoreCase(name)) break; // If it's a new modifier look for a free place if (i >= MAX_MODIFIED_MESH) { mm = &MMList[0]; for (i = 0; i < MAX_MODIFIED_MESH; i++, mm++) if (mm->meshName.empty()) break; if (i >= MAX_MODIFIED_MESH) { warning("Troppi Mesh modifier per %s: MAX %d", name.c_str(), MAX_MODIFIED_MESH); return; } *mm = SMeshModifier(name.c_str(), com, p); } else { mm->configure(name.c_str(), com, p); } } SMeshModifier::SMeshModifier(Common::SeekableReadStream &stream) { char stringBuffer[T3D_NAMELEN] = {}; stream.read(stringBuffer, T3D_NAMELEN); meshName = stringBuffer; Flags = stream.readSint32LE(); AddFlags = stream.readUint32LE(); RemoveFlags = stream.readUint32LE(); AddMatFlags = stream.readUint32LE(); RemoveMatFlags = stream.readUint32LE(); MatFrame = stream.readSint32LE(); BndLevel = stream.readUint16LE(); HaloesStatus = stream.readByte(); // TODO: Signed. stream.read(stringBuffer, T3D_NAMELEN); animName = stringBuffer; } SMeshModifier::SMeshModifier(const char *name, int16 com, void *p) { configure(name, com, p); } void SMeshModifier::configure(const char *name, int16 com, void *p) { this->Flags |= com; switch (com) { case MM_ADD_FLAGS: Flags = *((uint32 *)p); this->RemoveFlags &= ~Flags; this->AddFlags |= Flags; break; case MM_REMOVE_FLAGS: Flags = *((uint32 *)p); this->AddFlags &= ~Flags; this->RemoveFlags |= Flags; break; case MM_ADD_MAT_FLAGS: Flags = *((uint32 *)p); this->RemoveMatFlags &= ~Flags; this->AddMatFlags |= Flags; break; case MM_REMOVE_MAT_FLAGS: Flags = *((uint32 *)p); this->AddMatFlags &= ~Flags; this->RemoveMatFlags |= Flags; break; case MM_SET_MAT_FRAME: this->MatFrame = *((int32 *)p); break; case MM_ANIM_BLOCK: if (this->animName.empty()) this->animName = (char *)p; else this->animName.clear(); break; case MM_SET_BND_LEVEL: this->BndLevel = *((uint16 *)p); break; case MM_SET_HALOES: this->HaloesStatus = *((int8 *)p); break; } } void MeshModifiers::applyAllMeshModifiers(WGame &game, t3dBODY *b) { // Check if there is a modifier for this body struct SMeshModifier *mm = &MMList[0]; for (int32 j = 0; j < MAX_MODIFIED_MESH; j++, mm++) if ((!mm->meshName.empty()) && b->name.equalsIgnoreCase(mm->meshName)) { if (mm->getFlags() & MM_SET_BND_LEVEL) b->CurLevel = mm->getBndLevel(); if (mm->getFlags() & MM_SET_HALOES) { for (auto &l : b->LightTable) { if (!(l.Type & T3D_LIGHT_FLARE)) continue; if (mm->getHaloesStatus() > 0) l.Type |= T3D_LIGHT_LIGHTON; else l.Type &= ~T3D_LIGHT_LIGHTON; } } } for (int32 i = 0; i < (int32)b->NumMeshes(); i++) { modifyMesh(game, &b->MeshTable[i]); } } /* -----------------29/03/99 14.33------------------- * HideRoomMeshes * --------------------------------------------------*/ void HideRoomMeshes(Init &init, t3dBODY *body) { int32 cr, c, a, b, i, j, k, h, skip; t3dMESH *m; if (!(cr = getRoomFromStr(init, body->name))) return; // DebugFile("Hiding Room %s (%d)",body->Name,cr); for (a = 0; a < MAX_OBJS_IN_ROOM; a++) { if (!(c = init.Room[cr].objects[a])) continue; if (init.Obj[c].flags & NOUPDATE) continue; if (!(init.Obj[c].flags & ON) || (init.Obj[c].flags & HIDE)) { for (b = 0; b < MAX_OBJ_MESHLINKS; b++) { if (init.Obj[c].meshLinkIsEmpty(b)) continue; m = nullptr; const Common::String &str = init.Obj[c].getMeshLink(b); for (h = 0; h < (uint16)body->NumMeshes(); h++) { if (body->MeshTable[h].name.equalsIgnoreCase(str)) { m = &body->MeshTable[h]; break; } } if (m == nullptr) continue; // DebugFile("CandidateObj '%s'",Obj[c].meshlink[b]); skip = 0; for (i = 0; i < MAX_OBJS_IN_ROOM; i++) { if (!(k = init.Room[cr].objects[i]) || (k == c)) continue; if (!(init.Obj[k].flags & ON) || (init.Obj[k].flags & HIDE)) continue; for (j = 0; j < MAX_OBJ_MESHLINKS; j++) { if (init.Obj[k].meshLinkIsEmpty(j)) continue; if (!init.Obj[c].getMeshLink(b).equalsIgnoreCase(init.Obj[k].getMeshLink(j))) continue; // DebugFile("Skipped for %d,%d",k,j); skip ++; break; } } if (!skip && m) { // DebugFile("Hiding Mesh %s",Obj[c].meshlink[b]); m->Flags |= T3D_MESH_HIDDEN; } } } } } /* -----------------28/12/98 17.43------------------- * UpdateCharHead * --------------------------------------------------*/ void UpdateCharHead(int32 oc, t3dV3F *dir) { t3dCHARACTER *Ch = Character[oc]; t3dMESH *mesh; t3dHEADMOVE *t; t3dBONE *bone; t3dV3F tmp; int32 i, cf; t3dF32 s; if (!Ch || !(mesh = Ch->Mesh) || mHide || !dir) return; if ((bDialogActive) || (bT2DActive) || (InvStatus)) return; if (oc == ocCURPLAYER) oc = ocDARRELL + CurPlayer; t = &HeadMove[oc]; if ((Player->Mesh->CurFrame > ActionStart[aSTAND]) || !(Player->Mesh->Flags & T3D_MESH_DEFAULTANIM)) t3dVectFill(&t->DestAng, 0.0f); else if (t->OldPos != *dir) { t3dVectCopy(&tmp, &mesh->Trasl); tmp.y = CurFloorY + EYES_HEIGHT; t3dVectSub(&tmp, dir, &tmp); t->DestAng.x = t3dVectAngle(&tmp, &Ch->Dir); if (t->DestAng.x < -MAX_HEAD_ANGLE_X * 2) t->DestAng.x = -MAX_HEAD_ANGLE_X * 2; if (t->DestAng.x > MAX_HEAD_ANGLE_X * 2) t->DestAng.x = MAX_HEAD_ANGLE_X * 2; t->DestAng.y = -(t3dF32)asin((mPos.y - (CurFloorY + EYES_HEIGHT)) / t3dVectMod(&tmp)) * 180.0f / T3D_PI; if (t->DestAng.y < -MAX_HEAD_ANGLE_Y / 2) t->DestAng.y = -MAX_HEAD_ANGLE_Y / 2; if (t->DestAng.y > MAX_HEAD_ANGLE_Y / 2) t->DestAng.y = MAX_HEAD_ANGLE_Y / 2; t->DestAng.z = 0.0f; t3dVectCopy(&t->OldPos, dir); } if (t->DestAng != t->CurAng) { Player->Mesh->LastFrame = 0; if (Player->Mesh->Flags & T3D_MESH_DEFAULTANIM) { if (Player->Mesh->CurFrame < ActionStart[aSTAND]) Player->Mesh->CurFrame = ActionStart[aSTAND]; cf = 1; for (i = 1; i < Player->Mesh->DefaultAnim.NumBones; i++) { if (!(bone = &Player->Mesh->DefaultAnim.BoneTable[i]) || !(bone->Trasl) || !(bone->Matrix)) continue; t3dVectCopy(&bone->Trasl[cf], &bone->Trasl[Player->Mesh->CurFrame]); t3dMatCopy(&bone->Matrix[cf], &bone->Matrix[Player->Mesh->CurFrame]); } bone = &Player->Mesh->DefaultAnim.BoneTable[12]; } else { cf = Player->Mesh->CurFrame; bone = &Player->Mesh->Anim.BoneTable[12]; } if ((bone) && (bone->Trasl) && (bone->Matrix)) { t3dVectSub(&tmp, &t->DestAng, &t->CurAng); s = t3dVectMod(&tmp); if (s > MAX_HEAD_SPEED) { tmp.x *= (MAX_HEAD_SPEED / s); tmp.y *= (MAX_HEAD_SPEED / s); } t->CurAng.x += tmp.x; t->CurAng.y += tmp.y; t->CurAng.z = 0.0f; t3dMatRot(&bone->Matrix[cf], (t->CurAng.y * T3D_PI) / 180.0f, (t->CurAng.x * T3D_PI) / 180.0f, 0.0f); bone->Matrix[cf].Flags &= ~T3D_MATRIX_IDENTITY; // Player->Mesh->BlendPercent = 0; Player->Mesh->CurFrame = cf; } } // se siamo in un dialogo o RTV non gli faccio muovere la testolina if (bDialogActive) { t3dVectFill(&t->CurAng, 0.0f); t3dVectFill(&t->DestAng, 0.0f); t3dVectFill(&t->OldPos, 0.0f); } } /* -----------------22/06/00 12.15------------------- * ChangeMeshFlags * --------------------------------------------------*/ void ChangeMeshFlags(t3dMESH *m, int8 add, uint32 newflags) { if (!m) return; if (add > 0) { m->Flags |= newflags; _vm->addMeshModifier(m->name, MM_ADD_FLAGS, &newflags); } else { m->Flags &= ~newflags; _vm->addMeshModifier(m->name, MM_REMOVE_FLAGS, &newflags); } } /* -----------------29/06/00 11.22------------------- * ChangeHaloesStatus * --------------------------------------------------*/ void ChangeHaloesStatus(t3dBODY *b, int8 op) { if (b == nullptr) b = t3dCurRoom; if (b == nullptr) return; for (auto &l : b->LightTable) { if (!(l.Type & T3D_LIGHT_FLARE)) continue; if (op > 0) l.Type |= T3D_LIGHT_LIGHTON; else l.Type &= ~T3D_LIGHT_LIGHTON; } _vm->addMeshModifier(b->name.c_str(), MM_SET_HALOES, &op); } /* -----------------01/06/00 11.12------------------- * UpdateObjMesh * --------------------------------------------------*/ void UpdateObjMesh(Init &init, int32 in) { t3dMESH *m; int32 a; if (init.Obj[in].flags & NOUPDATE) return; for (a = 0; a < MAX_OBJ_MESHLINKS; a++) { m = LinkMeshToStr(init, init.Obj[in].getMeshLink(a)); if (m) { if ((init.Obj[in].flags & ON) && !(init.Obj[in].flags & HIDE)) // m->Flags &= ~T3D_MESH_HIDDEN; ChangeMeshFlags(m, -1, T3D_MESH_HIDDEN); else // m->Flags |= T3D_MESH_HIDDEN; ChangeMeshFlags(m, +1, T3D_MESH_HIDDEN); } else { //se non la trova in memoria aggiunge solo il modifier alla lista uint32 newflags; newflags = T3D_MESH_HIDDEN; if (!init.Obj[in].meshLinkIsEmpty(a)) { if ((init.Obj[in].flags & ON) && !(init.Obj[in].flags & HIDE)) _vm->addMeshModifier(init.Obj[in].getMeshLink(a), MM_REMOVE_FLAGS, &newflags); else _vm->addMeshModifier(init.Obj[in].getMeshLink(a), MM_ADD_FLAGS, &newflags); } } }//for } /* -----------------22/06/00 12.15------------------- * SetMeshMaterialMovieFrame * --------------------------------------------------*/ void SetMeshMaterialMovieFrame(t3dMESH *m, int8 op, int32 newframe) { if (!m || m->FList.empty() || !m->FList[0].getMaterial()) return; if (op == 0) m->setMovieFrame(newframe); else if (op > 0) m->setMovieFrame(m->getMovieFrame() + newframe); else if (op < 0) m->setMovieFrame(m->getMovieFrame() - newframe); newframe = m->getMovieFrame(); _vm->addMeshModifier(m->name, MM_SET_MAT_FRAME, &newframe); } /* -----------------22/06/00 12.15------------------- * ChangeMeshMaterialFlags * --------------------------------------------------*/ void ChangeMeshMaterialFlag(t3dMESH *m, int8 add, uint32 newflag) { if (!m || m->hasFaceMaterial()) return; if (add > 0) { m->FList[0].getMaterial()->addProperty(newflag); _vm->addMeshModifier(m->name, MM_ADD_MAT_FLAGS, &newflag); } else { m->FList[0].getMaterial()->clearFlag(newflag); _vm->addMeshModifier(m->name, MM_REMOVE_MAT_FLAGS, &newflag); } } /* -----------------20/04/99 15.29------------------- * t3dProcessGolfSky * --------------------------------------------------*/ void t3dProcessGolfSky(t3dMESH *gs) { uint32 i; t3dF32 GolfSkySpeed = 0.00009f; gVertex *gv; if (!gs) return ; gv = gs->VertexBuffer; for (i = 0; i < gs->NumVerts; i++, gv++) { gv->u1 += GolfSkySpeed; gv->v1 += GolfSkySpeed; } gs->Flags |= T3D_MESH_UPDATEVB; gs->VBptr = NULL; } } // End of namespace Watchmaker