Files
scummvm/engines/watchmaker/ll/ll_mesh.cpp
T
D G Turner 4ba6db3429 WATCHMAKER: Fix Another Likely Incorrect Code Causing GCC Compiler Warning
The previous commit errorneously included all my pending minor GCC warning
fixes, but these are not problematic as they don't really change behaviour.

However, as the previous commit message was referring to, this commit and
the previous change in ll_mesh.cpp do change the previous behaviour and
should be reviewed for correctness.
2023-05-02 21:43:18 +01:00

883 lines
26 KiB
C++

/* 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 <http://www.gnu.org/licenses/>.
*
*/
#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].meshlink[k][0] != '\0') && (m->name.equalsIgnoreCase((const char *)init.Obj[oNEXTPORTAL].meshlink[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, (char *)init.Obj[oNEXTPORTAL].meshlink[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; i<m->NumVerts; 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;
char *str;
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].meshlink[b][0] == '\0') continue;
m = nullptr;
str = (char *)init.Obj[c].meshlink[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].meshlink[j][0] == '\0') continue;
if (!Common::String((char *)init.Obj[c].meshlink[b]).equalsIgnoreCase((char *)init.Obj[k].meshlink[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, (char *)init.Obj[in].meshlink[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].meshlink[a][0] != '\0') {
if ((init.Obj[in].flags & ON) && !(init.Obj[in].flags & HIDE))
_vm->addMeshModifier((char *)init.Obj[in].meshlink[a], MM_REMOVE_FLAGS, &newflags);
else
_vm->addMeshModifier((char *)init.Obj[in].meshlink[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