/* 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