Initial commit
This commit is contained in:
729
engines/watchmaker/3d/animation.cpp
Normal file
729
engines/watchmaker/3d/animation.cpp
Normal file
@@ -0,0 +1,729 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_strcat
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_strcpy
|
||||
|
||||
#include "watchmaker/3d/animation.h"
|
||||
#include "watchmaker/3d/geometry.h"
|
||||
#include "watchmaker/3d/loader.h"
|
||||
#include "watchmaker/3d/math/llmath.h"
|
||||
#include "watchmaker/3d/t3d_body.h"
|
||||
#include "watchmaker/3d/t3d_mesh.h"
|
||||
#include "watchmaker/file_utils.h"
|
||||
#include "watchmaker/game.h"
|
||||
#include "watchmaker/ll/ll_system.h"
|
||||
#include "watchmaker/t3d.h"
|
||||
#include "watchmaker/types.h"
|
||||
#include "watchmaker/utils.h"
|
||||
#include "watchmaker/windows_hacks.h"
|
||||
|
||||
/* -----------------16/12/98 10.32-------------------
|
||||
* PRELOADEDANIMS
|
||||
* --------------------------------------------------*/
|
||||
#define MAX_BONES 40
|
||||
#define MAX_PRELOADED_ANIMS 8
|
||||
#define A3DFILEVERSION 5
|
||||
#define SCALE_DEFAULT_ANIM 1
|
||||
#define SCALE_ANIM 3
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
struct t3dLOADBONE {
|
||||
t3dV3F *Trasl;
|
||||
t3dV3F *Euler;
|
||||
uint32 NumBone;
|
||||
};
|
||||
|
||||
struct t3dLOADANIM {
|
||||
Common::String name;
|
||||
uint32 NumFrames = 0, NumBones = 0, HiBone = 0, LastTime = 0;
|
||||
t3dF32 *Dist = nullptr;
|
||||
t3dLOADBONE Bone[MAX_BONES] = {};
|
||||
};
|
||||
|
||||
t3dLOADANIM PreloadedAnim[MAX_PRELOADED_ANIMS];
|
||||
|
||||
/* -----------------30/12/98 10.56-------------------
|
||||
* t3dMatRotXYZ
|
||||
* --------------------------------------------------*/
|
||||
void t3dMatRotXYZ(t3dM3X3F *dest, t3dF32 x, t3dF32 y, t3dF32 z) {
|
||||
t3dM3X3F matrix, matrix_x, matrix_y, matrix_z;
|
||||
|
||||
t3dMatIdentity(&matrix_x);
|
||||
t3dMatIdentity(&matrix_y);
|
||||
t3dMatIdentity(&matrix_z);
|
||||
|
||||
matrix_x.M[4] = (float)cos(x);
|
||||
matrix_x.M[5] = (float)sin(x);
|
||||
matrix_x.M[7] = -(float)sin(x);
|
||||
matrix_x.M[8] = (float)cos(x);
|
||||
|
||||
matrix_y.M[0] = (float)cos(y);
|
||||
matrix_y.M[2] = -(float)sin(y);
|
||||
matrix_y.M[6] = (float)sin(y);
|
||||
matrix_y.M[8] = (float)cos(y);
|
||||
|
||||
matrix_z.M[0] = (float)cos(z);
|
||||
matrix_z.M[1] = (float)sin(z);
|
||||
matrix_z.M[3] = -(float)sin(z);
|
||||
matrix_z.M[4] = (float)cos(z);
|
||||
|
||||
t3dMatMul(&matrix, &matrix_x, &matrix_y);
|
||||
t3dMatMul(&matrix, &matrix, &matrix_z);
|
||||
|
||||
dest->M[0] = matrix.M[0];
|
||||
dest->M[2] = matrix.M[1];
|
||||
dest->M[1] = matrix.M[2];
|
||||
dest->M[6] = matrix.M[3];
|
||||
dest->M[8] = matrix.M[4];
|
||||
dest->M[7] = matrix.M[5];
|
||||
dest->M[3] = matrix.M[6];
|
||||
dest->M[5] = matrix.M[7];
|
||||
dest->M[4] = matrix.M[8];
|
||||
}
|
||||
|
||||
Common::Array<t3dPLIGHT> t3dBODY::getPositionalLight(uint8 pos) {
|
||||
Common::Array<t3dPLIGHT> result;
|
||||
for (const auto &light : PosLightTable) {
|
||||
if (light.Num == pos) {
|
||||
result.push_back(light);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* -----------------04/07/98 15.52-------------------
|
||||
* GetLightPosition
|
||||
* --------------------------------------------------*/
|
||||
uint8 GetLightPosition(t3dV3F *dest, uint8 pos) {
|
||||
if (!pos) return 0;
|
||||
|
||||
auto pLights = t3dCurRoom->getPositionalLight(pos);
|
||||
dest->y = CurFloorY;
|
||||
for (const auto &light : pLights) {
|
||||
if (light.Pos.x && light.Pos.z) {
|
||||
dest->x = light.Pos.x;
|
||||
dest->z = light.Pos.z;
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
if (pos != 99)
|
||||
warning("Can't find lpos %d in %s", pos, t3dCurRoom->name.c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -----------------04/07/98 15.52-------------------
|
||||
* GetLightPosition
|
||||
* --------------------------------------------------*/
|
||||
uint8 GetLightDirection(t3dV3F *dest, uint8 pos) {
|
||||
if (!pos) return 0;
|
||||
|
||||
auto pLights = t3dCurRoom->getPositionalLight(pos);
|
||||
dest->y = CurFloorY;
|
||||
for (const auto &light : pLights) {
|
||||
if (light.Dir.x && light.Dir.z) {
|
||||
dest->x = light.Dir.x;
|
||||
dest->z = light.Dir.x;
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
if (pos != 99)
|
||||
warning("Can't find ldir %d in %s", pos, t3dCurRoom->name.c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* -----------------15/12/98 16.26-------------------
|
||||
* t3dLoadAnimation
|
||||
* --------------------------------------------------*/
|
||||
int8 t3dLoadAnimation(WGame &game, const char *s, t3dMESH *mesh, uint16 Flag) {
|
||||
uint32 nf, nb, i, k, h, older, ScaleAnim, CurPreloadedAnim;
|
||||
uint32 j = 0;
|
||||
t3dLOADANIM *p;
|
||||
t3dLOADBONE *bone;
|
||||
t3dBONEANIM *db;
|
||||
t3dBONE *b;
|
||||
t3dV3F t;
|
||||
t3dF32 c;
|
||||
|
||||
// Prova a vedere se l'ho gia' precaricata
|
||||
for (CurPreloadedAnim = 0; CurPreloadedAnim < MAX_PRELOADED_ANIMS; CurPreloadedAnim++)
|
||||
if (PreloadedAnim[CurPreloadedAnim].NumFrames)
|
||||
if (PreloadedAnim[CurPreloadedAnim].name.equalsIgnoreCase(s))
|
||||
break;
|
||||
// Se la devo precaricare, cerco quella piu' vecchia e la scarico
|
||||
if (CurPreloadedAnim >= MAX_PRELOADED_ANIMS) {
|
||||
older = 0;
|
||||
// Prima cerco se ci sono ancora degli slot liberi
|
||||
for (CurPreloadedAnim = 0; CurPreloadedAnim < MAX_PRELOADED_ANIMS; CurPreloadedAnim++) {
|
||||
if (!PreloadedAnim[CurPreloadedAnim].NumFrames)
|
||||
break;
|
||||
else if (!(older) || (older > PreloadedAnim[CurPreloadedAnim].LastTime))
|
||||
older = PreloadedAnim[j = CurPreloadedAnim].LastTime;
|
||||
}
|
||||
// Se non c'erano slot liberi, rilascia vecchia animazione precaricata
|
||||
if (CurPreloadedAnim >= MAX_PRELOADED_ANIMS) {
|
||||
CurPreloadedAnim = j;
|
||||
//t DebugFile( "Precarico animazione %s nello slot %d occupato da %s", s, CurPreloadedAnim, PreloadedAnim[j].Name );
|
||||
// Disalloca tutto
|
||||
for (i = 0; i < MAX_BONES; i++) {
|
||||
t3dFree(PreloadedAnim[j].Bone[i].Trasl);
|
||||
t3dFree(PreloadedAnim[j].Bone[i].Euler);
|
||||
}
|
||||
delete[] PreloadedAnim[j].Dist;
|
||||
PreloadedAnim[j] = t3dLOADANIM();
|
||||
}
|
||||
//t else
|
||||
//t DebugFile( "Precarico animazione %s nello slot libero %d", s, CurPreloadedAnim );
|
||||
|
||||
p = &PreloadedAnim[CurPreloadedAnim];
|
||||
p->name = s;
|
||||
|
||||
// Carica la nuova animazione
|
||||
Common::String name = game.workDirs._a3dDir + replaceExtension(s, "a3d");
|
||||
|
||||
{
|
||||
auto stream = game.resolveFile(name.c_str());
|
||||
if (!stream) {
|
||||
warning("File %s not found", name.c_str());
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((i = stream->readByte()) != A3DFILEVERSION) {
|
||||
warning("%s file incompatible: current version: %d.\tFile version: %d", name.c_str(), A3DFILEVERSION, i);
|
||||
return -1;
|
||||
}
|
||||
|
||||
nb = stream->readSint16LE();
|
||||
nf = stream->readSint16LE();
|
||||
if (nf == 0) {
|
||||
warning("%s has N0 frames!", name.c_str());
|
||||
return -1;
|
||||
}
|
||||
if (nb >= MAX_BONES) {
|
||||
warning("%s has too many bones (%d, MAX is %d)!", name.c_str(), j, MAX_BONES);
|
||||
return -1;
|
||||
}
|
||||
p->NumBones = nb;
|
||||
p->NumFrames = nf;
|
||||
|
||||
for (i = 0; i < nb; i++) {
|
||||
j = (uint32)(stream->readByte());
|
||||
if (!(p->HiBone) || (p->HiBone < j))
|
||||
p->HiBone = j;
|
||||
|
||||
bone = &p->Bone[i];
|
||||
bone->NumBone = j;
|
||||
bone->Euler = t3dCalloc<t3dV3F>(nf);
|
||||
bone->Trasl = t3dCalloc<t3dV3F>(nf);
|
||||
|
||||
for (k = 0; k < nf; k++) {
|
||||
bone->Euler[k] = t3dV3F(*stream);
|
||||
}
|
||||
|
||||
for (k = 0; k < nf; k++) {
|
||||
bone->Trasl[k] = t3dV3F(*stream);
|
||||
}
|
||||
}
|
||||
if (stream->readByte()) {
|
||||
p->Dist = new t3dF32[nf]{};
|
||||
for (k = 0; k < nf; k++)
|
||||
p->Dist[k] = stream->readFloatLE();
|
||||
}
|
||||
} // Close file
|
||||
}
|
||||
//t else
|
||||
//t DebugFile( "Animazione %s gia' precaricata nello slot %d", s, CurPreloadedAnim );
|
||||
|
||||
p = &PreloadedAnim[CurPreloadedAnim];
|
||||
// Scrive l'ultima volta che l'ho usata
|
||||
p->LastTime = t3dReadTime();
|
||||
|
||||
// Finalmente copia l'animazione precaricata nella mesh
|
||||
if (Flag & T3D_MESH_DEFAULTANIM) {
|
||||
db = &mesh->DefaultAnim;
|
||||
mesh->Flags |= T3D_MESH_DEFAULTANIM;
|
||||
if (db) mesh->releaseAnim(T3D_MESH_DEFAULTANIM);
|
||||
if (db) mesh->releaseAnim(0);
|
||||
ScaleAnim = SCALE_DEFAULT_ANIM;
|
||||
db->NumFrames = p->NumFrames;
|
||||
} else {
|
||||
db = &mesh->Anim;
|
||||
mesh->Flags &= ~T3D_MESH_DEFAULTANIM;
|
||||
if (db) mesh->releaseAnim(0);
|
||||
ScaleAnim = SCALE_ANIM;
|
||||
db->NumFrames = (p->NumFrames - 2) * ScaleAnim + 2;
|
||||
}
|
||||
if (db->BoneTable) mesh->releaseAnim(0);
|
||||
mesh->NumNormals = 0;
|
||||
db->NumBones = 0;
|
||||
db->BoneTable = nullptr;
|
||||
db->BoneTable = t3dCalloc<t3dBONE>(p->HiBone + 1);
|
||||
db->NumBones = p->HiBone + 1;
|
||||
|
||||
c = 1.0f / (t3dF32)(ScaleAnim);
|
||||
for (i = 0; i < p->NumBones; i++) {
|
||||
bone = &p->Bone[i];
|
||||
b = &db->BoneTable[bone->NumBone];
|
||||
|
||||
b->Matrix = t3dCalloc<t3dM3X3F>(db->NumFrames);
|
||||
b->Trasl = t3dCalloc<t3dV3F>(db->NumFrames);
|
||||
|
||||
for (k = 0; k < db->NumFrames; k++) {
|
||||
j = ((k - 1) / ScaleAnim) + 1;
|
||||
h = ((k - 1) % ScaleAnim);
|
||||
|
||||
if ((!h) || (k < 1)) {
|
||||
if (k < 1)
|
||||
j = k;
|
||||
t3dMatRotXYZ(&b->Matrix[k], bone->Euler[j].x, bone->Euler[j].y, bone->Euler[j].z);
|
||||
memcpy(&b->Trasl[k], &bone->Trasl[j], sizeof(t3dV3F));
|
||||
} else {
|
||||
t3dVectSub(&t, &bone->Euler[j + 1], &bone->Euler[j]);
|
||||
if ((t.x < T3D_2PI) && (t.x > T3D_PI)) t.x = t.x - T3D_2PI;
|
||||
if ((t.x > -T3D_2PI) && (t.x < -T3D_PI)) t.x = t.x + T3D_2PI;
|
||||
if ((t.y < T3D_2PI) && (t.y > T3D_PI)) t.y = t.y - T3D_2PI;
|
||||
if ((t.y > -T3D_2PI) && (t.y < -T3D_PI)) t.y = t.y + T3D_2PI;
|
||||
if ((t.z < T3D_2PI) && (t.z > T3D_PI)) t.z = t.z - T3D_2PI;
|
||||
if ((t.z > -T3D_2PI) && (t.z < -T3D_PI)) t.z = t.z + T3D_2PI;
|
||||
t *= (c * (t3dF32)(h));
|
||||
t3dVectAdd(&t, &bone->Euler[j], &t);
|
||||
t3dMatRotXYZ(&b->Matrix[k], t.x, t.y, t.z);
|
||||
|
||||
t3dVectSub(&t, &bone->Trasl[j + 1], &bone->Trasl[j]);
|
||||
t *= (c * (t3dF32)(h));
|
||||
t3dVectAdd(&b->Trasl[k], &bone->Trasl[j], &t);
|
||||
}
|
||||
|
||||
/* if(!(mesh->Flags&T3D_MESH_CHARACTER))
|
||||
DebugFile("%3d;%3d;%9f;%9f;%9f;%9f;%9f;%9f;%9f;%9f;%9f;%9f;%9f;%9f;",k,i,
|
||||
(bone->Euler[j].x)*180.0f/T3D_PI,(bone->Euler[j].y)*180.0f/T3D_PI,(bone->Euler[j].z)*180.0f/T3D_PI,
|
||||
b->Matrix[k].M[0],b->Matrix[k].M[1],b->Matrix[k].M[2],
|
||||
b->Matrix[k].M[3],b->Matrix[k].M[4],b->Matrix[k].M[5],
|
||||
b->Matrix[k].M[6],b->Matrix[k].M[7],b->Matrix[k].M[8] );
|
||||
*/
|
||||
}
|
||||
|
||||
b->ModVertices.clear();
|
||||
// Poi inserisce tutti i vertici modificati nell'array gia' alloocato della dimensione giusta
|
||||
for (auto &modVertices : mesh->ModVertices) {
|
||||
if (modVertices.NumBone == bone->NumBone) {
|
||||
b->ModVertices.push_back(modVertices.NumVert);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (p->Dist) {
|
||||
db->Dist = new t3dF32[db->NumFrames]{};
|
||||
for (k = 0; k < db->NumFrames; k++)
|
||||
db->Dist[k] = p->Dist[k];
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* -----------------30/12/98 11.27-------------------
|
||||
* FixupAnim
|
||||
* --------------------------------------------------*/
|
||||
void FixupAnim(t3dMESH *mesh, uint8 pos, const char *room) {
|
||||
t3dBONEANIM *db;
|
||||
t3dBONE *bone, *bone0;
|
||||
t3dV3F lp, ld, Frame0Trasl, cc, tmp, tmp1, tmp2, zero;
|
||||
t3dM3X3F lm, mx, BoneInitMatrix;
|
||||
uint32 i, k, frame;
|
||||
t3dBODY *OldCurRoom = t3dCurRoom;
|
||||
|
||||
if (mesh->Flags & T3D_MESH_DEFAULTANIM) {
|
||||
db = &mesh->DefaultAnim;
|
||||
pos = 0;
|
||||
} else {
|
||||
db = &mesh->Anim;
|
||||
if (pos) {
|
||||
if (room && (room[0] != '\0')) {
|
||||
t3dBODY *roomPtr = _vm->_roomManager->getRoomIfLoaded(room);
|
||||
if (room) {
|
||||
t3dCurRoom = roomPtr;
|
||||
}
|
||||
}
|
||||
if (!GetLightPosition(&lp, pos) || (lp.x == 0.0f) || (lp.z == 0.0f)) pos = 0;
|
||||
if (!GetLightDirection(&ld, pos) || (ld.x == 0.0f) || (ld.z == 0.0f)) pos = 0;
|
||||
t3dCurRoom = OldCurRoom;
|
||||
|
||||
t3dVectSub(&ld, &ld, &lp);
|
||||
ld.z = -ld.z;
|
||||
t3dVectAdd(&ld, &ld, &lp);
|
||||
t3dMatView(&lm, &lp, &ld);
|
||||
|
||||
if ((!pos) || (mesh->Flags & (T3D_MESH_ABS_ANIM | T3D_MESH_CHARACTER))) {
|
||||
t3dVectCopy(&lp, &mesh->Trasl);
|
||||
t3dMatCopy(&lm, &mesh->Matrix);
|
||||
pos = 99;
|
||||
}
|
||||
|
||||
if (mesh->Flags & T3D_MESH_ABS_ANIM)
|
||||
t3dVectTransform(&cc, &CharCorrection, &lm);
|
||||
}
|
||||
}
|
||||
// Ora sistema tutte le altre bones 1..32 (mesh) e 33/34 (camera)
|
||||
for (i = 1; i < db->NumBones; i++) {
|
||||
if (!(bone = &db->BoneTable[i]) || !(bone->Trasl) || !(bone->Matrix)) continue;
|
||||
// Salva la prima matrice di ogni bone
|
||||
t3dMatCopy(&BoneInitMatrix, &bone->Matrix[0]);
|
||||
// Calcola scostamento iniziale bone per azioni assolute personaggi
|
||||
if (i == 1) t3dVectSub(&Frame0Trasl, &bone->Trasl[1], &bone->Trasl[0]);
|
||||
|
||||
for (k = 0; k < db->NumFrames; k++) {
|
||||
// Tutte le matrici diventano relative al frame 0
|
||||
t3dMatMulInv(&bone->Matrix[k], &bone->Matrix[k], &BoneInitMatrix);
|
||||
// Aggiunge la correzione a:
|
||||
// - Azioni di default (tutti frames personaggi)
|
||||
// - Azioni relative (tutti frames, personaggi e oggetti)
|
||||
// - Azioni assolute (personaggi frame 0)
|
||||
if ((mesh->Flags & T3D_MESH_DEFAULTANIM) || !(mesh->Flags & T3D_MESH_ABS_ANIM) ||
|
||||
((!k) && (mesh->Flags & T3D_MESH_ABS_ANIM) && (mesh->Flags & T3D_MESH_CHARACTER)))
|
||||
t3dVectAdd(&bone->Trasl[k], &CharCorrection, &bone->Trasl[k]);
|
||||
|
||||
if (pos) {
|
||||
// Oggetti relativi
|
||||
if (!(mesh->Flags & T3D_MESH_CHARACTER) && !(mesh->Flags & T3D_MESH_ABS_ANIM)) {
|
||||
t3dVectTransform(&ld, &bone->Trasl[k], &lm);
|
||||
t3dVectAdd(&bone->Trasl[k], &ld, &lp);
|
||||
}
|
||||
// Personaggi assoluti
|
||||
else if ((mesh->Flags & T3D_MESH_ABS_ANIM) && (mesh->Flags & T3D_MESH_CHARACTER) && (k)) {
|
||||
t3dVectSub(&bone->Trasl[k], &bone->Trasl[k], &Frame0Trasl);
|
||||
t3dVectTransformInv(&bone->Trasl[k], &bone->Trasl[k], &lm);
|
||||
t3dVectAdd(&bone->Trasl[k], &bone->Trasl[k], &CharCorrection);
|
||||
|
||||
t3dMatMul(&bone->Matrix[k], &bone->Matrix[k], &lm);
|
||||
}
|
||||
}
|
||||
/* if(!(mesh->Flags&T3D_MESH_CHARACTER))
|
||||
DebugFile("%3d;%3d;%9f;%9f;%9f;%9f;%9f;%9f;%9f;%9f;%9f;",k,i,
|
||||
bone->Matrix[k].M[0],bone->Matrix[k].M[1],bone->Matrix[k].M[2],
|
||||
bone->Matrix[k].M[3],bone->Matrix[k].M[4],bone->Matrix[k].M[5],
|
||||
bone->Matrix[k].M[6],bone->Matrix[k].M[7],bone->Matrix[k].M[8] );
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
if (db->Dist)
|
||||
for (k = 0; k < db->NumFrames; k++)
|
||||
if ((mesh->Flags & T3D_MESH_CHARACTER) && ((!k) || (mesh->Flags & T3D_MESH_DEFAULTANIM)))
|
||||
db->Dist[k] -= CharCorrection.z;
|
||||
|
||||
if (!(bone0 = &db->BoneTable[0]) || !(bone0->Trasl) || !(bone0->Matrix)) {
|
||||
bone0->Matrix = t3dCalloc<t3dM3X3F>(db->NumFrames);
|
||||
bone0->Trasl = t3dCalloc<t3dV3F>(db->NumFrames);
|
||||
} else
|
||||
warning("Guarda che il bone0 e' gia' stato allocato nella mesh %s", mesh->name.c_str());
|
||||
|
||||
for (k = 0; k < db->NumFrames; k++) {
|
||||
t3dVectCopy(&bone0->Trasl[k], &mesh->Trasl);
|
||||
t3dMatCopy(&bone0->Matrix[k], &mesh->Matrix);
|
||||
}
|
||||
|
||||
if ((mesh->Flags & T3D_MESH_CHARACTER) && !(mesh->Flags & T3D_MESH_DEFAULTANIM)) {
|
||||
if (!(bone = &db->BoneTable[1]) || !(bone->Trasl) || !(bone->Matrix))
|
||||
return ;
|
||||
|
||||
t3dVectInit(&tmp1, bone->Trasl[1].x, 0.0f, bone->Trasl[1].z);
|
||||
t3dVectInit(&tmp, 0.0f, 0.0f, 1.0f);
|
||||
t3dVectTransform(&tmp, &tmp, &bone->Matrix[1]);
|
||||
tmp.y = 0;
|
||||
t3dVectFill(&zero, 0.0f);
|
||||
t3dMatView(&mx, &zero, &tmp);
|
||||
t3dVectTransform(&cc, &CharCorrection, &mx);
|
||||
t3dVectSub(&tmp1, &tmp1, &cc);
|
||||
|
||||
for (frame = 0; frame < db->NumFrames; frame++) {
|
||||
t3dVectInit(&tmp2, bone->Trasl[frame].x, 0.0f, bone->Trasl[frame].z);
|
||||
t3dVectInit(&tmp, 0.0f, 0.0f, 1.0f);
|
||||
t3dVectTransform(&tmp, &tmp, &bone->Matrix[frame]);
|
||||
tmp.y = 0;
|
||||
t3dVectFill(&zero, 0.0f);
|
||||
t3dMatView(&mx, &zero, &tmp);
|
||||
t3dVectTransform(&cc, &CharCorrection, &mx);
|
||||
t3dVectSub(&tmp2, &tmp2, &cc);
|
||||
|
||||
t3dVectSub(&tmp, &tmp2, &tmp1);
|
||||
// t3dVectTransform( &tmp, &tmp, &mesh->Matrix );
|
||||
|
||||
tmp.x += bone->Trasl[1].x - bone->Trasl[0].x;
|
||||
tmp.z += bone->Trasl[1].z - bone->Trasl[0].z;
|
||||
|
||||
t3dVectCopy(&bone0->Trasl[frame], &tmp);
|
||||
t3dVectInit(&tmp, 0.0f, 0.0f, -1.0f);
|
||||
t3dVectTransform(&tmp, &tmp, &bone->Matrix[frame]);
|
||||
tmp.z = -tmp.z;
|
||||
tmp.y = 0;
|
||||
t3dVectFill(&zero, 0.0f);
|
||||
t3dMatView(&bone0->Matrix[frame], &zero, &tmp);
|
||||
}
|
||||
|
||||
for (i = 1; i < db->NumBones; i++) {
|
||||
if (!(bone = &db->BoneTable[i]) || !(bone->Trasl) || !(bone->Matrix))
|
||||
continue;
|
||||
|
||||
for (k = 0; k < db->NumFrames; k++) {
|
||||
t3dVectSub(&bone->Trasl[k], &bone->Trasl[k], &bone0->Trasl[k]);
|
||||
t3dVectTransform(&bone->Trasl[k], &bone->Trasl[k], &bone0->Matrix[k]);
|
||||
t3dMatMulInv(&bone->Matrix[k], &bone->Matrix[k], &bone0->Matrix[k]);
|
||||
}
|
||||
}
|
||||
|
||||
for (k = 0; k < db->NumFrames; k++) {
|
||||
t3dMatMulInv(&bone0->Matrix[k], &mesh->Matrix, &bone0->Matrix[k]);
|
||||
t3dVectTransform(&tmp, &bone0->Trasl[k], &mesh->Matrix);
|
||||
t3dVectAdd(&bone0->Trasl[k], &mesh->Trasl, &tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* -----------------13/04/99 14.57-------------------
|
||||
* LoadShadowMeshes
|
||||
* --------------------------------------------------*/
|
||||
t3dBODY *LoadShadowMeshes(WGame &game, const char *pname, t3dBODY *Body) {
|
||||
uint16 ref;
|
||||
char Name[255];
|
||||
t3dBODY *shadow = new t3dBODY();
|
||||
gVertex *Original = Body->MeshTable[0].VertexBuffer;
|
||||
t3dF32 dist, rez;
|
||||
|
||||
strcpy(Name, pname);
|
||||
strncpy(&Name[strlen(pname) - 4], "_Shadow.t3d\0", 12);
|
||||
uint16 numBodys = 0;
|
||||
shadow = _vm->_roomManager->loadRoom(Name, shadow, &numBodys, (T3D_NOLIGHTMAPS | T3D_NORECURSION | T3D_NOVOLUMETRICLIGHTS | T3D_NOCAMERAS | T3D_NOBOUNDS | T3D_STATIC_SET0 | T3D_STATIC_SET1));
|
||||
if (!shadow) return nullptr;
|
||||
|
||||
for (uint16 i = 0; i < shadow->NumMeshes(); i++) {
|
||||
t3dMESH &m = shadow->MeshTable[i];
|
||||
m.VBptr = m.VertexBuffer;
|
||||
for (uint16 j = 0; j < m.NumFaces(); j++) {
|
||||
t3dFACE &f = m.FList[j];
|
||||
for (uint16 n = 0; n < 3; n++) {
|
||||
t3dV3F pnt;
|
||||
pnt.x = m.VBptr[f.VertexIndex[n]].x;
|
||||
pnt.y = m.VBptr[f.VertexIndex[n]].y;
|
||||
pnt.z = m.VBptr[f.VertexIndex[n]].z;
|
||||
|
||||
ref = 0;
|
||||
dist = 999999999.0f;
|
||||
for (uint16 k = 0; k < Body->MeshTable[0].NumVerts; k++) {
|
||||
t3dV3F tpnt;
|
||||
tpnt.x = Original[k].x;
|
||||
tpnt.y = Original[k].y;
|
||||
tpnt.z = Original[k].z;
|
||||
if ((rez = t3dVectDistance(&pnt, &tpnt)) < dist) {
|
||||
dist = rez;
|
||||
ref = k;
|
||||
}
|
||||
}
|
||||
f.VertexIndex[n] = ref;
|
||||
}
|
||||
}
|
||||
m.VBptr = nullptr;
|
||||
delete[] m.VertexBuffer;
|
||||
m.VertexBuffer = nullptr;
|
||||
delete[] m.OldVertexBuffer;
|
||||
m.OldVertexBuffer = nullptr;
|
||||
delete[] m.SavedVertexBuffer;
|
||||
m.SavedVertexBuffer = nullptr;
|
||||
|
||||
m.VertexBuffer = Body->MeshTable[0].VertexBuffer;
|
||||
m.NumVerts = Body->MeshTable[0].NumVerts;
|
||||
m.Flags |= T3D_MESH_CHARACTER; //this is a character
|
||||
}
|
||||
return shadow;
|
||||
}
|
||||
|
||||
|
||||
/* -----------------30/12/98 11.27-------------------
|
||||
* t3dLoadCharacter
|
||||
* --------------------------------------------------*/
|
||||
t3dCHARACTER *t3dLoadCharacter(WGame &game, const char *pname, uint16 num) {
|
||||
warning("LoadCharacter(%s)", pname);
|
||||
uint8 Mirror = 1;
|
||||
uint16 numBody = 0, f;
|
||||
t3dV3F tmp;
|
||||
// gVertex *v;
|
||||
|
||||
t3dCHARACTER *b = new t3dCHARACTER[1] {};
|
||||
b->Body = _vm->_roomManager->loadRoom(pname, b->Body, &numBody, (T3D_NOLIGHTMAPS | T3D_NORECURSION | T3D_NOVOLUMETRICLIGHTS | T3D_NOCAMERAS | T3D_STATIC_SET0 | T3D_STATIC_SET1));
|
||||
if (!b->Body) {
|
||||
delete[] b;
|
||||
return nullptr;
|
||||
}
|
||||
b->Mesh = &b->Body->MeshTable[0];
|
||||
b->CurRoom = t3dCurRoom;
|
||||
b->Flags = T3D_CHARACTER_HIDE | T3D_CHARACTER_REALTIMELIGHTING;
|
||||
if (num >= 2) b->Flags |= T3D_CHARACTER_BNDHIDE;
|
||||
//Try to load animation
|
||||
if (t3dLoadAnimation(game, pname, b->Mesh, T3D_MESH_DEFAULTANIM) == -1) {
|
||||
warning("t3dLoadCharacter: Error loading %s", pname);
|
||||
delete[] b;
|
||||
return nullptr;
|
||||
}
|
||||
FixupAnim(b->Mesh, 0, "");
|
||||
|
||||
// Zero's all the Normals vars, 'cause I recalc all the normals runtime...
|
||||
b->Body->NumNormals = 0;
|
||||
b->Body->NumVerticesNormals = 0;
|
||||
|
||||
for (uint16 i = 0; i < b->Body->NumMeshes(); i++) {
|
||||
t3dMESH &mesh = b->Body->MeshTable[i];
|
||||
for (f = 0; f < mesh.NumFaces(); f++) {
|
||||
mesh.FList[f].n = nullptr;
|
||||
}
|
||||
//sb
|
||||
//sb mesh->Flags|=T3D_MESH_CASTREALTIMESHADOWS;
|
||||
//sb
|
||||
}
|
||||
b->Body->NList.clear();
|
||||
//sb
|
||||
//sb b->Flags|=T3D_CHARACTER_CASTREALTIMESHADOWS;
|
||||
//sb
|
||||
// Per gli specchi
|
||||
if (Mirror) { // Ogni personaggio potrebbe apparire in uno specchio
|
||||
b->Body->MirrorMatTable.resize(b->Body->NumMaterials());
|
||||
|
||||
rCopyMaterialList(b->Body->MirrorMatTable, b->Body->MatTable, b->Body->NumMaterials());
|
||||
}
|
||||
|
||||
// Per le ombre, altezza e raggio del cilindro
|
||||
b->Height = (t3dF32)sqrt(b->Mesh->BBox[0].p.x * b->Mesh->BBox[0].p.x + b->Mesh->BBox[0].p.z * b->Mesh->BBox[0].p.z);
|
||||
b->Radius = (t3dF32)sqrt(b->Mesh->BBox[5].p.x * b->Mesh->BBox[5].p.x + b->Mesh->BBox[5].p.z * b->Mesh->BBox[5].p.z);
|
||||
if (b->Radius < b->Height) b->Radius = b->Height;
|
||||
b->Height = (b->Mesh->BBox[0].p.y - b->Mesh->BBox[2].p.y) * 1.2f;
|
||||
|
||||
// No bounding box detection
|
||||
/* t3dVectFill(&b->Mesh->BBox[0].p,0.0f);
|
||||
t3dVectFill(&b->Mesh->BBox[1].p,0.0f);
|
||||
t3dVectFill(&b->Mesh->BBox[2].p,0.0f);
|
||||
t3dVectFill(&b->Mesh->BBox[3].p,0.0f);
|
||||
t3dVectFill(&b->Mesh->BBox[4].p,0.0f);
|
||||
t3dVectFill(&b->Mesh->BBox[5].p,0.0f);
|
||||
t3dVectFill(&b->Mesh->BBox[6].p,0.0f);
|
||||
t3dVectFill(&b->Mesh->BBox[7].p,0.0f);
|
||||
b->Mesh->Flags|=T3D_MESH_NOBOUNDBOX;
|
||||
*/
|
||||
for (uint16 i = 0; i < b->Body->NumMeshes(); i++) {
|
||||
b->Body->MeshTable[i].Flags |= T3D_MESH_CHARACTER;
|
||||
b->Body->MeshTable[i].Flags &= ~T3D_MESH_MIRROR;
|
||||
}
|
||||
|
||||
t3dVectFill(&b->Pos, 0.0f);
|
||||
t3dVectInit(&tmp, 0.0f, 0.0f, -1.0f);
|
||||
t3dVectAdd(&tmp, &b->Pos, &tmp);
|
||||
t3dMatView(&b->Mesh->Matrix, &b->Pos, &tmp);
|
||||
|
||||
b->Mesh->Matrix.Flags &= ~T3D_MATRIX_IDENTITY;
|
||||
b->Mesh->CurFrame = 4;
|
||||
b->Mesh->LastFrame = 0;
|
||||
b->Mesh->BlendPercent = 255;
|
||||
|
||||
b->Walk.OldPanel = -1;
|
||||
b->Walk.CurPanel = -1;
|
||||
b->Walk.NumPathNodes = -1;
|
||||
|
||||
t3dVectInit(&b->Dir, 0.0f, 0.0f, -1.0f);
|
||||
t3dVectTransform(&b->Dir, &b->Dir, &b->Mesh->Matrix); //rotate by Character angle
|
||||
|
||||
//sb
|
||||
if (num < 2)
|
||||
b->Shadow = LoadShadowMeshes(game, pname, b->Body);
|
||||
else
|
||||
b->Shadow = nullptr;
|
||||
//sb
|
||||
return b;
|
||||
}
|
||||
|
||||
/* -----------------25/09/98 16.07-------------------
|
||||
* GetFullLightPosition
|
||||
* --------------------------------------------------*/
|
||||
uint8 GetFullLightDirection(t3dV3F *dest, uint8 pos) {
|
||||
if (!pos) return 0;
|
||||
|
||||
auto pLights = t3dCurRoom->getPositionalLight(pos);
|
||||
for (const auto &light : pLights) {
|
||||
if (light.Dir.x && light.Dir.z) {
|
||||
*dest = light.Dir;
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
|
||||
if (pos != 99)
|
||||
DebugLogFile("Can't find fldir %d in %s", pos, t3dCurRoom->name.c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -----------------21/12/98 16.40-------------------
|
||||
* ReleasePreloadedAnims
|
||||
* --------------------------------------------------*/
|
||||
void ReleasePreloadedAnims() {
|
||||
int32 i, j;
|
||||
|
||||
for (j = 0; j < MAX_PRELOADED_ANIMS; j++) {
|
||||
// Disalloca tutto
|
||||
for (i = 0; i < MAX_BONES; i++) {
|
||||
t3dFree(PreloadedAnim[j].Bone[i].Trasl);
|
||||
t3dFree(PreloadedAnim[j].Bone[i].Euler);
|
||||
}
|
||||
delete[] PreloadedAnim[j].Dist;
|
||||
PreloadedAnim[j] = t3dLOADANIM();
|
||||
}
|
||||
}
|
||||
|
||||
/* -----------------02/05/00 9.30--------------------
|
||||
* CompareLightPosition
|
||||
* --------------------------------------------------*/
|
||||
uint8 CompareLightPosition(char *roomname, uint8 pos1, t3dV3F *pos2, t3dF32 acceptable_dist) {
|
||||
t3dV3F p1;
|
||||
t3dBODY *t;
|
||||
|
||||
if ((pos1 <= 0) || (pos2 == nullptr)) return FALSE;
|
||||
|
||||
// cerco la stanza
|
||||
t = nullptr;
|
||||
if (roomname && (roomname[0] != '\0')) {
|
||||
t = _vm->_roomManager->getRoomIfLoaded(roomname);
|
||||
} else t = t3dCurRoom;
|
||||
|
||||
if (!t) return FALSE;
|
||||
|
||||
auto pLights = t->getPositionalLight(pos1);
|
||||
bool foundLight = false;
|
||||
for (auto &light : pLights) {
|
||||
if (light.Pos.x && light.Pos.z) {
|
||||
p1.x = light.Pos.x;
|
||||
p1.y = light.Pos.y;
|
||||
p1.z = light.Pos.z;
|
||||
foundLight = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!foundLight) return FALSE;
|
||||
|
||||
if (t3dVectSquaredDistance(&p1, pos2) <= acceptable_dist) return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
44
engines/watchmaker/3d/animation.h
Normal file
44
engines/watchmaker/3d/animation.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WATCHMAKER_ANIMATION_H
|
||||
#define WATCHMAKER_ANIMATION_H
|
||||
|
||||
#include "watchmaker/t3d.h"
|
||||
#include "watchmaker/3d/t3d_body.h"
|
||||
#include "watchmaker/work_dirs.h"
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
uint8 GetLightDirection(t3dV3F *dest, uint8 pos);
|
||||
unsigned char GetLightPosition(t3dV3F *dest, unsigned char pos);
|
||||
uint8 GetFullLightDirection(t3dV3F *dest, uint8 pos);
|
||||
|
||||
void FixupAnim(t3dMESH *mesh, unsigned char pos, const char *room);
|
||||
t3dBODY *LoadShadowMeshes(WGame &game, const char *pname, t3dBODY *Body);
|
||||
int8 t3dLoadAnimation(WGame &game, const char *s, t3dMESH *mesh, uint16 Flag);
|
||||
t3dCHARACTER *t3dLoadCharacter(WGame &game, const char *pname, uint16 num);
|
||||
void ReleasePreloadedAnims();
|
||||
uint8 CompareLightPosition(char *roomname, uint8 pos1, t3dV3F *pos2, t3dF32 acceptable_dist);
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
|
||||
#endif // WATCHMAKER_ANIMATION_H
|
||||
105
engines/watchmaker/3d/dds_header.cpp
Normal file
105
engines/watchmaker/3d/dds_header.cpp
Normal file
@@ -0,0 +1,105 @@
|
||||
/* 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 "common/textconsole.h"
|
||||
#include "common/ptr.h"
|
||||
#include "watchmaker/3d/dds_header.h"
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
DDSHeader::DDSHeader(Common::SeekableReadStream &stream) {
|
||||
//warning("TODO: Implement DDS Header parsing");
|
||||
uint32 retv = MKTAG(' ', 'S', 'D', 'D');
|
||||
uint32 magic = stream.readUint32LE();
|
||||
if (magic != retv) {
|
||||
error("parseDDSHeader: Wrong Magic, expected %08X, got %08X\n", retv, magic);
|
||||
}
|
||||
// The size counts the datastructure, which doesn't include the magic
|
||||
int initialPos = stream.pos();
|
||||
uint32 size = stream.readUint32LE();
|
||||
/*uint32 flags = */ stream.readUint32LE();
|
||||
this->height = stream.readUint32LE();
|
||||
this->width = stream.readUint32LE();
|
||||
/*uint32 dataSize = */ stream.readUint32LE();
|
||||
stream.seek(13 * 4, SEEK_CUR);
|
||||
stream.readUint32LE();
|
||||
uint32 pfFlags = stream.readUint32LE();
|
||||
assert(pfFlags & 0x4); // For now we assume compressed DDS only.
|
||||
compression = (DxtCompression)stream.readUint32LE();
|
||||
// Since we're ignoring a fair amount of header, we still need to position
|
||||
// ourselves as if we read it.
|
||||
stream.seek(initialPos + size, SEEK_SET);
|
||||
}
|
||||
|
||||
uint32 blockSize(DxtCompression compression) {
|
||||
switch (compression) {
|
||||
case DxtCompression::DXT1:
|
||||
return 8;
|
||||
default:
|
||||
return 16;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 DDSHeader::dataSize() const {
|
||||
int blockCount = ceil(width / 4.0) * ceil(height / 4.0);
|
||||
return blockCount * blockSize(compression);
|
||||
}
|
||||
|
||||
class DDSTextureData : public TextureData {
|
||||
private:
|
||||
unsigned int _dataSize = 0;
|
||||
byte *_data = nullptr;
|
||||
DDSHeader _header;
|
||||
public:
|
||||
DDSTextureData(byte *data, uint32 dataSize, DDSHeader header) : TextureData(header.compression),
|
||||
_data(data),
|
||||
_dataSize(dataSize),
|
||||
_header(header) {}
|
||||
~DDSTextureData() override {
|
||||
delete[] _data;
|
||||
}
|
||||
int getWidth() const override {
|
||||
return _header.width;
|
||||
}
|
||||
int getHeight() const override {
|
||||
return _header.height;
|
||||
}
|
||||
int getDataSize() const override {
|
||||
return _dataSize;
|
||||
}
|
||||
const void *getData() const override {
|
||||
return _data;
|
||||
}
|
||||
};
|
||||
|
||||
Common::SharedPtr<TextureData> loadDdsTexture(Common::SeekableReadStream &stream) {
|
||||
DDSHeader header(stream);
|
||||
return loadDdsTexture(stream, header);
|
||||
}
|
||||
|
||||
Common::SharedPtr<TextureData> loadDdsTexture(Common::SeekableReadStream &stream, DDSHeader &header) {
|
||||
assert(header.width > 0);
|
||||
unsigned char *data = new unsigned char[header.dataSize()]();
|
||||
stream.read(data, header.dataSize());
|
||||
return Common::SharedPtr<TextureData>(new DDSTextureData(data, header.dataSize(), header));
|
||||
}
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
73
engines/watchmaker/3d/dds_header.h
Normal file
73
engines/watchmaker/3d/dds_header.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WATCHMAKER_DDSHEADER_H
|
||||
#define WATCHMAKER_DDSHEADER_H
|
||||
|
||||
#include "common/ptr.h"
|
||||
#include "common/stream.h"
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
enum class DxtCompression : uint32 {
|
||||
UNCOMPRESSED = 0,
|
||||
DXT1 = MKTAG('1', 'T', 'X', 'D'),
|
||||
DXT2 = MKTAG('2', 'T', 'X', 'D'),
|
||||
DXT3 = MKTAG('3', 'T', 'X', 'D'),
|
||||
DXT4 = MKTAG('4', 'T', 'X', 'D'),
|
||||
DXT5 = MKTAG('5', 'T', 'X', 'D')
|
||||
};
|
||||
|
||||
class TextureData {
|
||||
public:
|
||||
DxtCompression _compression;
|
||||
TextureData(DxtCompression compression) : _compression(compression) {}
|
||||
virtual ~TextureData() {}
|
||||
virtual int getWidth() const = 0;
|
||||
virtual int getHeight() const = 0;
|
||||
virtual int getDataSize() const = 0;
|
||||
virtual const void *getData() const = 0;
|
||||
};
|
||||
|
||||
class Texture {
|
||||
public:
|
||||
virtual ~Texture() {}
|
||||
virtual void assignData(const TextureData &data) = 0;
|
||||
virtual void bind() = 0;
|
||||
};
|
||||
|
||||
|
||||
struct DDSHeader {
|
||||
DDSHeader() {}
|
||||
DDSHeader(Common::SeekableReadStream &stream);
|
||||
int height = 0;
|
||||
int width = 0;
|
||||
uint32 dataSize() const;
|
||||
DxtCompression compression = DxtCompression::UNCOMPRESSED;
|
||||
};
|
||||
|
||||
//Common::SharedPtr<Texture> loadTgaTextureData(Common::SeekableReadStream &stream);
|
||||
Common::SharedPtr<TextureData> loadDdsTexture(Common::SeekableReadStream &stream, DDSHeader &header);
|
||||
Common::SharedPtr<TextureData> loadDdsTexture(Common::SeekableReadStream &stream);
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
|
||||
#endif // WATCHMAKER_DDSHEADER_H
|
||||
3412
engines/watchmaker/3d/geometry.cpp
Normal file
3412
engines/watchmaker/3d/geometry.cpp
Normal file
File diff suppressed because it is too large
Load Diff
90
engines/watchmaker/3d/geometry.h
Normal file
90
engines/watchmaker/3d/geometry.h
Normal file
@@ -0,0 +1,90 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WATCHMAKER_GEOMETRY_H
|
||||
#define WATCHMAKER_GEOMETRY_H
|
||||
|
||||
#include "watchmaker/t3d.h"
|
||||
|
||||
#define MAX_RECURSION_LEVEL 10
|
||||
|
||||
#define MAX_PARTICLES 10
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
#define LEFTCLIP 0
|
||||
#define RIGHTCLIP 1
|
||||
#define TOPCLIP 2
|
||||
#define BOTTOMCLIP 3
|
||||
#define NUMCLIPPLANES 4
|
||||
|
||||
extern t3dNORMAL ClipPlanes[NUMCLIPPLANES];
|
||||
|
||||
extern t3dBODY *t3dCurRoom, *t3dOrigRoom;
|
||||
extern t3dCAMERA *t3dCurCamera;
|
||||
extern t3dM3X3F t3dCurViewMatrix;
|
||||
extern t3dBODY *PortalCrossed;
|
||||
extern t3dCHARACTER *t3dCurCharacter;
|
||||
extern uint32 t3d_NumMeshesVisible;
|
||||
extern t3dMESH *t3d_VisibleMeshes[];
|
||||
|
||||
extern t3dBODY *t3dRxt;
|
||||
extern t3dBODY *t3dSky;
|
||||
//s extern t3dBODY *t3dSun;
|
||||
|
||||
extern uint8 FloorHit;
|
||||
extern t3dV3F t3d3dMousePos;
|
||||
extern t3dV3F FloorHitCoords;
|
||||
extern uint32 StatNumTris, StatNumVerts;
|
||||
|
||||
struct WindowInfo;
|
||||
|
||||
uint16 t3dBackfaceCulling(NormalList &normals, uint32 NumNormals, t3dV3F *eye);
|
||||
|
||||
void t3dReleaseBody(t3dBODY *b);
|
||||
void t3dReleaseCharacter(t3dCHARACTER *b);
|
||||
unsigned char t3dCreateSmokeParticle(unsigned int Num, unsigned char Type, unsigned int Opacity);
|
||||
void t3dCalcRejectedMeshFromPortal(t3dBODY *body);
|
||||
void t3dSetViewport(t3dCAMERA *cam, WindowInfo &info, t3dF32 fov, uint8 sup);
|
||||
t3dF32 t3dCheckWithFloor();
|
||||
void t3dCreateProceduralSky();
|
||||
void t3dCalcMeshBones(t3dMESH *mesh, int32 last);
|
||||
void t3dResetPipeline();
|
||||
void t3dRotateMoveCamera(t3dCAMERA *cam, t3dF32 AngleX, t3dF32 AngleY, t3dF32 AngleSpeed);
|
||||
void t3dReleaseParticles();
|
||||
void t3dResetMesh(t3dMESH *mesh);
|
||||
void t3dShowBoundingBox(t3dBODY *b);
|
||||
void t3dShowBounds(t3dPAN *p, uint32 numpan);
|
||||
bool t3dTransformBody(t3dBODY *b);
|
||||
void t3dTransformSky();
|
||||
bool t3dTransformCharacter(t3dCHARACTER *c);
|
||||
void t3dProcessPortals();
|
||||
t3dBODY *t3dCheckPortalCrossed(t3dV3F *a);
|
||||
void t3dSortMeshes();
|
||||
void QueueMaterialList(MaterialTable &MatList, unsigned int NumMat, signed short int ViewMatrixNum);
|
||||
void ProcessMaterialList();
|
||||
void t3dAddTriangle(t3dF32 x1, t3dF32 y1, t3dF32 x2, t3dF32 y2, t3dF32 x3, t3dF32 y3,
|
||||
int32 r, int32 g, int32 b, int32 a);
|
||||
void t3dAddQuad(t3dF32 x1, t3dF32 y1, t3dF32 x2, t3dF32 y2, t3dF32 x3, t3dF32 y3, t3dF32 x4, t3dF32 y4,
|
||||
int32 r, int32 g, int32 b, int32 a);
|
||||
} // End of namespace Watchmaker
|
||||
|
||||
#endif // WATCHMAKER_GEOMETRY_H
|
||||
464
engines/watchmaker/3d/light.cpp
Normal file
464
engines/watchmaker/3d/light.cpp
Normal file
@@ -0,0 +1,464 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_strcat
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_strcpy
|
||||
|
||||
#include "watchmaker/3d/light.h"
|
||||
#include "watchmaker/3d/geometry.h"
|
||||
#include "watchmaker/3d/loader.h"
|
||||
#include "watchmaker/3d/math/llmath.h"
|
||||
#include "watchmaker/3d/t3d_body.h"
|
||||
#include "watchmaker/3d/t3d_mesh.h"
|
||||
#include "watchmaker/file_utils.h"
|
||||
#include "watchmaker/game.h"
|
||||
#include "watchmaker/ll/ll_system.h"
|
||||
#include "watchmaker/renderer.h"
|
||||
#include "watchmaker/t3d.h"
|
||||
#include "watchmaker/types.h"
|
||||
#include "watchmaker/utils.h"
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
/* -----------------29/05/99 11.41-------------------
|
||||
* Illumina un t3dVERTEX (per WmGen)
|
||||
* --------------------------------------------------*/
|
||||
uint8 LightVertex(t3dVERTEX *vv, t3dV3F *v, t3dLIGHT *light) {
|
||||
t3dF32 dist, direction, ang, deg, Intensity1 = 1.0f, Intensity2 = 1.0f;
|
||||
t3dV3F vdist, dir, finallight;
|
||||
t3dF32 half_hotspot = DEGREE_TO_RADIANS(light->HotSpot) * 0.5f,
|
||||
half_falloff = DEGREE_TO_RADIANS(light->FallOff) * 0.5f;
|
||||
|
||||
t3dVectSub(&vdist, v, &light->Source);
|
||||
dist = t3dVectMod(&vdist);
|
||||
|
||||
t3dVectFill(&finallight, 0.0f);
|
||||
|
||||
if ((light->Type & T3D_LIGHT_SPOTLIGHT)) {
|
||||
t3dVectSub(&dir, &light->Target, &light->Source); // Serve per Spot
|
||||
direction = t3dVectMod(&dir);
|
||||
|
||||
ang = (float)acos(t3dVectDot(&vdist, &dir) / (direction * dist));
|
||||
if ((ang > (half_hotspot))) {
|
||||
if (ang > (half_falloff)) {
|
||||
Intensity2 = 0.0f;
|
||||
Intensity1 = 0.0f;
|
||||
} else {
|
||||
Intensity1 = 1.0;
|
||||
deg = half_hotspot + (ang - half_hotspot);
|
||||
Intensity2 = (half_falloff - deg) / (half_falloff - half_hotspot);
|
||||
}
|
||||
} else {
|
||||
Intensity1 = 1.0;
|
||||
Intensity2 = 1.0;
|
||||
}
|
||||
|
||||
if ((light->Type & T3D_LIGHT_ATTENUATION)) {
|
||||
if ((dist > light->NearRange)) {
|
||||
if (dist > light->FarRange) {
|
||||
Intensity1 = 0.0f;
|
||||
Intensity2 = 0.0f;
|
||||
} else {
|
||||
dist = light->NearRange + (dist - light->NearRange);
|
||||
Intensity2 *= (light->FarRange - dist) / (light->FarRange - light->NearRange);
|
||||
Intensity1 *= 1.0f;
|
||||
}
|
||||
} else {
|
||||
Intensity1 *= 1.0f;
|
||||
Intensity2 *= 1.0f;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ((light->Type & T3D_LIGHT_ATTENUATION)) {
|
||||
if ((dist < light->NearRange)) {
|
||||
Intensity1 = 1.0f;
|
||||
Intensity2 = 1.0f;
|
||||
} else {
|
||||
Intensity1 = 1.0f;
|
||||
|
||||
if (dist > light->FarRange)
|
||||
Intensity2 = 0.0f;
|
||||
else {
|
||||
dist = light->NearRange + (dist - light->NearRange);
|
||||
Intensity2 *= (light->FarRange - dist) / (light->FarRange - light->NearRange);
|
||||
Intensity1 *= 1.0f;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Intensity1 = 1.0;
|
||||
Intensity2 = 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
if ((Intensity1 == 0.0f) || (Intensity2 == 0.0f)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
finallight = light->Color * (Intensity1 * Intensity2 * light->Multiplier);
|
||||
|
||||
if (finallight.x > 255.0f) finallight.x = 255.0f;
|
||||
if (finallight.y > 255.0f) finallight.y = 255.0f;
|
||||
if (finallight.z > 255.0f) finallight.z = 255.0f;
|
||||
vv->r = (uint8)finallight.x;
|
||||
vv->g = (uint8)finallight.y;
|
||||
vv->b = (uint8)finallight.z;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* -----------------29/05/99 11.41-------------------
|
||||
* Illumina un gVertex (per game)
|
||||
* --------------------------------------------------*/
|
||||
uint8 LightgVertex(gVertex *v, t3dLIGHT *light) {
|
||||
t3dVERTEX vv;
|
||||
t3dV3F vt;
|
||||
|
||||
vt.x = v->x;
|
||||
vt.y = v->y;
|
||||
vt.z = v->z;
|
||||
|
||||
if (LightVertex(&vv, &vt, light))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/* -----------------29/05/99 11.55-------------------
|
||||
* setDirectoryAndName
|
||||
* --------------------------------------------------*/
|
||||
Common::String setDirectoryAndName(const Common::String &path, const Common::String &name) {
|
||||
int32 len = name.size();
|
||||
|
||||
auto backSlashPos = name.findLastOf("\\");
|
||||
|
||||
if (backSlashPos != Common::String::npos) {
|
||||
len = backSlashPos;
|
||||
}
|
||||
|
||||
return path + name.substr(0, len);
|
||||
}
|
||||
|
||||
/* -----------------29/05/99 12.03-------------------
|
||||
* LoadVolumetricMap
|
||||
* --------------------------------------------------*/
|
||||
void LoadVolumetricMap(WorkDirs &workDirs, const char *pname, t3dBODY *b) {
|
||||
uint32 i, j, k;
|
||||
|
||||
auto stream = workDirs.resolveFile(pname);
|
||||
if (!(stream)) {
|
||||
//t DebugLogWindow("File %s not found: assuming no volumetriclights informations",pname);
|
||||
return ;
|
||||
}
|
||||
|
||||
if ((i = stream->readSint32LE()) != VOLLIGHTFILEVERSION) {
|
||||
warning("Invalid File version: %s file version is: %d\t You need the version: %d", pname, i, VOLLIGHTFILEVERSION);
|
||||
return ;
|
||||
}
|
||||
|
||||
b->VolumetricLights = Common::SharedPtr<t3dVolLights>(new t3dVolLights());
|
||||
b->VolumetricLights->CellsSize = stream->readFloatLE();
|
||||
b->VolumetricLights->xcells = stream->readSint32LE();
|
||||
b->VolumetricLights->ycells = stream->readSint32LE();
|
||||
b->VolumetricLights->zcells = stream->readSint32LE();
|
||||
|
||||
b->VolumetricLights->VolMap.resize(b->VolumetricLights->ycells * b->VolumetricLights->xcells * b->VolumetricLights->zcells);
|
||||
for (i = 0; i < b->VolumetricLights->ycells - 1; i++) {
|
||||
for (j = 0; j < b->VolumetricLights->zcells - 1; j++) {
|
||||
for (k = 0; k < b->VolumetricLights->xcells - 1; k++) {
|
||||
b->VolumetricLights->VolMap[(k) + ((j)*b->VolumetricLights->xcells) + ((i)*b->VolumetricLights->xcells * b->VolumetricLights->zcells)] = stream->readByte();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* -----------------29/05/99 12.04-------------------
|
||||
* t3dLoadOutdoorLights
|
||||
* --------------------------------------------------*/
|
||||
void t3dLoadOutdoorLights(const char *pname, t3dBODY *b, int32 ora) {
|
||||
warning("STUBBED, t3dLoadOutdoorLights");
|
||||
#if 0
|
||||
t3dU32 i, j, k;
|
||||
t3dMESH *m;
|
||||
gVertex *gv;
|
||||
t3dU32 nverts;
|
||||
char Name[T3D_NAMELEN];
|
||||
t3dU32 len;
|
||||
DWORD *Buf, *t;
|
||||
t3dLIGHT *l;
|
||||
|
||||
if (!pname || !b) return;
|
||||
|
||||
i = 0;
|
||||
if (ora >= 1130) i++;
|
||||
if ((ora >= 1300) && (ora <= 1310)) i++;
|
||||
if (ora >= 1800) i++;
|
||||
if (ora >= 2030) i++;
|
||||
|
||||
if (i == (t3dU32)t3dCurOliSet) return;
|
||||
|
||||
len = strlen(pname);
|
||||
memset(Name, 0, sizeof(Name));
|
||||
strncpy(Name, pname, len - 4);
|
||||
strcat(Name, ".oli");
|
||||
|
||||
if (!(t3dOpenFile(Name))) {
|
||||
DebugLogWindow("Unable to open OLI file %s", Name);
|
||||
return ;
|
||||
}
|
||||
|
||||
if ((i = t3dRead32()) != OUTDOORLIGHTSFILEVERSION) {
|
||||
DebugLogWindow("Invalid File version: %s file version is: %d\t You need the version: %d", pname, i, VOLLIGHTFILEVERSION);
|
||||
return ;
|
||||
}
|
||||
|
||||
if ((nverts = t3dRead32()) != b->NumTotVerts) {
|
||||
DebugLogWindow("Old OLI File %s!", pname);
|
||||
t3dCurOliSet = i;
|
||||
t3dCreateProceduralSky();
|
||||
return ;
|
||||
}
|
||||
|
||||
Buf = t = (DWORD *)t3dMalloc(nverts * sizeof(DWORD));
|
||||
|
||||
t3dCurOliSet = 0;
|
||||
t3dCurTime = ora;
|
||||
if (ora >= 1130) {
|
||||
t3dReadData(Buf, nverts * sizeof(DWORD));
|
||||
t3dCurOliSet++;
|
||||
}
|
||||
if ((ora >= 1300) && (ora <= 1310)) {
|
||||
t3dReadData(Buf, nverts * sizeof(DWORD));
|
||||
t3dCurOliSet++;
|
||||
}
|
||||
if (ora >= 1800) {
|
||||
t3dReadData(Buf, nverts * sizeof(DWORD));
|
||||
t3dCurOliSet++;
|
||||
}
|
||||
if (ora >= 2030) {
|
||||
t3dReadData(Buf, nverts * sizeof(DWORD));
|
||||
t3dCurOliSet++;
|
||||
}
|
||||
|
||||
t3dReadData(Buf, nverts * sizeof(DWORD));
|
||||
t3dCloseFile();
|
||||
|
||||
for (i = 0, m = b->MeshTable; i < b->NumMeshes; i++, m++) {
|
||||
#ifndef WMGEN
|
||||
m->VBptr = m->VertexBuffer;
|
||||
#endif
|
||||
for (j = 0, gv = m->VBptr; j < m->NumVerts; j++, gv++, t++) {
|
||||
gv->diffuse = *t;
|
||||
}
|
||||
m->Flags |= T3D_MESH_UPDATEVB;
|
||||
#ifndef WMGEN
|
||||
m->VBptr = nullptr;
|
||||
#endif
|
||||
}
|
||||
t3dFree(Buf);
|
||||
|
||||
t3dVectCopy(&b->AmbientLight, &OliAmbient[t3dCurOliSet]);
|
||||
|
||||
l = b->LightTable;
|
||||
for (k = 0; k < b->NumLights; k++, l++) {
|
||||
if (l->Type & T3D_LIGHT_SOLARVARIATION) {
|
||||
if (l->Type & T3D_LIGHT_SUN)
|
||||
t3dVectCopy(&l->Source, &l->SolarPos[t3dCurOliSet]);
|
||||
t3dVectCopy(&l->Color, &l->SolarColor[t3dCurOliSet]);
|
||||
|
||||
l->Type |= T3D_LIGHT_LIGHTON;
|
||||
if ((t3dCurOliSet == 0) && (l->Type & T3D_LIGHT_OFF_MORNING)) l->Type &= ~T3D_LIGHT_LIGHTON;
|
||||
if ((t3dCurOliSet == 1) && (l->Type & T3D_LIGHT_OFF_AFTERNOON)) l->Type &= ~T3D_LIGHT_LIGHTON;
|
||||
if ((t3dCurOliSet == 2) && (l->Type & T3D_LIGHT_OFF_EVENING)) l->Type &= ~T3D_LIGHT_LIGHTON;
|
||||
if ((t3dCurOliSet == 3) && (l->Type & T3D_LIGHT_OFF_NIGHT)) l->Type &= ~T3D_LIGHT_LIGHTON;
|
||||
|
||||
if (l->Color.x > 255.0f) l->Color.x = 255.0f;
|
||||
if (l->Color.y > 255.0f) l->Color.y = 255.0f;
|
||||
if (l->Color.z > 255.0f) l->Color.z = 255.0f;
|
||||
if (l->Color.x < 0.0f) l->Color.x = 0.0f;
|
||||
if (l->Color.y < 0.0f) l->Color.y = 0.0f;
|
||||
if (l->Color.z < 0.0f) l->Color.z = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
t3dCreateProceduralSky();
|
||||
#endif
|
||||
}
|
||||
|
||||
/* -----------------29/05/99 12.01-------------------
|
||||
* GetBoundaries
|
||||
* --------------------------------------------------*/
|
||||
void GetBoundaries(t3dBODY *b, t3dF32 *minx, t3dF32 *miny, t3dF32 *minz, t3dF32 *maxx, t3dF32 *maxy, t3dF32 *maxz) {
|
||||
gVertex *gv;
|
||||
|
||||
*minx = *miny = *minz = 999999999.9f;
|
||||
*maxx = *maxy = *maxz = -999999999.9f;
|
||||
|
||||
for (uint32 i = 0; i < b->NumMeshes(); i++) {
|
||||
#ifndef WMGEN
|
||||
gv = b->MeshTable[i].VertexBuffer;
|
||||
#else
|
||||
gv = (gVertex *)(m->VBptr);
|
||||
#endif
|
||||
|
||||
for (uint32 j = 0; j < b->MeshTable[i].NumVerts; j++, gv++) {
|
||||
if (gv->x < *minx) *minx = gv->x;
|
||||
if (gv->y < *miny) *miny = gv->y;
|
||||
if (gv->z < *minz) *minz = gv->z;
|
||||
|
||||
if (gv->x > *maxx) *maxx = gv->x;
|
||||
if (gv->y > *maxy) *maxy = gv->y;
|
||||
if (gv->z > *maxz) *maxz = gv->z;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
t3dLIGHT::t3dLIGHT(WGame &game, t3dBODY *b, WorkDirs &workDirs, Common::SeekableReadStream &stream) {
|
||||
Type = stream.readUint32LE(); // Legge tipo
|
||||
// DebugFile("%d: SPOT %X ATTEN %X SHAD %X",light,Light[light].Type&T3D_LIGHT_SPOTLIGHT,Light[light].Type&T3D_LIGHT_ATTENUATION,Light[light].Type&T3D_LIGHT_CASTSHADOWS);
|
||||
Source = t3dV3F(stream) * SCALEFACTOR; // Legge Source
|
||||
Target = t3dV3F(stream) * SCALEFACTOR; // Legge Target
|
||||
|
||||
HotSpot = stream.readFloatLE() * SCALEFACTOR;
|
||||
FallOff = stream.readFloatLE() * SCALEFACTOR;
|
||||
|
||||
Color = t3dV3F(stream); // Legge Color
|
||||
|
||||
NearRange = stream.readFloatLE() * SCALEFACTOR;
|
||||
FarRange = stream.readFloatLE() * SCALEFACTOR;
|
||||
|
||||
Multiplier = stream.readFloatLE();
|
||||
Flicker = stream.readByte();
|
||||
|
||||
t3dBackfaceCulling(b->NList, (uint16)(b->NumNormals + b->NumVerticesNormals), &Source); // Setta le facce che sono backface
|
||||
//f t3dPreLigthVertices(b->NList, b->VList, (t3dU16)b->NumVerts, &Light[light]); // Illumina facce che non sono backface
|
||||
|
||||
|
||||
if (Flicker) { // Aggiorna Vertici visibili per flicker
|
||||
Type |= T3D_LIGHT_PULSE;
|
||||
setupVisibleVerticesFromLight(b);
|
||||
AnimLight.LastRandomizer = 0;
|
||||
}
|
||||
|
||||
if (Type & T3D_LIGHT_FLARE) { // Se ha una flare
|
||||
//f Light[light].Type&=~T3D_LIGHT_LIGHTON; // La spegne
|
||||
FlareSize = stream.readFloatLE() * SCALEFACTOR; // Legge il size della flare
|
||||
|
||||
Common::String name = readT3dString(stream); // Legge nome dellaq texture
|
||||
Common::String appo;
|
||||
#ifndef WMGEN
|
||||
if (hasFileExtension(name, "avi")) {
|
||||
appo = workDirs._moviesDir + name; // altrimenti prende quello di default
|
||||
} else {
|
||||
appo = workDirs._mapsDir + name;; // altrimenti prende quello di default
|
||||
}
|
||||
#else
|
||||
strcpy(Appo, WmMapsDir);
|
||||
strcat(Appo, Name);
|
||||
#endif
|
||||
|
||||
#ifndef WMGEN
|
||||
if (!(game._renderer->addMaterial(Material[0], appo, 15, 0))) { // Aggiunge il materiale
|
||||
warning("File %s not found", appo.c_str());
|
||||
Material[0].Texture = nullptr;
|
||||
assert(false);
|
||||
}
|
||||
//f rAddNumFacesMaterial(&Light[light].Material[0], /*f2*/7); // Aggiunge 7 facce ???
|
||||
Material[0].addProperty(T3D_MATERIAL_FLARE); // Assegna al materiale la prop flare
|
||||
warning("TODO!, Implement the user vertex buffer");
|
||||
#if 0
|
||||
Light[light].Material[0].VB = rGetUserVertexBuffer();
|
||||
#endif
|
||||
warning("TODO: Lights");
|
||||
//Material[0].NumAllocatedVerts += 45;
|
||||
#endif
|
||||
}
|
||||
|
||||
Particle = nullptr;
|
||||
if (Type & T3D_LIGHT_CANDLESMOKE) { // Se ha una smoke-particle
|
||||
Particle = Common::SharedPtr<t3dParticle>(new t3dParticle(stream)); // Legge data
|
||||
}
|
||||
if (Type & T3D_LIGHT_SOLARVARIATION) { // Se ha una variazione in base al sole
|
||||
if (!(Type & T3D_LIGHT_OFF_MORNING)) {
|
||||
SolarPos[0] = t3dV3F(stream);
|
||||
SolarColor[0] = t3dV3F::fromStreamAsBytes(stream);
|
||||
}
|
||||
if (!(Type & T3D_LIGHT_OFF_AFTERNOON)) {
|
||||
t3dVectCopy(&SolarPos[1], &Source);
|
||||
t3dVectCopy(&SolarColor[1], &Color);
|
||||
}
|
||||
if (!(Type & T3D_LIGHT_OFF_EVENING)) {
|
||||
SolarPos[2] = t3dV3F(stream);
|
||||
SolarColor[2] = t3dV3F::fromStreamAsBytes(stream);
|
||||
}
|
||||
if (!(Type & T3D_LIGHT_OFF_NIGHT)) {
|
||||
SolarPos[3] = t3dV3F(stream);
|
||||
SolarColor[3] = t3dV3F::fromStreamAsBytes(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* -----------------10/06/99 16.02-------------------
|
||||
* SetVisibleFromLight
|
||||
* --------------------------------------------------*/
|
||||
void t3dLIGHT::SetVisibleFromLight(gVertex *v) {
|
||||
AnimLight.VisVerts.push_back(v);
|
||||
}
|
||||
|
||||
|
||||
/* -----------------10/06/99 16.02-------------------
|
||||
* setupVisibleVerticesFromLight
|
||||
* --------------------------------------------------*/
|
||||
void t3dLIGHT::setupVisibleVerticesFromLight(t3dBODY *b) {
|
||||
gVertex *gv;
|
||||
for (uint32 k = 0; k < b->NumMeshes(); k++) {
|
||||
t3dMESH &m = b->MeshTable[k];
|
||||
#ifndef WMGEN
|
||||
m.VBptr = m.VertexBuffer;
|
||||
gv = m.VBptr;
|
||||
#else
|
||||
gv = m->VBptr;
|
||||
#endif
|
||||
for (int j = 0; j < m.NumVerts; j++, gv++)
|
||||
if (LightgVertex(gv, this))
|
||||
SetVisibleFromLight(gv);
|
||||
|
||||
#ifndef WMGEN
|
||||
gv = nullptr;
|
||||
m.VBptr = nullptr;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
t3dPLIGHT::t3dPLIGHT(Common::SeekableReadStream &stream) {
|
||||
Num = stream.readByte(); // Legge numero pos
|
||||
|
||||
Pos.x = stream.readFloatLE(); // Legge Pos
|
||||
Pos.y = stream.readFloatLE();
|
||||
Pos.z = stream.readFloatLE();
|
||||
|
||||
Dir.x = stream.readFloatLE(); // Legge Dir
|
||||
Dir.y = stream.readFloatLE();
|
||||
Dir.z = stream.readFloatLE();
|
||||
}
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
46
engines/watchmaker/3d/light.h
Normal file
46
engines/watchmaker/3d/light.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WATCHMAKER_LIGHT_H
|
||||
#define WATCHMAKER_LIGHT_H
|
||||
|
||||
#include "watchmaker/t3d.h"
|
||||
|
||||
#define LIGHT_MAPVERSION 1
|
||||
#define VOLLIGHTFILEVERSION 1
|
||||
#define OUTDOORLIGHTSFILEVERSION 2
|
||||
|
||||
#define LIGHT_COORDS (1<<0)
|
||||
#define LIGHT_LIGHTMAPS (1<<1)
|
||||
#define LIGHT_SHADOWMAPS (1<<2)
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
void GetBoundaries(t3dBODY *b, float *minx, float *miny, float *minz, float *maxx, float *maxy, float *maxz);
|
||||
unsigned char LightgVertex(gVertex *v, t3dLIGHT *light);
|
||||
void t3dLoadOutdoorLights(const char *pname, t3dBODY *b, int32 ora);
|
||||
void LoadVolumetricMap(WorkDirs &workDirs, const char *pname, t3dBODY *b);
|
||||
Common::String setDirectoryAndName(const Common::String &path, const Common::String &name);
|
||||
uint8 LightVertex(t3dVERTEX *vv, t3dV3F *v, t3dLIGHT *light);
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
|
||||
#endif // WATCHMAKER_LIGHT_H
|
||||
653
engines/watchmaker/3d/loader.cpp
Normal file
653
engines/watchmaker/3d/loader.cpp
Normal file
@@ -0,0 +1,653 @@
|
||||
/* 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/3d/loader.h"
|
||||
#include "common/stream.h"
|
||||
#include "watchmaker/3d/geometry.h"
|
||||
#include "watchmaker/3d/light.h"
|
||||
#include "watchmaker/3d/math/llmath.h"
|
||||
#include "watchmaker/3d/t3d_body.h"
|
||||
#include "watchmaker/3d/t3d_mesh.h"
|
||||
#include "watchmaker/game.h"
|
||||
#include "watchmaker/ll/ll_mesh.h"
|
||||
#include "watchmaker/ll/ll_system.h"
|
||||
#include "watchmaker/renderer.h"
|
||||
#include "watchmaker/t3d.h"
|
||||
#include "watchmaker/types.h"
|
||||
#include "watchmaker/utils.h"
|
||||
#include "watchmaker/windows_hacks.h"
|
||||
#include "watchmaker/work_dirs.h"
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
#define T3DFILEVERSION 11
|
||||
|
||||
t3dV3F CharCorrection;
|
||||
t3dF32 CurFloorY;
|
||||
int32 t3dCurTime = 900, t3dCurOliSet = 0;
|
||||
|
||||
t3dPathCamera::t3dPathCamera(Common::SeekableReadStream &stream) {
|
||||
NumCamera = stream.readByte();
|
||||
PathIndex = stream.readByte();
|
||||
Direction = stream.readByte();
|
||||
}
|
||||
|
||||
t3dCAMERA::t3dCAMERA(Common::SeekableReadStream &stream) {
|
||||
Index = stream.readByte();
|
||||
|
||||
Source = t3dV3F(stream) * SCALEFACTOR;
|
||||
Target = t3dV3F(stream) * SCALEFACTOR;
|
||||
|
||||
t3dVectCopy(&MaxTarget, &Target);
|
||||
|
||||
// Camera[camera].Fov=t3dReadReal();
|
||||
Fov = RADIANS_TO_DEGREE(stream.readFloatLE()); //FOV
|
||||
NearClipPlane = stream.readFloatLE() * SCALEFACTOR;
|
||||
FarClipPlane = stream.readFloatLE() * SCALEFACTOR;
|
||||
|
||||
int numPaths = stream.readByte();
|
||||
CameraPaths.reserve(numPaths);
|
||||
for (int i = 0; i < numPaths; i++) {
|
||||
CameraPaths.push_back(t3dPathCamera(stream));
|
||||
}
|
||||
}
|
||||
|
||||
t3dCAMERAPATH::t3dCAMERAPATH(Common::SeekableReadStream &stream) {
|
||||
int numPoints = stream.readSint16LE();
|
||||
CarrelloDist = stream.readSint32LE();
|
||||
|
||||
PList.resize(numPoints);
|
||||
for (int j = 0; j < numPoints; j++) {
|
||||
PList[j].x = stream.readFloatLE() * SCALEFACTOR;
|
||||
PList[j].y = stream.readFloatLE() * SCALEFACTOR;
|
||||
PList[j].z = stream.readFloatLE() * SCALEFACTOR;
|
||||
}
|
||||
}
|
||||
void decodeLoaderFlags(uint32 flags) {
|
||||
warning("%d: T3D_GENERATESHADOWMAPS", flags & T3D_GENERATESHADOWMAPS);
|
||||
warning("%d: T3D_NOLIGHTMAPS", flags & T3D_NOLIGHTMAPS);
|
||||
warning("%d: T3D_NORECURSION", flags & T3D_NORECURSION);
|
||||
warning("%d: T3D_HALFTEXTURESIZE", flags & T3D_HALFTEXTURESIZE);
|
||||
warning("%d: T3D_FULLSCREEN", flags & T3D_FULLSCREEN);
|
||||
warning("%d: T3D_FASTRENDERING", flags & T3D_FASTRENDERING);
|
||||
warning("%d: T3D_OUTDOORLIGHTS", flags & T3D_OUTDOORLIGHTS);
|
||||
warning("%d: T3D_NOVOLUMETRICLIGHTS", flags & T3D_NOVOLUMETRICLIGHTS);
|
||||
warning("%d: T3D_NOBOUNDS", flags & T3D_NOBOUNDS);
|
||||
warning("%d: T3D_NOCAMERAS", flags & T3D_NOCAMERAS);
|
||||
warning("%d: T3D_NONEXCLUSIVEMOUSE", flags & T3D_NONEXCLUSIVEMOUSE);
|
||||
warning("%d: T3D_RECURSIONLEVEL1", flags & T3D_RECURSIONLEVEL1);
|
||||
warning("%d: T3D_SKY", flags & T3D_SKY);
|
||||
warning("%d: T3D_PRELOAD_RXT", flags & T3D_PRELOAD_RXT);
|
||||
warning("%d: T3D_STATIC_SET0", flags & T3D_STATIC_SET0);
|
||||
warning("%d: T3D_STATIC_SET1", flags & T3D_STATIC_SET1);
|
||||
warning("%d: T3D_NOSHADOWS", flags & T3D_NOSHADOWS);
|
||||
warning("%d: T3D_NOICONS", flags & T3D_NOICONS);
|
||||
warning("%d: T3D_NOSOUND", flags & T3D_NOSOUND);
|
||||
warning("%d: T3D_PRELOADBASE", flags & T3D_PRELOADBASE);
|
||||
warning("%d: T3D_NOMUSIC", flags & T3D_NOMUSIC);
|
||||
warning("%d: T3D_DEBUGMODE", flags & T3D_DEBUGMODE);
|
||||
warning("%d: T3D_FASTFILE", flags & T3D_FASTFILE);
|
||||
warning("%d: T3D_HIPOLYPLAYERS", flags & T3D_HIPOLYPLAYERS);
|
||||
warning("%d: T3D_HIPOLYCHARACTERS", flags & T3D_HIPOLYCHARACTERS);
|
||||
}
|
||||
|
||||
Common::String constructPath(const Common::String &prefix, const Common::String &filename, const char *suffix) {
|
||||
Common::String name = prefix + filename;
|
||||
uint16 len = name.size();
|
||||
if (suffix != nullptr) {
|
||||
uint16 suffixLen = strlen(suffix);
|
||||
name = name.substr(0, len - suffixLen) + suffix;
|
||||
assert(suffixLen == 3);
|
||||
}
|
||||
return Common::String(Common::move(name));
|
||||
}
|
||||
|
||||
class RoomManagerImplementation : public RoomManager {
|
||||
WGame *_game;
|
||||
#define MAX_LOADED_FILES 100
|
||||
RecStruct LoadedFiles[MAX_LOADED_FILES];
|
||||
uint16 NumLoadedFiles = 0;
|
||||
public:
|
||||
RoomManagerImplementation(WGame *game) : _game(game) {}
|
||||
#define MAX_T3D_LOADLIST_ITEMS 50
|
||||
struct _t3dLOADLIST {
|
||||
Common::String pname = {};
|
||||
uint32 LoaderFlags = 0;
|
||||
t3dMESH *m = nullptr;
|
||||
};
|
||||
_t3dLOADLIST t3dLoadList[MAX_T3D_LOADLIST_ITEMS] = {};
|
||||
|
||||
void addToLoadList(t3dMESH *m, const Common::String &pname, uint32 _LoaderFlags) override {
|
||||
if (!pname.empty()) {
|
||||
int32 a;
|
||||
for (a = 0; a < MAX_T3D_LOADLIST_ITEMS; a++) {
|
||||
if (t3dLoadList[a].pname.empty()) {
|
||||
t3dLoadList[a].LoaderFlags = _LoaderFlags;
|
||||
t3dLoadList[a].m = m;
|
||||
t3dLoadList[a].pname = pname;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (a >= MAX_T3D_LOADLIST_ITEMS)
|
||||
warning("Cannot add %s to LoadList", pname.c_str());
|
||||
} else {
|
||||
warning("Invalid parameters invoking AddToLoadList()");
|
||||
warning("Mesh (%s), pname %s", m->name.c_str(), pname.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
_t3dLOADLIST* getFromLoadList() {
|
||||
for (int a = 0; a < MAX_T3D_LOADLIST_ITEMS; a++) {
|
||||
if (!t3dLoadList[a].pname.empty())
|
||||
return &t3dLoadList[a];
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
t3dBODY *getRoomIfLoaded(const Common::String &roomname) override {
|
||||
t3dBODY *t = nullptr;
|
||||
for (int i = 0; i < NumLoadedFiles; i++)
|
||||
if ((LoadedFiles[i].b != nullptr) && LoadedFiles[i].b->name.equalsIgnoreCase(roomname))
|
||||
t = LoadedFiles[i].b;
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
|
||||
t3dBODY* loadRoom(const Common::String &pname, t3dBODY *b, uint16 *NumBody, uint32 LoaderFlags) override;
|
||||
t3dBODY* loadSingleRoom(const Common::String &pname, uint16 *NumBody, uint32 LoaderFlags);
|
||||
void hideRoomMeshesMatching(const Common::String &pname) override {
|
||||
for (int i = 0; i < NumLoadedFiles; i++)
|
||||
if (LoadedFiles[i].b)
|
||||
if (LoadedFiles[i].b->name.equalsIgnoreCase(pname)) {
|
||||
HideRoomMeshes(_game->init, LoadedFiles[i].b);
|
||||
}
|
||||
}
|
||||
Common::Array<t3dBODY*> getLoadedFiles() override {
|
||||
// TODO: This won't need to be a copy if we maintain a Common::Array only containing the valid ones.
|
||||
Common::Array<t3dBODY*> files;
|
||||
for (int i = 0; i < NumLoadedFiles; i++)
|
||||
if (LoadedFiles[i].b)
|
||||
files.push_back(LoadedFiles[i].b);
|
||||
return files;
|
||||
}
|
||||
t3dBODY *checkIfAlreadyLoaded(const Common::String &Name) override {
|
||||
if (Name.empty()) return nullptr;
|
||||
|
||||
for (uint16 i = 0; i < NumLoadedFiles; i++) {
|
||||
if ((LoadedFiles[i].b != nullptr) && /*(LoadedFiles[i].Name != nullptr) &&*/ (!LoadedFiles[i].name.empty()))
|
||||
if (LoadedFiles[i].name.equalsIgnoreCase(Name))
|
||||
return LoadedFiles[i].b;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
t3dMESH *linkMeshToStr(Init &init, const Common::String &str) override {
|
||||
if (str.empty()) return nullptr;
|
||||
|
||||
// Cerca tra le camere
|
||||
if (str.equalsIgnoreCase("camera"))
|
||||
return &init._globals._invVars.CameraDummy;
|
||||
// Cerca tra i personaggi
|
||||
for (uint16 i = 0; i < T3D_MAX_CHARACTERS; i++)
|
||||
if ((Character[i]) && (str.equalsIgnoreCase(init.Obj[i].getMeshLink(0))))
|
||||
return Character[i]->Mesh;
|
||||
// Cerca nelle stanze caricate
|
||||
for (uint16 i = 0; i < NumLoadedFiles; i++) {
|
||||
if (LoadedFiles[i].b)
|
||||
for (uint16 j = 0; j < LoadedFiles[i].b->NumMeshes(); j++) {
|
||||
if (str.equalsIgnoreCase(LoadedFiles[i].b->MeshTable[j].name))
|
||||
return &LoadedFiles[i].b->MeshTable[j];
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
void releaseBody(const Common::String &name, const Common::String &altName) override {
|
||||
for (int j = 0; j < NumLoadedFiles; j++) {
|
||||
if (LoadedFiles[j].name.equalsIgnoreCase(name) || LoadedFiles[j].name.equalsIgnoreCase(altName)) {
|
||||
t3dReleaseBody(LoadedFiles[j].b);
|
||||
LoadedFiles[j].b = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void releaseLoadedFiles(uint32 exceptFlag) override {
|
||||
for (int i = 0; i < NumLoadedFiles; i++) {
|
||||
if (LoadedFiles[i].b && !(LoadedFiles[i].Flags & exceptFlag)) {
|
||||
t3dReleaseBody(LoadedFiles[i].b);
|
||||
LoadedFiles[i] = RecStruct(); // TODO: Deduplicate.
|
||||
}
|
||||
}
|
||||
}
|
||||
private:
|
||||
void loadFromList();
|
||||
};
|
||||
|
||||
RoomManager *RoomManager::create(WGame *game) {
|
||||
return new RoomManagerImplementation(game);
|
||||
}
|
||||
|
||||
/* -----------------10/06/99 16.04-------------------
|
||||
* t3dLoadRoom
|
||||
* --------------------------------------------------*/
|
||||
t3dBODY* RoomManagerImplementation::loadRoom(const Common::String &pname, t3dBODY *b, uint16 *NumBody, uint32 _LoaderFlags) {
|
||||
warning("t3dLoadRoom(%s, b, %d, %d)", pname.c_str(), *NumBody, _LoaderFlags);
|
||||
struct _t3dLOADLIST *l;
|
||||
t3dBODY *r = nullptr;
|
||||
t3dBODY *rez = nullptr;
|
||||
|
||||
// reset everything that was previously in the load list
|
||||
for (int i = 0; i < MAX_T3D_LOADLIST_ITEMS; i++) {
|
||||
t3dLoadList[i] = _t3dLOADLIST();
|
||||
}
|
||||
|
||||
// Add the base stanza to the upload list
|
||||
addToLoadList(nullptr, pname, _LoaderFlags);
|
||||
|
||||
while ((l = getFromLoadList())) {
|
||||
uint16 num = 0;
|
||||
if (l->m) {
|
||||
if ((rez = _vm->_roomManager->checkIfAlreadyLoaded(l->pname)))
|
||||
l->m->PortalList = rez;
|
||||
else {
|
||||
// if (l->m->Flags&T3D_MESH_PREPROCESSPORTAL)
|
||||
// body=l->m->PortalList = t3dLoadSingleRoom( l->pname, l->m->PortalList, &num, (l->LoaderFlags|T3D_HALFTEXTURESIZE) );
|
||||
// else
|
||||
// TODO: This should increase some refcount on the PortalList
|
||||
warning("TODO: Handle refcounts on PortalList");
|
||||
l->m->PortalList = loadSingleRoom(l->pname, &num, l->LoaderFlags);
|
||||
}
|
||||
} else
|
||||
r = loadSingleRoom(l->pname, NumBody, l->LoaderFlags);
|
||||
|
||||
*l = _t3dLOADLIST();
|
||||
}
|
||||
|
||||
if (!(_LoaderFlags & T3D_NORECURSION)) {
|
||||
for (uint16 i = 0; i < NumLoadedFiles; i++)
|
||||
if (LoadedFiles[i].b)
|
||||
t3dCalcRejectedMeshFromPortal(LoadedFiles[i].b);
|
||||
}
|
||||
|
||||
warning("Room loaded");
|
||||
return r;
|
||||
}
|
||||
|
||||
t3dBODY* RoomManagerImplementation::loadSingleRoom(const Common::String &_pname, uint16 *NumBody, uint32 _LoaderFlags) {
|
||||
//warning("t3dLoadSingleRoom(workDirs, %s, b, %d, %d)", _pname, *NumBody, _LoaderFlags);
|
||||
//decodeLoaderFlags(_LoaderFlags);
|
||||
Common::String pname(_pname);
|
||||
|
||||
WorkDirs &workdirs = _game->workDirs;
|
||||
|
||||
if (pname.equalsIgnoreCase("r1c.t3d"))
|
||||
if (((t3dCurTime >= 1300) && (t3dCurTime <= 1310)) || (t3dCurTime >= 1800)) //se viene cambiato l'orario cambiarlo anche in UpdateRoomVis...
|
||||
pname = "r1c-notte.t3d";
|
||||
if (pname.equalsIgnoreCase("r15.t3d"))
|
||||
if (((t3dCurTime >= 1300) && (t3dCurTime <= 1310)) || (t3dCurTime >= 1800))
|
||||
pname = "r15-notte.t3d";
|
||||
|
||||
auto name = constructPath(workdirs._t3dDir, pname);
|
||||
|
||||
//warning("t3dLoadSingleRoom opening(%s)", name.c_str());
|
||||
auto stream = openFile(name);
|
||||
if (!(stream)) { // Apre file
|
||||
warning("t3dLoadSingleRoom: Failed to open(%s)", name.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (*NumBody != 0) {
|
||||
// TODO: This currently means that we never free the dependant bodies.
|
||||
warning("Loading a dependant body, should also be deleted alongside the base body");
|
||||
}
|
||||
t3dBODY *b = new t3dBODY();
|
||||
|
||||
//warning("Loading %s ...", name.c_str());
|
||||
*b = t3dBODY(); // Azzera Body
|
||||
|
||||
uint16 fileVersion = stream->readByte();
|
||||
if (fileVersion != T3DFILEVERSION) { // Controlla la versione del file
|
||||
warning("%s file incompatible: current version: %d.\tFile version: %d", name.c_str(), T3DFILEVERSION, fileVersion);
|
||||
delete b;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
{
|
||||
uint16 j = 1;
|
||||
while (j < MAX_LOADED_FILES && LoadedFiles[j].b != nullptr) {
|
||||
j++;
|
||||
}
|
||||
if (j >= MAX_LOADED_FILES) {
|
||||
warning("Too many t3d files loaded!");
|
||||
delete b;
|
||||
return nullptr;
|
||||
}
|
||||
if ((j + 1) > NumLoadedFiles)
|
||||
NumLoadedFiles = j + 1;
|
||||
|
||||
LoadedFiles[j].name = _pname; // Aggiunge il file alla lista
|
||||
LoadedFiles[j].Flags = LoaderFlags; // Aggiunge Flags alla lista
|
||||
LoadedFiles[j].b = b; // Aggiunge Body alla lista
|
||||
j = 0;
|
||||
}
|
||||
b->loadFromStream(*_game, pname, *stream, _LoaderFlags);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
t3dParticle::t3dParticle(Common::SeekableReadStream &stream) {
|
||||
t3dF32 difR1, difG1, difB1;
|
||||
t3dF32 difR2, difG2, difB2;
|
||||
Num = (uint32)stream.readFloatLE();
|
||||
Lung = stream.readFloatLE();
|
||||
Size = stream.readFloatLE();
|
||||
Seg1 = stream.readFloatLE();
|
||||
Seg2 = stream.readFloatLE();
|
||||
Dim1 = stream.readFloatLE() / 1000.0f;
|
||||
Dim2 = stream.readFloatLE() / 1000.0f;
|
||||
Speed = stream.readFloatLE() / 10.0f;
|
||||
Speed1 = stream.readFloatLE() / 10.0f;
|
||||
Speed2 = stream.readFloatLE() / 10.0f;
|
||||
Caos = stream.readFloatLE() / 10;
|
||||
Caos1 = stream.readFloatLE() / 10;
|
||||
Caos2 = stream.readFloatLE() / 10;
|
||||
Delay = (uint32)stream.readFloatLE();
|
||||
OR1 = (uint8)stream.readSint32LE();
|
||||
R1 = (uint8)stream.readSint32LE();
|
||||
G1 = (uint8)stream.readSint32LE();
|
||||
B1 = (uint8)stream.readSint32LE();
|
||||
R2 = (uint8)stream.readSint32LE();
|
||||
G2 = (uint8)stream.readSint32LE();
|
||||
B2 = (uint8)stream.readSint32LE();
|
||||
R3 = (uint8)stream.readSint32LE();
|
||||
G3 = (uint8)stream.readSint32LE();
|
||||
B3 = (uint8)stream.readSint32LE();
|
||||
Type = (uint8)stream.readSint32LE();
|
||||
|
||||
#ifndef WMGEN
|
||||
ParticleIndex = t3dCreateSmokeParticle(Num,
|
||||
Type,
|
||||
OR1);
|
||||
#endif
|
||||
difR1 = (R2 - R1) / (Seg1 / Speed1);
|
||||
difG1 = (G2 - G1) / (Seg1 / Speed1);
|
||||
difB1 = (B2 - B1) / (Seg1 / Speed1);
|
||||
difR2 = (R3 - R2) / (Seg2 / Speed2);
|
||||
difG2 = (G3 - G2) / (Seg2 / Speed2);
|
||||
difB2 = (B3 - B2) / (Seg2 / Speed2);
|
||||
R2 = difR1;
|
||||
G2 = difG1;
|
||||
B2 = difB1;
|
||||
R3 = difR2;
|
||||
G3 = difG2;
|
||||
B3 = difB2;
|
||||
}
|
||||
|
||||
/* -----------------24/05/00 10.24-------------------
|
||||
* t3dPrecalcLight
|
||||
* --------------------------------------------------*/
|
||||
void t3dPrecalcLight(t3dBODY *b, uint8 *sun) {
|
||||
t3dV3F tmp, l, *normal;
|
||||
t3dVERTEX vv;
|
||||
t3dF32 nlight;
|
||||
int32 k, aa, rr, gg, bb;
|
||||
uint32 i, j, cv;
|
||||
|
||||
for (i = 0, cv = 0; i < b->NumMeshes(); i++) { // Si ripassa tutte le mesh
|
||||
t3dMESH &Mesh = b->MeshTable[i];
|
||||
#ifndef WMGEN
|
||||
Mesh.VBptr = Mesh.VertexBuffer;
|
||||
#endif
|
||||
for (j = 0; j < Mesh.NumVerts; j++, cv++) { // Si passa tutti i vertici
|
||||
rr = RGBA_GETRED(Mesh.VBptr[j].diffuse);
|
||||
gg = RGBA_GETGREEN(Mesh.VBptr[j].diffuse);
|
||||
bb = RGBA_GETBLUE(Mesh.VBptr[j].diffuse);
|
||||
aa = RGBA_GETALPHA(Mesh.VBptr[j].diffuse);
|
||||
tmp.x = Mesh.VBptr[j].x;
|
||||
tmp.y = Mesh.VBptr[j].y;
|
||||
tmp.z = Mesh.VBptr[j].z;
|
||||
for (k = 0; k < (int)b->NumLights(); k++) { // Si passa tutte le luci
|
||||
if ((b->LightTable[k].Type & T3D_LIGHT_REALTIME) || (b->LightTable[k].Type & T3D_LIGHT_FLARE) || !(b->LightTable[k].Type & T3D_LIGHT_LIGHTON)) continue;
|
||||
|
||||
t3dVectSub(&l, &b->LightTable[k].Source, &tmp); // Calcola vettore luce->vertice
|
||||
t3dVectNormalize(&l); // lo normalizza
|
||||
|
||||
normal = &Mesh.NList[j]->n; // Calcola normale
|
||||
if ((nlight = t3dVectDot(normal, &l)) >= 0) {
|
||||
if (LightVertex(&vv, &tmp, &b->LightTable[k])) {
|
||||
if ((sun) && (!sun[cv]) && (b->LightTable[k].Type & T3D_LIGHT_SUN)) {
|
||||
rr += t3dFloatToInt(vv.r * nlight * 0.50f);
|
||||
gg += t3dFloatToInt(vv.g * nlight * 0.35f);
|
||||
bb += t3dFloatToInt(vv.b * nlight * 0.27f);
|
||||
} else {
|
||||
rr += t3dFloatToInt(vv.r * nlight);
|
||||
gg += t3dFloatToInt(vv.g * nlight);
|
||||
bb += t3dFloatToInt(vv.b * nlight);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (rr < 0) rr = 0;
|
||||
if (gg < 0) gg = 0;
|
||||
if (bb < 0) bb = 0;
|
||||
if (rr > 255) rr = 255;
|
||||
if (gg > 255) gg = 255;
|
||||
if (bb > 255) bb = 255;
|
||||
|
||||
Mesh.VBptr[j].diffuse = RGBA_MAKE(rr, gg, bb, aa);
|
||||
}
|
||||
#ifndef WMGEN
|
||||
Mesh.VBptr = nullptr;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* -----------------10/06/99 16.06-------------------
|
||||
* t3dLoadSky
|
||||
* --------------------------------------------------*/
|
||||
void t3dLoadSky(WGame &game, t3dBODY * /*body*/) {
|
||||
t3dF32 Skyminx, Skyminy, Skyminz, Skymaxx, Skymaxy, Skymaxz;
|
||||
uint16 n = 0, i;
|
||||
gVertex *gv;
|
||||
// t3dF32 Tile=1.5f;
|
||||
t3dF32 div;
|
||||
|
||||
if (!(t3dSky = _vm->_roomManager->loadRoom("sky.t3d", t3dSky, &n, T3D_NORECURSION | T3D_NOLIGHTMAPS | T3D_NOVOLUMETRICLIGHTS | T3D_NOCAMERAS | T3D_NOBOUNDS | T3D_STATIC_SET0))) {
|
||||
warning("Error during t3dLoadRoom: Sky not loaded");
|
||||
}
|
||||
|
||||
GetBoundaries(t3dSky, &Skyminx, &Skyminy, &Skyminz, &Skymaxx, &Skymaxy, &Skymaxz);
|
||||
|
||||
for (i = 0; i < t3dSky->NumMeshes(); i++) {
|
||||
gv = t3dSky->MeshTable[i].VertexBuffer;
|
||||
for (n = 0; n < t3dSky->MeshTable[i].NumVerts; n++, gv++) {
|
||||
gv->x -= Skyminx + ((Skymaxx - Skyminx) / 2.0f);
|
||||
gv->y -= Skyminy + ((Skymaxy - Skyminy) / 2.0f);
|
||||
gv->z -= Skyminz + ((Skymaxz - Skyminz) / 2.0f);
|
||||
div = (t3dF32)sqrt(gv->x * gv->x + gv->y * gv->y + gv->z * gv->z);
|
||||
gv->x /= div;
|
||||
gv->y /= div;
|
||||
gv->z /= div;
|
||||
|
||||
gv->x *= 15000;
|
||||
gv->y *= 500;
|
||||
gv->z *= 15000;
|
||||
|
||||
gv->u1 *= 1.0f;
|
||||
gv->v1 *= 1.0f;
|
||||
}
|
||||
|
||||
t3dSky->MeshTable[0].Radius = 15000.0f * 2;
|
||||
}
|
||||
|
||||
for (n = 0; n < t3dSky->NumNormals; n++) {
|
||||
t3dSky->NList[n]->dist *= 15000.0f;
|
||||
}
|
||||
|
||||
for (n = 0; n < t3dSky->NumMaterials(); n++) {
|
||||
t3dSky->MatTable[n]->addProperty(T3D_MATERIAL_SKY);
|
||||
t3dSky->MatTable[n]->addProperty(T3D_MATERIAL_NOLIGHTMAP);
|
||||
}
|
||||
}
|
||||
|
||||
/* -----------------02/08/99 15.40-------------------
|
||||
* t3dAddVertexBuffer
|
||||
* --------------------------------------------------*/
|
||||
Common::SharedPtr<VertexBuffer> t3dAddVertexBuffer(t3dBODY *b, uint32 numv) {
|
||||
return b->addVertexBuffer();
|
||||
}
|
||||
|
||||
/* -----------------10/06/99 16.03-------------------
|
||||
* t3dOptimizeMaterialList
|
||||
* --------------------------------------------------*/
|
||||
void t3dOptimizeMaterialList(t3dBODY *b) {
|
||||
for (uint32 i = 0; i < b->NumMaterials(); i++) { // Scorre tutti materilai di un body
|
||||
MaterialPtr Mat = b->MatTable[i];
|
||||
if ((Mat == nullptr) || /*(!Mat->Texture->Name) ||*/ (Mat->Movie) || (Mat->hasFlag(T3D_MATERIAL_MOVIE))) // Se non esiste o non ha texture
|
||||
continue; // esce
|
||||
|
||||
for (uint32 j = 0; j < b->NumMaterials(); j++) { // Cerca materiali uguali
|
||||
MaterialPtr CurMat = b->MatTable[j];
|
||||
if (Mat == CurMat)
|
||||
continue;
|
||||
|
||||
if (CurMat == nullptr /*|| (!CurMat->Texture->Name)*/)
|
||||
continue;
|
||||
|
||||
if (Mat->Texture->name.equalsIgnoreCase(CurMat->Texture->name)) { // Se ha lo setsso nome di texture
|
||||
//warning("TODO: Implement Material-merging");
|
||||
// This is currently broken.
|
||||
|
||||
Mat = rMergeMaterial(Mat, CurMat); // Unisce i due materiali
|
||||
for (uint32 k = 0; k < b->NumMeshes(); k++) { // Aggiorna in tutte le mesh id materiale
|
||||
auto &m = b->MeshTable[k];
|
||||
for (int q = 0; q < m.NumFaces(); q++) {
|
||||
auto &f = m.FList[q];
|
||||
if (f.getMaterialIndex() == j)
|
||||
f.setMaterialIndex(i);
|
||||
}
|
||||
}
|
||||
warning("Deduplicating: %s (%d v %d", Mat->Texture->name.c_str(), i, j);
|
||||
b->MatTable[j] = nullptr; // TODO: This should probably happen in rMergeMaterial
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: The optimization leaves a bunch of materials as nullptr, we need to update all the
|
||||
// references to them. Currently we do this by subtracting 1 from all references that were above
|
||||
// a removed material. This works, but isn't really optimal.
|
||||
//int subtract = 0;
|
||||
for (uint32 i = 0; i < b->NumMaterials(); i++) {
|
||||
if (!b->MatTable[i]) {
|
||||
b->MatTable.remove_at(i);
|
||||
//subtract++;
|
||||
for (uint32 k = 0; k < b->NumMeshes(); k++) {
|
||||
auto &m = b->MeshTable[k];
|
||||
for (int q = 0; q < m.NumFaces(); q++) {
|
||||
auto &f = m.FList[q];
|
||||
if (f.getMaterialIndex() >= i) {
|
||||
f.setMaterialIndex(f.getMaterialIndex() - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* -----------------30/07/99 10.55-------------------
|
||||
* t3dFinalizeMaterialList
|
||||
* --------------------------------------------------*/
|
||||
void t3dFinalizeMaterialList(t3dBODY *b) {
|
||||
for (uint32 i = 0; i < b->NumMeshes(); i++) {
|
||||
t3dMESH &Mesh = b->MeshTable[i];
|
||||
#ifndef WMGEN
|
||||
Mesh.VBptr = Mesh.VertexBuffer;
|
||||
#endif
|
||||
for (uint32 j = 0; j < Mesh.NumFaces(); j++) {
|
||||
t3dFACE &Face = Mesh.FList[j];
|
||||
MaterialPtr Mat = Face.getMaterial();
|
||||
if (Face.lightmap) {
|
||||
Mat = nullptr;
|
||||
for (const auto &material : Face.getMaterial()->AddictionalMaterial) {
|
||||
if (material->Texture->ID == Face.lightmap->Texture->ID) {
|
||||
Mat = material;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (Mat == nullptr) {
|
||||
warning("%s: Can't find Lightmap Sub-Material!", Mesh.name.c_str());
|
||||
warning("%d %d", Face.getMaterial()->NumAddictionalMaterial, Face.lightmap->Texture->ID);
|
||||
for (const auto &material : Face.getMaterial()->AddictionalMaterial) {
|
||||
warning("%d", material->Texture->ID);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 k = 0;
|
||||
for (k = 0; k < (uint32)Mat->NumAllocatedMesh; k++)
|
||||
if (Mat->FlagsList[k] == &Mesh.Flags)
|
||||
break;
|
||||
|
||||
if (k >= (uint32)Mat->NumAllocatedMesh) {
|
||||
Mat->FlagsList.push_back(&Mesh.Flags);
|
||||
Mat->NumAllocatedMesh++;
|
||||
Mesh.Flags |= T3D_MESH_UPDATEVB;
|
||||
}
|
||||
Mesh.Flags |= T3D_MESH_UPDATEVB;
|
||||
|
||||
for (uint32 h = 0; h < 3; h++) {
|
||||
for (k = 0; k < (uint32)Mat->NumAllocatedVerts(); k++)
|
||||
if (Mat->VertsList[k] == &Mesh.VBptr[Face.VertexIndex[h]])
|
||||
break;
|
||||
|
||||
if (k >= (uint32)Mat->NumAllocatedVerts()) {
|
||||
Mat->VertsList.push_back(&Mesh.VBptr[Face.VertexIndex[h]]);
|
||||
}
|
||||
assert(k < Mat->VertsList.size());
|
||||
Face.setMatVertexIndex(h, k);
|
||||
}
|
||||
|
||||
}
|
||||
#ifndef WMGEN
|
||||
Mesh.VBptr = nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
for (uint32 i = 0; i < b->NumMaterials(); i++) {
|
||||
auto &Mat = b->MatTable[i];
|
||||
if (!Mat) {
|
||||
warning("nullptr");
|
||||
}
|
||||
Mat->VBO = b->addVertexBuffer(); // t3dAddVertexBuffer(b, Mat->NumAllocatedVerts);
|
||||
for (int j = 0; j < Mat->NumAddictionalMaterial; j++)
|
||||
Mat->AddictionalMaterial[j]->VBO = t3dAddVertexBuffer(b, Mat->AddictionalMaterial[j]->NumAllocatedVerts());
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
96
engines/watchmaker/3d/loader.h
Normal file
96
engines/watchmaker/3d/loader.h
Normal file
@@ -0,0 +1,96 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WATCHMAKER_LOADER_H
|
||||
#define WATCHMAKER_LOADER_H
|
||||
|
||||
#include "watchmaker/t3d.h"
|
||||
#include "watchmaker/types.h"
|
||||
#include "watchmaker/work_dirs.h"
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
#define SCALEFACTOR 1.0f//(1.0f/7.0f)
|
||||
|
||||
#define MAX_MIRRORS 10
|
||||
|
||||
#define T3D_GENERATESHADOWMAPS (1<<0) //Generate shadow maps
|
||||
#define T3D_NOLIGHTMAPS (1<<1) //view without lightmaps
|
||||
#define T3D_NORECURSION (1<<2) //do not recurse sub-rooms mirrors, reflections
|
||||
#define T3D_HALFTEXTURESIZE (1<<3) //Half the texture dimension when load .t3d texture
|
||||
#define T3D_FULLSCREEN (1<<4) //run in fullscreen
|
||||
#define T3D_FASTRENDERING (1<<5) //render shadow/light maps with minimum dimension
|
||||
#define T3D_OUTDOORLIGHTS (1<<6) //load .oli files for outdoor lights informations
|
||||
#define T3D_NOVOLUMETRICLIGHTS (1<<7) //do not load .vol file
|
||||
#define T3D_NOBOUNDS (1<<8) //do not load .vol file
|
||||
#define T3D_NOCAMERAS (1<<9) //do not load .vol file
|
||||
#define T3D_NONEXCLUSIVEMOUSE (1<<10) // mouse is not in exclusive mode
|
||||
#define T3D_RECURSIONLEVEL1 (1<<12) // one recursion level only
|
||||
#define T3D_SKY (1<<13) // if the sky is visible
|
||||
#define T3D_PRELOAD_RXT (1<<14) // preload extern
|
||||
#define T3D_STATIC_SET0 (1<<15) // static loaded elements
|
||||
#define T3D_STATIC_SET1 (1<<16) // static loaded elements
|
||||
#define T3D_NOSHADOWS (1<<17) // do not calc shadows
|
||||
#define T3D_NOICONS (1<<18) // do not load icons
|
||||
#define T3D_NOSOUND (1<<19) // do not use sound system
|
||||
#define T3D_PRELOADBASE (1<<20) // preload basic elements
|
||||
#define T3D_NOMUSIC (1<<21) // do not use music system
|
||||
#define T3D_DEBUGMODE (1<<22) // debug mode
|
||||
#define T3D_FASTFILE (1<<23) // fastfile
|
||||
#define T3D_HIPOLYPLAYERS (1<<24) // hipoly players (darrell e victoria hipoly)
|
||||
#define T3D_HIPOLYCHARACTERS (1<<25) // hipoly characters (gli abitanti del castello hipoly)
|
||||
|
||||
// TODO: Unglobalize
|
||||
extern t3dV3F CharCorrection;
|
||||
extern t3dF32 CurFloorY;
|
||||
extern int32 t3dCurTime, t3dCurOliSet;
|
||||
|
||||
struct RecStruct {
|
||||
Common::String name;
|
||||
t3dBODY *b = nullptr;
|
||||
uint32 Flags = 0;
|
||||
};
|
||||
|
||||
void t3dOptimizeMaterialList(t3dBODY *b);
|
||||
void t3dFinalizeMaterialList(t3dBODY *b);
|
||||
void t3dPrecalcLight(t3dBODY *b, unsigned char *sun);
|
||||
void t3dLoadSky(WGame &game, t3dBODY *b);
|
||||
|
||||
Common::String constructPath(const Common::String &prefix, const Common::String &filename, const char *suffix = nullptr);
|
||||
|
||||
class RoomManager {
|
||||
public:
|
||||
virtual ~RoomManager() {}
|
||||
virtual void addToLoadList(t3dMESH *m, const Common::String &pname, uint32 LoaderFlags) = 0;
|
||||
virtual t3dBODY* loadRoom(const Common::String &pname, t3dBODY *b, uint16 *NumBody, uint32 LoaderFlags) = 0;
|
||||
static RoomManager *create(WGame *game);
|
||||
virtual t3dBODY *getRoomIfLoaded(const Common::String &roomname) = 0;
|
||||
virtual t3dMESH *linkMeshToStr(Init &init, const Common::String &str) = 0;
|
||||
virtual void hideRoomMeshesMatching(const Common::String &pname) = 0;
|
||||
virtual void releaseBody(const Common::String &name, const Common::String &altName) = 0;
|
||||
virtual void releaseLoadedFiles(uint32 exceptFlag) = 0;
|
||||
virtual t3dBODY *checkIfAlreadyLoaded(const Common::String &Name) = 0;
|
||||
virtual Common::Array<t3dBODY*> getLoadedFiles() = 0;
|
||||
};
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
|
||||
#endif // WATCHMAKER_LOADER_H
|
||||
299
engines/watchmaker/3d/material.cpp
Normal file
299
engines/watchmaker/3d/material.cpp
Normal file
@@ -0,0 +1,299 @@
|
||||
/* 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/3d/material.h"
|
||||
#include "common/util.h"
|
||||
#include "watchmaker/3d/render/opengl_2d.h"
|
||||
#include "watchmaker/render.h"
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
MaterialPtr rAddMaterial(gMaterial &Material, const Common::String &TextName, int NumFaces, unsigned int LoaderFlags) {
|
||||
// TODO: This is duplicated in opengl_3d.cpp
|
||||
warning("TODO: Fix rAddMaterial");
|
||||
#if 0
|
||||
bool AlreadyLoaded = FALSE;
|
||||
int len = strlen(TextName);
|
||||
|
||||
if (((TextName[len - 1 - 0] == 'i') || (TextName[len - 1 - 0] == 'I')) &&
|
||||
((TextName[len - 1 - 1] == 'v') || (TextName[len - 1 - 1] == 'V')) &&
|
||||
((TextName[len - 1 - 2] == 'a') || (TextName[len - 1 - 2] == 'A'))) {
|
||||
if ((Material.Movie = gLoadMovie(TextName)) == NULL)
|
||||
return NULL;
|
||||
if ((Material.Texture = gUserTexture(64,
|
||||
128)) == NULL)
|
||||
// if( (Material->Texture=gUserTexture( Material->Movie->g_psiStreamInfo.rcFrame.right,
|
||||
// Material->Movie->g_psiStreamInfo.rcFrame.bottom)) == NULL )
|
||||
return NULL;
|
||||
Material.Flags |= T3D_MATERIAL_MOVIE;
|
||||
} else {
|
||||
if ((Material.Texture = gLoadTexture(TextName, LoaderFlags)) == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//f
|
||||
//f Material->FacesList=(WORD *)t3dRealloc(Material->FacesList,sizeof(WORD)*3*NumFaces+1);
|
||||
//f Material->NumAllocatedFaces+=3*NumFaces+1;
|
||||
Material.FacesList.resize(Material.FacesList.size() + NumFaces * 3);
|
||||
Material.NumAllocatedFaces += NumFaces * 3;
|
||||
//f
|
||||
Material.Flags |= T3D_MATERIAL_NOLIGHTMAP;
|
||||
return Material;
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void gMaterial::addProperty(int flag) {
|
||||
this->Flags |= flag;
|
||||
}
|
||||
|
||||
void gMaterial::clearFlag(int flag) {
|
||||
this->Flags &= ~flag;
|
||||
}
|
||||
|
||||
bool gMaterial::hasFlag(int flag) {
|
||||
return this->Flags & flag;
|
||||
}
|
||||
|
||||
void gMaterial::addColor(unsigned char r_add, unsigned char g_add, unsigned char b_add) {
|
||||
int rr, gg, bb;
|
||||
|
||||
rr = this->r;
|
||||
gg = this->g;
|
||||
bb = this->b;
|
||||
|
||||
rr += r;
|
||||
gg += g;
|
||||
bb += b;
|
||||
|
||||
rr = MIN(MAX(rr, 0), 255);
|
||||
gg = MIN(MAX(gg, 0), 255);
|
||||
bb = MIN(MAX(bb, 0), 255);
|
||||
|
||||
this->r = (unsigned char)rr;
|
||||
this->g = (unsigned char)gg;
|
||||
this->b = (unsigned char)bb;
|
||||
}
|
||||
|
||||
bool gMaterial::addNumFacesAdditionalMaterial(MaterialPtr am, unsigned int num) {
|
||||
if (!num || !am)
|
||||
return false;
|
||||
|
||||
Common::SharedPtr<gMaterial> cm;
|
||||
int i;
|
||||
for (i = 0; i < this->NumAddictionalMaterial; i++) {
|
||||
cm = this->AddictionalMaterial[i];
|
||||
if (cm->Texture->ID == am->Texture->ID)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == this->NumAddictionalMaterial) {
|
||||
this->AddictionalMaterial.push_back(Common::SharedPtr<gMaterial>(new gMaterial(*am)));
|
||||
cm = this->AddictionalMaterial.back();
|
||||
cm->FacesList.resize(0);
|
||||
this->NumAddictionalMaterial++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool gMaterial::addNumFaces(unsigned int num) {
|
||||
// TODO: Remove, as this is not necessary with a Common::Array
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
MaterialPtr rMergeMaterial(MaterialPtr Mat1, MaterialPtr Mat2) {
|
||||
if (!Mat1 || !Mat2)
|
||||
return nullptr;
|
||||
|
||||
for (int i = 0; i < Mat2->NumAddictionalMaterial; i++) {
|
||||
Mat1->addNumFacesAdditionalMaterial(Mat2->AddictionalMaterial[i],
|
||||
/*Mat2->AddictionalMaterial[i]->NumAllocatedFaces*/ Mat2->AddictionalMaterial[i]->NumFaces());
|
||||
}
|
||||
//reset mat2
|
||||
rRemoveMaterial(Mat2);
|
||||
*Mat2 = gMaterial();
|
||||
|
||||
return Mat1;
|
||||
}
|
||||
|
||||
void rRemoveMaterials(Common::Array<Common::SharedPtr<gMaterial>> &m) {
|
||||
for (auto &material : m) {
|
||||
material->clear();
|
||||
}
|
||||
m.clear();
|
||||
}
|
||||
|
||||
Common::SharedPtr<gMaterial> rCopyMaterial(Common::SharedPtr<gMaterial> Mat1, Common::SharedPtr<gMaterial> Mat2) {
|
||||
if (!Mat1 || !Mat2)
|
||||
return nullptr;
|
||||
|
||||
Mat1->clearFaceList();
|
||||
Mat1->AddictionalMaterial.clear();
|
||||
Mat1->clearFaceList();
|
||||
Mat1->VertsList.clear();
|
||||
//t3dFree(Mat1->FlagsList);
|
||||
*Mat1 = gMaterial();
|
||||
|
||||
if (Mat2->NumFaces()) {
|
||||
for (int i = 0; i < Mat2->NumFaces(); i++) {
|
||||
Mat1->addFace(Mat2->getFace(i));
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < Mat2->NumFaces(); i++) {
|
||||
if (Mat2->getFace(i) >= Mat2->VertsList.size()) {
|
||||
warning("TODO");
|
||||
}
|
||||
}
|
||||
if (Mat2->NumAllocatedVerts()) {
|
||||
Mat1->VertsList = Mat2->VertsList;
|
||||
}
|
||||
if (Mat2->NumAllocatedMesh) {
|
||||
Mat1->FlagsList = Mat2->FlagsList;
|
||||
}
|
||||
|
||||
Mat1->Texture = Mat2->Texture;
|
||||
Mat1->Movie = Mat2->Movie;
|
||||
Mat1->Flags = Mat2->Flags;
|
||||
Mat1->VBO = Mat2->VBO;
|
||||
Mat1->NumAllocatedMesh = Mat2->NumAllocatedMesh;
|
||||
Mat1->r = Mat2->r;
|
||||
Mat1->g = Mat2->g;
|
||||
Mat1->b = Mat2->b;
|
||||
Mat1->NumAddictionalMaterial = Mat2->NumAddictionalMaterial;
|
||||
|
||||
rCopyMaterialList(Mat1->AddictionalMaterial, Mat2->AddictionalMaterial, Mat2->NumAddictionalMaterial); // TODO: Does this mean that we don't copy any extras?
|
||||
|
||||
return Mat1;
|
||||
}
|
||||
|
||||
void rCopyMaterialList(MaterialTable &dst, MaterialTable &src, uint count) {
|
||||
dst.resize(count);
|
||||
if (count > src.size()) {
|
||||
error("Copying more materials than there are in the src");
|
||||
}
|
||||
for (uint i = 0; i < count; i++) {
|
||||
if (!dst[i]) {
|
||||
dst[i] = Common::SharedPtr<gMaterial>(new gMaterial());
|
||||
}
|
||||
rCopyMaterial(dst[i], src[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void gMaterial::clear() {
|
||||
// TODO: This flag clearing doesn't happen in the original, but shouldn't matter as the class is instantiated again when used in Particles.
|
||||
Flags = 0;
|
||||
|
||||
if (Movie) {
|
||||
Movie = nullptr;
|
||||
}
|
||||
FacesList.clear();
|
||||
VertsList.clear();
|
||||
FlagsList.clear();
|
||||
// rDeleteVertexBuffer(m->VB);
|
||||
VBO = 0;
|
||||
|
||||
for (int j = 0; j < NumAddictionalMaterial; j++) {
|
||||
Common::SharedPtr<gMaterial> cm = AddictionalMaterial[j];
|
||||
cm->FacesList.clear();
|
||||
cm->VertsList.clear();
|
||||
cm->FlagsList.clear();
|
||||
// rDeleteVertexBuffer(cm->VB);
|
||||
cm->VBO = 0;
|
||||
}
|
||||
AddictionalMaterial.clear();
|
||||
}
|
||||
|
||||
|
||||
void rRemoveMaterial(Common::SharedPtr<gMaterial> &m) {
|
||||
m->clear();
|
||||
}
|
||||
|
||||
|
||||
/* -----------------29/07/99 15.53-------------------
|
||||
* Aggiunge un materiale alla MaterialList
|
||||
* --------------------------------------------------*/
|
||||
void rAddToMaterialList(gMaterial &mat, signed short int ViewMatrixNum) {
|
||||
gBatchBlock *bb = nullptr;
|
||||
|
||||
if ((mat.Flags & T3D_MATERIAL_MOVIE)) {
|
||||
warning("Movie: %s %d", mat.Movie->_name.c_str(), mat.Texture->ID);
|
||||
mat.Movie->updateMovie();
|
||||
}
|
||||
|
||||
if ((mat.NumFaces() >= 3) && (mat.VBO)) {
|
||||
if (mat.Texture) {
|
||||
// if (mat.Texture->name == "./TMaps/bianco.tga")
|
||||
// return;
|
||||
}
|
||||
bb = rNewBatchBlock(mat.Texture->ID, mat.Flags, 0, 0);
|
||||
bb->ViewMatrixNum = ViewMatrixNum;
|
||||
bb->FacesList = mat.getFacesList();
|
||||
bb->VBO = mat.VBO;
|
||||
for (uint f = 0; f < bb->FacesList.size(); f++) {
|
||||
if (bb->FacesList[f] >= bb->VBO->_buffer.size()) {
|
||||
for (uint o = 0; o < bb->FacesList.size(); o++) {
|
||||
warning("%d", bb->FacesList[o]);
|
||||
}
|
||||
warning("%d > %d (%d)", bb->FacesList[f], bb->VBO->_buffer.size(), bb->NumVerts());
|
||||
}
|
||||
}
|
||||
mat.emptyFacesList(); // We may want to keep the reservation to avoid the extra reallocs here.
|
||||
}
|
||||
|
||||
for (auto &cm : mat.AddictionalMaterial) {
|
||||
if (cm->NumFaces() < 3) continue;
|
||||
if (cm->VBO == NULL) continue;
|
||||
bb = rNewBatchBlock(mat.Texture->ID, mat.Flags, cm->Texture->ID, cm->Flags);
|
||||
bb->ViewMatrixNum = ViewMatrixNum;
|
||||
bb->FacesList = cm->getFacesList();
|
||||
bb->VBO = cm->VBO;
|
||||
cm->emptyFacesList();
|
||||
}
|
||||
}
|
||||
|
||||
void rAddToMaterialList(MaterialPtr mat, signed short int ViewMatrixNum) {
|
||||
if (mat) {
|
||||
rAddToMaterialList(*mat, ViewMatrixNum);
|
||||
}
|
||||
}
|
||||
|
||||
/* -----------------31/05/99 10.07-------------------
|
||||
* Costruisce la lista dei materiali ordinata
|
||||
* --------------------------------------------------*/
|
||||
void rBuildMaterialList(MaterialTable &MatList, unsigned int NumMat, signed short int ViewMatrixNum) {
|
||||
if (NumMat == 0)
|
||||
return;
|
||||
|
||||
for (auto &mat : MatList) {
|
||||
rAddToMaterialList(mat, ViewMatrixNum);
|
||||
}
|
||||
}
|
||||
|
||||
MaterialTable rCreateMaterialList(int num) {
|
||||
MaterialTable list;
|
||||
// We avoid actually allocating the gMaterial-objects, as we want the size() to
|
||||
// represent the actually loaded elements.
|
||||
list.reserve(num);
|
||||
return list;
|
||||
}
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
99
engines/watchmaker/3d/material.h
Normal file
99
engines/watchmaker/3d/material.h
Normal file
@@ -0,0 +1,99 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WATCHMAKER_MATERIAL_H
|
||||
#define WATCHMAKER_MATERIAL_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/ptr.h"
|
||||
#include "watchmaker/3d/texture.h"
|
||||
#include "watchmaker/3d/movie.h"
|
||||
#include "watchmaker/3d/vertex.h"
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
struct gMaterial;
|
||||
typedef Common::SharedPtr<gMaterial> MaterialPtr;
|
||||
typedef Common::Array<MaterialPtr> MaterialTable;
|
||||
|
||||
struct VertexBuffer;
|
||||
// Material definition
|
||||
struct gMaterial {
|
||||
gTexture *Texture = nullptr; // pointer to texture struct
|
||||
Common::SharedPtr<gMovie> Movie; // pointer to movie struct
|
||||
unsigned int Flags = 0; // material flags
|
||||
int NumFaces() {
|
||||
return FacesList.size();
|
||||
}; // current number of faces to be processed
|
||||
void addFace(uint16 face) {
|
||||
FacesList.push_back(face);
|
||||
}
|
||||
uint16 getFace(int index) const {
|
||||
return FacesList[index];
|
||||
}
|
||||
void clearFaceList() {
|
||||
FacesList.clear();
|
||||
}
|
||||
void emptyFacesList() {
|
||||
FacesList.resize(0);
|
||||
}
|
||||
Common::Array<uint16> getFacesList() {
|
||||
return FacesList;
|
||||
}
|
||||
private:
|
||||
Common::Array<uint16> FacesList; // list of verts indices
|
||||
public:
|
||||
Common::Array<gVertex *> VertsList; // pointers to pointers to verts
|
||||
int NumAllocatedVerts() {
|
||||
return this->VertsList.size();
|
||||
}; // number of allocated vertex in mat VB
|
||||
Common::SharedPtr<VertexBuffer> VBO = nullptr;
|
||||
// LPDIRECT3DVERTEXBUFFER7 VB; // mat VB struct
|
||||
int NumAllocatedMesh = 0; // num mesh to check for modifications
|
||||
Common::Array<unsigned int *> FlagsList; // vector of pointer to mesh flags
|
||||
unsigned char r, g, b; // default material color
|
||||
int NumAddictionalMaterial = 0; // number of addictional material (lightmaps)
|
||||
MaterialTable AddictionalMaterial; // pointer to addictional material struct
|
||||
public:
|
||||
gMaterial() : r(0), g(0), b(0) {
|
||||
|
||||
}
|
||||
void addColor(unsigned char r, unsigned char g, unsigned char b);
|
||||
void addProperty(int flag);
|
||||
bool hasFlag(int flag);
|
||||
void clearFlag(int flag);
|
||||
bool addNumFaces(unsigned int num);
|
||||
bool addNumFacesAdditionalMaterial(MaterialPtr am, unsigned int num);
|
||||
void clear();
|
||||
};
|
||||
|
||||
MaterialPtr rAddMaterial(MaterialTable &MList, const Common::String &TextName, int NumFaces, unsigned int LoaderFlags);
|
||||
MaterialPtr rAddMaterial(gMaterial &Material, const Common::String &TextName, int NumFaces, unsigned int LoaderFlags);
|
||||
void rRemoveMaterial(MaterialPtr &m);
|
||||
void rRemoveMaterials(MaterialTable &m);
|
||||
void rCopyMaterialList(MaterialTable &dst, MaterialTable &src, uint count);
|
||||
MaterialPtr rMergeMaterial(MaterialPtr Mat1, MaterialPtr Mat2);
|
||||
void rAddToMaterialList(gMaterial &mat, signed short int ViewMatrixNum);
|
||||
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
|
||||
#endif // WATCHMAKER_MATERIAL_H
|
||||
26
engines/watchmaker/3d/math/Matrix4x4.cpp
Normal file
26
engines/watchmaker/3d/math/Matrix4x4.cpp
Normal file
@@ -0,0 +1,26 @@
|
||||
/* 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/3d/math/Matrix4x4.h"
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
69
engines/watchmaker/3d/math/Matrix4x4.h
Normal file
69
engines/watchmaker/3d/math/Matrix4x4.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WATCHMAKER_MATRIX4X4_H
|
||||
#define WATCHMAKER_MATRIX4X4_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/textconsole.h"
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
struct Matrix4x4 {
|
||||
float data[16] = {};
|
||||
|
||||
void setIdentity() {
|
||||
setValue(1, 1, 1.0f);
|
||||
setValue(2, 2, 1.0f);
|
||||
setValue(3, 3, 1.0f);
|
||||
setValue(4, 4, 1.0f);
|
||||
}
|
||||
|
||||
void setValue(int row, int col, float value) {
|
||||
data[(col - 1) * 4 + (row - 1)] = value;
|
||||
}
|
||||
float getValue(int row, int col) const {
|
||||
return data[(col - 1) * 4 + (row - 1)];
|
||||
}
|
||||
void print() const {
|
||||
for (int row = 1; row <= 4; row++) {
|
||||
for (int col = 1; col <= 4; col++) {
|
||||
warning("%f ", getValue(row, col));
|
||||
}
|
||||
warning(" ");
|
||||
}
|
||||
}
|
||||
bool operator==(const Matrix4x4 &rhs) const {
|
||||
for (int row = 1; row <= 4; row++) {
|
||||
for (int col = 1; col <= 4; col++) {
|
||||
if (getValue(row, col) != rhs.getValue(row, col)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
|
||||
#endif // WATCHMAKER_MATRIX4X4_H
|
||||
427
engines/watchmaker/3d/math/llmath.cpp
Normal file
427
engines/watchmaker/3d/math/llmath.cpp
Normal file
@@ -0,0 +1,427 @@
|
||||
/* 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/3d/math/llmath.h"
|
||||
#include "watchmaker/utils.h"
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
int32 t3dFloatToInt(t3dF32 nfloat) {
|
||||
int32 sint = nfloat;
|
||||
// warning("STUBBED: t3dFloatToInt");
|
||||
/*
|
||||
__asm
|
||||
{
|
||||
fld nfloat
|
||||
fistp sint
|
||||
}*/
|
||||
return sint;
|
||||
}
|
||||
|
||||
void t3dMatIdentity(t3dM3X3F *d) {
|
||||
d->M[1] = d->M[2] = d->M[3] = d->M[5] = d->M[6] = d->M[7] = 0.0;
|
||||
d->M[0] = d->M[4] = d->M[8] = 1.0;
|
||||
|
||||
d->Flags |= T3D_MATRIX_IDENTITY;
|
||||
}
|
||||
|
||||
void t3dMatMul(t3dM3X3F *Dest, t3dM3X3F *a, t3dM3X3F *b) {
|
||||
t3dM3X3F Tmp, *d = &Tmp;
|
||||
/* t3dM3X3F Tmp,*d=&Tmp;
|
||||
int r,c;
|
||||
|
||||
if (Dest == a || Dest == b)
|
||||
d=&Tmp;
|
||||
else
|
||||
d=Dest;
|
||||
|
||||
for (r=0; r<3; r++)
|
||||
for (c=0; c<3; c++)
|
||||
d->M[r][c]=a->M[r][0]*b->M[0][c]+a->M[r][1]*b->M[1][c]+a->M[r][2]*b->M[2][c];*/
|
||||
|
||||
d->M[0] = (a->M[0] * b->M[0] + a->M[1] * b->M[3] + a->M[2] * b->M[6]);
|
||||
d->M[1] = (a->M[0] * b->M[1] + a->M[1] * b->M[4] + a->M[2] * b->M[7]);
|
||||
d->M[2] = (a->M[0] * b->M[2] + a->M[1] * b->M[5] + a->M[2] * b->M[8]);
|
||||
|
||||
d->M[3] = (a->M[3] * b->M[0] + a->M[4] * b->M[3] + a->M[5] * b->M[6]);
|
||||
d->M[4] = (a->M[3] * b->M[1] + a->M[4] * b->M[4] + a->M[5] * b->M[7]);
|
||||
d->M[5] = (a->M[3] * b->M[2] + a->M[4] * b->M[5] + a->M[5] * b->M[8]);
|
||||
|
||||
d->M[6] = (a->M[6] * b->M[0] + a->M[7] * b->M[3] + a->M[8] * b->M[6]);
|
||||
d->M[7] = (a->M[6] * b->M[1] + a->M[7] * b->M[4] + a->M[8] * b->M[7]);
|
||||
d->M[8] = (a->M[6] * b->M[2] + a->M[7] * b->M[5] + a->M[8] * b->M[8]);
|
||||
|
||||
if (d != Dest)
|
||||
t3dMatCopy(Dest, &Tmp);
|
||||
|
||||
}
|
||||
|
||||
void t3dMatCopy(t3dM3X3F *d, t3dM3X3F *s) {
|
||||
d->M[0] = s->M[0];
|
||||
d->M[1] = s->M[1];
|
||||
d->M[2] = s->M[2];
|
||||
d->M[3] = s->M[3];
|
||||
d->M[4] = s->M[4];
|
||||
d->M[5] = s->M[5];
|
||||
d->M[6] = s->M[6];
|
||||
d->M[7] = s->M[7];
|
||||
d->M[8] = s->M[8];
|
||||
d->Flags = 0;
|
||||
}
|
||||
|
||||
void t3dMatView(t3dM3X3F *dest, t3dV3F *eye, t3dV3F *center) {
|
||||
t3dM3X3F *fm = dest;
|
||||
t3dM3X3F fmat;
|
||||
|
||||
// D3DVECTOR from,at,up;
|
||||
|
||||
if ((!eye) || (!dest)) return;
|
||||
|
||||
// F
|
||||
t3dF32 dx = (t3dF32)(center->x - eye->x);
|
||||
t3dF32 dy = (t3dF32)(center->y - eye->y);
|
||||
t3dF32 dz = (t3dF32)(center->z - eye->z);
|
||||
|
||||
t3dF32 dd = (dx * dx + dy * dy + dz * dz);
|
||||
if (dd == 0.0)dd = 1.0;
|
||||
dd = (float)sqrt((t3dF64)dd); // dd = ||F||
|
||||
|
||||
t3dF32 d2 = (dz * dz + dx * dx);
|
||||
if (d2 == 0.0)d2 = 1.0;
|
||||
d2 = (float)sqrt((t3dF64)d2); // |s|
|
||||
|
||||
t3dF32 fcosa = (dz / d2);
|
||||
t3dF32 fsina = (dx / d2);
|
||||
fm->M[0] = fcosa;
|
||||
fm->M[1] = 0;
|
||||
fm->M[2] = -fsina;
|
||||
fm->M[3] = 0;
|
||||
fm->M[4] = 1;
|
||||
fm->M[5] = 0;
|
||||
fm->M[6] = fsina;
|
||||
fm->M[7] = 0;
|
||||
fm->M[8] = fcosa;
|
||||
|
||||
fcosa = (d2 / dd);
|
||||
fsina = (dy / dd);
|
||||
fmat.M[0] = 1;
|
||||
fmat.M[1] = 0;
|
||||
fmat.M[2] = 0;
|
||||
fmat.M[3] = 0;
|
||||
fmat.M[4] = fcosa;
|
||||
fmat.M[5] = -fsina;
|
||||
fmat.M[6] = 0;
|
||||
fmat.M[7] = fsina;
|
||||
fmat.M[8] = fcosa;
|
||||
t3dMatMul(dest, &fmat, dest);
|
||||
|
||||
const float roll = 0.0f;
|
||||
fcosa = (t3dF32)cos((-roll) / 180.0f * T3D_PI);
|
||||
fsina = (t3dF32)sin((-roll) / 180.0f * T3D_PI);
|
||||
fmat.M[0] = fcosa;
|
||||
fmat.M[1] = fsina;
|
||||
fmat.M[2] = 0;
|
||||
fmat.M[3] = -fsina;
|
||||
fmat.M[4] = fcosa;
|
||||
fmat.M[5] = 0;
|
||||
fmat.M[6] = 0;
|
||||
fmat.M[7] = 0;
|
||||
fmat.M[8] = 1;
|
||||
t3dMatMul(dest, &fmat, dest);
|
||||
|
||||
dest->Flags &= ~T3D_MATRIX_IDENTITY;
|
||||
}
|
||||
|
||||
void t3dVectTransform(t3dV3F *d, t3dV3F *s, t3dM3X3F *mat) {
|
||||
t3dV3F Tmp;
|
||||
Tmp.x = (s->x * mat->M[0]) + (s->y * mat->M[1]) + (s->z * mat->M[2]);
|
||||
Tmp.y = (s->x * mat->M[3]) + (s->y * mat->M[4]) + (s->z * mat->M[5]);
|
||||
Tmp.z = (s->x * mat->M[6]) + (s->y * mat->M[7]) + (s->z * mat->M[8]);
|
||||
d->x = Tmp.x;
|
||||
d->y = Tmp.y;
|
||||
d->z = Tmp.z;
|
||||
}
|
||||
|
||||
void t3dVectTransformInv(t3dV3F *d, t3dV3F *s, t3dM3X3F *mat) {
|
||||
t3dV3F Tmp;
|
||||
Tmp.x = (s->x * mat->M[0]) + (s->y * mat->M[3]) + (s->z * mat->M[6]);
|
||||
Tmp.y = (s->x * mat->M[1]) + (s->y * mat->M[4]) + (s->z * mat->M[7]);
|
||||
Tmp.z = (s->x * mat->M[2]) + (s->y * mat->M[5]) + (s->z * mat->M[8]);
|
||||
d->x = Tmp.x;
|
||||
d->y = Tmp.y;
|
||||
d->z = Tmp.z;
|
||||
}
|
||||
|
||||
void t3dVectCross(t3dV3F *d, t3dV3F *v2, t3dV3F *v3) {
|
||||
t3dV3F Tmp;
|
||||
Tmp.x = (v2->y * v3->z) - (v2->z * v3->y);
|
||||
Tmp.y = (v2->z * v3->x) - (v2->x * v3->z);
|
||||
Tmp.z = (v2->x * v3->y) - (v2->y * v3->x);
|
||||
d->x = Tmp.x;
|
||||
d->y = Tmp.y;
|
||||
d->z = Tmp.z;
|
||||
}
|
||||
|
||||
void t3dVectSub(t3dV3F *d, t3dV3F *a, t3dV3F *b) { // d = a - b
|
||||
d->x = a->x - b->x;
|
||||
d->y = a->y - b->y;
|
||||
d->z = a->z - b->z;
|
||||
}
|
||||
|
||||
void t3dVectAdd(t3dV3F *d, t3dV3F *a, t3dV3F *b) { // d = a - b
|
||||
d->x = a->x + b->x;
|
||||
d->y = a->y + b->y;
|
||||
d->z = a->z + b->z;
|
||||
}
|
||||
|
||||
void t3dVectFill(t3dV3F *d, t3dF32 a) {
|
||||
d->x = a;
|
||||
d->y = a;
|
||||
d->z = a;
|
||||
}
|
||||
|
||||
void t3dVectInit(t3dV3F *d, t3dF32 a1, t3dF32 a2, t3dF32 a3) {
|
||||
d->x = a1;
|
||||
d->y = a2;
|
||||
d->z = a3;
|
||||
}
|
||||
|
||||
void t3dVectCopy(t3dV3F *d, t3dV3F *s) {
|
||||
memcpy(d, s, sizeof(t3dV3F));
|
||||
}
|
||||
|
||||
|
||||
t3dF32 t3dVectMod(t3dV3F *c) {
|
||||
t3dF32 mod = (c->x * c->x + c->y * c->y + c->z * c->z);
|
||||
if (mod)
|
||||
return (float)sqrt((double)mod);
|
||||
else
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
t3dF32 t3dVectDistance(t3dV3F *a, t3dV3F *b) {
|
||||
t3dF32 mod;
|
||||
t3dV3F c;
|
||||
c.x = b->x - a->x;
|
||||
c.y = b->y - a->y;
|
||||
c.z = b->z - a->z;
|
||||
mod = (c.x * c.x + c.y * c.y + c.z * c.z);
|
||||
|
||||
if (mod)
|
||||
return ((float)sqrt((double)mod));
|
||||
else
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
t3dF32 t3dVectDot(t3dV3F *a, t3dV3F *b) {
|
||||
return (t3dF32)(a->x * b->x + a->y * b->y + a->z * b->z);
|
||||
}
|
||||
|
||||
void t3dMatMulInv(t3dM3X3F *Dest, t3dM3X3F *a, t3dM3X3F *b) {
|
||||
t3dM3X3F Tmp, *d = &Tmp;
|
||||
|
||||
d->M[0] = (a->M[0] * b->M[0] + a->M[1] * b->M[1] + a->M[2] * b->M[2]);
|
||||
d->M[1] = (a->M[0] * b->M[3] + a->M[1] * b->M[4] + a->M[2] * b->M[5]);
|
||||
d->M[2] = (a->M[0] * b->M[6] + a->M[1] * b->M[7] + a->M[2] * b->M[8]);
|
||||
|
||||
d->M[3] = (a->M[3] * b->M[0] + a->M[4] * b->M[1] + a->M[5] * b->M[2]);
|
||||
d->M[4] = (a->M[3] * b->M[3] + a->M[4] * b->M[4] + a->M[5] * b->M[5]);
|
||||
d->M[5] = (a->M[3] * b->M[6] + a->M[4] * b->M[7] + a->M[5] * b->M[8]);
|
||||
|
||||
d->M[6] = (a->M[6] * b->M[0] + a->M[7] * b->M[1] + a->M[8] * b->M[2]);
|
||||
d->M[7] = (a->M[6] * b->M[3] + a->M[7] * b->M[4] + a->M[8] * b->M[5]);
|
||||
d->M[8] = (a->M[6] * b->M[6] + a->M[7] * b->M[7] + a->M[8] * b->M[8]);
|
||||
|
||||
if (d != Dest)
|
||||
t3dMatCopy(Dest, &Tmp);
|
||||
}
|
||||
|
||||
void t3dPlaneNormal(t3dNORMAL *n, t3dV3F *p0, t3dV3F *p1, t3dV3F *p2) {
|
||||
t3dV3F a, b;
|
||||
|
||||
t3dVectSub(&a, p1, p0);
|
||||
t3dVectSub(&b, p2, p0);
|
||||
t3dVectCross(&n->n, &a, &b);
|
||||
t3dVectNormalize(&n->n);
|
||||
|
||||
n->dist = t3dVectDot(&n->n, p0);
|
||||
}
|
||||
|
||||
void t3dVectNormalize(t3dV3F *c) {
|
||||
t3dF32 mod = (float)sqrt((double)(c->x * c->x + c->y * c->y + c->z * c->z));
|
||||
if (!mod)return;
|
||||
mod = 1.0f / mod;
|
||||
c->x = c->x * mod;
|
||||
c->y = c->y * mod;
|
||||
c->z = c->z * mod;
|
||||
}
|
||||
|
||||
void t3dMatRot(t3dM3X3F *matrix, t3dF32 x, t3dF32 y, t3dF32 z) {
|
||||
/* t3dF32 cx, cy, cz, sx, sy, sz,sxsy,szsy,szcy,czcy;
|
||||
|
||||
sx = sin(x);cx = cos(x); // qui ci vorrebbe una FSINCOS in asm
|
||||
sy = sin(y);cy = cos(y);
|
||||
sz = sin(z);cz = cos(z);
|
||||
sxsy=sx*sy;szsy=sz*sy;szcy=sz*cy;czcy=cz*cy;
|
||||
matrix->M[0] = czcy + sx*szsy ;
|
||||
matrix->M[1] = -szcy + sxsy*cz ;
|
||||
matrix->M[2] = cx*sy;
|
||||
matrix->M[3] = cx*sz;
|
||||
matrix->M[4] = cx*cz;
|
||||
matrix->M[5] = -sx;
|
||||
matrix->M[6] = -cz*sy + sx*szcy;
|
||||
matrix->M[7] = szsy + sx*czcy;
|
||||
matrix->M[8] = cx*cy ;*/
|
||||
|
||||
|
||||
t3dM3X3F matrix_x, matrix_y, matrix_z;
|
||||
|
||||
t3dMatIdentity(&matrix_x);
|
||||
t3dMatIdentity(&matrix_y);
|
||||
t3dMatIdentity(&matrix_z);
|
||||
|
||||
/* | 1 0 0 0 | x' = x
|
||||
| 0 cos <20> -sin <20> 0 | y' = (cos <20>) * y - (sin <20>) * z
|
||||
| 0 sin <20> cos <20> 0 | z' = (sin <20>) * y + (cos <20>) * z
|
||||
| 0 0 0 1 |*/
|
||||
|
||||
matrix_x.M[4] = (float)cos(x);
|
||||
matrix_x.M[5] = -(float)sin(x);
|
||||
matrix_x.M[7] = (float)sin(x);
|
||||
matrix_x.M[8] = (float)cos(x);
|
||||
|
||||
/* | cos <20> 0 sin <20> 0 | x' = (cos <20>) * x + (sin <20>) * z
|
||||
| 0 1 0 0 | y' = y
|
||||
| -sin <20> 0 cos <20> 0 | z' = -(sin <20>) * x + (cos <20>) * z
|
||||
| 0 0 0 1 |*/
|
||||
|
||||
matrix_y.M[0] = (float)cos(y);
|
||||
matrix_y.M[2] = (float)sin(y);
|
||||
matrix_y.M[6] = -(float)sin(y);
|
||||
matrix_y.M[8] = (float)cos(y);
|
||||
|
||||
/* | cos <20> -sin <20> 0 0 | x' = (cos <20>) * x - (sin <20>) * y
|
||||
| sin <20> cos <20> 0 0 | y' = (sin <20>) * x + (cos <20>) * y
|
||||
| 0 0 1 0 | z' = z
|
||||
| 0 0 0 1 |*/
|
||||
|
||||
matrix_z.M[0] = (float)cos(z);
|
||||
matrix_z.M[1] = -(float)sin(z);
|
||||
matrix_z.M[3] = (float)sin(z);
|
||||
matrix_z.M[4] = (float)cos(z);
|
||||
|
||||
t3dMatMul(matrix, &matrix_x, &matrix_y);
|
||||
t3dMatMul(matrix, matrix, &matrix_z);
|
||||
}
|
||||
|
||||
t3dF32 t3dVectPlaneDistance(t3dV3F start, t3dNORMAL n) {
|
||||
return t3dVectDot(&start, &n.n) - n.dist;
|
||||
}
|
||||
|
||||
uint8 t3dVectPlaneIntersection(t3dV3F *inter, t3dV3F start, t3dV3F end, t3dNORMAL n) {
|
||||
t3dF32 divi;
|
||||
t3dF32 d1 = t3dVectPlaneDistance(start, n);
|
||||
t3dF32 d2 = t3dVectPlaneDistance(end, n);
|
||||
|
||||
if ((d1 < 0) && (d2 < 0))
|
||||
return 0;
|
||||
else if ((d1 >= 0) && (d2 >= 0))
|
||||
return 1;
|
||||
|
||||
|
||||
if ((d1 < 0) && (d2 >= 0)) {
|
||||
d2 = d2 - d1;
|
||||
divi = -d1 / d2;
|
||||
inter->x = start.x + divi * (end.x - start.x);
|
||||
inter->y = start.y + divi * (end.y - start.y);
|
||||
inter->z = start.z + divi * (end.z - start.z);
|
||||
return 2;
|
||||
} else {
|
||||
d1 = d1 - d2;
|
||||
divi = -d2 / d1;
|
||||
inter->x = end.x + divi * (start.x - end.x);
|
||||
inter->y = end.y + divi * (start.y - end.y);
|
||||
inter->z = end.z + divi * (start.z - end.z);
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
uint8 t3dVectTriangleIntersection(t3dV3F *inter, t3dV3F start, t3dV3F end,
|
||||
t3dV3F v1, t3dV3F v2, t3dV3F v3, t3dNORMAL n) {
|
||||
t3dV3F appo;
|
||||
t3dNORMAL normal;
|
||||
|
||||
if (t3dVectPlaneIntersection(inter, start, end, n) <= 1)
|
||||
return 0;
|
||||
|
||||
t3dVectAdd(&appo, &n.n, &v1);
|
||||
t3dPlaneNormal(&normal, &appo, &v1, &v2);
|
||||
|
||||
if (t3dVectPlaneDistance(*inter, normal) >= 0.0f) {
|
||||
t3dVectAdd(&appo, &n.n, &v2);
|
||||
t3dPlaneNormal(&normal, &appo, &v2, &v3);
|
||||
if (t3dVectPlaneDistance(*inter, normal) >= 0.0f) {
|
||||
t3dVectAdd(&appo, &n.n, &v3);
|
||||
t3dPlaneNormal(&normal, &appo, &v3, &v1);
|
||||
if (t3dVectPlaneDistance(*inter, normal) >= 0.0f)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
t3dF32 t3dVectSquaredDistance(t3dV3F *a, t3dV3F *b) {
|
||||
t3dV3F c;
|
||||
c.x = b->x - a->x;
|
||||
c.y = b->y - a->y;
|
||||
c.z = b->z - a->z;
|
||||
|
||||
return (c.x * c.x + c.y * c.y + c.z * c.z);
|
||||
}
|
||||
|
||||
t3dF32 t3dPointSquaredDistance(t3dV3F *c) {
|
||||
return (c->x * c->x + c->y * c->y + c->z * c->z);
|
||||
}
|
||||
|
||||
void t3dMatReflect(t3dM3X3F *Matrix, t3dV3F *mirrorpos, t3dNORMAL *n) {
|
||||
// | 1-2*nx*nx -2*nx*ny -2*nx*nz -2*nx*k |
|
||||
// | -2*ny*nx 1-2*ny*ny -2*ny*nz -2*ny*k |
|
||||
// | -2*nz*nx -2*nz*ny 1-2*nz*nz -2*nz*k |
|
||||
// | 0 0 0 1 |
|
||||
|
||||
Matrix->M[0] = 1 - 2 * n->n.x * n->n.x;
|
||||
Matrix->M[1] = -2 * n->n.x * n->n.y;
|
||||
Matrix->M[2] = -2 * n->n.x * n->n.z;
|
||||
Matrix->M[3] = -2 * n->n.y * n->n.x;
|
||||
Matrix->M[4] = 1 - 2 * n->n.y * n->n.y;
|
||||
Matrix->M[5] = -2 * n->n.y * n->n.z;
|
||||
Matrix->M[6] = -2 * n->n.z * n->n.x;
|
||||
Matrix->M[7] = -2 * n->n.z * n->n.y;
|
||||
Matrix->M[8] = 1 - 2 * n->n.z * n->n.z;
|
||||
|
||||
mirrorpos->x = -2 * n->n.x * n->dist;
|
||||
mirrorpos->y = -2 * n->n.y * n->dist;
|
||||
mirrorpos->z = -2 * n->n.z * n->dist;
|
||||
|
||||
}
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
66
engines/watchmaker/3d/math/llmath.h
Normal file
66
engines/watchmaker/3d/math/llmath.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WATCHMAKER_LLMATH_H
|
||||
#define WATCHMAKER_LLMATH_H
|
||||
|
||||
#include "watchmaker/t3d.h"
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
void t3dMatCopy(t3dM3X3F *d, t3dM3X3F *s);
|
||||
void t3dMatIdentity(t3dM3X3F *d);
|
||||
void t3dMatSet(t3dM3X3F *d,
|
||||
t3dF32 _m11, t3dF32 _m12, t3dF32 _m13,
|
||||
t3dF32 _m21, t3dF32 _m22, t3dF32 _m23,
|
||||
t3dF32 _m31, t3dF32 _m32, t3dF32 _m33);
|
||||
void t3dMatMul(t3dM3X3F *Dest, t3dM3X3F *a, t3dM3X3F *b);
|
||||
void t3dMatRotAxis(t3dM3X3F *m, t3dF32 x, t3dF32 y, t3dF32 z, t3dF32 rad);
|
||||
void t3dMatRot(t3dM3X3F *matrix, t3dF32 x, t3dF32 y, t3dF32 z);
|
||||
void t3dMatReflect(t3dM3X3F *Matrix, t3dV3F *mirrorpos, t3dNORMAL *n);
|
||||
void t3dMatView(t3dM3X3F *dest, t3dV3F *eye, t3dV3F *center);
|
||||
void t3dVectTransform(t3dV3F *d, t3dV3F *s, t3dM3X3F *mat);
|
||||
void t3dVectTransformInv(t3dV3F *d, t3dV3F *s, t3dM3X3F *mat);
|
||||
void t3dVectInit(t3dV3F *a, t3dF32 x, t3dF32 y, t3dF32 z);
|
||||
void t3dVectCross(t3dV3F *d, t3dV3F *v2, t3dV3F *v3);
|
||||
void t3dVectSub(t3dV3F *d, t3dV3F *a, t3dV3F *b); // d = a - b
|
||||
void t3dVectAdd(t3dV3F *d, t3dV3F *a, t3dV3F *b); // d = a - b
|
||||
void t3dVectFill(t3dV3F *d, t3dF32 a);
|
||||
void t3dVectCopy(t3dV3F *d, t3dV3F *s);
|
||||
t3dF32 t3dVectMod(t3dV3F *c);
|
||||
t3dF32 t3dVectDistance(t3dV3F *a, t3dV3F *b);
|
||||
t3dF32 t3dVectSquaredDistance(t3dV3F *a, t3dV3F *b);
|
||||
t3dF32 t3dPointSquaredDistance(t3dV3F *c);
|
||||
void t3dVectNormalize(t3dV3F *c);
|
||||
t3dF32 t3dVectDot(t3dV3F *a, t3dV3F *b);
|
||||
void t3dMatMulInv(t3dM3X3F *Dest, t3dM3X3F *a, t3dM3X3F *b);
|
||||
void t3dVectReflection(t3dV3F *r, t3dV3F *p1, t3dNORMAL *plane, t3dF32 dist);
|
||||
void t3dMatInv(t3dM3X3F *d, t3dM3X3F *s);
|
||||
void t3dPlaneNormal(t3dNORMAL *n, t3dV3F *p0, t3dV3F *p1, t3dV3F *p2);
|
||||
void t3dVector2dTo3d(t3dV3F *end, t3dV2F *start);
|
||||
int32 t3dFloatToInt(t3dF32 nfloat);
|
||||
t3dF32 t3dVectPlaneDistance(t3dV3F start, t3dNORMAL n); //return the distance of start from plane normal n
|
||||
uint8 t3dVectPlaneIntersection(t3dV3F *inter, t3dV3F start, t3dV3F end, t3dNORMAL n); //if return value !=0 inter contains the intersection point
|
||||
uint8 t3dVectTriangleIntersection(t3dV3F *inter, t3dV3F start, t3dV3F end, t3dV3F v1, t3dV3F v2, t3dV3F v3, t3dNORMAL n); //return 1 if the vector from start to end pass trought the triangle v1,v2,v3
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
|
||||
#endif // WATCHMAKER_LLMATH_H
|
||||
90
engines/watchmaker/3d/mem_management.cpp
Normal file
90
engines/watchmaker/3d/mem_management.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
/* 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/3d/mem_management.h"
|
||||
#include "watchmaker/types.h"
|
||||
#include "watchmaker/ll/ll_system.h"
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
static int8 *MemoryPool = nullptr;
|
||||
static uint32 MemoryPoolPointer = 0;
|
||||
static uint32 MaxAllocatedMem = 0;
|
||||
|
||||
// Memory Management
|
||||
// Only linear (non dynamic) stack allocations
|
||||
|
||||
|
||||
/* -----------------10/06/99 16.06-------------------
|
||||
* t3dAllocMemoryPool
|
||||
* --------------------------------------------------*/
|
||||
uint8 t3dAllocMemoryPool(uint32 pool) {
|
||||
uint8 allocated = 0;
|
||||
|
||||
MemoryPoolPointer = 0;
|
||||
while ((allocated == 0) && (pool > 0)) {
|
||||
if (!(MemoryPool = t3dCalloc<int8>(pool)))
|
||||
pool -= 10000;
|
||||
else
|
||||
allocated = 1;
|
||||
}
|
||||
|
||||
if (allocated == 0)
|
||||
return 0;
|
||||
else {
|
||||
MaxAllocatedMem = pool;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* -----------------10/06/99 16.07-------------------
|
||||
* t3dDeallocMemoryPool
|
||||
* --------------------------------------------------*/
|
||||
void t3dDeallocMemoryPool() {
|
||||
if (MemoryPool == nullptr) return;
|
||||
t3dFree(MemoryPool);
|
||||
MemoryPool = nullptr;
|
||||
MaxAllocatedMem = 0;
|
||||
}
|
||||
|
||||
/* -----------------10/06/99 16.07-------------------
|
||||
* t3dAlloc
|
||||
* --------------------------------------------------*/
|
||||
void *t3dAlloc(uint32 size) {
|
||||
if (MemoryPool == nullptr) return nullptr;
|
||||
MemoryPoolPointer += size;
|
||||
if (MemoryPoolPointer > MaxAllocatedMem) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &MemoryPool[MemoryPoolPointer - size];
|
||||
}
|
||||
|
||||
/* -----------------10/06/99 16.07-------------------
|
||||
* t3dDealloc
|
||||
* --------------------------------------------------*/
|
||||
void *t3dDealloc(uint32 size) {
|
||||
if (MemoryPool == nullptr) return nullptr;
|
||||
MemoryPoolPointer -= size;
|
||||
return &MemoryPool[MemoryPoolPointer];
|
||||
}
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
34
engines/watchmaker/3d/mem_management.h
Normal file
34
engines/watchmaker/3d/mem_management.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WATCHMAKER_MEM_MANAGEMENT_H
|
||||
#define WATCHMAKER_MEM_MANAGEMENT_H
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
unsigned char t3dAllocMemoryPool(unsigned int pool);
|
||||
void t3dDeallocMemoryPool();
|
||||
void *t3dAlloc(unsigned int size);
|
||||
void *t3dDealloc(unsigned int size);
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
|
||||
#endif // WATCHMAKER_MEM_MANAGEMENT_H
|
||||
219
engines/watchmaker/3d/movie.cpp
Normal file
219
engines/watchmaker/3d/movie.cpp
Normal file
@@ -0,0 +1,219 @@
|
||||
/* 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/3d/movie.h"
|
||||
#include "watchmaker/3d/dds_header.h"
|
||||
#include "watchmaker/file_utils.h"
|
||||
#include "watchmaker/windows_hacks.h"
|
||||
#include "watchmaker/work_dirs.h"
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
gMovie::gMovie(Common::SharedPtr<Common::SeekableReadStream> stream, Texture *texture, const Common::String &name) : _name(name), _stream(stream), _texture(texture) {
|
||||
_numFrames = stream->readUint16LE();
|
||||
_width = stream->readUint16LE();
|
||||
_height = stream->readUint16LE();
|
||||
_keyFrame = stream->readByte();
|
||||
_frameRate = stream->readByte();
|
||||
|
||||
_header = DDSHeader(*stream);
|
||||
_numBlocks = _width * _height / 16;
|
||||
_curFrame = 0xFFFF;
|
||||
|
||||
_frameOffsets = new uint32[_numFrames] {};
|
||||
if (!_frameOffsets) {
|
||||
error("gLoadMovie FAILED: Can't alloc Movie->frameOffsets struct");
|
||||
}
|
||||
|
||||
_buffer = new uint8[bufferSize()] {};
|
||||
_surfaceBuffer = new uint8[_header.dataSize()] {};
|
||||
_frameStream = new Common::MemoryReadStream(_surfaceBuffer, _header.dataSize(), DisposeAfterUse::NO);
|
||||
if (!_buffer) {
|
||||
error("gLoadMovie FAILED: Can't alloc Movie->buffer struct");
|
||||
}
|
||||
|
||||
//read frame offsets
|
||||
for (int i = 0; i < _numFrames; i++) {
|
||||
_frameOffsets[i] = _stream->readUint32LE();
|
||||
}
|
||||
|
||||
_startTime = 0;
|
||||
}
|
||||
|
||||
gMovie::~gMovie() {
|
||||
delete[] _frameOffsets;
|
||||
delete[] _buffer;
|
||||
delete[] _surfaceBuffer;
|
||||
delete _frameStream;
|
||||
}
|
||||
|
||||
Common::SharedPtr<gMovie> gLoadMovie(WorkDirs &workDirs, const char *TextName, Texture *texture) {
|
||||
//convert .avi name in .wmm
|
||||
Common::String finalName = replaceExtension(TextName, "wmm");
|
||||
|
||||
auto stream = workDirs.resolveFile(finalName);
|
||||
if (!stream) {
|
||||
DebugLogFile("gLoadMovie FAILED: Can't find movie file\n");
|
||||
return nullptr;
|
||||
}
|
||||
auto Movie = Common::SharedPtr<gMovie>(new gMovie(stream, texture, TextName));
|
||||
Movie->_name = TextName;
|
||||
if (!Movie) {
|
||||
DebugLogFile("gLoadMovie FAILED: Can't alloc Movie struct");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Movie->frameRate=240;
|
||||
return Movie;
|
||||
}
|
||||
|
||||
void gMovie::loadThisFrameData(uint16 frame) {
|
||||
_stream->seek(_frameOffsets[frame], SEEK_SET);
|
||||
//read frame data
|
||||
int32 size = 0;
|
||||
if ((frame + 1) == _numFrames) {
|
||||
size = _stream->size() - _frameOffsets[frame];
|
||||
} else {
|
||||
size = _frameOffsets[frame + 1] - _frameOffsets[frame];
|
||||
}
|
||||
assert(size <= (int32)bufferSize());
|
||||
_stream->read(_buffer, size);
|
||||
}
|
||||
|
||||
//build a new frame by difference from previous
|
||||
void gMovie::buildNewFrame(byte *surf, uint16 frame) {
|
||||
loadThisFrameData(frame);
|
||||
|
||||
DWORD bitArraySize = _numBlocks >> 3;
|
||||
byte *buf = &_buffer[bitArraySize];
|
||||
WORD curBlock = 0;
|
||||
|
||||
for (int i = 0; i < bitArraySize; i++) {
|
||||
byte block = _buffer[i];
|
||||
if (!block) {
|
||||
curBlock += 8;
|
||||
continue; //everything is equal
|
||||
}
|
||||
|
||||
for (int j = 0; j < 8; j++, curBlock++) {
|
||||
if (block & (1 << j)) {
|
||||
memcpy(&surf[curBlock << 3], buf, 8);
|
||||
buf += 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool gMovie::setFrame(uint16 newFrame) {
|
||||
warning("Set Frame: %d\t%s", newFrame, _name.c_str());
|
||||
if (_curFrame == newFrame)
|
||||
return true;
|
||||
|
||||
//do we have to replace the whole frame or do we have to built it?
|
||||
bool rebuildFrame = true;
|
||||
if (_curFrame == 0xFFFF) rebuildFrame = false;
|
||||
else if (!(newFrame % _keyFrame)) rebuildFrame = false; //it's a keyframe
|
||||
|
||||
_header.dataSize();
|
||||
#if 0
|
||||
DDSURFACEDESC2 ddsd2;
|
||||
ddsd2.dwSize = sizeof(DDSURFACEDESC2);
|
||||
|
||||
if ((mv->surf->Lock(NULL, &ddsd2, DDLOCK_NOSYSLOCK | DDLOCK_WAIT, NULL))) { // Lock and fill with the dds
|
||||
DebugLogFile("gMovie_SetFrame: Can't lock surface DDS");
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
if (!rebuildFrame) {
|
||||
loadThisFrameData(newFrame);
|
||||
memcpy(_surfaceBuffer, _buffer, _header.dataSize());
|
||||
} else {
|
||||
if ((_curFrame + 1) != newFrame) { //we can't directly build this frame because the current frame is not his previous
|
||||
uint16 startFrame;
|
||||
uint16 prevKey = (newFrame / _keyFrame) * _keyFrame;
|
||||
|
||||
if ((_curFrame > newFrame) || (_curFrame < prevKey)) {
|
||||
loadThisFrameData(prevKey);
|
||||
memcpy(_surfaceBuffer, _buffer, _header.dataSize());
|
||||
startFrame = prevKey + 1;
|
||||
} else startFrame = _curFrame + 1;
|
||||
for (uint16 i = startFrame; i < newFrame; i++) {
|
||||
buildNewFrame(_surfaceBuffer, i);
|
||||
}
|
||||
}
|
||||
buildNewFrame(_surfaceBuffer, newFrame);
|
||||
}
|
||||
|
||||
_frameStream->seek(0, SEEK_SET);
|
||||
auto tex = loadDdsTexture(*_frameStream, _header);
|
||||
_texture->assignData(*tex);
|
||||
#if 0
|
||||
if (mat->Texture->lpDDSurface->Blt(NULL, mv->surf, NULL, DDBLT_WAIT, NULL) != DD_OK) {
|
||||
DebugLogFile("gMovie_SetFrame: Can't Blit DDS texture");
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
_curFrame = newFrame;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//*********************************************************************************************
|
||||
bool gMovie::updateMovie() {
|
||||
int16 newFrame = 0;
|
||||
|
||||
if (_paused)
|
||||
return TRUE;
|
||||
|
||||
warning("Update Movie: %s", _name.c_str());
|
||||
|
||||
if ((_curFrame == 0xFFFF) || (!_startTime)) {
|
||||
_startTime = timeGetTime();
|
||||
newFrame = 0;
|
||||
} else {
|
||||
// Use the time to find which frame we should be drawing
|
||||
uint32 curTime = timeGetTime();
|
||||
DWORD elapsedTime = curTime - _startTime;
|
||||
newFrame = (WORD)((float)elapsedTime / (1000.f / (float)_frameRate));
|
||||
|
||||
if (newFrame >= _numFrames) {
|
||||
_startTime = curTime;
|
||||
newFrame = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return setFrame(newFrame);
|
||||
}
|
||||
|
||||
int gMovie::frameSize(int index) {
|
||||
if ((index + 1) < _numFrames) {
|
||||
return _frameOffsets[index + 1] - _frameOffsets[index];
|
||||
} else {
|
||||
return _stream->size() - _frameOffsets[index];
|
||||
}
|
||||
}
|
||||
|
||||
uint32 gMovie::bufferSize() const {
|
||||
return (_numBlocks / 8) + 8 * _numBlocks; //bit array + max different blocks
|
||||
}
|
||||
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
74
engines/watchmaker/3d/movie.h
Normal file
74
engines/watchmaker/3d/movie.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WATCHMAKER_MOVIE_H
|
||||
#define WATCHMAKER_MOVIE_H
|
||||
|
||||
#include "common/memstream.h"
|
||||
#include "watchmaker/3d/dds_header.h"
|
||||
#include "watchmaker/types.h"
|
||||
#include "watchmaker/utils.h"
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
struct gMovie {
|
||||
private:
|
||||
Common::MemoryReadStream *_frameStream = nullptr;
|
||||
public:
|
||||
Common::String _name;
|
||||
Common::SharedPtr<Common::SeekableReadStream> _stream;
|
||||
uint16 _numFrames;
|
||||
uint16 _curFrame;
|
||||
uint16 _width;
|
||||
uint16 _height;
|
||||
uint16 _numBlocks;
|
||||
uint32 _startTime;
|
||||
uint8 _keyFrame;
|
||||
uint8 _frameRate;
|
||||
|
||||
uint32 *_frameOffsets;
|
||||
uint8 *_buffer;
|
||||
uint8 *_surfaceBuffer;
|
||||
|
||||
DDSHeader _header;
|
||||
|
||||
Texture *_texture = nullptr;
|
||||
|
||||
bool _paused = false;
|
||||
|
||||
gMovie(Common::SharedPtr<Common::SeekableReadStream> stream, Texture *texture, const Common::String &name);
|
||||
~gMovie();
|
||||
|
||||
bool setFrame(uint16 newFrame);
|
||||
void loadThisFrameData(uint16 frame);
|
||||
void buildNewFrame(byte *surf, uint16 frame);
|
||||
bool updateMovie();
|
||||
private:
|
||||
int frameSize(int index);
|
||||
uint32 bufferSize() const;
|
||||
};
|
||||
|
||||
class WorkDirs;
|
||||
Common::SharedPtr<gMovie> gLoadMovie(WorkDirs &workDirs, const char *TextName, Texture *texture);
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
|
||||
#endif // WATCHMAKER_MOVIE_H
|
||||
36
engines/watchmaker/3d/render/opengl.cpp
Normal file
36
engines/watchmaker/3d/render/opengl.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
/* 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/3d/render/opengl.h"
|
||||
#include "watchmaker/utils.h"
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
//*********************************************************************************************
|
||||
bool rGetStencilBitDepth() {
|
||||
#if 0
|
||||
return gStencilBitDepth;
|
||||
#endif
|
||||
//warning("TODO: Implement rGetStencilBitDepth");
|
||||
return false;
|
||||
}
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
29
engines/watchmaker/3d/render/opengl.h
Normal file
29
engines/watchmaker/3d/render/opengl.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WATCHMAKER_OPENGL_H
|
||||
#define WATCHMAKER_OPENGL_H
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
|
||||
#endif // WATCHMAKER_OPENGL_H
|
||||
369
engines/watchmaker/3d/render/opengl_2d.cpp
Normal file
369
engines/watchmaker/3d/render/opengl_2d.cpp
Normal file
@@ -0,0 +1,369 @@
|
||||
/* 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/game.h"
|
||||
|
||||
#if defined(USE_OPENGL_GAME)
|
||||
|
||||
#include "graphics/pixelformat.h"
|
||||
#include "watchmaker/3d/render/opengl_2d.h"
|
||||
#include "watchmaker/3d/render/opengl_renderer.h"
|
||||
#include "watchmaker/game.h"
|
||||
#include "watchmaker/rect.h"
|
||||
#include "watchmaker/render.h"
|
||||
#include "watchmaker/renderer.h"
|
||||
#include "watchmaker/sdl_wrapper.h"
|
||||
#include "watchmaker/tga_util.h"
|
||||
#include "watchmaker/utils.h"
|
||||
#include "watchmaker/work_dirs.h"
|
||||
|
||||
#include "graphics/opengl/system_headers.h"
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
Common::Rect gBlitterExtends;
|
||||
int gStencilBitDepth;
|
||||
|
||||
unsigned int CurLoaderFlags;
|
||||
|
||||
//*********************************************************************************************
|
||||
unsigned int Renderer::BitmapList::acquirePosition() {
|
||||
unsigned int pos = 1;
|
||||
|
||||
while (!bitmaps[pos].isEmpty()) {
|
||||
pos++;
|
||||
}
|
||||
|
||||
if (pos > MAX_BITMAP_LIST)
|
||||
return 0;
|
||||
|
||||
if (pos > _numBitmaps)
|
||||
_numBitmaps = pos;
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
unsigned int Renderer::getBitmapDimX(int32 id) const {
|
||||
return _bitmapList.bitmaps[id].DimX;
|
||||
}
|
||||
|
||||
unsigned int Renderer::getBitmapDimY(int32 id) const {
|
||||
return _bitmapList.bitmaps[id].DimY;
|
||||
}
|
||||
|
||||
unsigned int Renderer::getBitmapRealDimX(int32 id) const {
|
||||
return _bitmapList.bitmaps[id].RealDimX;
|
||||
}
|
||||
|
||||
unsigned int Renderer::getBitmapRealDimY(int32 id) const {
|
||||
return _bitmapList.bitmaps[id].RealDimY;
|
||||
}
|
||||
|
||||
|
||||
//************************************************************************************************************************
|
||||
void rUpdateExtends(int x1, int y1, int x2, int y2) {
|
||||
//Update extends
|
||||
if (x1 < gBlitterExtends.left)
|
||||
gBlitterExtends.left = x1;
|
||||
if (y1 < gBlitterExtends.top)
|
||||
gBlitterExtends.top = y1;
|
||||
if (x2 > gBlitterExtends.right)
|
||||
gBlitterExtends.right = x2;
|
||||
if (y2 > gBlitterExtends.bottom)
|
||||
gBlitterExtends.bottom = y2;
|
||||
}
|
||||
|
||||
//************************************************************************************************************************
|
||||
void rGetExtends(int *x1, int *y1, int *x2, int *y2) {
|
||||
*x1 = gBlitterExtends.left;
|
||||
*y1 = gBlitterExtends.top;
|
||||
*x2 = gBlitterExtends.right;
|
||||
*y2 = gBlitterExtends.bottom;
|
||||
}
|
||||
|
||||
//************************************************************************************************************************
|
||||
void rResetExtends() {
|
||||
gBlitterExtends.left = SHRT_MAX;
|
||||
gBlitterExtends.top = SHRT_MAX;
|
||||
gBlitterExtends.right = SHRT_MIN;
|
||||
gBlitterExtends.bottom = SHRT_MIN;
|
||||
}
|
||||
|
||||
// TODO: Move this to Renderer
|
||||
extern Common::Rect gBlitterViewport;
|
||||
bool gClipToBlitterViewport(int *sposx, int *sposy, int *sdimx, int *sdimy,
|
||||
int *dposx, int *dposy) {
|
||||
int dwWidth, dwHeight;
|
||||
|
||||
dwWidth = (gBlitterViewport.right - gBlitterViewport.left);
|
||||
dwHeight = (gBlitterViewport.bottom - gBlitterViewport.top);
|
||||
|
||||
if (((*dposx) + (*sdimx)) > dwWidth) {
|
||||
(*sdimx) = (*sdimx) - ((*dposx) + (*sdimx) - dwWidth);
|
||||
}
|
||||
if (((*dposy) + (*sdimy)) > dwHeight) {
|
||||
(*sdimy) = (*sdimy) - ((*dposy) + (*sdimy) - dwHeight);
|
||||
}
|
||||
|
||||
if ((*dposx) < gBlitterViewport.left) {
|
||||
(*sposx) += gBlitterViewport.left - (*dposx);
|
||||
(*sdimx) -= gBlitterViewport.left - (*dposx);
|
||||
(*dposx) = gBlitterViewport.left;
|
||||
}
|
||||
if ((*dposy) < gBlitterViewport.top) {
|
||||
(*sposy) += gBlitterViewport.top - (*dposy);
|
||||
(*sdimy) -= gBlitterViewport.top - (*dposy);
|
||||
(*dposy) = gBlitterViewport.top;
|
||||
}
|
||||
|
||||
if (((*sdimx) <= 0) || ((*sdimy) <= 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void renderTexture(WGame &game, gTexture &bitmap, Common::Rect srcRect, Common::Rect dstRect) {
|
||||
checkGlError("Entering renderTexture");
|
||||
glClearColor(0, 0, 1, 0);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glEnable(GL_ALPHA_TEST);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDepthFunc(GL_ALWAYS);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
bitmap._texture->bind();
|
||||
glLoadIdentity();
|
||||
glTranslatef(0, 0, 0.0);
|
||||
|
||||
float bottomSrc = ((float)srcRect.bottom) / bitmap.RealDimY;
|
||||
float topSrc = ((float)srcRect.top) / bitmap.RealDimY;
|
||||
float leftSrc = ((float)srcRect.left) / bitmap.RealDimX;
|
||||
float rightSrc = ((float)srcRect.right) / bitmap.RealDimX;
|
||||
|
||||
Common::Rect viewport = game._renderer->_viewport;
|
||||
float bottomDst = 1.0 - ((dstRect.bottom == 0 ? 0 : ((double)dstRect.bottom) / viewport.height()) * 2.0);
|
||||
float topDst = 1.0 - ((dstRect.top == 0 ? 0 : ((double)dstRect.top) / viewport.height()) * 2.0);
|
||||
float leftDst = ((dstRect.left == 0 ? 0 : ((double)dstRect.left) / viewport.width()) * 2.0) - 1.0;
|
||||
float rightDst = ((dstRect.right == 0 ? 0 : ((double)dstRect.right) / viewport.width()) * 2.0) - 1.0;
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
|
||||
glTexCoord2f(leftSrc, bottomSrc); // Bottom Left
|
||||
glVertex3f(leftDst, bottomDst, 0.0f);
|
||||
|
||||
glTexCoord2f(rightSrc, bottomSrc); // Bottom Right
|
||||
glVertex3f(rightDst, bottomDst, 0.0f);
|
||||
|
||||
glTexCoord2f(rightSrc, topSrc); // Top Right
|
||||
glVertex3f(rightDst, topDst, 0.0f);
|
||||
|
||||
glTexCoord2f(leftSrc, topSrc); // Top Left
|
||||
glVertex3f(leftDst, topDst, 0.0f);
|
||||
|
||||
glEnd();
|
||||
glFlush();
|
||||
checkGlError("Exiting renderTexture");
|
||||
}
|
||||
|
||||
void gTexture::render(WGame &game, Common::Rect src, Common::Rect dst) {
|
||||
// Render self
|
||||
if (_texture) {
|
||||
renderTexture(game, *this, src, dst);
|
||||
}
|
||||
for (uint i = 0; i < _blitsOnTop.size(); i++) {
|
||||
_blitsOnTop[i].texture->render(game, _blitsOnTop[i].src, _blitsOnTop[i].dst);
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::blitScreenBuffer() {
|
||||
checkGlError("Entering rBlitScreenBuffer");
|
||||
g_renderer->enter2Dmode();
|
||||
_bitmapList.bitmaps[BACK_BUFFER].render(*_game, _game->_renderer->_viewport, _game->_renderer->_viewport);
|
||||
g_renderer->exit2Dmode();
|
||||
checkGlError("Exiting rBlitScreenBuffer");
|
||||
}
|
||||
|
||||
void Renderer::clearBitmap(int dst, int dposx, int dposy, int sdimx, int sdimy, unsigned char r, unsigned char g, unsigned char b) {
|
||||
warning("STUBBED: rClear(%d, %d, %d, %d, %d", dst, dposx, dposy, sdimx, sdimy);
|
||||
_bitmapList.bitmaps[dst].clear();
|
||||
}
|
||||
|
||||
//************************************************************************************************************************
|
||||
void rBlitter(WGame &game, int dst, int src, int dposx, int dposy,
|
||||
int sposx, int sposy, int sdimx, int sdimy) {
|
||||
auto &bitmapList = game._renderer->_bitmapList.bitmaps;
|
||||
// TODO: This currently gets called a bit too much.
|
||||
warning("TODO: Stubbed rBlitter(%s, %d, %d, %d, %d, %d, %d, %d, %d)", bitmapList[src].name.c_str(), dst, src, dposx, dposy, sposx, sposy, sdimx, sdimy);
|
||||
|
||||
auto &bitmap = bitmapList[src];
|
||||
|
||||
assert(dst == 0);
|
||||
auto &dstBitmap = bitmapList[dst];
|
||||
|
||||
checkGlError("rBlitter Start");
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
int dwWidth, dwHeight;
|
||||
|
||||
dwWidth = game._renderer->_viewport.width();
|
||||
dwHeight = game._renderer->_viewport.height();
|
||||
|
||||
if ((sdimx <= 0)) {
|
||||
sdimx = bitmapList[src].DimX;
|
||||
}
|
||||
if ((sdimy <= 0)) {
|
||||
sdimy = bitmapList[src].DimY;
|
||||
}
|
||||
|
||||
if ((dposx >= dwWidth) || (dposy >= dwHeight) || (sposx >= dwWidth) || (sposy >= dwHeight) ||
|
||||
((dposx + sdimx) <= 0) || ((dposy + sdimy) <= 0) || ((sposx + sdimx) <= 0) || ((sposy + sdimy) <= 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (dst == 0) {
|
||||
if (!gClipToBlitterViewport(&sposx, &sposy, &sdimx, &sdimy, &dposx, &dposy)) {
|
||||
error("gClipToBlitterViewport report an error");
|
||||
return;
|
||||
}
|
||||
|
||||
rUpdateExtends(dposx, dposy, dposx + sdimx, dposy + sdimy);
|
||||
}
|
||||
|
||||
if ((sdimx == 0) && (sdimy == 0)) {
|
||||
sdimx = bitmapList[src].DimX;
|
||||
sdimy = bitmapList[src].DimY;
|
||||
}
|
||||
|
||||
{
|
||||
Common::Rect srcRect;
|
||||
// Source rect
|
||||
srcRect.top = sposy;
|
||||
srcRect.left = sposx;
|
||||
srcRect.right = sposx + sdimx;
|
||||
srcRect.bottom = sposy + sdimy;
|
||||
|
||||
Common::Rect dstRect;
|
||||
// Destination rect
|
||||
// Convention in dpos is that 0,0 is upper left hand corner, increasing down the y-axis.
|
||||
dstRect.top = dposy;
|
||||
dstRect.left = dposx;
|
||||
dstRect.right = dposx + sdimx;
|
||||
dstRect.bottom = dposy + sdimy;
|
||||
if (((dstRect.bottom - dstRect.top) <= 0) || ((dstRect.right - dstRect.left) <= 0) || ((srcRect.bottom - srcRect.top) <= 0) || ((srcRect.right - srcRect.left) <= 0) ||
|
||||
(dstRect.right <= 0) || (srcRect.right <= 0) || (dstRect.bottom < 0) || (srcRect.bottom < 0)) {
|
||||
// DebugLogWindow("gBlitter: blit not needed: dimx:%d dimy:%d", ( sr.top-sr.bottom ),( sr.left-sr.right ));
|
||||
return;
|
||||
}
|
||||
dstBitmap.blitInto(&bitmap, srcRect, dstRect);
|
||||
}
|
||||
checkGlError("rBlitter End");
|
||||
|
||||
// DebugLogFile("gBlitter(%d %d)",dst,src);
|
||||
//gBlitter(d, s, sposx, sposy, sdimx, sdimy, dposx, dposy, 0);
|
||||
//#endif
|
||||
}
|
||||
|
||||
// Straight from Wintermute:
|
||||
void applyColorKey(Graphics::Surface &surf, byte ckRed, byte ckGreen, byte ckBlue, bool replaceAlpha) {
|
||||
// this is taken from Graphics::TransparentSurface
|
||||
// only difference is that we set the pixel
|
||||
// color to transparent black, like D3DX,
|
||||
// if it matches the color key
|
||||
for (int y = 0; y < surf.h; y++) {
|
||||
for (int x = 0; x < surf.w; x++) {
|
||||
uint32 pix = ((uint32 *)surf.getPixels())[y * surf.w + x];
|
||||
uint8 r, g, b, a;
|
||||
surf.format.colorToARGB(pix, a, r, g, b);
|
||||
if (r == ckRed && g == ckGreen && b == ckBlue) {
|
||||
a = 0;
|
||||
r = 0;
|
||||
g = 0;
|
||||
b = 0;
|
||||
((uint32 *)surf.getPixels())[y * surf.w + x] = surf.format.ARGBToColor(a, r, g, b);
|
||||
} else if (replaceAlpha) {
|
||||
a = 255;
|
||||
((uint32 *)surf.getPixels())[y * surf.w + x] = surf.format.ARGBToColor(a, r, g, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int rLoadBitmapImage(WGame &game, const char *TextName, unsigned char flags) {
|
||||
WorkDirs &workDirs = game.workDirs;
|
||||
if (flags & rTEXTURESURFACE) {
|
||||
warning("TODO: support texture surface loading");
|
||||
// return ((int) gLoadTexture(TextName, flags));
|
||||
}
|
||||
|
||||
assert(TextName);
|
||||
auto stream = workDirs.resolveFile(TextName);
|
||||
if (!stream) {
|
||||
warning("gLoadBitmapImage: Cannot find %s.", TextName);
|
||||
return -1;
|
||||
}
|
||||
|
||||
const Graphics::PixelFormat RGBA32 = Graphics::PixelFormat::createFormatRGBA32();
|
||||
|
||||
unsigned int pos = game._renderer->_bitmapList.acquirePosition();
|
||||
if (pos == 0) {
|
||||
warning("rLoadBitmap: Can't create more bitmaps");
|
||||
return -1;
|
||||
}
|
||||
gTexture *Texture = &game._renderer->_bitmapList.bitmaps[pos];
|
||||
*Texture = gTexture();
|
||||
Texture->Flags = CurLoaderFlags;
|
||||
auto surface = ReadTgaImage(TextName, *stream, RGBA32, Texture->Flags);
|
||||
applyColorKey(*surface, 0, 0, 0, false);
|
||||
auto texData = createTextureFromSurface(*surface, GL_RGBA);
|
||||
Texture->_texture = createGLTexture();
|
||||
Texture->_texture->assignData(*texData);
|
||||
Texture->name = TextName;
|
||||
|
||||
if (flags & rSURFACESTRETCH) { // Also rSURFACEFLIP
|
||||
static bool warned = false;
|
||||
if (!warned) {
|
||||
warning("TODO: rSURFACESTRETCH");
|
||||
warned = true;
|
||||
}
|
||||
// HACK: Just set a dimension at all:
|
||||
Texture->DimX = surface->w;
|
||||
Texture->DimY = surface->h;
|
||||
} else {
|
||||
Texture->DimX = surface->w;
|
||||
Texture->DimY = surface->h;
|
||||
}
|
||||
|
||||
Texture->RealDimX = surface->w;
|
||||
Texture->RealDimY = surface->h;
|
||||
// TODO: Colour-keying
|
||||
return pos;
|
||||
}
|
||||
|
||||
void rSetLoaderFlags(unsigned int NewLoaderFlags) {
|
||||
CurLoaderFlags = NewLoaderFlags;
|
||||
}
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
|
||||
#endif // USE_OPENGL_GAME
|
||||
36
engines/watchmaker/3d/render/opengl_2d.h
Normal file
36
engines/watchmaker/3d/render/opengl_2d.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WATCHMAKER_OPENGL2D_H
|
||||
#define WATCHMAKER_OPENGL2D_H
|
||||
|
||||
#include "watchmaker/render.h"
|
||||
#include "watchmaker/3d/render/opengl_3d.h"
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
extern int gStencilBitDepth;
|
||||
|
||||
extern unsigned int CurLoaderFlags;
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
|
||||
#endif // WATCHMAKER_OPENGL2D_H
|
||||
840
engines/watchmaker/3d/render/opengl_3d.cpp
Normal file
840
engines/watchmaker/3d/render/opengl_3d.cpp
Normal file
@@ -0,0 +1,840 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_strcat
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_strcpy
|
||||
|
||||
#include "watchmaker/3d/render/opengl_3d.h"
|
||||
#include "watchmaker/windows_hacks.h"
|
||||
#include "watchmaker/t3d.h"
|
||||
#include "watchmaker/3d/math/Matrix4x4.h"
|
||||
#include "watchmaker/3d/render/opengl_renderer.h"
|
||||
#include "watchmaker/ll/ll_system.h"
|
||||
#include "watchmaker/3d/render/opengl_2d.h"
|
||||
#include "watchmaker/renderer.h"
|
||||
#include "watchmaker/globvar.h"
|
||||
#include "watchmaker/work_dirs.h"
|
||||
|
||||
#ifdef USE_OPENGL_GAME
|
||||
|
||||
#include "graphics/opengl/system_headers.h"
|
||||
#include "watchmaker/3d/render/shadows.h"
|
||||
#include "watchmaker/file_utils.h"
|
||||
#include "watchmaker/tga_util.h"
|
||||
|
||||
#define MAXTEXTURES 2000
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
#define T3D_FASTFILE (1<<23) // fastfile
|
||||
|
||||
// Tecture formats
|
||||
int NumAvailableFormats = 0;
|
||||
gAvailFormat AvailableFormats[50];
|
||||
gAvailFormat *gCurrentFormat;
|
||||
|
||||
// Point VB
|
||||
int g_lpD3DPointsBuffer;
|
||||
unsigned int gNumPointsBuffer;
|
||||
|
||||
// Tecture list
|
||||
gTexture gTextureList[MAXTEXTURES];
|
||||
unsigned int gNumTextureList = 0;
|
||||
|
||||
// {ines array
|
||||
uint16 gLinesArray[MAX_LINES];
|
||||
unsigned int gNumLinesArray = 0;
|
||||
|
||||
// screen traingles
|
||||
Vertex gTriangles[100];
|
||||
unsigned int gNumTrianglesArray = 0;
|
||||
|
||||
// camera info
|
||||
Matrix4x4 rWorldMatrix;
|
||||
Matrix4x4 rProjectionMatrix;
|
||||
float gNearPlane, gFarPlane;
|
||||
|
||||
// saved matrix
|
||||
Matrix4x4 rLinesViewMatrix;
|
||||
|
||||
// user matrix
|
||||
#define MAX_USER_VIEW_MATRICES 2000 // TODO: Why do we get so many of them?
|
||||
Matrix4x4 rUserViewMatrix[MAX_USER_VIEW_MATRICES];
|
||||
unsigned int rNumUserViewMatrices = 0;
|
||||
|
||||
// user vertext buffer
|
||||
void *g_lpD3DUserVertexBuffer = nullptr;
|
||||
unsigned int g_dwD3DUserVertexBufferCounter = 0;
|
||||
|
||||
//***********************************************************************************************
|
||||
uint16 *rGetLinesArrayPtr() {
|
||||
return &gLinesArray[gNumLinesArray];
|
||||
}
|
||||
|
||||
//***********************************************************************************************
|
||||
void rAddLinesArray() {
|
||||
gNumLinesArray++;
|
||||
}
|
||||
|
||||
//***********************************************************************************************
|
||||
void *rLockPointArray() {
|
||||
warning("TODO: Implement rLockPointArray");
|
||||
#if 0
|
||||
HRESULT hResult;
|
||||
LPVOID v;
|
||||
|
||||
if ((hResult = g_lpD3DPointsBuffer->Lock(DDLOCK_SURFACEMEMORYPTR, &v, NULL)) != D3D_OK) {
|
||||
char str[255];
|
||||
GetDDErrorString(hResult, str, 1);
|
||||
DebugLogFile("rLockPointArray: Unable to lock points vertexbuffer:\r\n%s", str);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gVertex *gv = (gVertex *)v;
|
||||
return &gv[rGetNumPointArray()];
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void rAddTrianglesArray(float x, float y, int r, int g, int b, int a) {
|
||||
gTriangles[gNumTrianglesArray].sx = x;
|
||||
gTriangles[gNumTrianglesArray].sy = y;
|
||||
gTriangles[gNumTrianglesArray].sz = 1.0f;
|
||||
gTriangles[gNumTrianglesArray].color = RGBA_MAKE(r, g, b, a);
|
||||
gNumTrianglesArray++;
|
||||
}
|
||||
|
||||
|
||||
//***********************************************************************************************
|
||||
void rUnlockPointArray() {
|
||||
warning("TODO: Implement rUnlockPointArray");
|
||||
#if 0
|
||||
g_lpD3DPointsBuffer->Unlock();
|
||||
#endif
|
||||
}
|
||||
|
||||
//***********************************************************************************************
|
||||
unsigned int rGetNumPointArray() {
|
||||
return gNumPointsBuffer;
|
||||
}
|
||||
|
||||
//***********************************************************************************************
|
||||
void rAddPointArray() {
|
||||
gNumPointsBuffer++;
|
||||
}
|
||||
|
||||
//***********************************************************************************************
|
||||
bool rSetViewMatrix(float _00, float _01, float _02,
|
||||
float _03, float _04, float _05,
|
||||
float _06, float _07, float _08,
|
||||
float _tx, float _ty, float _tz) {
|
||||
Matrix4x4 rViewMatrix;
|
||||
rViewMatrix.setIdentity();
|
||||
|
||||
rViewMatrix.setValue(1, 1, _00);
|
||||
rViewMatrix.setValue(1, 2, _01);
|
||||
rViewMatrix.setValue(1, 3, _02);
|
||||
rViewMatrix.setValue(1, 4, _tx);
|
||||
|
||||
rViewMatrix.setValue(2, 1, _03);
|
||||
rViewMatrix.setValue(2, 2, _04);
|
||||
rViewMatrix.setValue(2, 3, _05);
|
||||
rViewMatrix.setValue(2, 4, _ty);
|
||||
|
||||
rViewMatrix.setValue(3, 1, -_06);
|
||||
rViewMatrix.setValue(3, 2, -_07);
|
||||
rViewMatrix.setValue(3, 3, -_08);
|
||||
rViewMatrix.setValue(3, 4, _tz);
|
||||
|
||||
rViewMatrix.setValue(4, 1, 0.0f);
|
||||
rViewMatrix.setValue(4, 2, 0.0f);
|
||||
rViewMatrix.setValue(4, 3, 0.0f);
|
||||
rViewMatrix.setValue(4, 4, 1.0f);
|
||||
|
||||
g_renderer->setTransformMatrix(TransformMatrix::VIEW, rViewMatrix);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void rSetViewMatrix(const t3dM3X3F &viewMatrix, const t3dV3F &translation) {
|
||||
rSetViewMatrix(viewMatrix.M[0], viewMatrix.M[1], viewMatrix.M[2],
|
||||
viewMatrix.M[3], viewMatrix.M[4], viewMatrix.M[5],
|
||||
viewMatrix.M[6], viewMatrix.M[7], viewMatrix.M[8],
|
||||
translation.x, translation.y, -translation.z);
|
||||
}
|
||||
|
||||
void rSaveViewMatrix() {
|
||||
g_renderer->pushModelView();
|
||||
}
|
||||
|
||||
//***********************************************************************************************
|
||||
void rRestoreViewMatrix() {
|
||||
g_renderer->popModelView();
|
||||
}
|
||||
|
||||
//***********************************************************************************************
|
||||
bool rBuildLinesViewMatrix(float _00, float _01, float _02,
|
||||
float _03, float _04, float _05,
|
||||
float _06, float _07, float _08,
|
||||
float _tx, float _ty, float _tz) {
|
||||
rLinesViewMatrix.setIdentity();
|
||||
|
||||
rLinesViewMatrix.setValue(1, 1, _00);
|
||||
rLinesViewMatrix.setValue(1, 2, _01);
|
||||
rLinesViewMatrix.setValue(1, 3, _02);
|
||||
rLinesViewMatrix.setValue(1, 4, _tx);
|
||||
|
||||
rLinesViewMatrix.setValue(2, 1, _03);
|
||||
rLinesViewMatrix.setValue(2, 2, _04);
|
||||
rLinesViewMatrix.setValue(2, 3, _05);
|
||||
rLinesViewMatrix.setValue(2, 4, _ty);
|
||||
|
||||
rLinesViewMatrix.setValue(3, 1, -_06);
|
||||
rLinesViewMatrix.setValue(3, 2, -_07);
|
||||
rLinesViewMatrix.setValue(3, 3, -_08);
|
||||
rLinesViewMatrix.setValue(3, 4, -_tz);
|
||||
|
||||
rLinesViewMatrix.setValue(4, 1, 0.0f);
|
||||
rLinesViewMatrix.setValue(4, 2, 0.0f);
|
||||
rLinesViewMatrix.setValue(4, 3, 0.0f);
|
||||
rLinesViewMatrix.setValue(4, 4, 1.0f);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int rBuildLinesViewMatrix(const t3dM3X3F &viewMatrix, const t3dV3F &translation) {
|
||||
return rBuildLinesViewMatrix(viewMatrix.M[0], viewMatrix.M[1], viewMatrix.M[2],
|
||||
viewMatrix.M[3], viewMatrix.M[4], viewMatrix.M[5],
|
||||
viewMatrix.M[6], viewMatrix.M[7], viewMatrix.M[8],
|
||||
translation.x, translation.y, translation.z);
|
||||
}
|
||||
|
||||
//***********************************************************************************************
|
||||
int rAddUserViewMatrix(float _00, float _01, float _02,
|
||||
float _03, float _04, float _05,
|
||||
float _06, float _07, float _08,
|
||||
float _tx, float _ty, float _tz) {
|
||||
Matrix4x4 rTempViewMatrix;
|
||||
Matrix4x4 *um;
|
||||
unsigned int i;
|
||||
|
||||
rTempViewMatrix.setIdentity();
|
||||
|
||||
rTempViewMatrix.setValue(1, 1, _00);
|
||||
rTempViewMatrix.setValue(1, 2, _01);
|
||||
rTempViewMatrix.setValue(1, 3, _02);
|
||||
rTempViewMatrix.setValue(1, 4, _tx);
|
||||
|
||||
rTempViewMatrix.setValue(2, 1, _03);
|
||||
rTempViewMatrix.setValue(2, 2, _04);
|
||||
rTempViewMatrix.setValue(2, 3, _05);
|
||||
rTempViewMatrix.setValue(2, 4, _ty);
|
||||
|
||||
rTempViewMatrix.setValue(3, 1, -_06);
|
||||
rTempViewMatrix.setValue(3, 2, -_07);
|
||||
rTempViewMatrix.setValue(3, 3, -_08);
|
||||
rTempViewMatrix.setValue(3, 4, -_tz);
|
||||
|
||||
rTempViewMatrix.setValue(4, 1, 0.0f);
|
||||
rTempViewMatrix.setValue(4, 2, 0.0f);
|
||||
rTempViewMatrix.setValue(4, 3, 0.0f);
|
||||
rTempViewMatrix.setValue(4, 4, 1.0f);
|
||||
|
||||
auto &tmp = rTempViewMatrix;
|
||||
//warning("Adding: ");
|
||||
//tmp.print();
|
||||
for (i = 0, um = &rUserViewMatrix[0]; i < rNumUserViewMatrices; i++, um++) {
|
||||
//warning("Comparing %d", i);
|
||||
//um->print();
|
||||
if (*um == tmp) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
if (i >= MAX_USER_VIEW_MATRICES) {
|
||||
DebugLogFile("Too many UserViewMatrix %d (MAX is %d)\n", i, MAX_USER_VIEW_MATRICES);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*um = tmp;
|
||||
|
||||
rNumUserViewMatrices ++;
|
||||
return rNumUserViewMatrices - 1;
|
||||
}
|
||||
|
||||
int rAddUserViewMatrix(const t3dM3X3F &viewMatrix, const t3dV3F &translation) {
|
||||
return rAddUserViewMatrix(viewMatrix.M[0], viewMatrix.M[1], viewMatrix.M[2],
|
||||
viewMatrix.M[3], viewMatrix.M[4], viewMatrix.M[5],
|
||||
viewMatrix.M[6], viewMatrix.M[7], viewMatrix.M[8],
|
||||
translation.x, translation.y, translation.z);
|
||||
}
|
||||
|
||||
void rResetPipeline() {
|
||||
gNumLinesArray = 0;
|
||||
gNumPointsBuffer = 0;
|
||||
gNumShadowBoxesList = 0;
|
||||
rNumUserViewMatrices = 0;
|
||||
g_dwD3DUserVertexBufferCounter = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
//*********************************************************************************************
|
||||
void *rGetUserVertexBuffer() {
|
||||
return g_lpD3DUserVertexBuffer;
|
||||
}
|
||||
|
||||
//*********************************************************************************************
|
||||
unsigned int rGetUserVertexBufferCounter() {
|
||||
return g_dwD3DUserVertexBufferCounter;
|
||||
}
|
||||
|
||||
//*********************************************************************************************
|
||||
void rSetUserVertexBufferCounter(unsigned int uvbc) {
|
||||
g_dwD3DUserVertexBufferCounter = uvbc;
|
||||
}
|
||||
|
||||
gVertex *rLockVertexPtr(void *vb, int flags) {
|
||||
warning("TODO: Implement rLockVertexPtr");
|
||||
#if 0
|
||||
LPVOID v;
|
||||
DWORD dim, lock_flags;
|
||||
HRESULT hResult;
|
||||
|
||||
LPDIRECT3DVERTEXBUFFER7 lpD3DVertexBuffer1 = (LPDIRECT3DVERTEXBUFFER7)vb;
|
||||
|
||||
lock_flags = DDLOCK_SURFACEMEMORYPTR;
|
||||
if (flags & rVBLOCK_READONLY)
|
||||
lock_flags |= DDLOCK_READONLY;
|
||||
else if (flags & rVBLOCK_WRITEONLY)
|
||||
lock_flags |= DDLOCK_WRITEONLY;
|
||||
if (flags & rVBLOCK_NOSYSLOCK)
|
||||
lock_flags |= DDLOCK_NOSYSLOCK;
|
||||
|
||||
if ((hResult = lpD3DVertexBuffer1->Lock(lock_flags, &v, &dim)) != D3D_OK) {
|
||||
char str[255];
|
||||
GetDDErrorString(hResult, str, 1);
|
||||
DebugLogFile("Unable to lock vertexbuffer:\r\n%s", str);
|
||||
return NULL;
|
||||
}
|
||||
return (gVertex *)v;
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Graphics::Surface *gCreateSurface(int width, int height, void *ptr) {
|
||||
auto surface = new Graphics::Surface();
|
||||
surface->w = width;
|
||||
surface->h = height;
|
||||
surface->pitch = width * 4; // TODO
|
||||
surface->setPixels(ptr);
|
||||
return surface;
|
||||
}
|
||||
|
||||
//***********************************************************************************************
|
||||
bool rUnlockVertexPtr(void *vb) {
|
||||
warning("Implement rUnlockVertexPtr");
|
||||
#if 0
|
||||
LPDIRECT3DVERTEXBUFFER7 lpD3DVertexBuffer1 = (LPDIRECT3DVERTEXBUFFER7)vb;
|
||||
|
||||
if (lpD3DVertexBuffer1->Unlock() != D3D_OK) {
|
||||
DebugLogFile("VertexBuffer Unlock error");
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
//***********************************************************************************************
|
||||
void rSetLinesViewMatrix() {
|
||||
g_renderer->setTransformMatrix(TransformMatrix::VIEW, rLinesViewMatrix);
|
||||
}
|
||||
|
||||
//***********************************************************************************************
|
||||
void rSetUserViewMatrix(int num) {
|
||||
auto &matrix = rUserViewMatrix[num];
|
||||
|
||||
g_renderer->setTransformMatrix(TransformMatrix::VIEW, matrix);
|
||||
}
|
||||
|
||||
|
||||
//*********************************************************************************************
|
||||
unsigned int gGetTextureListPosition() {
|
||||
unsigned int pos = 1;
|
||||
|
||||
while (!gTextureList[pos].isEmpty()) { // TODO: Do we need the surface?
|
||||
pos++;
|
||||
}
|
||||
|
||||
if (pos > MAXTEXTURES)
|
||||
return 0;
|
||||
|
||||
if (pos > gNumTextureList)
|
||||
gNumTextureList = pos;
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
//*********************************************************************************************
|
||||
void gBuildAlternateName(char *AltName, const char *Name) {
|
||||
int len, i, j;
|
||||
|
||||
if (!Name || !AltName) return;
|
||||
|
||||
len = strlen(Name);
|
||||
memset(AltName, 0, len + 4);
|
||||
memcpy(AltName, Name, len);
|
||||
|
||||
for (i = len - 1; i >= 0; i--) {
|
||||
if ((AltName[i] == '.') && (i < (len - 3))) {
|
||||
AltName[i + 1] = 'd';
|
||||
AltName[i + 2] = 'd';
|
||||
AltName[i + 3] = 's';
|
||||
}
|
||||
if (AltName[i] == '\\' || AltName[i] == '/') {
|
||||
for (j = len; j >= i; j--)
|
||||
AltName[j + 3] = AltName[j];
|
||||
|
||||
AltName[i + 0] = 'D';
|
||||
AltName[i + 1] = 'D';
|
||||
AltName[i + 2] = 'S';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//warning("Build alternate name %s -> %s", Name, AltName);
|
||||
}
|
||||
|
||||
//*********************************************************************************************
|
||||
void gBuildAlternateName(char *AltName, char *Name) {
|
||||
int len, i, j;
|
||||
|
||||
if (!Name || !AltName) return;
|
||||
|
||||
len = strlen(Name);
|
||||
memset(AltName, 0, len + 4);
|
||||
memcpy(AltName, Name, len);
|
||||
|
||||
for (i = len - 1; i >= 0; i--) {
|
||||
if ((AltName[i] == '.') && (i < (len - 3))) {
|
||||
AltName[i + 1] = 'd';
|
||||
AltName[i + 2] = 'd';
|
||||
AltName[i + 3] = 's';
|
||||
}
|
||||
if (AltName[i] == '\\') {
|
||||
for (j = len; j >= i; j--)
|
||||
AltName[j + 3] = AltName[j];
|
||||
|
||||
AltName[i + 0] = 'D';
|
||||
AltName[i + 1] = 'D';
|
||||
AltName[i + 2] = 'S';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//*********************************************************************************************
|
||||
gTexture *gUserTexture(Texture *texture, unsigned int dimx, unsigned int dimy) {
|
||||
gTexture *Texture;
|
||||
int pos;
|
||||
//DDSURFACEDESC2 DDSurfDesc;
|
||||
|
||||
pos = gGetTextureListPosition();
|
||||
if (pos == 0) {
|
||||
DebugLogFile("gUserTexture: Can't create more textures");
|
||||
return nullptr;
|
||||
}
|
||||
Texture = &gTextureList[pos];
|
||||
*Texture = gTexture();
|
||||
Texture->Flags = CurLoaderFlags;
|
||||
|
||||
{
|
||||
#if 0
|
||||
memset(&DDSurfDesc, 0, sizeof(DDSURFACEDESC2));
|
||||
memcpy(&DDSurfDesc.ddpfPixelFormat, &gCurrentFormat->SurfaceDesc, sizeof(DDPIXELFORMAT));
|
||||
DDSurfDesc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_PIXELFORMAT;
|
||||
if (gRenderFlags & gAGPSUPPORTED) {
|
||||
//Alloc texture in AGP
|
||||
DDSurfDesc.ddsCaps.dwCaps = DDSCAPS_NONLOCALVIDMEM | DDSCAPS_VIDEOMEMORY |
|
||||
DDSCAPS_TEXTURE;
|
||||
} else {
|
||||
//No AGP support; alloc in sysmem
|
||||
DDSurfDesc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
|
||||
DDSurfDesc.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE;
|
||||
}
|
||||
#endif
|
||||
if (dimx > 8) {
|
||||
if (dimx > 16) {
|
||||
if (dimx > 32) {
|
||||
if (dimx > 64) {
|
||||
if (dimx > 128) {
|
||||
dimx = 256;
|
||||
} else {
|
||||
dimx = 128;
|
||||
}
|
||||
} else {
|
||||
dimx = 64;
|
||||
}
|
||||
} else {
|
||||
dimx = 32;
|
||||
}
|
||||
} else {
|
||||
dimx = 16;
|
||||
}
|
||||
}
|
||||
if (dimy > 8) {
|
||||
if (dimy > 16) {
|
||||
if (dimy > 32) {
|
||||
if (dimy > 64) {
|
||||
if (dimy > 128) {
|
||||
dimy = 256;
|
||||
} else {
|
||||
dimy = 128;
|
||||
}
|
||||
} else {
|
||||
dimy = 64;
|
||||
}
|
||||
} else {
|
||||
dimy = 32;
|
||||
}
|
||||
} else {
|
||||
dimy = 16;
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
DDSurfDesc.dwWidth = dimx;
|
||||
DDSurfDesc.dwHeight = dimy;
|
||||
|
||||
if (!(Texture->lpDDSurface = gCreateSurface(&DDSurfDesc, Texture->lpDDSurface))) {
|
||||
DebugLogFile("gCreateSurface FAILED: Can't create surface");
|
||||
return NULL;
|
||||
}
|
||||
strcpy(Texture->Name, "UserTexture");
|
||||
gClear(Texture->lpDDSurface, 0, 0, dimx, dimy, 0, 0, 0);
|
||||
#endif
|
||||
Texture->ID = pos;
|
||||
|
||||
Texture->DimX = dimx;
|
||||
Texture->DimY = dimy;
|
||||
#if 0
|
||||
DDCOLORKEY ddck;
|
||||
ddck.dwColorSpaceLowValue = 0;
|
||||
ddck.dwColorSpaceHighValue = 0;
|
||||
Texture->lpDDSurface->SetColorKey(DDCKEY_SRCBLT, &ddck);
|
||||
#endif
|
||||
}
|
||||
|
||||
Texture->_texture = texture;
|
||||
return Texture;
|
||||
}
|
||||
|
||||
class SurfaceBackedTextureData : public TextureData {
|
||||
bool _owned = true;
|
||||
public:
|
||||
Graphics::Surface *_surface;
|
||||
SurfaceBackedTextureData(Graphics::Surface *surface, bool owned = true) : TextureData(DxtCompression::UNCOMPRESSED), _surface(surface), _owned(owned) {}
|
||||
~SurfaceBackedTextureData() override {
|
||||
if (_owned) {
|
||||
_surface->free();
|
||||
delete _surface;
|
||||
}
|
||||
}
|
||||
int getWidth() const override {
|
||||
return _surface->w;
|
||||
}
|
||||
int getHeight() const override {
|
||||
return _surface->h;
|
||||
}
|
||||
int getDataSize() const override {
|
||||
return _surface->w * _surface->h * _surface->format.bytesPerPixel;
|
||||
}
|
||||
const void *getData() const override {
|
||||
return _surface->getPixels();
|
||||
}
|
||||
};
|
||||
|
||||
Common::SharedPtr<TextureData> createTextureFromSurface(Graphics::Surface &surface, int texFormat) {
|
||||
return Common::SharedPtr<TextureData>(new SurfaceBackedTextureData(&surface, false));
|
||||
}
|
||||
|
||||
//*********************************************************************************************
|
||||
gTexture *gLoadTexture(WorkDirs &workDirs, const char *TextName, unsigned int _LoaderFlags) {
|
||||
//bool bAlpha = FALSE
|
||||
bool bUseAlternate = FALSE;
|
||||
gTexture *texture = nullptr;
|
||||
int32 pos = 0;
|
||||
char AlternateName[500] {};
|
||||
uint32 date1 = 0, date2 = 0, time1 = 0, time2 = 0;
|
||||
//uint32 magic,retv;
|
||||
unsigned long dwWidth = 0, dwHeight = 0;
|
||||
//DDSURFACEDESC2 DDSurfDesc;
|
||||
//Graphics::Surface *lpSSource = nullptr;
|
||||
|
||||
if (!TextName) return nullptr;
|
||||
//lpSSource = nullptr;
|
||||
|
||||
//warning("gLoadTexture(%s)", TextName);
|
||||
// Check if already loaded
|
||||
for (uint32 i = 0; i < gNumTextureList; i++) {
|
||||
if (gTextureList[i].name.equalsIgnoreCase(TextName)) {
|
||||
//Texture already loaded; just assign pointers
|
||||
texture = &gTextureList[i];
|
||||
texture->ID = i;
|
||||
return texture;
|
||||
}
|
||||
}
|
||||
|
||||
/* VERSIONE ORIGINALE by FAB
|
||||
gBuildAlternateName( AlternateName, TextName );
|
||||
if( ( CurLoaderFlags & T3D_FASTFILE ) || ( !t3dGetFileDate( &date1, &time1, TextName ) ) )
|
||||
bUseAlternate = TRUE;
|
||||
if( !t3dGetFileDate( &date2, &time2, AlternateName ) )
|
||||
{
|
||||
if( bUseAlternate == TRUE )
|
||||
{
|
||||
DebugLogFile("gAddMaterial:gLoadTexture: Cannot find %s and alternate %s.\n", TextName, AlternateName );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else if( bUseAlternate == FALSE )
|
||||
{
|
||||
if( ( date2 > date1 ) || ( ( date2 == date1 ) && ( time2 >= time1 ) ) )
|
||||
bUseAlternate = TRUE;
|
||||
}
|
||||
*/
|
||||
|
||||
gBuildAlternateName(AlternateName, TextName);
|
||||
|
||||
if (!t3dGetFileDate(&date1, &time1, TextName)) // if it doesn't find the .tga texture, try the dds
|
||||
bUseAlternate = TRUE;
|
||||
|
||||
if (!t3dGetFileDate(&date2, &time2, AlternateName)) { //se non trova la texture .dds
|
||||
if (bUseAlternate == TRUE) { // does not find the .dds texture and furthermore the .tga does not exist
|
||||
DebugLogFile("gAddMaterial:gLoadTexture: Cannot find %s and alternate %s.\n", TextName, AlternateName);
|
||||
return nullptr;
|
||||
}
|
||||
} else if (bUseAlternate == FALSE) { // if there is the .dds and there is also the .tga see which is newer
|
||||
if ((date2 > date1) || ((date2 == date1) && (time2 >= time1)))
|
||||
bUseAlternate = TRUE;
|
||||
}
|
||||
|
||||
|
||||
if ((pos = gGetTextureListPosition()) == 0) {
|
||||
DebugLogFile("gLoadTexture: Can't create more textures");
|
||||
return nullptr;
|
||||
}
|
||||
texture = &gTextureList[pos];
|
||||
*texture = gTexture();
|
||||
texture->_texture = createGLTexture();
|
||||
|
||||
if (bUseAlternate) {
|
||||
auto stream = workDirs.resolveFile(AlternateName);
|
||||
if (!stream) {
|
||||
DebugLogFile("gAddMaterial:gLoadTexture: Cannot find %s.\n", AlternateName);
|
||||
return nullptr;
|
||||
}
|
||||
auto ddsTextureData = loadDdsTexture(*stream);
|
||||
texture->_texture->assignData(*ddsTextureData);
|
||||
dwWidth = ddsTextureData->getWidth();
|
||||
dwHeight = ddsTextureData->getHeight();
|
||||
//lpSSource = nullptr;
|
||||
#if 0
|
||||
if (gRenderFlags & gDXT1SUPPORTED) {
|
||||
/* if( gRenderFlags & gAGPSUPPORTED )
|
||||
{ // Alloc texture in AGP
|
||||
DDSurfDesc.ddsCaps.dwCaps= DDSCAPS_NONLOCALVIDMEM | DDSCAPS_VIDEOMEMORY | DDSCAPS_TEXTURE;
|
||||
}
|
||||
else
|
||||
*/ { //No AGP support; alloc in sysmem
|
||||
DDSurfDesc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
|
||||
DDSurfDesc.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE;
|
||||
}
|
||||
lpSSource = Texture->lpDDSurface;
|
||||
} else
|
||||
DDSurfDesc.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
|
||||
if (!(lpSSource = gCreateSurface(&DDSurfDesc, lpSSource))) {
|
||||
DebugLogFile("gLoadTexture: gCreateSurface FAILED: Can't create surface DDS");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((lpSSource->Lock(NULL, &DDSurfDesc, DDLOCK_NOSYSLOCK | DDLOCK_WAIT, NULL))) { // Lock and fill with the dds
|
||||
DebugLogFile("gLoadTexture: Can't lock surface DDS");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
t3dReadData(DDSurfDesc.lpSurface, DDSurfDesc.dwLinearSize);
|
||||
|
||||
if ((lpSSource->Unlock(NULL))) {
|
||||
DebugLogFile("gLoadTexture: Can't unlock surface DDS");
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
stream = nullptr;
|
||||
} else { // TGA
|
||||
auto stream = workDirs.resolveFile(TextName);
|
||||
auto image = ReadTgaImage(TextName, *stream, Graphics::PixelFormat::createFormatRGBA32(), 0); // TODO Flags
|
||||
SurfaceBackedTextureData texData(image);
|
||||
|
||||
texture->_texture->assignData(texData);
|
||||
#if 0
|
||||
//warning("TODO: Handle TGA");
|
||||
if (!t3dOpenFile(TextName)) {
|
||||
DebugLogFile("gAddMaterial:gLoadTexture: Cannot find %s.\n", TextName);
|
||||
return NULL;
|
||||
}
|
||||
// Parse the PPM header
|
||||
if (!loadTGAHeader(&dwWidth, &dwHeight)) {
|
||||
t3dCloseFile();
|
||||
DebugLogFile("gAddMaterial: gLoadTexture: Could not load or parse TGA header in %s.\n", TextName);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#if 0 // Replaced by createTextureFromSurface
|
||||
if (!(gRenderFlags & gDXT1SUPPORTED) || (bUseAlternate == FALSE)) {
|
||||
memset(&DDSurfDesc, 0, sizeof(DDSURFACEDESC2));
|
||||
memcpy(&DDSurfDesc.ddpfPixelFormat, &gCurrentFormat->SurfaceDesc, sizeof(DDPIXELFORMAT));
|
||||
DDSurfDesc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_PIXELFORMAT;
|
||||
/* if (gRenderFlags&gAGPSUPPORTED)
|
||||
{ //Alloc texture in AGP
|
||||
DDSurfDesc.ddsCaps.dwCaps= DDSCAPS_NONLOCALVIDMEM | DDSCAPS_VIDEOMEMORY |
|
||||
DDSCAPS_TEXTURE;
|
||||
}
|
||||
else
|
||||
*/ { //No AGP support; alloc in sysmem
|
||||
DDSurfDesc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
|
||||
DDSurfDesc.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE;
|
||||
}
|
||||
DDSurfDesc.dwWidth = dwWidth;
|
||||
DDSurfDesc.dwHeight = dwHeight;
|
||||
if (!(Texture->lpDDSurface = gCreateSurface(&DDSurfDesc, Texture->lpDDSurface))) {
|
||||
DebugLogFile("gLoadTexture: gCreateSurface FAILED: Can't create surface");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
texture->name = TextName;
|
||||
|
||||
if (bUseAlternate) {
|
||||
#if 0
|
||||
// DebugFile( "Carico |%s|", AlternateName );
|
||||
if (!(gRenderFlags & gDXT1SUPPORTED)) {
|
||||
if (Texture->lpDDSurface->Blt(NULL, lpSSource, NULL, DDBLT_WAIT, NULL) != DD_OK) {
|
||||
DebugLogFile("gLoadTexture: Can't Blit DDS texture");
|
||||
return NULL;
|
||||
}
|
||||
lpSSource->Release();
|
||||
} else
|
||||
Texture->lpDDSurface = lpSSource;
|
||||
#endif
|
||||
} else {
|
||||
#if 0
|
||||
// DebugFile( "Carico |%s|", TextName );
|
||||
Texture->lpDDSurface->Lock(NULL, &DDSurfDesc, DDLOCK_NOSYSLOCK | DDLOCK_WAIT, NULL); //Lock and fill with the tga
|
||||
if (gCurrentFormat->abits)
|
||||
bAlpha = TRUE;
|
||||
|
||||
if (!ReadTgaImage(TextName, &DDSurfDesc, bAlpha)) {
|
||||
DebugLogFile("gLoadTexture: Error reading TGA file");
|
||||
return NULL;
|
||||
}
|
||||
Texture->lpDDSurface->Unlock(NULL);
|
||||
#endif
|
||||
}
|
||||
texture->RealDimX = dwWidth;
|
||||
texture->RealDimY = dwHeight;
|
||||
|
||||
if (_LoaderFlags & rSURFACEHALF) {
|
||||
warning("Half-res loading not implemented");
|
||||
#if 0
|
||||
LPDIRECTDRAWSURFACE7 surf;
|
||||
HRESULT err;
|
||||
|
||||
dwWidth /= 2;
|
||||
dwHeight /= 2;
|
||||
|
||||
memset(&DDSurfDesc, 0, sizeof(DDSURFACEDESC2));
|
||||
memcpy(&DDSurfDesc.ddpfPixelFormat, &gCurrentFormat->SurfaceDesc, sizeof(DDPIXELFORMAT));
|
||||
DDSurfDesc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_PIXELFORMAT;
|
||||
/* if (gRenderFlags&gAGPSUPPORTED)
|
||||
{ //Alloc texture in AGP
|
||||
DDSurfDesc.ddsCaps.dwCaps= DDSCAPS_NONLOCALVIDMEM | DDSCAPS_VIDEOMEMORY |
|
||||
DDSCAPS_TEXTURE;
|
||||
}
|
||||
else
|
||||
*/ { //No AGP support; alloc in sysmem
|
||||
DDSurfDesc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
|
||||
DDSurfDesc.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE;
|
||||
}
|
||||
surf = NULL;
|
||||
DDSurfDesc.dwWidth = dwWidth;
|
||||
DDSurfDesc.dwHeight = dwHeight;
|
||||
if (!(surf = gCreateSurface(&DDSurfDesc, surf))) {
|
||||
DebugLogFile("gLoadTexture (rSURFACEHALF) FAILED: Can't create surface");
|
||||
return NULL;
|
||||
}
|
||||
if ((err = surf->Blt(NULL, Texture->lpDDSurface, NULL, 0, NULL)) != DD_OK) {
|
||||
char str[255];
|
||||
GetDDErrorString(err, str, 1);
|
||||
DebugLogFile("gLoadTexture: BltStretch failed.\n%s", str);
|
||||
}
|
||||
|
||||
//Release old texture
|
||||
Texture->lpDDSurface->Release();
|
||||
//Assign the newone
|
||||
Texture->lpDDSurface = surf;
|
||||
#endif
|
||||
}
|
||||
|
||||
texture->ID = pos;
|
||||
|
||||
texture->Flags = CurLoaderFlags;
|
||||
texture->DimX = dwWidth;
|
||||
texture->DimY = dwHeight;
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
|
||||
bool Renderer::addMaterial(gMaterial &material, const Common::String &name, int NumFaces, unsigned int _LoaderFlags) {
|
||||
//warning("AddMaterial(%s)", name.c_str());
|
||||
if (hasFileExtension(name, "avi")) {
|
||||
auto tex = createGLTexture();
|
||||
if ((material.Movie = gLoadMovie(*_workDirs, name.c_str(), tex)) == nullptr)
|
||||
return false;
|
||||
if ((material.Texture = gUserTexture(tex, 64, 128)) == nullptr)
|
||||
// if( (Material->Texture=gUserTexture( Material->Movie->g_psiStreamInfo.rcFrame.right,
|
||||
// Material->Movie->g_psiStreamInfo.rcFrame.bottom)) == NULL )
|
||||
return false;
|
||||
material.addProperty(T3D_MATERIAL_MOVIE);
|
||||
} else {
|
||||
if ((material.Texture = gLoadTexture(*_workDirs, name.c_str(), _LoaderFlags)) == nullptr)
|
||||
return false;
|
||||
}
|
||||
|
||||
//f
|
||||
material.addProperty(T3D_MATERIAL_NOLIGHTMAP);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
|
||||
#endif // USE_OPENGL_GAME
|
||||
67
engines/watchmaker/3d/render/opengl_3d.h
Normal file
67
engines/watchmaker/3d/render/opengl_3d.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WATCHMAKER_OPENGL_3D_H
|
||||
#define WATCHMAKER_OPENGL_3D_H
|
||||
|
||||
#include "watchmaker/windows_hacks.h"
|
||||
#include "watchmaker/render.h"
|
||||
|
||||
#define MAXTEXTURES 2000
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
struct gAvailFormat {
|
||||
//DDPIXELFORMAT SurfaceDesc;
|
||||
char rbits;
|
||||
char gbits;
|
||||
char bbits;
|
||||
char abits;
|
||||
};
|
||||
|
||||
struct Vertex {
|
||||
float sx, sy, sz, rhw;
|
||||
uint32 color;
|
||||
};
|
||||
|
||||
extern unsigned int gNumTrianglesArray;
|
||||
extern unsigned int gNumLinesArray;
|
||||
|
||||
extern gAvailFormat *gCurrentFormat;
|
||||
extern int NumAvailableFormats;
|
||||
extern gAvailFormat AvailableFormats[];
|
||||
|
||||
extern gTexture gTextureList[];
|
||||
extern unsigned int gNumTextureList;
|
||||
|
||||
extern uint16 gLinesArray[];
|
||||
extern unsigned int gNumLinesArray;
|
||||
extern unsigned int gNumTrianglesArray;
|
||||
extern Vertex gTriangles[];
|
||||
extern int g_lpD3DPointsBuffer;
|
||||
extern void *g_lpD3DUserVertexBuffer;
|
||||
extern unsigned int g_dwD3DUserVertexBufferCounter;
|
||||
extern unsigned int gNumPointsBuffer;
|
||||
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
|
||||
#endif // WATCHMAKER_OPENGL_3D_H
|
||||
239
engines/watchmaker/3d/render/opengl_renderer.cpp
Normal file
239
engines/watchmaker/3d/render/opengl_renderer.cpp
Normal file
@@ -0,0 +1,239 @@
|
||||
/* 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/3d/render/opengl_renderer.h"
|
||||
#include "watchmaker/t3d.h"
|
||||
|
||||
#if defined(USE_OPENGL_GAME)
|
||||
|
||||
#include "graphics/opengl/system_headers.h"
|
||||
#include "math/glmath.h"
|
||||
|
||||
#include "math/glmath.h"
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
OpenGLRenderer *g_renderer = nullptr;
|
||||
|
||||
void OpenGLRenderer::drawIndexedPrimitivesVBO(PrimitiveType primitiveType, Common::SharedPtr<VertexBuffer> VBO, int firstVertex, int numVertices, Common::Array<uint16> faces, uint32 numFaces) {
|
||||
assert(numFaces <= faces.size());
|
||||
|
||||
assert(primitiveType == PrimitiveType::TRIANGLE);
|
||||
|
||||
float fNearPlane = 1.0f;//5000.0f;
|
||||
float fFarPlane = 15000.0f;
|
||||
float width = 1024;
|
||||
float height = 768;
|
||||
|
||||
glEnable(GL_ALPHA_TEST);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
|
||||
float fAspect = 60.0f;//curCamera->FovRad;
|
||||
auto perspectiveMatrix = Math::makePerspectiveMatrix(fAspect, width / height, fNearPlane, fFarPlane);
|
||||
glLoadMatrixf(perspectiveMatrix.getData());
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPushMatrix();
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
glBegin(GL_TRIANGLES);
|
||||
for (uint32 i = 0; i < numFaces; i++) {
|
||||
uint16 index = faces[i];
|
||||
assert(index <= VBO->_buffer.size());
|
||||
auto &vertex = VBO->_buffer[index];
|
||||
//warning("%d/%d %d: [%f, %f, %f], [%f, %f], [%f, %f]", i, numFaces, index, vertex.x, vertex.y, vertex.z, vertex.u1, vertex.v1, vertex.u2, vertex.v2);
|
||||
//glColor4f((float)i/numFaces, 1.0f, 0.0f, 1.0f);
|
||||
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
glTexCoord2f(vertex.u1, vertex.v1);
|
||||
glVertex3f(vertex.x, vertex.y, -vertex.z);
|
||||
}
|
||||
glEnd();
|
||||
|
||||
glFlush();
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
}
|
||||
|
||||
void OpenGLRenderer::drawPrimitives(PrimitiveType primitiveType, Vertex *vertices, int numPrimitives) {
|
||||
assert(primitiveType == PrimitiveType::TRIANGLE);
|
||||
glBegin(GL_TRIANGLES);
|
||||
for (int i = 0; i < numPrimitives; i++) {
|
||||
auto &vertex = vertices[i];
|
||||
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
glVertex3f(vertex.sx, vertex.sy, -vertex.sz);
|
||||
}
|
||||
glEnd();
|
||||
glFlush();
|
||||
}
|
||||
void OpenGLRenderer::drawIndexedPrimitivesVBO(PrimitiveType primitiveType, int VBO, int firstVertex, int numVertices, uint16 *faces, uint32 numFaces) {
|
||||
//warning("TODO: Implement drawIndexedPrimitivesVBO");
|
||||
}
|
||||
|
||||
|
||||
void OpenGLRenderer::drawIndexedPrimitivesVBO(PrimitiveType primitiveType, gBatchBlock &bb) {
|
||||
drawIndexedPrimitivesVBO(primitiveType,
|
||||
bb.VBO, 0, bb.NumVerts(),
|
||||
bb.FacesList,
|
||||
bb.NumFaces()/*, 0x0*/
|
||||
);
|
||||
}
|
||||
|
||||
void OpenGLRenderer::setTransformMatrix(TransformMatrix which, const Matrix4x4 &matrix) {
|
||||
GLint oldMatrixMode;
|
||||
glGetIntegerv(GL_MATRIX_MODE, &oldMatrixMode);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadMatrixf(matrix.data);
|
||||
glScalef(1.0f, 1.0f, -1.0f);
|
||||
glMatrixMode(oldMatrixMode);
|
||||
}
|
||||
|
||||
void OpenGLRenderer::pushModelView() {
|
||||
GLint oldMatrixMode;
|
||||
glGetIntegerv(GL_MATRIX_MODE, &oldMatrixMode);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPushMatrix();
|
||||
glMatrixMode(oldMatrixMode);
|
||||
}
|
||||
|
||||
void OpenGLRenderer::popModelView() {
|
||||
GLint oldMatrixMode;
|
||||
glGetIntegerv(GL_MATRIX_MODE, &oldMatrixMode);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPopMatrix();
|
||||
glMatrixMode(oldMatrixMode);
|
||||
}
|
||||
|
||||
void OpenGLRenderer::setTextureWrapMode(int index, TextureWrapMode mode) {
|
||||
GLint openGlWrapMode = 0;
|
||||
switch (mode) {
|
||||
case TextureWrapMode::WRAP:
|
||||
openGlWrapMode = GL_REPEAT;
|
||||
break;
|
||||
case TextureWrapMode::CLAMP:
|
||||
openGlWrapMode = GL_CLAMP;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, openGlWrapMode);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, openGlWrapMode);
|
||||
}
|
||||
|
||||
void OpenGLRenderer::setTexture(int stage, void *texture) {
|
||||
if (texture == nullptr) {
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
} else {
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
void OpenGLRenderer::setTexture(int stage, const gTexture &texture) {
|
||||
texture._texture->bind();
|
||||
}
|
||||
|
||||
void setGlFeature(GLint feature, bool state) {
|
||||
if (state) {
|
||||
glEnable(feature);
|
||||
} else {
|
||||
glDisable(feature);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLRenderer::setRenderState(RenderState state, int value) {
|
||||
switch (state) {
|
||||
case RenderState::ZENABLE:
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
setGlFeature(GL_DEPTH_TEST, value);
|
||||
break;
|
||||
case RenderState::ALPHAREF: // ALPHA-func is never changed.
|
||||
glAlphaFunc(GL_ALWAYS, value);
|
||||
// fall through
|
||||
// FIXME: Is this intended?
|
||||
case RenderState::ALPHABLEND:
|
||||
setGlFeature(GL_BLEND, value);
|
||||
break; // TODO
|
||||
|
||||
case RenderState::LIGHT:
|
||||
case RenderState::CLIP:
|
||||
case RenderState::EXTENT:
|
||||
case RenderState::ZWRITE_ENABLE:
|
||||
case RenderState::TEXTUREFACTOR:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
//warning("TODO: Implement setRenderState");
|
||||
}
|
||||
|
||||
GLenum translateBlendFactorToGL(BlendFactor factor) {
|
||||
switch (factor) {
|
||||
case BlendFactor::ONE:
|
||||
return GL_ONE;
|
||||
case BlendFactor::ZERO:
|
||||
return GL_ZERO;
|
||||
case BlendFactor::SRCALPHA:
|
||||
return GL_SRC_ALPHA;
|
||||
case BlendFactor::INVSRCALPHA:
|
||||
return GL_ONE_MINUS_SRC_ALPHA;
|
||||
case BlendFactor::INVSRCCOLOR:
|
||||
return GL_ONE_MINUS_SRC_COLOR;
|
||||
case BlendFactor::SRCCOLOR:
|
||||
return GL_SRC_COLOR;
|
||||
case BlendFactor::DESTCOLOR:
|
||||
return GL_DST_COLOR;
|
||||
case BlendFactor::INVDESTCOLOR:
|
||||
return GL_ONE_MINUS_DST_COLOR;
|
||||
default:
|
||||
return GL_INVALID_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLRenderer::setBlendFunc(BlendFactor src, BlendFactor dst) {
|
||||
glBlendFunc(translateBlendFactorToGL(src), translateBlendFactorToGL(dst));
|
||||
}
|
||||
|
||||
void OpenGLRenderer::enter2Dmode() {
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
checkGlError("Exiting enter2Dmode");
|
||||
}
|
||||
|
||||
void OpenGLRenderer::exit2Dmode() {
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
checkGlError("exit2Dmode");
|
||||
}
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
|
||||
#endif // USE_OPENGL_GAME
|
||||
110
engines/watchmaker/3d/render/opengl_renderer.h
Normal file
110
engines/watchmaker/3d/render/opengl_renderer.h
Normal file
@@ -0,0 +1,110 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WATCHMAKER_OPENGL_RENDERER_H
|
||||
#define WATCHMAKER_OPENGL_RENDERER_H
|
||||
|
||||
|
||||
#include "watchmaker/3d/math/Matrix4x4.h"
|
||||
#include "watchmaker/utils.h"
|
||||
#include "watchmaker/render.h"
|
||||
#include "watchmaker/3d/render/opengl_3d.h"
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
enum class TransformMatrix {
|
||||
PROJECTION,
|
||||
VIEW
|
||||
};
|
||||
|
||||
enum class RenderState {
|
||||
LIGHT,
|
||||
CLIP,
|
||||
EXTENT,
|
||||
ALPHABLEND,
|
||||
ALPHAREF, // TODO
|
||||
ZENABLE, // TODO
|
||||
ZWRITE_ENABLE, // TODO
|
||||
TEXTUREFACTOR // TODO
|
||||
};
|
||||
|
||||
enum class BlendFactor {
|
||||
ONE,
|
||||
ZERO,
|
||||
SRCALPHA,
|
||||
INVSRCALPHA,
|
||||
INVSRCCOLOR,
|
||||
SRCCOLOR,
|
||||
DESTCOLOR,
|
||||
INVDESTCOLOR
|
||||
};
|
||||
|
||||
enum class TextureWrapMode {
|
||||
WRAP,
|
||||
CLAMP
|
||||
};
|
||||
|
||||
enum class PrimitiveType {
|
||||
LINE,
|
||||
TRIANGLE
|
||||
};
|
||||
|
||||
Common::SharedPtr<TextureData> createTextureFromSurface(Graphics::Surface &surface, int texFormat);
|
||||
Texture *createGLTexture();
|
||||
|
||||
class OpenGLRenderer {
|
||||
public:
|
||||
void enter2Dmode();
|
||||
void exit2Dmode();
|
||||
|
||||
void pushModelView();
|
||||
void popModelView();
|
||||
void setTransformMatrix(TransformMatrix which, const Matrix4x4 &matrix);
|
||||
// TODO: This should be split.
|
||||
void setRenderState(RenderState state, int value);
|
||||
void setBlendFunc(BlendFactor src, BlendFactor dst);
|
||||
bool error() const {
|
||||
//warning("TODO: Implement error");
|
||||
return false;
|
||||
}
|
||||
Common::String getErrorString() {
|
||||
warning("TODO: Implement getErrorString");
|
||||
return "";
|
||||
}
|
||||
// TODO: This just maps to the D3D way to setting textures
|
||||
void setTexture(int stage, void *texture);
|
||||
void setTexture(int stage, const gTexture &texture);
|
||||
void setTextureWrapMode(int index, TextureWrapMode mode);
|
||||
|
||||
void drawPrimitives(PrimitiveType primitiveType, Vertex *vertices, int numPrimitives);
|
||||
void drawIndexedPrimitivesVBO(PrimitiveType primitiveType, int VBO, int firstVertex, int numVertices, uint16 *faces, uint32 numFaces);
|
||||
void drawIndexedPrimitivesVBO(PrimitiveType primitiveType, Common::SharedPtr<VertexBuffer> VBO, int firstVertex, int numVertices, Common::Array<uint16> faces, uint32 numFaces);
|
||||
void drawIndexedPrimitivesVBO(PrimitiveType primitiveType, gBatchBlock &bb);
|
||||
bool supportsMultiTexturing() const { // TODO
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
extern OpenGLRenderer *g_renderer;
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
|
||||
#endif // WATCHMAKER_OPENGL_RENDERER_H
|
||||
96
engines/watchmaker/3d/render/opengl_texture.cpp
Normal file
96
engines/watchmaker/3d/render/opengl_texture.cpp
Normal file
@@ -0,0 +1,96 @@
|
||||
/* 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/3d/render/opengl_texture.h"
|
||||
#include "common/textconsole.h"
|
||||
#include "graphics/opengl/system_headers.h"
|
||||
#include "watchmaker/3d/dds_header.h"
|
||||
#include "watchmaker/render.h"
|
||||
|
||||
#ifdef USE_OPENGL_GAME
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
GLuint dxtCompressionToTextureFormat(DxtCompression compression) {
|
||||
switch (compression) {
|
||||
case DxtCompression::UNCOMPRESSED:
|
||||
default:
|
||||
return GL_RGBA;
|
||||
case DxtCompression::DXT1:
|
||||
return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
|
||||
case DxtCompression::DXT2:
|
||||
error("DXT2 Support is not implemented");
|
||||
case DxtCompression::DXT3:
|
||||
return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
|
||||
case DxtCompression::DXT4:
|
||||
error("DXT4 Support is not implemented");
|
||||
case DxtCompression::DXT5:
|
||||
return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
|
||||
}
|
||||
}
|
||||
|
||||
class OpenGLTexture : public Texture {
|
||||
public:
|
||||
unsigned int _texId;
|
||||
OpenGLTexture() {
|
||||
glGenTextures(1, &_texId);
|
||||
}
|
||||
OpenGLTexture(unsigned int texId) : _texId(texId) {}
|
||||
void assignData(const TextureData &data) override {
|
||||
glBindTexture(GL_TEXTURE_2D, _texId);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
|
||||
|
||||
// TODO: Check both compiletime and runtime for the existence of EXT_texture_compression_s3tc
|
||||
GLuint texFormat = dxtCompressionToTextureFormat(data._compression);
|
||||
bool compressed = data._compression != DxtCompression::UNCOMPRESSED;
|
||||
|
||||
if (compressed) {
|
||||
glCompressedTexImage2D(GL_TEXTURE_2D, // target
|
||||
0, // level
|
||||
texFormat, // internalFormat
|
||||
data.getWidth(), // width
|
||||
data.getHeight(), // height
|
||||
0, // border
|
||||
data.getDataSize(),
|
||||
data.getData()
|
||||
);
|
||||
checkGlError("glCompressedTexImage");
|
||||
} else {
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, texFormat, data.getWidth(), data.getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, data.getData());
|
||||
checkGlError("glTexImage2D");
|
||||
}
|
||||
}
|
||||
void bind() override {
|
||||
glBindTexture(GL_TEXTURE_2D, _texId);
|
||||
checkGlError("OpenGLTexture::bind");
|
||||
};
|
||||
};
|
||||
|
||||
Texture *createGLTexture() {
|
||||
return new OpenGLTexture();
|
||||
}
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
|
||||
#endif // USE_OPENGL_GAME
|
||||
32
engines/watchmaker/3d/render/opengl_texture.h
Normal file
32
engines/watchmaker/3d/render/opengl_texture.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WATCHMAKER_3D_OPENGL_TEXTURE_H
|
||||
#define WATCHMAKER_3D_OPENGL_TEXTURE_H
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
class Texture;
|
||||
Texture *createGLTexture();
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
|
||||
#endif // WATCHMAKER_3D_OPENGL_TEXTURE_H
|
||||
621
engines/watchmaker/3d/render/render.cpp
Normal file
621
engines/watchmaker/3d/render/render.cpp
Normal file
@@ -0,0 +1,621 @@
|
||||
/* 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/render.h"
|
||||
#include "watchmaker/windows_hacks.h"
|
||||
#include "watchmaker/3d/render/opengl_3d.h"
|
||||
#include "watchmaker/render.h"
|
||||
#include "watchmaker/3d/render/opengl_renderer.h"
|
||||
#include "watchmaker/3d/render/opengl_2d.h"
|
||||
#include "watchmaker/3d/render/shadows.h"
|
||||
#include "watchmaker/ll/ll_regen.h"
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
unsigned int bLightmaps = FALSE; // if lightmaps are activated
|
||||
unsigned int bDisableShadows = FALSE; // if shadows should be disabled
|
||||
unsigned int bDisableMultiTexturing = FALSE; // if multitexturing should be disabled
|
||||
|
||||
gBatchBlock BatchBlockList[MAX_BATCH_BLOCKS];
|
||||
gBatchBlock BatchBlockListSpecial[MAX_BATCH_BLOCKS_SPECIAL];
|
||||
//gBatchBlock BatchBlockListLightmaps[MAX_BATCH_BLOCKS_LIGHTMAPS];
|
||||
gBatchBlock BatchBlockListSky[MAX_BATCH_BLOCKS_SKY];
|
||||
|
||||
unsigned int NumBatchBlocks = 0;
|
||||
unsigned int NumBatchBlocksSpecial = 0;
|
||||
//unsigned int NumBatchBlocksLightmaps=0;
|
||||
unsigned int NumBatchBlocksSky = 0;
|
||||
|
||||
/* -----------------13/08/99 10.34-------------------
|
||||
* Comparazione per BB
|
||||
* --------------------------------------------------*/
|
||||
int cmpbb(const void *a, const void *b) {
|
||||
const gBatchBlock *v1 = (const gBatchBlock *)a;
|
||||
const gBatchBlock *v2 = (const gBatchBlock *)b;
|
||||
|
||||
if (v1->Texture2 < v2->Texture2) return -1;
|
||||
else if (v1->Texture2 > v2->Texture2) return 1;
|
||||
else if (v1->Texture1 < v2->Texture1) return -1;
|
||||
else if (v1->Texture1 > v2->Texture1) return 1;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
/* -----------------31/05/99 10.12-------------------
|
||||
* Attiva o disattiva lo ZBuffer
|
||||
* --------------------------------------------------*/
|
||||
bool rSetZBufferState(bool state) {
|
||||
g_renderer->setRenderState(RenderState::ZENABLE, state);
|
||||
g_renderer->setRenderState(RenderState::ZWRITE_ENABLE, state);
|
||||
|
||||
return !g_renderer->error();
|
||||
}
|
||||
|
||||
|
||||
/* -----------------25/06/99 11.14-------------------
|
||||
* Renderizza il cielo senza considerare lo zbuffer
|
||||
* --------------------------------------------------*/
|
||||
void RenderSky() {
|
||||
unsigned int i;
|
||||
bool hres;
|
||||
gBatchBlock *bb;
|
||||
|
||||
if (!NumBatchBlocksSky)
|
||||
return;
|
||||
|
||||
if (!rSetZBufferState(false)) {
|
||||
DebugLogFile("Can't rSetZBufferState FALSE");
|
||||
return ;
|
||||
}
|
||||
|
||||
g_renderer->setRenderState(RenderState::ALPHABLEND, TRUE);
|
||||
g_renderer->setRenderState(RenderState::ALPHAREF, 0x00000055);
|
||||
g_renderer->setBlendFunc(BlendFactor::ONE, BlendFactor::INVSRCALPHA);
|
||||
if (g_renderer->error()) {
|
||||
return;
|
||||
}
|
||||
|
||||
bb = &BatchBlockListSky[0];
|
||||
for (i = 0; i < NumBatchBlocksSky; i++, bb++) {
|
||||
if (bb->Texture1 < 0) continue;
|
||||
rSetUserViewMatrix(bb->ViewMatrixNum);
|
||||
|
||||
if (bb->Texture1)
|
||||
g_renderer->setTexture(0, gTextureList[bb->Texture1]);
|
||||
else
|
||||
g_renderer->setTexture(0, nullptr);
|
||||
|
||||
g_renderer->drawIndexedPrimitivesVBO(PrimitiveType::TRIANGLE, *bb);
|
||||
hres = !g_renderer->error();
|
||||
if (!hres) {
|
||||
Common::String str = g_renderer->getErrorString();
|
||||
DebugLogWindow("DrawIndexedPrimitiveVB ERROR:\n\r%s", str.c_str());
|
||||
}
|
||||
bb->Texture1 = -3;
|
||||
bb->Texture2 = -3;
|
||||
}
|
||||
|
||||
if (!rSetZBufferState(true)) {
|
||||
DebugLogFile("Can't rSetZBufferState TRUE");
|
||||
return ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* -----------------31/05/99 10.19-------------------
|
||||
* Renderizza la Geometria
|
||||
* --------------------------------------------------*/
|
||||
void RenderGeometry() {
|
||||
signed short int LastViewMatrixNum, LastTexture1, LastTexture2;
|
||||
gBatchBlock *bb;
|
||||
bool hres = false;
|
||||
|
||||
RenderSky();
|
||||
//warning("TODO: Texture configuration");
|
||||
#if 0
|
||||
g_renderer->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0);
|
||||
g_renderer->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 1);
|
||||
g_renderer->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
|
||||
g_renderer->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
|
||||
#endif
|
||||
g_renderer->setTextureWrapMode(1, TextureWrapMode::CLAMP);
|
||||
|
||||
g_renderer->setRenderState(RenderState::TEXTUREFACTOR, 0xFFFFFFFF);
|
||||
g_renderer->setRenderState(RenderState::ALPHAREF, 0x00000000);
|
||||
|
||||
g_renderer->setRenderState(RenderState::ALPHABLEND, FALSE);
|
||||
if (g_renderer->error()) {
|
||||
return;
|
||||
}
|
||||
|
||||
LastViewMatrixNum = LastTexture1 = LastTexture2 = -2;
|
||||
bb = &BatchBlockList[0];
|
||||
qsort(bb, NumBatchBlocks, sizeof(gBatchBlock), cmpbb);
|
||||
for (uint i = 0; i < NumBatchBlocks; i++, bb++) {
|
||||
if (bb->Texture1 < 0) continue;
|
||||
|
||||
if (bb->ViewMatrixNum != LastViewMatrixNum) {
|
||||
rSetUserViewMatrix(bb->ViewMatrixNum);
|
||||
LastViewMatrixNum = bb->ViewMatrixNum;
|
||||
}
|
||||
if (bb->Texture1 != LastTexture1) {
|
||||
if (bb->Texture1)
|
||||
g_renderer->setTexture(0, gTextureList[bb->Texture1]);
|
||||
else
|
||||
g_renderer->setTexture(0, nullptr);
|
||||
LastTexture1 = bb->Texture1;
|
||||
}
|
||||
if ((g_renderer->supportsMultiTexturing()) && (bb->Texture2 != LastTexture2)) {
|
||||
if (bb->Texture2 > 0) {
|
||||
if (LastTexture2 <= 0) {
|
||||
//warning("TODO: Texture configuration");
|
||||
#if 0
|
||||
g_renderer->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE);
|
||||
g_renderer->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
|
||||
g_renderer->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT);
|
||||
g_renderer->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2);
|
||||
g_renderer->SetTextureStageState(1, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
|
||||
#endif
|
||||
g_renderer->setTextureWrapMode(1, TextureWrapMode::CLAMP);
|
||||
}
|
||||
g_renderer->setTexture(1, gTextureList[bb->Texture2]);
|
||||
} else if (LastTexture2 > 0) {
|
||||
//warning("TODO: Texture configuration");
|
||||
#if 0
|
||||
g_renderer->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
|
||||
g_renderer->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
|
||||
#endif
|
||||
g_renderer->setTexture(1, nullptr);
|
||||
}
|
||||
LastTexture2 = bb->Texture2;
|
||||
}
|
||||
|
||||
g_renderer->drawIndexedPrimitivesVBO(PrimitiveType::TRIANGLE, *bb);
|
||||
|
||||
hres = !g_renderer->error();
|
||||
if (!hres) {
|
||||
Common::String str = g_renderer->getErrorString();
|
||||
DebugLogWindow("DrawIndexedPrimitiveVB ERROR:\n\r%s", str.c_str());
|
||||
}
|
||||
bb->Texture1 = -3;
|
||||
}
|
||||
//warning("TODO: Texture configuration");
|
||||
#if 0
|
||||
g_renderer->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
|
||||
g_renderer->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
|
||||
#endif
|
||||
|
||||
// 2nd pass: lightmaps, if device doesn't support multi-texturing
|
||||
if ((!g_renderer->supportsMultiTexturing()) && (bLightmaps)) {
|
||||
g_renderer->setRenderState(RenderState::ZWRITE_ENABLE, FALSE);
|
||||
|
||||
#if 0 // TODO
|
||||
g_renderer->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 1); // use mapping coordinates set 1
|
||||
#endif
|
||||
g_renderer->setBlendFunc(BlendFactor::ZERO, BlendFactor::SRCCOLOR);
|
||||
g_renderer->setRenderState(RenderState::ALPHABLEND, true);
|
||||
if (g_renderer->error()) {
|
||||
return;
|
||||
}
|
||||
|
||||
LastViewMatrixNum = LastTexture1 = LastTexture2 = -2;
|
||||
bb = &BatchBlockList[0];
|
||||
for (uint i = 0; i < NumBatchBlocks; i++, bb++) {
|
||||
if (bb->Texture2 <= 0) continue;
|
||||
|
||||
if (bb->ViewMatrixNum != LastViewMatrixNum) {
|
||||
rSetUserViewMatrix(bb->ViewMatrixNum);
|
||||
LastViewMatrixNum = bb->ViewMatrixNum;
|
||||
}
|
||||
if (bb->Texture2 != LastTexture2) {
|
||||
g_renderer->setTexture(0, gTextureList[bb->Texture2]);
|
||||
LastTexture2 = bb->Texture2;
|
||||
}
|
||||
|
||||
g_renderer->drawIndexedPrimitivesVBO(PrimitiveType::TRIANGLE, *bb);
|
||||
hres = !g_renderer->error();
|
||||
if (!hres) {
|
||||
Common::String str = g_renderer->getErrorString();
|
||||
DebugLogWindow("DrawIndexedPrimitiveVB ERROR:\n\r%s", str.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
g_renderer->setRenderState(RenderState::ZWRITE_ENABLE, TRUE);
|
||||
#if 0 // TODO
|
||||
g_renderer->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0); // mapping coordinates back to set 0
|
||||
#endif
|
||||
}
|
||||
|
||||
// Clipmaps
|
||||
g_renderer->setRenderState(RenderState::ALPHABLEND, TRUE);
|
||||
g_renderer->setRenderState(RenderState::ALPHAREF, 0x00000055);
|
||||
|
||||
g_renderer->setBlendFunc(BlendFactor::ONE, BlendFactor::INVSRCALPHA);
|
||||
if (g_renderer->error()) {
|
||||
return;
|
||||
}
|
||||
|
||||
LastViewMatrixNum = LastTexture1 = LastTexture2 = -2;
|
||||
bb = &BatchBlockListSpecial[0];
|
||||
qsort(bb, NumBatchBlocksSpecial, sizeof(gBatchBlock), cmpbb);
|
||||
for (uint i = 0; i < NumBatchBlocksSpecial; i++, bb++) {
|
||||
if (bb->Texture1 < 0) continue;
|
||||
if (!(bb->Flags1 & T3D_MATERIAL_CLIPMAP) ||
|
||||
(bb->Flags1 & T3D_MATERIAL_FLARE) ||
|
||||
(bb->Flags1 & T3D_MATERIAL_SMOKE))
|
||||
continue;
|
||||
|
||||
if (bb->ViewMatrixNum != LastViewMatrixNum) {
|
||||
rSetUserViewMatrix(bb->ViewMatrixNum);
|
||||
LastViewMatrixNum = bb->ViewMatrixNum;
|
||||
}
|
||||
if (bb->Texture1 != LastTexture1) {
|
||||
if (bb->Texture1)
|
||||
g_renderer->setTexture(0, gTextureList[bb->Texture1]);
|
||||
else
|
||||
g_renderer->setTexture(0, nullptr);
|
||||
LastTexture1 = bb->Texture1;
|
||||
}
|
||||
|
||||
g_renderer->drawIndexedPrimitivesVBO(PrimitiveType::TRIANGLE, *bb);
|
||||
hres = !g_renderer->error();
|
||||
if (!hres) {
|
||||
Common::String str = g_renderer->getErrorString();
|
||||
DebugLogWindow("DrawIndexedPrimitiveVB ERROR:\n\r%s", str.c_str());
|
||||
}
|
||||
bb->Texture1 = -3;
|
||||
bb->Texture2 = -3;
|
||||
}
|
||||
|
||||
// Render Smoke or Flare materials
|
||||
g_renderer->setRenderState(RenderState::ALPHAREF, 0x00000055);
|
||||
g_renderer->setRenderState(RenderState::ZWRITE_ENABLE, FALSE);
|
||||
if (g_renderer->error()) {
|
||||
return;
|
||||
}
|
||||
|
||||
LastViewMatrixNum = LastTexture1 = LastTexture2 = -2;
|
||||
bb = &BatchBlockListSpecial[0];
|
||||
for (uint i = 0; i < NumBatchBlocksSpecial; i++, bb++) {
|
||||
if (bb->Texture1 < 0) continue;
|
||||
if (!(bb->Flags1 & T3D_MATERIAL_FLARE) &&
|
||||
!(bb->Flags1 & T3D_MATERIAL_SMOKE))
|
||||
continue;
|
||||
|
||||
if (bb->Flags1 & T3D_MATERIAL_FLARE_SUN) {
|
||||
g_renderer->setBlendFunc(BlendFactor::ONE, BlendFactor::INVSRCCOLOR);
|
||||
} else if (bb->Flags1 & T3D_MATERIAL_FLARESOFT) {
|
||||
g_renderer->setRenderState(RenderState::ZENABLE, FALSE);
|
||||
g_renderer->setBlendFunc(BlendFactor::DESTCOLOR, BlendFactor::ONE);
|
||||
} else if (bb->Flags1 & T3D_MATERIAL_SMOKE) {
|
||||
g_renderer->setBlendFunc(BlendFactor::SRCALPHA, BlendFactor::ONE);
|
||||
} else {
|
||||
g_renderer->setBlendFunc(BlendFactor::SRCCOLOR, BlendFactor::ONE);
|
||||
}
|
||||
if (g_renderer->error()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (bb->ViewMatrixNum != LastViewMatrixNum) {
|
||||
rSetUserViewMatrix(bb->ViewMatrixNum);
|
||||
LastViewMatrixNum = bb->ViewMatrixNum;
|
||||
}
|
||||
if (bb->Texture1 != LastTexture1) {
|
||||
if (bb->Texture1)
|
||||
g_renderer->setTexture(0, gTextureList[bb->Texture1]);
|
||||
else
|
||||
g_renderer->setTexture(0, nullptr);
|
||||
LastTexture1 = bb->Texture1;
|
||||
}
|
||||
|
||||
g_renderer->drawIndexedPrimitivesVBO(PrimitiveType::TRIANGLE, *bb);
|
||||
if (!hres) {
|
||||
Common::String str = g_renderer->getErrorString();
|
||||
DebugLogWindow("DrawIndexedPrimitiveVB ERROR:\n\r%s", str.c_str());
|
||||
}
|
||||
bb->Texture1 = -3;
|
||||
bb->Texture2 = -3;
|
||||
}
|
||||
g_renderer->setRenderState(RenderState::ZWRITE_ENABLE, TRUE);
|
||||
hres = !g_renderer->error();
|
||||
if (!hres) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Print transparent/translucent materials
|
||||
g_renderer->setRenderState(RenderState::ALPHAREF, 0x0000002);
|
||||
|
||||
LastViewMatrixNum = LastTexture1 = LastTexture2 = -2;
|
||||
bb = &BatchBlockListSpecial[0];
|
||||
for (uint i = 0; i < NumBatchBlocksSpecial; i++, bb++) {
|
||||
if (bb->Texture1 < 0) continue;
|
||||
if ((bb->Flags1 & T3D_MATERIAL_FLARE) ||
|
||||
(bb->Flags1 & T3D_MATERIAL_SMOKE))
|
||||
continue;
|
||||
|
||||
if (bb->Flags1 & T3D_MATERIAL_GLASS) {
|
||||
g_renderer->setBlendFunc(BlendFactor::DESTCOLOR, BlendFactor::ZERO);
|
||||
return;
|
||||
} else if (bb->Flags1 & T3D_MATERIAL_OPACITY) {
|
||||
g_renderer->setBlendFunc(BlendFactor::ONE, BlendFactor::SRCCOLOR);
|
||||
} else if (bb->Flags1 & T3D_MATERIAL_BOTTLE) {
|
||||
g_renderer->setBlendFunc(BlendFactor::ONE, BlendFactor::INVDESTCOLOR);
|
||||
} else if (bb->Flags1 & T3D_MATERIAL_ADDITIVE) {
|
||||
g_renderer->setBlendFunc(BlendFactor::DESTCOLOR, BlendFactor::ONE);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
if (g_renderer->error()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (bb->ViewMatrixNum != LastViewMatrixNum) {
|
||||
rSetUserViewMatrix(bb->ViewMatrixNum);
|
||||
LastViewMatrixNum = bb->ViewMatrixNum;
|
||||
}
|
||||
if (bb->Texture1 != LastTexture1) {
|
||||
if (bb->Texture1)
|
||||
g_renderer->setTexture(0, gTextureList[bb->Texture1]);
|
||||
else
|
||||
g_renderer->setTexture(0, nullptr);
|
||||
LastTexture1 = bb->Texture1;
|
||||
}
|
||||
|
||||
g_renderer->drawIndexedPrimitivesVBO(PrimitiveType::TRIANGLE, *bb);
|
||||
hres = !g_renderer->error();
|
||||
if (!hres) {
|
||||
Common::String str = g_renderer->getErrorString();
|
||||
DebugLogWindow("DrawIndexedPrimitiveVB ERROR:\n\r%s", str.c_str());
|
||||
}
|
||||
bb->Texture1 = -3;
|
||||
bb->Texture2 = -3;
|
||||
}
|
||||
|
||||
// Render blank materials
|
||||
// ???
|
||||
}
|
||||
|
||||
/* -----------------31/05/99 10.55-------------------
|
||||
* Renderizza la scena
|
||||
* --------------------------------------------------*/
|
||||
bool rRenderScene() {
|
||||
unsigned int i, j;
|
||||
bool hres;
|
||||
//static unsigned int dwFrameCount = 0;
|
||||
|
||||
g_renderer->setRenderState(RenderState::LIGHT, false);
|
||||
g_renderer->setRenderState(RenderState::CLIP, true);
|
||||
g_renderer->setRenderState(RenderState::EXTENT, false);
|
||||
|
||||
// Added:
|
||||
ResetScreenBuffer();
|
||||
|
||||
if (!gStencilBitDepth && !bDisableShadows) {
|
||||
//tb
|
||||
//Render Projected shadow into shadow surface
|
||||
for (j = 0; j < gNumShadowBoxesList; j++) {
|
||||
SHADOWBOX *sb = ShadowBoxesList[j];
|
||||
rSetUserViewMatrix(sb->ViewMatrixNum);
|
||||
if (bDisableShadows) break;
|
||||
warning("TODO: Shadows");
|
||||
#if 0
|
||||
for (i = 0; i < sb->NumShadowsList; i++) {
|
||||
if (!(hres = RenderProjectiveShadow(&sb->ShadowsList[i]))) {
|
||||
Common::String str = g_renderer->getErrorString();
|
||||
DebugLogFile("Unable to RenderProjectiveShadow into a texture: %s | %d %d | %d", str.c_str(), S_OK, DD_OK, hres);
|
||||
bDisableShadows = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (sb->ShadowsList[i].ProjectiveTexture.lpDDSurface) {
|
||||
if (hres = sb->ShadowsList[i].ProjectiveTexture.lpDDSurface->BltFast(0, 0, g_pddsShadowBuffer, NULL, DDBLTFAST_NOCOLORKEY) != S_OK) {
|
||||
Common::String str = g_renderer->getErrorString();
|
||||
DebugLogWindow("Unable to blitfast Shadowbuffer into a texture: %s", str.c_str());
|
||||
bDisableShadows = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
/* if (g_pddsBackBuffer && !j)
|
||||
{
|
||||
RECT rect;
|
||||
rect.left=rect.top=0;
|
||||
rect.right=rect.bottom=256;
|
||||
|
||||
if (FAILED(hres=g_pddsBackBuffer->BltFast(0,0,sb->ShadowsList[i].ProjectiveTexture.lpDDSurface,&rect,DDBLTFAST_NOCOLORKEY)))
|
||||
{
|
||||
Common::String str = g_renderer->getErrorString();
|
||||
DebugLogWindow("Unable to blit projective texture: %s",str);
|
||||
bDisableShadows=TRUE;
|
||||
break;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
#endif
|
||||
}
|
||||
//tb
|
||||
}
|
||||
|
||||
// Begin the scene.
|
||||
#if 0
|
||||
if (FAILED(g_pd3dDevice->BeginScene()))
|
||||
goto closescene;
|
||||
#endif
|
||||
RenderGeometry();
|
||||
|
||||
if (gStencilBitDepth && !bDisableShadows) {
|
||||
//sb
|
||||
rSaveViewMatrix();
|
||||
g_renderer->setRenderState(RenderState::ALPHAREF, 0x00000002);
|
||||
hres = !g_renderer->error();
|
||||
if (!hres) {
|
||||
Common::String str = g_renderer->getErrorString();
|
||||
DebugLogWindow("Unable to SetRenderState for Shadowbuffer: %s", str.c_str());
|
||||
bDisableShadows = TRUE;
|
||||
}
|
||||
|
||||
//Render Shadows volumes
|
||||
for (j = 0; j < gNumShadowBoxesList; j++) {
|
||||
SHADOWBOX *sb = ShadowBoxesList[j];
|
||||
rSetUserViewMatrix(sb->ViewMatrixNum);
|
||||
for (i = 0; i < sb->NumShadowsList; i++)
|
||||
RenderShadow(&sb->ShadowsList[i], sb->ShadowsList[i].VB);
|
||||
|
||||
if (i) {
|
||||
RenderShadowBox(sb, sb->VBO);
|
||||
|
||||
unsigned int width, height, bpp;
|
||||
rGetScreenInfos(&width, &height, &bpp);
|
||||
DrawShadow(0, 0, width, height, sb->Intensity);
|
||||
}
|
||||
}
|
||||
rRestoreViewMatrix();
|
||||
//sb
|
||||
} else if (!bDisableShadows) {
|
||||
//tb
|
||||
for (j = 0; j < gNumShadowBoxesList; j++) {
|
||||
SHADOWBOX *sb = ShadowBoxesList[j];
|
||||
rSetUserViewMatrix(sb->ViewMatrixNum);
|
||||
for (i = 0; i < sb->NumShadowsList; i++)
|
||||
if (!(hres = DrawProjectiveShadow(&sb->ShadowsList[i]))) {
|
||||
Common::String str = g_renderer->getErrorString();
|
||||
DebugLogFile("Unable to DrawProjectiveShadow: %s", str.c_str());
|
||||
bDisableShadows = TRUE;
|
||||
}
|
||||
}
|
||||
//tb
|
||||
}
|
||||
|
||||
if (gNumLinesArray && gNumPointsBuffer) {
|
||||
rSaveViewMatrix();
|
||||
rSetLinesViewMatrix();
|
||||
|
||||
g_renderer->setBlendFunc(BlendFactor::ONE, BlendFactor::ZERO);
|
||||
g_renderer->setRenderState(RenderState::ALPHABLEND, false);
|
||||
if (g_renderer->error()) {
|
||||
goto closescene;
|
||||
}
|
||||
|
||||
g_renderer->setTexture(0, nullptr);
|
||||
/*
|
||||
hres=g_pd3dDevice->DrawIndexedPrimitiveVB( D3DPT_LINELIST,
|
||||
g_lpD3DPointsBuffer,0,gNumPointsBuffer,
|
||||
gLinesArray, gNumLinesArray,0);
|
||||
*/
|
||||
g_renderer->drawIndexedPrimitivesVBO(PrimitiveType::LINE, g_lpD3DPointsBuffer, 0, gNumPointsBuffer, gLinesArray, gNumLinesArray/*, 0*/);
|
||||
hres = g_renderer->error();
|
||||
if (!hres) {
|
||||
Common::String str = g_renderer->getErrorString();
|
||||
DebugLogWindow("DrawIndexedPrimitiveVB ERROR:\n\r%s", str.c_str());
|
||||
}
|
||||
rRestoreViewMatrix();
|
||||
gNumLinesArray = 0;
|
||||
}
|
||||
|
||||
|
||||
if (gNumTrianglesArray) {
|
||||
rSetZBufferState(FALSE);
|
||||
|
||||
g_renderer->setRenderState(RenderState::ALPHAREF, 0x0000000);
|
||||
g_renderer->setBlendFunc(BlendFactor::ONE, BlendFactor::SRCALPHA);
|
||||
g_renderer->setRenderState(RenderState::ALPHABLEND, true);
|
||||
if (g_renderer->error()) {
|
||||
goto closescene;
|
||||
}
|
||||
|
||||
g_renderer->setTexture(0, nullptr);
|
||||
g_renderer->drawPrimitives(PrimitiveType::TRIANGLE,
|
||||
/*D3DFVF_TLVERTEX,*/ gTriangles,
|
||||
gNumTrianglesArray/*, 0x0*/);
|
||||
hres = !g_renderer->error();
|
||||
if (!hres) {
|
||||
Common::String str = g_renderer->getErrorString();
|
||||
DebugLogWindow("DrawIndexedPrimitiveVB ERROR:\n\r%s", str.c_str());
|
||||
}
|
||||
gNumTrianglesArray = 0;
|
||||
rSetZBufferState(TRUE);
|
||||
}
|
||||
#if 0
|
||||
g_pd3dDevice->EndScene();
|
||||
#endif
|
||||
NumBatchBlocks = 0;
|
||||
NumBatchBlocksSpecial = 0;
|
||||
// NumBatchBlocksLightmaps=0;
|
||||
NumBatchBlocksSky = 0;
|
||||
|
||||
//dwFrameCount++;
|
||||
|
||||
return TRUE;
|
||||
// End the scene.
|
||||
|
||||
closescene:
|
||||
#if 0
|
||||
g_pd3dDevice->EndScene();
|
||||
#endif
|
||||
DebugLogFile("Error during renderscene");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/* -----------------13/08/99 10.34-------------------
|
||||
* Aggiunge un nuovo BatchBlock
|
||||
* --------------------------------------------------*/
|
||||
gBatchBlock *rNewBatchBlock(signed short int T1, unsigned int F1, signed short int T2, unsigned int F2) {
|
||||
gBatchBlock *bb;
|
||||
|
||||
bb = nullptr;
|
||||
if ((F1 & T3D_MATERIAL_GLASS) ||
|
||||
(F1 & T3D_MATERIAL_OPACITY) ||
|
||||
(F1 & T3D_MATERIAL_CLIPMAP) ||
|
||||
(F1 & T3D_MATERIAL_SMOKE) ||
|
||||
(F1 & T3D_MATERIAL_BOTTLE) ||
|
||||
(F1 & T3D_MATERIAL_FLARE) ||
|
||||
(F1 & T3D_MATERIAL_ADDITIVE)) {
|
||||
if ((NumBatchBlocksSpecial + 1) < MAX_BATCH_BLOCKS_SPECIAL)
|
||||
bb = &BatchBlockListSpecial[NumBatchBlocksSpecial++];
|
||||
else
|
||||
DebugLogFile("Too many BB Special: %d (MAX is %d)!", NumBatchBlocksSpecial, MAX_BATCH_BLOCKS_SPECIAL);
|
||||
}
|
||||
// else if( (T2>0) )
|
||||
// {
|
||||
// if( (NumBatchBlocksLightmaps+1) < MAX_BATCH_BLOCKS_LIGHTMAPS )
|
||||
// bb=&BatchBlockList[NumBatchBlocksLightmaps++];
|
||||
// else
|
||||
// DebugLogFile("Too many BB LightMaps: %d (MAX is %d)!",NumBatchBlocksLightmaps,MAX_BATCH_BLOCKS_LIGHTMAPS);
|
||||
// }
|
||||
else if ((F1 & T3D_MATERIAL_SKY)) {
|
||||
if ((NumBatchBlocksSky + 1) < MAX_BATCH_BLOCKS_SKY)
|
||||
bb = &BatchBlockListSky[NumBatchBlocksSky++];
|
||||
else
|
||||
DebugLogFile("Too many BB Sky: %d (MAX is %d)!", NumBatchBlocksSky, MAX_BATCH_BLOCKS_SKY);
|
||||
} else {
|
||||
if ((NumBatchBlocks + 1) < MAX_BATCH_BLOCKS)
|
||||
bb = &BatchBlockList[NumBatchBlocks++];
|
||||
else
|
||||
DebugLogFile("Too many BB: %d (MAX is %d)!", NumBatchBlocks, MAX_BATCH_BLOCKS);
|
||||
}
|
||||
|
||||
if (!bb) return nullptr;
|
||||
|
||||
*bb = gBatchBlock(T1, T2, F1, F2);
|
||||
return bb;
|
||||
}
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
29
engines/watchmaker/3d/render/render.h
Normal file
29
engines/watchmaker/3d/render/render.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WATCHMAKER_3D_RENDER_H
|
||||
#define WATCHMAKER_3D_RENDER_H
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
|
||||
#endif // WATCHMAKER_3D_RENDER_H
|
||||
945
engines/watchmaker/3d/render/shadows.cpp
Normal file
945
engines/watchmaker/3d/render/shadows.cpp
Normal file
@@ -0,0 +1,945 @@
|
||||
/* 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/3d/render/shadows.h"
|
||||
#include "watchmaker/3d/math/Matrix4x4.h"
|
||||
|
||||
|
||||
#define MAX_SHADOW_BOXES 20 // max shadows
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
SHADOWBOX *ShadowBoxesList[MAX_SHADOW_BOXES];
|
||||
unsigned int gNumShadowBoxesList = 0;
|
||||
|
||||
unsigned int gGetTextureListPosition();
|
||||
extern unsigned int CurLoaderFlags;
|
||||
#if 0
|
||||
#pragma pack(1)
|
||||
struct COLORVERTEX { // vertex structures
|
||||
D3DVECTOR p;
|
||||
D3DCOLOR c;
|
||||
};
|
||||
|
||||
struct TRANSCOLORVERTEX { // transformed vertex
|
||||
D3DVECTOR p;
|
||||
D3DVALUE rhw;
|
||||
D3DCOLOR c;
|
||||
};
|
||||
#pragma pack()
|
||||
#endif
|
||||
#define MAX_SHADOW_BOXES 20 // max shadows
|
||||
|
||||
bool g_bUseOneBitStencil = FALSE; // if Stencil buffer if 1 bit deep only
|
||||
DWORD g_max_StencilVal = 255; // maximum value the stencil buffer will hold
|
||||
#if 0
|
||||
D3DSTENCILOP g_StencDecOp, g_StencIncOp; // increment e decrement functions
|
||||
|
||||
LPDIRECTDRAWSURFACE7 g_pddsShadowBuffer = NULL;
|
||||
LPDIRECTDRAWSURFACE7 g_pddsShadowZBuffer = NULL;
|
||||
#endif
|
||||
//************************************************************************************************
|
||||
inline void SetIdentityMatrix(Matrix4x4 &m) { // set D3D matrix to identity
|
||||
m.setIdentity();
|
||||
}
|
||||
|
||||
#if 0
|
||||
//************************************************************************************************
|
||||
int ccw(COLORVERTEX *P[], int i, int j, int k) { // for convex-hull
|
||||
double a = P[i]->p.x - P[j]->p.x,
|
||||
b = P[i]->p.y - P[j]->p.y,
|
||||
c = P[k]->p.x - P[j]->p.x,
|
||||
d = P[k]->p.y - P[j]->p.y;
|
||||
return a * d - b * c <= 0; // true if points i, j, k counterclockwise
|
||||
}
|
||||
|
||||
//*********************************************************************************************
|
||||
int cmpl(const void *a, const void *b) { // for convex-hull
|
||||
float v;
|
||||
COLORVERTEX **av, **bv;
|
||||
|
||||
av = (COLORVERTEX **)a;
|
||||
bv = (COLORVERTEX **)b;
|
||||
|
||||
v = (*av)->p.x - (*bv)->p.x;
|
||||
|
||||
if (v > 0) return 1;
|
||||
if (v < 0) return -1;
|
||||
|
||||
v = (*bv)->p.y - (*av)->p.y;
|
||||
|
||||
if (v > 0) return 1;
|
||||
if (v < 0) return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//*********************************************************************************************
|
||||
int cmph(const void *a, const void *b) {
|
||||
return cmpl(b, a); // for convex-hull
|
||||
}
|
||||
|
||||
//*********************************************************************************************
|
||||
int make_chain(COLORVERTEX *V[], int n, int (*cmp)(const void *, const void *)) { // for convex-hull
|
||||
int i, j, s = 1;
|
||||
COLORVERTEX *t;
|
||||
|
||||
qsort(V, n, sizeof(COLORVERTEX *), cmp);
|
||||
for (i = 2; i < n; i++) {
|
||||
for (j = s; j >= 1 && ccw(V, i, j, j - 1); j--)
|
||||
{}
|
||||
s = j + 1;
|
||||
t = V[s];
|
||||
V[s] = V[i];
|
||||
V[i] = t;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
//*********************************************************************************************
|
||||
int ch2d(COLORVERTEX *P[], int n) { // for convex-hull
|
||||
int u = make_chain(P, n, cmpl); // make lower hull
|
||||
if (!n) return 0;
|
||||
P[n] = P[0];
|
||||
return u + make_chain(P + u, n - u + 1, cmph); // make upper hull
|
||||
}
|
||||
|
||||
//************************************************************************************************
|
||||
void Find2DConvexHull(DWORD nverts, COLORVERTEX *pntptr, DWORD *cNumOutIdxs, WORD **OutHullIdxs) { // find a convex hull
|
||||
COLORVERTEX **PntPtrs;
|
||||
DWORD i;
|
||||
|
||||
*cNumOutIdxs = 0; //max space needed is n+1 indices
|
||||
*OutHullIdxs = (WORD *)malloc((nverts + 1) * (sizeof(DWORD) + sizeof(COLORVERTEX *)));
|
||||
|
||||
PntPtrs = (COLORVERTEX **) & (*OutHullIdxs)[nverts + 1];
|
||||
|
||||
// alg requires array of ptrs to verts (for qsort) instead of array of verts, so do the conversion
|
||||
for (i = 0; i < nverts; i++) {
|
||||
PntPtrs[i] = &pntptr[i];
|
||||
}
|
||||
|
||||
*cNumOutIdxs = ch2d(PntPtrs, nverts);
|
||||
|
||||
// convert back to array of idxs
|
||||
for (i = 0; i < *cNumOutIdxs; i++) {
|
||||
(*OutHullIdxs)[i] = (WORD)(PntPtrs[i] - &pntptr[0]);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* -----------------25/08/1999 16.41-----------------
|
||||
* find 2D convex hull for the object
|
||||
* --------------------------------------------------*/
|
||||
bool rMakeShadowVolume(SHADOWBOX *sb, gVertex *InVerts, DWORD nverts, float lightm[9]) {
|
||||
warning("Stubbed: rMakeShadowVolume");
|
||||
#if 0
|
||||
Matrix4x4 matWorld, matView, matProj, IDmat;
|
||||
DWORD i;
|
||||
HRESULT hr;
|
||||
LPDIRECT3DDEVICE7 pd3dDevice = g_pd3dDevice;
|
||||
unsigned int AlphaVal = 98;
|
||||
SHADOW *shad = &sb->ShadowsList[sb->NumShadowsList++];
|
||||
|
||||
// Get a ptr to the ID3D object to create materials and/or lights. Note:
|
||||
// the Release() call just serves to decrease the ref count.
|
||||
LPDIRECT3D7 pD3D;
|
||||
pd3dDevice->GetDirect3D(&pD3D);
|
||||
pD3D->Release();
|
||||
|
||||
LPDIRECT3DVERTEXBUFFER7 VB_Proj;
|
||||
D3DVERTEXBUFFERDESC vbDesc;
|
||||
vbDesc.dwSize = sizeof(D3DVERTEXBUFFERDESC);
|
||||
vbDesc.dwCaps = D3DVBCAPS_SYSTEMMEMORY;
|
||||
vbDesc.dwFVF = D3DFVF_XYZ | D3DFVF_DIFFUSE;
|
||||
// xyz+color so we can render them in showshadvol mode
|
||||
|
||||
// Create vertex buffer to hold shadow volumes verts
|
||||
if (shad->VB == NULL) {
|
||||
// now form array of indices that will make the tris
|
||||
ZeroMemory(shad, sizeof(SHADOW));
|
||||
shad->num_objverts = nverts;
|
||||
vbDesc.dwNumVertices = nverts * 2; // *2 to hold top of shadvol for infin light source
|
||||
|
||||
if (FAILED(hr = pD3D->CreateVertexBuffer(&vbDesc, &shad->VB, 0)))
|
||||
return hr;
|
||||
|
||||
// alloc enough to hold largest-case shadvol (max # of verts in c-hull is nverts)
|
||||
// (nverts+1)*2 for tri mesh to hold shadvol sides + nverts to hold tri-fan
|
||||
shad->pwShadVolIndices = (WORD *)t3dCalloc(sizeof(WORD) * (nverts + 1) * 2);
|
||||
}
|
||||
|
||||
// create VB_Proj vertex buffer as a target for the vertex-projection operation used to compute
|
||||
// the silhouette
|
||||
vbDesc.dwNumVertices = nverts;
|
||||
vbDesc.dwFVF = D3DFVF_XYZRHW;
|
||||
// even though RHW not used, must specify it or ProcessVerts will not consider this as a valid
|
||||
// target to xform verts into
|
||||
|
||||
if (FAILED(hr = pD3D->CreateVertexBuffer(&vbDesc, &VB_Proj, NULL)))
|
||||
return hr;
|
||||
|
||||
// must lock VB, then copy verts into its space.
|
||||
COLORVERTEX *VBvertptr;
|
||||
|
||||
shad->VB->Lock(DDLOCK_NOSYSLOCK | DDLOCK_WRITEONLY | DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR,
|
||||
(VOID **) &VBvertptr, NULL);
|
||||
|
||||
// have to copy verts into VB memory. I reformat into COLORVERTEX to do this.
|
||||
// could prevent reformat and do a straight memcpy if Find2DConvexHull used D3DVERTEX tho.
|
||||
COLORVERTEX *cvptr = VBvertptr;
|
||||
gVertex *d3dvptr = InVerts;
|
||||
|
||||
// reformat D3DVERTEX array to COLORVERTEX array
|
||||
for (i = 0; i < nverts; i++) {
|
||||
cvptr->p.x = d3dvptr->x;
|
||||
cvptr->p.y = d3dvptr->y;
|
||||
cvptr->p.z = d3dvptr->z;
|
||||
cvptr->c = RGBA_MAKE(0xff, 0x0, 0x0, 0xff); // shadvol is semi-transparent black
|
||||
cvptr++;
|
||||
d3dvptr++;
|
||||
}
|
||||
|
||||
shad->VB->Unlock();
|
||||
|
||||
// save cur matrices so we can use xform pipeln to project verts supafast
|
||||
pd3dDevice->GetTransform(D3DTRANSFORMSTATE_WORLD, &matWorld);
|
||||
pd3dDevice->GetTransform(D3DTRANSFORMSTATE_VIEW, &matView);
|
||||
pd3dDevice->GetTransform(D3DTRANSFORMSTATE_PROJECTION, &matProj);
|
||||
|
||||
SetIdentityMatrix(IDmat);
|
||||
|
||||
pd3dDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &IDmat);
|
||||
pd3dDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &IDmat);
|
||||
|
||||
// for view matrix, all we want is anything that projects the verts onto a plane
|
||||
// perp to light direction. so any eyepoint is OK (try to make obj near origin though,
|
||||
// so look at one of the verts). dont care what direction is view up vector (y).
|
||||
rSetViewMatrix(lightm[0], lightm[1], lightm[2],
|
||||
lightm[3], lightm[4], lightm[5],
|
||||
lightm[6], lightm[7], lightm[8],
|
||||
0.0f, 0.0f, 0.0f);
|
||||
|
||||
// do the planar projection
|
||||
VB_Proj->ProcessVertices(D3DVOP_TRANSFORM,
|
||||
0, // write new verts at idx 0
|
||||
nverts,
|
||||
shad->VB,
|
||||
0, // read src verts from idx 0
|
||||
pd3dDevice,
|
||||
0x0); // no flags
|
||||
|
||||
pd3dDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &matWorld);
|
||||
pd3dDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &matView);
|
||||
pd3dDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &matProj);
|
||||
|
||||
COLORVERTEX *pntptr;
|
||||
|
||||
VB_Proj->Lock(DDLOCK_NOSYSLOCK | DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR,
|
||||
(void **) &pntptr, NULL);
|
||||
|
||||
WORD *OutHullIdxs;
|
||||
DWORD n_idxs;
|
||||
|
||||
Find2DConvexHull(nverts, pntptr, &n_idxs, &OutHullIdxs); // This is the function supplied with dx6
|
||||
|
||||
VB_Proj->Unlock();
|
||||
VB_Proj->Release(); // just needed the indices of hull
|
||||
|
||||
shad->VB->Lock(DDLOCK_NOSYSLOCK | DDLOCK_WRITEONLY | DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR,
|
||||
(void **) &VBvertptr, NULL);
|
||||
|
||||
// make shadow volume by taking hull verts and project them along light dir far enough
|
||||
// to be offscreen
|
||||
|
||||
// add verts to end of VB
|
||||
for (i = 0; i < n_idxs; i++) {
|
||||
VBvertptr[nverts + i].p.x = VBvertptr[OutHullIdxs[i]].p.x - (2000.0f * lightm[6]); // scale factor of 10 should be enough
|
||||
VBvertptr[nverts + i].p.y = VBvertptr[OutHullIdxs[i]].p.y - (2000.0f * lightm[7]); // scale factor of 10 should be enough
|
||||
VBvertptr[nverts + i].p.z = VBvertptr[OutHullIdxs[i]].p.z - (2000.0f * lightm[8]); // scale factor of 10 should be enough
|
||||
VBvertptr[nverts + i].c = RGBA_MAKE(0x0, 0xff, 0x0, 0xff);
|
||||
}
|
||||
|
||||
shad->totalverts = nverts + n_idxs;
|
||||
|
||||
// now form array of indices that will make the tris
|
||||
// shad vol will have n_idxs square sides
|
||||
|
||||
shad->num_side_indices = (n_idxs + 1) * 2;
|
||||
|
||||
// if shadvol is not capped, shadow may be drawn in place where a backfacing cap is missing even
|
||||
// though no geometry is there
|
||||
|
||||
//f shad->num_cap_indices=n_idxs;
|
||||
shad->num_cap_indices = 0;
|
||||
|
||||
WORD *idxptr;
|
||||
|
||||
idxptr = shad->pwShadVolSideIndices = shad->pwShadVolIndices;
|
||||
|
||||
// tris for all facets but final one
|
||||
for (i = 0; i < n_idxs; i++) {
|
||||
// outhullidx[i] is the index of the ith vertex of the n_idx convex hull verts
|
||||
// nverts+i is the index of the projected vert corresponding to the OutHullIdx[i] vertex
|
||||
*idxptr++ = OutHullIdxs[i];
|
||||
*idxptr++ = (WORD)(nverts + i);
|
||||
}
|
||||
// add tris for final facet (i==n_idxs)
|
||||
*idxptr++ = OutHullIdxs[0];
|
||||
*idxptr++ = (WORD)(nverts + 0);
|
||||
|
||||
//m shad->pwShadVolCapIndices=idxptr;
|
||||
|
||||
free(OutHullIdxs); // allocated by Find2DConvexHull
|
||||
shad->VB->Unlock();
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
/* -----------------25/08/1999 16.41-----------------
|
||||
* makes a shadow box to avoid stenciled shadows over the object
|
||||
* --------------------------------------------------*/
|
||||
bool rMakeShadowBox(SHADOWBOX *sb, float BoxX, float BoxY, float BoxZ, WORD intens) {
|
||||
warning("Stubbed: rMakeShadowBox");
|
||||
#if 0
|
||||
bool hr;
|
||||
LPDIRECT3DDEVICE7 pd3dDevice = g_pd3dDevice;
|
||||
|
||||
// Get a ptr to the ID3D object to create materials and/or lights. Note:
|
||||
// the Release() call just serves to decrease the ref count.
|
||||
LPDIRECT3D7 pD3D;
|
||||
pd3dDevice->GetDirect3D(&pD3D);
|
||||
pD3D->Release();
|
||||
|
||||
D3DVERTEXBUFFERDESC vbDesc;
|
||||
vbDesc.dwSize = sizeof(D3DVERTEXBUFFERDESC);
|
||||
vbDesc.dwCaps = D3DVBCAPS_SYSTEMMEMORY;
|
||||
vbDesc.dwFVF = D3DFVF_XYZ | D3DFVF_DIFFUSE;
|
||||
// xyz+color so we can render them in showshadvol mode
|
||||
|
||||
// Create vertex buffer to hold shadow volumes verts
|
||||
if (sb->VB == NULL) {
|
||||
sb->NumVerts = 16;
|
||||
sb->NumIndices = 12 * 3;
|
||||
vbDesc.dwNumVertices = sb->NumVerts;
|
||||
if (FAILED(hr = pD3D->CreateVertexBuffer(&vbDesc, &sb->VB, 0)))
|
||||
return hr;
|
||||
|
||||
// alloc enough to hold largest-case shadvol (max # of verts in c-hull is nverts)
|
||||
// (nverts+1)*2 for tri mesh to hold shadvol sides + nverts to hold tri-fan
|
||||
sb->pwIndices = (WORD *)t3dCalloc(sizeof(WORD) * sb->NumIndices);
|
||||
|
||||
WORD *curind = sb->pwIndices;
|
||||
*curind++ = 0;
|
||||
*curind++ = 1;
|
||||
*curind++ = 2; // Base scura
|
||||
*curind++ = 2;
|
||||
*curind++ = 1;
|
||||
*curind++ = 3;
|
||||
*curind++ = 0;
|
||||
*curind++ = 4;
|
||||
*curind++ = 1; // Bordo sinistro scuro
|
||||
*curind++ = 1;
|
||||
*curind++ = 4;
|
||||
*curind++ = 5;
|
||||
*curind++ = 2;
|
||||
*curind++ = 6;
|
||||
*curind++ = 0; // Bordo destro scuro
|
||||
*curind++ = 0;
|
||||
*curind++ = 6;
|
||||
*curind++ = 4;
|
||||
*curind++ = 12;
|
||||
*curind++ = 13;
|
||||
*curind++ = 14; // Testa chiara
|
||||
*curind++ = 14;
|
||||
*curind++ = 13;
|
||||
*curind++ = 15;
|
||||
*curind++ = 11;
|
||||
*curind++ = 15;
|
||||
*curind++ = 9; // Bordo sinistro chiaro
|
||||
*curind++ = 9;
|
||||
*curind++ = 15;
|
||||
*curind++ = 13;
|
||||
*curind++ = 10;
|
||||
*curind++ = 14;
|
||||
*curind++ = 11; // Bordo destro chiaro
|
||||
*curind++ = 11;
|
||||
*curind++ = 14;
|
||||
*curind++ = 15;
|
||||
}
|
||||
sb->NumShadowsList = 0;
|
||||
sb->Intensity = intens;
|
||||
|
||||
// must lock VB, then copy verts into its space.
|
||||
COLORVERTEX *VBvertptr;
|
||||
sb->VB->Lock(DDLOCK_NOSYSLOCK | DDLOCK_WRITEONLY | DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR,
|
||||
(VOID **) &VBvertptr, NULL);
|
||||
|
||||
// have to copy verts into VB memory. I reformat into COLORVERTEX to do this.
|
||||
// could prevent reformat and do a straight memcpy if Find2DConvexHull used D3DVERTEX tho.
|
||||
COLORVERTEX *cvptr = VBvertptr;
|
||||
D3DCOLOR cshadow = RGBA_MAKE(0x0, 0x0, 0x0, intens);
|
||||
D3DCOLOR clight = RGBA_MAKE(0x0, 0x0, 0x0, 0);
|
||||
|
||||
// 0: Base Piu' distante scuro
|
||||
cvptr->p.x = BoxX;
|
||||
cvptr->p.y = 5.0f;
|
||||
cvptr->p.z = BoxZ;
|
||||
cvptr->c = cshadow;
|
||||
cvptr ++;
|
||||
// 1: Base Sinistra scuro
|
||||
cvptr->p.x = -BoxZ;
|
||||
cvptr->p.y = 5.0f;
|
||||
cvptr->p.z = BoxX;
|
||||
cvptr->c = cshadow;
|
||||
cvptr ++;
|
||||
// 2: Base Destra scuro
|
||||
cvptr->p.x = BoxZ;
|
||||
cvptr->p.y = 5.0f;
|
||||
cvptr->p.z = -BoxX;
|
||||
cvptr->c = cshadow;
|
||||
cvptr ++;
|
||||
// 3: Base Piu' vicino scuro
|
||||
cvptr->p.x = -BoxX;
|
||||
cvptr->p.y = 5.0f;
|
||||
cvptr->p.z = -BoxZ;
|
||||
cvptr->c = cshadow;
|
||||
cvptr ++;
|
||||
// 4: Testa Piu' distante scura
|
||||
cvptr->p.x = BoxX;
|
||||
cvptr->p.y = BoxY;
|
||||
cvptr->p.z = BoxZ;
|
||||
cvptr->c = cshadow;
|
||||
cvptr ++;
|
||||
// 5: Testa Sinistra scuro
|
||||
cvptr->p.x = -BoxZ;
|
||||
cvptr->p.y = BoxY;
|
||||
cvptr->p.z = BoxX;
|
||||
cvptr->c = cshadow;
|
||||
cvptr ++;
|
||||
// 6: Testa Destra scuro
|
||||
cvptr->p.x = BoxZ;
|
||||
cvptr->p.y = BoxY;
|
||||
cvptr->p.z = -BoxX;
|
||||
cvptr->c = cshadow;
|
||||
cvptr ++;
|
||||
// 7: Testa Piu' vicino scuro
|
||||
cvptr->p.x = -BoxX;
|
||||
cvptr->p.y = BoxY;
|
||||
cvptr->p.z = -BoxZ;
|
||||
cvptr->c = cshadow;
|
||||
cvptr ++;
|
||||
// 8: Base Piu' distante chiaro
|
||||
cvptr->p.x = BoxX;
|
||||
cvptr->p.y = 5.0f;
|
||||
cvptr->p.z = BoxZ;
|
||||
cvptr->c = clight;
|
||||
cvptr ++;
|
||||
// 9: Base Sinistra chiaro
|
||||
cvptr->p.x = -BoxZ;
|
||||
cvptr->p.y = 5.0f;
|
||||
cvptr->p.z = BoxX;
|
||||
cvptr->c = clight;
|
||||
cvptr ++;
|
||||
// 10: Base Destra chiaro
|
||||
cvptr->p.x = BoxZ;
|
||||
cvptr->p.y = 5.0f;
|
||||
cvptr->p.z = -BoxX;
|
||||
cvptr->c = clight;
|
||||
cvptr ++;
|
||||
// 11: Base Piu' vicino chiaro
|
||||
cvptr->p.x = -BoxX;
|
||||
cvptr->p.y = 5.0f;
|
||||
cvptr->p.z = -BoxZ;
|
||||
cvptr->c = clight;
|
||||
cvptr ++;
|
||||
// 12: Testa Piu' distante chiaro
|
||||
cvptr->p.x = BoxX;
|
||||
cvptr->p.y = BoxY;
|
||||
cvptr->p.z = BoxZ;
|
||||
cvptr->c = clight;
|
||||
cvptr ++;
|
||||
// 13: Testa Sinistra chiaro
|
||||
cvptr->p.x = -BoxZ;
|
||||
cvptr->p.y = BoxY;
|
||||
cvptr->p.z = BoxX;
|
||||
cvptr->c = clight;
|
||||
cvptr ++;
|
||||
// 14: Testa Destra chiaro
|
||||
cvptr->p.x = BoxZ;
|
||||
cvptr->p.y = BoxY;
|
||||
cvptr->p.z = -BoxX;
|
||||
cvptr->c = clight;
|
||||
cvptr ++;
|
||||
// 15: Testa Piu' vicino chiaro
|
||||
cvptr->p.x = -BoxX;
|
||||
cvptr->p.y = BoxY;
|
||||
cvptr->p.z = -BoxZ;
|
||||
cvptr->c = clight;
|
||||
cvptr ++;
|
||||
|
||||
sb->VB->Unlock();
|
||||
|
||||
ShadowBoxesList[gNumShadowBoxesList++] = sb;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
/* -----------------25/08/1999 17.24-----------------
|
||||
* renders a stenciled convex hull
|
||||
* --------------------------------------------------*/
|
||||
bool RenderShadow(SHADOW *pShad,
|
||||
void *lpVBuf) {
|
||||
warning("TODO: Stubbed RenderShadow");
|
||||
#if 0
|
||||
LPDIRECT3DDEVICE7 pd3dDevice = g_pd3dDevice;
|
||||
|
||||
pd3dDevice->SetTexture(0, NULL);
|
||||
|
||||
// Turn depth buffer off, and stencil buffer on
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, FALSE);
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_STENCILENABLE, TRUE);
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_SHADEMODE, D3DSHADE_FLAT); // dont want to bother interpolating color
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_CW);
|
||||
|
||||
// Set up stencil compare fuction, reference value, and masks
|
||||
// Stencil test passes if ((ref & mask) cmpfn (stencil & mask)) is true
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_STENCILFUNC, D3DCMP_ALWAYS);
|
||||
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_STENCILZFAIL, D3DSTENCILOP_KEEP);
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_STENCILFAIL, D3DSTENCILOP_KEEP);
|
||||
|
||||
if (g_bUseOneBitStencil) {
|
||||
// If ztest passes, write !(g_bInvertStencilBufferSense) into stencil buffer
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_STENCILREF, 0x1);
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_STENCILMASK, 0x1);
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_STENCILWRITEMASK, 0x1);
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_STENCILPASS, D3DSTENCILOP_REPLACE);
|
||||
} else {
|
||||
// If ztest passes, inc/decrement stencil buffer value
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_STENCILREF, 0x1);
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_STENCILMASK, 0xffffffff);
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_STENCILWRITEMASK, 0xffffffff);
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_STENCILPASS, g_StencIncOp);
|
||||
}
|
||||
|
||||
// Since destcolor=SRCBLEND * SRC_COLOR + DESTBLEND * DEST_COLOR,
|
||||
// this should result in the tri color being completely dropped
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE);
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_ZERO);
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_ONE);
|
||||
|
||||
// draw front-side of shadow volume in stencil/z only
|
||||
pd3dDevice->DrawIndexedPrimitiveVB(D3DPT_TRIANGLESTRIP, lpVBuf, 0, pShad->totalverts,
|
||||
pShad->pwShadVolSideIndices,
|
||||
pShad->num_side_indices, 0x0);
|
||||
|
||||
// Now reverse cull order so back sides of shadow volume are written.
|
||||
if (g_bUseOneBitStencil) {
|
||||
// write 0's/1's into stencil buffer to erase pixels beyond back of shadow
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_STENCILREF, 0x0);
|
||||
} else {
|
||||
// increment stencil buffer value
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_STENCILPASS, g_StencDecOp);
|
||||
}
|
||||
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_CCW);
|
||||
// Draw back-side of shadow volume in stencil/z only
|
||||
pd3dDevice->DrawIndexedPrimitiveVB(D3DPT_TRIANGLESTRIP, lpVBuf, 0, pShad->totalverts,
|
||||
pShad->pwShadVolSideIndices,
|
||||
pShad->num_side_indices, 0x0);
|
||||
|
||||
// Restore render states
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_NONE);
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, TRUE);
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_STENCILENABLE, FALSE);
|
||||
//f pd3dDevice->SetRenderState( D3DRENDERSTATE_ALPHABLENDENABLE, FALSE );
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_SHADEMODE, D3DSHADE_GOURAUD);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
/* -----------------25/08/1999 17.25-----------------
|
||||
* renders an object stenciled shadows box
|
||||
* --------------------------------------------------*/
|
||||
bool RenderShadowBox(SHADOWBOX *pSB,
|
||||
int lpVBuf) {
|
||||
warning("TODO: RenderShadowBox");
|
||||
#if 0
|
||||
LPDIRECT3DDEVICE7 pd3dDevice = g_pd3dDevice;
|
||||
|
||||
pd3dDevice->SetTexture(0, NULL);
|
||||
|
||||
// Turn depth buffer off, and stencil buffer on
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, FALSE);
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_STENCILENABLE, TRUE);
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_SHADEMODE, D3DSHADE_FLAT);
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_NONE);
|
||||
|
||||
// Set up stencil compare fuction, reference value, and masks
|
||||
// Stencil test passes if ((ref & mask) cmpfn (stencil & mask)) is true
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_STENCILREF, 0x1);
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_STENCILFUNC, D3DCMP_LESSEQUAL);
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_STENCILZFAIL, D3DSTENCILOP_ZERO);
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_STENCILFAIL, D3DSTENCILOP_ZERO);
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_STENCILPASS, D3DSTENCILOP_ZERO);
|
||||
|
||||
// Since destcolor=SRCBLEND * SRC_COLOR + DESTBLEND * DEST_COLOR,
|
||||
// this should result in the tri color being completely dropped
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE);
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA);
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA);
|
||||
|
||||
pd3dDevice->DrawIndexedPrimitiveVB(D3DPT_TRIANGLELIST, lpVBuf, 0, pSB->NumVerts,
|
||||
pSB->pwIndices,
|
||||
pSB->NumIndices, 0x0);
|
||||
|
||||
// Restore render states
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, TRUE);
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_STENCILENABLE, FALSE);
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_SHADEMODE, D3DSHADE_GOURAUD);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
/* -----------------25/08/1999 17.25-----------------
|
||||
* Name: DrawShadow()
|
||||
* Desc: Draws a big grey polygon over scene, and blend it with pixels with
|
||||
* stencil 1, which are in shadow. Could optimize this by keeping track
|
||||
* of rendered 2D extent rect of all shadow vols.
|
||||
* --------------------------------------------------*/
|
||||
bool DrawShadow(unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2, WORD intens) {
|
||||
warning("Stubbed: DrawShadow");
|
||||
#if 0
|
||||
LPDIRECT3DDEVICE7 pd3dDevice = g_pd3dDevice;
|
||||
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, FALSE);
|
||||
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_STENCILENABLE, TRUE);
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE);
|
||||
|
||||
// Since destcolor=SRCBLEND * SRC_COLOR + DESTBLEND * DEST_COLOR,
|
||||
// this results in destcolor= (AlphaSrc) * SRC_COLOR + (1-AlphaSrc)*DestColor
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA);
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA);
|
||||
|
||||
// stencil cmp func is defined as (ref cmpfn stencbufval).
|
||||
|
||||
// Only write where stencil val >= 1. (count indicates # of shadows that overlap that pixel)
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_STENCILREF, 0x1);
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_STENCILFUNC, D3DCMP_LESSEQUAL);
|
||||
|
||||
//f pd3dDevice->SetRenderState( D3DRENDERSTATE_STENCILPASS, D3DSTENCILOP_KEEP );
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_STENCILPASS, D3DSTENCILOP_ZERO);
|
||||
|
||||
// Set the world matrix to identity to draw the big grey square
|
||||
D3DMATRIX matWorld, matIdentity;
|
||||
pd3dDevice->GetTransform(D3DTRANSFORMSTATE_WORLD, &matWorld);
|
||||
SetIdentityMatrix(matIdentity);
|
||||
pd3dDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &matIdentity);
|
||||
// pd3dDevice->SetTransform( D3DTRANSFORMSTATE_VIEW, &matIdentity );
|
||||
// pd3dDevice->SetTransform( D3DTRANSFORMSTATE_PROJECTION, &matIdentity );
|
||||
|
||||
TRANSCOLORVERTEX sqverts[4];
|
||||
WORD sqindices[6];
|
||||
|
||||
sqverts[0].p.z = sqverts[1].p.z = sqverts[2].p.z = sqverts[3].p.z = 0.0f;
|
||||
sqverts[0].rhw = sqverts[1].rhw = sqverts[3].rhw = sqverts[3].rhw = 0.0f;
|
||||
sqverts[0].c = sqverts[1].c = sqverts[2].c = sqverts[3].c = RGBA_MAKE(0x0, 0x0, 0x0, intens);
|
||||
|
||||
sqindices[0] = 0;
|
||||
sqindices[1] = 2;
|
||||
sqindices[2] = 1;
|
||||
sqindices[3] = 0;
|
||||
sqindices[4] = 3;
|
||||
sqindices[5] = 2;
|
||||
|
||||
sqverts[0].p.x = (float)x1;
|
||||
sqverts[0].p.y = (float)y1;
|
||||
sqverts[1].p.x = (float)x2;
|
||||
sqverts[1].p.y = (float)y1;
|
||||
sqverts[2].p.x = (float)x2;
|
||||
sqverts[2].p.y = (float)y2;
|
||||
sqverts[3].p.x = (float)x1;
|
||||
sqverts[3].p.y = (float)y2;
|
||||
|
||||
pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, (D3DFVF_XYZRHW | D3DFVF_DIFFUSE),
|
||||
sqverts, 4, sqindices, 6, 0x0);
|
||||
|
||||
// Restore render states
|
||||
pd3dDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &matWorld);
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, TRUE);
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_STENCILENABLE, FALSE);
|
||||
pd3dDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, FALSE);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
/* -----------------25/08/1999 17.28-----------------
|
||||
* prepare shadow for projection to a texture
|
||||
* --------------------------------------------------*/
|
||||
bool rMakeProjectiveShadow(SHADOWBOX *sb, void *InVerts, DWORD nverts) {
|
||||
warning("Stubbed. rMakeProjectiveShadow");
|
||||
#if 0
|
||||
SHADOW *shad = &sb->ShadowsList[0];
|
||||
D3DVERTEXBUFFERDESC vbDesc;
|
||||
LPDIRECT3D7 pD3D;
|
||||
LPDIRECT3DDEVICE7 pd3dDevice = g_pd3dDevice;
|
||||
int pos;
|
||||
|
||||
if (shad->VB == NULL) {
|
||||
pd3dDevice->GetDirect3D(&pD3D);
|
||||
pD3D->Release();
|
||||
vbDesc.dwSize = sizeof(D3DVERTEXBUFFERDESC);
|
||||
vbDesc.dwCaps = D3DVBCAPS_SYSTEMMEMORY;
|
||||
vbDesc.dwFVF = D3DFVF_XYZRHW | D3DFVF_DIFFUSE;
|
||||
|
||||
// now form array of indices that will make the tris
|
||||
shad->num_objverts = nverts;
|
||||
vbDesc.dwNumVertices = nverts; // *2 to hold top of shadvol for infin light source
|
||||
|
||||
if (FAILED(pD3D->CreateVertexBuffer(&vbDesc, &shad->VB, 0))) {
|
||||
DebugLogFile("Unable to create VertexBuffer");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//Alloc indices for triangles
|
||||
shad->pwShadVolSideIndices = (WORD *)t3dCalloc(sizeof(WORD) * (nverts + 1) * 3);
|
||||
}
|
||||
|
||||
if (!g_pddsShadowBuffer) {
|
||||
HRESULT LastError;
|
||||
DDSURFACEDESC2 ddsd;
|
||||
|
||||
memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
|
||||
ddsd.dwSize = sizeof(DDSURFACEDESC2);
|
||||
memcpy(&ddsd, &GraphicsModes[gCurrGraphicsMode].SurfDesc, sizeof(DDSURFACEDESC2));
|
||||
ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_PIXELFORMAT;
|
||||
ddsd.ddsCaps.dwCaps = DDSCAPS_3DDEVICE;
|
||||
|
||||
ddsd.dwWidth = 256;
|
||||
ddsd.dwHeight = 256;
|
||||
|
||||
g_pddsShadowBuffer = gCreateSurface(&ddsd, g_pddsShadowBuffer);
|
||||
if (!g_pddsShadowBuffer) {
|
||||
DebugLogFile("Unable to create ShadowBuffer");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
|
||||
ddsd.dwSize = sizeof(DDSURFACEDESC2);
|
||||
g_pddsZBuffer->GetSurfaceDesc(&ddsd);
|
||||
|
||||
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
|
||||
ddsd.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
|
||||
ddsd.dwWidth = 256;
|
||||
ddsd.dwHeight = 256;
|
||||
|
||||
g_pddsShadowZBuffer = gCreateSurface(&ddsd, g_pddsZBuffer);
|
||||
if (!g_pddsShadowZBuffer) {
|
||||
char str[200];
|
||||
LastError = 0;
|
||||
GetDDErrorString(LastError, str, 1);
|
||||
|
||||
DebugLogFile("CreateSurface for ShadowBuffer Z-buffer failed.\r\n%s", str);
|
||||
return FALSE;
|
||||
}
|
||||
LastError = g_pddsShadowBuffer->AddAttachedSurface(g_pddsShadowZBuffer);
|
||||
if (LastError != DD_OK) {
|
||||
char str[200];
|
||||
GetDDErrorString(LastError, str, 1);
|
||||
DebugLogFile("AddAttachedBuffer To ShadowBuffer failed for Z-Buffer.%s", str);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!shad->ProjectiveTexture.lpDDSurface) {
|
||||
DDSURFACEDESC2 DDSurfDesc;
|
||||
memset(&DDSurfDesc, 0, sizeof(DDSURFACEDESC2));
|
||||
memcpy(&DDSurfDesc.ddpfPixelFormat, &gCurrentFormat->SurfaceDesc, sizeof(DDPIXELFORMAT));
|
||||
memcpy(&DDSurfDesc, &GraphicsModes[gCurrGraphicsMode].SurfDesc, sizeof(DDSURFACEDESC2));
|
||||
DDSurfDesc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_PIXELFORMAT;
|
||||
if (gRenderFlags & gAGPSUPPORTED) {
|
||||
//Alloc texture in AGP
|
||||
DDSurfDesc.ddsCaps.dwCaps = DDSCAPS_NONLOCALVIDMEM | DDSCAPS_VIDEOMEMORY |
|
||||
DDSCAPS_TEXTURE;
|
||||
} else {
|
||||
//No AGP support; alloc in sysmem
|
||||
DDSurfDesc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
|
||||
DDSurfDesc.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE;
|
||||
}
|
||||
DDSurfDesc.dwWidth = 256;
|
||||
DDSurfDesc.dwHeight = 256;
|
||||
if (!(shad->ProjectiveTexture.lpDDSurface = gCreateSurface(&DDSurfDesc, shad->ProjectiveTexture.lpDDSurface))) {
|
||||
DebugLogFile("rMakeProjectiveShadow: gCreateSurface FAILED: Can't create surface");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pos = gGetTextureListPosition();
|
||||
if (pos == 0) {
|
||||
DebugLogFile("rMakeProjectiveShadow: Can't create more textures");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&gTextureList[pos], 0, sizeof(gTexture));
|
||||
strcpy(gTextureList[pos].Name, "Texture Buffer Shadow");
|
||||
gTextureList[pos].lpDDSurface = shad->ProjectiveTexture.lpDDSurface;
|
||||
gTextureList[pos].RealDimX = 256;
|
||||
gTextureList[pos].RealDimY = 256;
|
||||
gTextureList[pos].DimX = 256;
|
||||
gTextureList[pos].DimY = 256;
|
||||
gTextureList[pos].Flags = CurLoaderFlags;
|
||||
}
|
||||
|
||||
ShadowBoxesList[gNumShadowBoxesList++] = sb;
|
||||
sb->NumShadowsList = 1;
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* -----------------25/08/1999 17.28-----------------
|
||||
* renders shadow to a specific texture
|
||||
* --------------------------------------------------*/
|
||||
bool RenderProjectiveShadow(SHADOW *pShad) {
|
||||
warning("Stubbed. RenderPojectiveShadow");
|
||||
#if 0
|
||||
HRESULT hres;
|
||||
LPDIRECT3DDEVICE7 pd3dDevice = g_pd3dDevice;
|
||||
LPDIRECTDRAWSURFACE7 OldRenderTarget;
|
||||
D3DVIEWPORT7 NewViewport;
|
||||
|
||||
memset(&gOldViewport, 0, sizeof(D3DVIEWPORT7));
|
||||
if (hres = pd3dDevice->GetViewport(&gOldViewport) != D3D_OK) {
|
||||
DebugLogFile("Unable to get ViewPort2");
|
||||
return hres;
|
||||
}
|
||||
memcpy(&NewViewport, &gOldViewport, sizeof(D3DVIEWPORT7));
|
||||
|
||||
if (hres = pd3dDevice->GetRenderTarget(&OldRenderTarget) != D3D_OK) {
|
||||
DebugLogFile("Can't GetRenderTarget for shadow");
|
||||
return hres;
|
||||
}
|
||||
if (hres = pd3dDevice->SetRenderTarget(g_pddsShadowBuffer, 0) != D3D_OK) {
|
||||
DebugLogFile("Can't SetRenderTarget for shadow");
|
||||
return hres;
|
||||
}
|
||||
|
||||
NewViewport.dwHeight = NewViewport.dwWidth = 256;
|
||||
if (hres = pd3dDevice->SetViewport(&NewViewport) != D3D_OK) {
|
||||
DebugLogFile("Unable to set ShadowBuffer viewport");
|
||||
return hres;
|
||||
}
|
||||
|
||||
D3DRECT rect;
|
||||
rect.x1 = rect.y1 = 0;
|
||||
rect.x2 = 256;
|
||||
rect.y2 = 256;
|
||||
if (hres = pd3dDevice->Clear(1, &rect, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xFFFFFFFF, 1.0f, 0) != D3D_OK) {
|
||||
DebugLogFile("Unable to clear2 ShadowBuffer viewport");
|
||||
return hres;
|
||||
}
|
||||
|
||||
if (hres = g_pd3dDevice->BeginScene() != D3D_OK) {
|
||||
DebugLogFile("Unable to begin Shadow scene");
|
||||
return hres;
|
||||
}
|
||||
|
||||
if (hres = pd3dDevice->SetTexture(0, NULL)) return hres;
|
||||
|
||||
if (hres = pd3dDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, FALSE)) return hres;
|
||||
if (hres = pd3dDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, D3DZB_FALSE)) return hres;
|
||||
if (hres = pd3dDevice->SetRenderState(D3DRENDERSTATE_SHADEMODE, D3DSHADE_FLAT)) return hres; // dont want to bother interpolating color
|
||||
if (hres = pd3dDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_CW)) return hres;
|
||||
if (hres = pd3dDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, FALSE)) return hres;
|
||||
if (hres = pd3dDevice->SetRenderState(D3DRENDERSTATE_ALPHATESTENABLE, FALSE)) return hres;
|
||||
|
||||
if (hres = pd3dDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_ONE)) return hres;
|
||||
if (hres = pd3dDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_ZERO)) return hres;
|
||||
|
||||
if (hres = pd3dDevice->DrawIndexedPrimitiveVB(D3DPT_TRIANGLELIST, pShad->VB, 0, pShad->totalverts,
|
||||
pShad->pwShadVolSideIndices,
|
||||
pShad->num_side_indices, 0x0) != D3D_OK) {
|
||||
DebugLogFile("Unable to DrawIndexedPrimitive for projected shadow");
|
||||
return hres;
|
||||
}
|
||||
|
||||
if (hres = g_pd3dDevice->EndScene() != D3D_OK) {
|
||||
DebugLogFile("Unable to end shadow scene");
|
||||
return hres;
|
||||
}
|
||||
|
||||
if (hres = g_pd3dDevice->SetRenderTarget(OldRenderTarget, 0) != D3D_OK) {
|
||||
DebugLogFile("Can't SetRenderTarget for shadows");
|
||||
return hres;
|
||||
}
|
||||
|
||||
if (hres = pd3dDevice->SetViewport(&gOldViewport) != D3D_OK) {
|
||||
DebugLogFile("Unable to restore viewport");
|
||||
return hres;
|
||||
}
|
||||
|
||||
if (hres = pd3dDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_NONE)) return hres;
|
||||
if (hres = pd3dDevice->SetRenderState(D3DRENDERSTATE_SHADEMODE, D3DSHADE_GOURAUD)) return hres;
|
||||
if (hres = pd3dDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, TRUE)) return hres;
|
||||
if (hres = pd3dDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, D3DZB_TRUE)) return hres;
|
||||
if (hres = pd3dDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE)) return hres;
|
||||
if (hres = pd3dDevice->SetRenderState(D3DRENDERSTATE_ALPHATESTENABLE, TRUE)) return hres;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
/* -----------------25/08/1999 17.31-----------------
|
||||
* draw projected shadow texture to the room
|
||||
* --------------------------------------------------*/
|
||||
bool DrawProjectiveShadow(SHADOW *pShad) {
|
||||
warning("Stubbed: DrawProjectiveShadow");
|
||||
#if 0
|
||||
bool hres;
|
||||
|
||||
if (hres = g_pd3dDevice->SetTextureStageState(0, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP) != DD_OK) return hres;
|
||||
if (hres = g_pd3dDevice->SetRenderState(D3DRENDERSTATE_ALPHATESTENABLE, FALSE) != DD_OK) return hres;
|
||||
|
||||
if (hres = g_pd3dDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_ZERO) != DD_OK) return hres;
|
||||
if (hres = g_pd3dDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_SRCCOLOR) != DD_OK) return hres;
|
||||
if (hres = g_pd3dDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE) != DD_OK) return hres;
|
||||
|
||||
if (hres = g_pd3dDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_CW) != DD_OK) return hres;
|
||||
if (hres = g_pd3dDevice->SetTexture(0, pShad->ProjectiveTexture.lpDDSurface) != DD_OK) return hres;
|
||||
|
||||
if (hres = g_pd3dDevice->DrawIndexedPrimitiveVB(D3DPT_TRIANGLELIST,
|
||||
pShad->ProjVertsVB, 0, pShad->totalverts,
|
||||
pShad->pwShadVolCapIndices,
|
||||
pShad->num_cap_indices, 0x0) != DD_OK) {
|
||||
char str[255];
|
||||
GetDDErrorString(hres, str, 1);
|
||||
DebugLogFile("DrawIndexedPrimitiveVB ERROR:\n\r%s", str);
|
||||
}
|
||||
pShad->num_cap_indices = 0;
|
||||
|
||||
if (hres = g_pd3dDevice->SetRenderState(D3DRENDERSTATE_ALPHATESTENABLE, TRUE) != DD_OK) return hres;
|
||||
if (hres = g_pd3dDevice->SetTextureStageState(0, D3DTSS_ADDRESS, D3DTADDRESS_WRAP) != DD_OK) return hres;
|
||||
if (hres = g_pd3dDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_NONE) != DD_OK) return hres;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
44
engines/watchmaker/3d/render/shadows.h
Normal file
44
engines/watchmaker/3d/render/shadows.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WATCHMAKER_SHADOWS_H
|
||||
#define WATCHMAKER_SHADOWS_H
|
||||
|
||||
#include "watchmaker/render.h"
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
extern SHADOWBOX *ShadowBoxesList[];
|
||||
extern unsigned int gNumShadowBoxesList;
|
||||
extern void *g_pddsShadowBuffer;
|
||||
extern void *g_pddsShadowZBuffer;
|
||||
|
||||
//extern D3DSTENCILOP g_StencDecOp,g_StencIncOp;
|
||||
bool RenderShadow(SHADOW *pShad, void *lpVBuf);
|
||||
bool RenderShadowBox(SHADOWBOX *pSB, int VBO);
|
||||
bool DrawShadow(unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2, WORD intens);
|
||||
extern DWORD g_max_StencilVal; // maximum value the stencil buffer will hold
|
||||
extern bool RenderProjectiveShadow(SHADOW *pShad);
|
||||
bool DrawProjectiveShadow(SHADOW *pShad);
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
|
||||
#endif // WATCHMAKER_SHADOWS_H
|
||||
613
engines/watchmaker/3d/t3d_body.cpp
Normal file
613
engines/watchmaker/3d/t3d_body.cpp
Normal file
@@ -0,0 +1,613 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_strcat
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_strcpy
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_sprintf
|
||||
|
||||
#include "watchmaker/3d/t3d_body.h"
|
||||
#include "common/stream.h"
|
||||
#include "watchmaker/3d/light.h"
|
||||
#include "watchmaker/3d/loader.h"
|
||||
#include "watchmaker/3d/math/llmath.h"
|
||||
#include "watchmaker/3d/t3d_face.h"
|
||||
#include "watchmaker/3d/t3d_mesh.h"
|
||||
#include "watchmaker/file_utils.h"
|
||||
#include "watchmaker/game.h"
|
||||
#include "watchmaker/ll/ll_system.h"
|
||||
#include "watchmaker/renderer.h"
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
#define CAMFILEVERSION 2
|
||||
#define BNDFILEVERSION 2
|
||||
|
||||
void t3dLoadMaterials(WGame &game, t3dBODY *b, Common::SeekableReadStream &stream, int numMaterials) {
|
||||
int16 loader_numtextures = 0;
|
||||
WorkDirs &workdirs = game.workDirs;
|
||||
for (uint16 material = 0; material < numMaterials; material++) { // Legge Materiali
|
||||
char Name[100] = {}, Appo[100] = {};
|
||||
unsigned int Flags = 0, flag = 0;
|
||||
#ifndef WMGEN
|
||||
int len;
|
||||
#endif
|
||||
|
||||
unsigned char AmbientR = (uint8)(stream.readFloatLE()); // legge Ambient
|
||||
unsigned char AmbientG = (uint8)(stream.readFloatLE());
|
||||
unsigned char AmbientB = (uint8)(stream.readFloatLE());
|
||||
|
||||
for (uint16 kk = 0; kk < T3D_NAMELEN; kk++) // Legge noem della texture
|
||||
Name[kk] = (uint8)stream.readByte();
|
||||
|
||||
Flags = stream.readSint32LE(); // Legge Flags
|
||||
|
||||
#ifndef WMGEN
|
||||
len = strlen(Name);
|
||||
if (((Name[len - 1] == 'i') || (Name[len - 1] == 'I')) &&
|
||||
((Name[len - 2] == 'v') || (Name[len - 2] == 'V')) &&
|
||||
((Name[len - 3] == 'a') || (Name[len - 3] == 'A'))) {
|
||||
strcpy(Appo, workdirs._moviesDir.c_str()); // altrimenti prende quello di default
|
||||
} else {
|
||||
strcpy(Appo, workdirs._mapsDir.c_str()); // altrimenti prende quello di default
|
||||
}
|
||||
strcat(Appo, Name); // Attacca nome Immagine
|
||||
#else
|
||||
strcpy(Appo, WmMapsDir); // altrimenti prende quello di default
|
||||
strcat(Appo, Name); // Attacca nome TGA
|
||||
#endif
|
||||
|
||||
|
||||
// if( LoaderFlags&T3D_HALFTEXTURESIZE ) // Se ho settato texture dimezzate
|
||||
// strcpy(Appo,WmHalfMapsDir); // cambio path
|
||||
// else
|
||||
//f strcat(Appo,"grid.tga");
|
||||
|
||||
if (LoaderFlags & T3D_HALFTEXTURESIZE) flag = rSURFACEHALF; // Se deve scalare le textures
|
||||
else flag = 0;
|
||||
MaterialPtr mat(new gMaterial());
|
||||
assert(b->MatTable.size() == material);
|
||||
b->MatTable.push_back(mat);
|
||||
//warning("Loading material %d", material);
|
||||
#ifndef WMGEN
|
||||
if (!(game._renderer->addMaterial(*mat, Appo,/*f1*/0, flag))) { // Carica e scala texture
|
||||
warning("Material file %s not found, ", Appo); // Se non trova la texture
|
||||
mat->Texture = nullptr;
|
||||
assert(0);
|
||||
//return nullptr;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
mat->addProperty(Flags); // Aggiunge i Flags al materiale
|
||||
// if(LoaderFlags&T3D_NOLIGHTMAPS)
|
||||
mat->addColor(AmbientR, AmbientG, AmbientB); // Sovrascrive Ambient con quello gloable
|
||||
mat->addColor((uint8)b->AmbientLight.x, (uint8)b->AmbientLight.y, (uint8)b->AmbientLight.z);
|
||||
loader_numtextures++;
|
||||
}
|
||||
assert(mat->Texture);
|
||||
}//__for_material
|
||||
(void)loader_numtextures;
|
||||
}
|
||||
|
||||
void t3dLoadMeshes(t3dBODY *b, uint32 numMeshes, t3dMESH *&ReceiveRipples, uint8 &Mirror, Common::SeekableReadStream &stream) {
|
||||
b->MeshTable.clear();
|
||||
b->MeshTable.reserve(numMeshes);
|
||||
for (uint32 mesh = 0; mesh < numMeshes; mesh++) {
|
||||
b->MeshTable.push_back(Common::move(t3dMESH(b, stream, ReceiveRipples, Mirror)));
|
||||
}
|
||||
}
|
||||
|
||||
void t3dBODY::allocateNormals() {
|
||||
int nListSize = this->NumNormals + this->NumVerticesNormals;
|
||||
this->NList.clear();
|
||||
this->NList.reserve(nListSize);
|
||||
for (int i = 0; i < nListSize; i++) { // Alloca Normali globali
|
||||
this->NList.push_back(Common::SharedPtr<t3dNORMAL>(new t3dNORMAL()));
|
||||
}
|
||||
}
|
||||
|
||||
void t3dBODY::initNormals(Common::SeekableReadStream &stream) {
|
||||
uint nListSize = this->NumNormals + this->NumVerticesNormals;
|
||||
assert(this->NList.size() == nListSize);
|
||||
for (uint16 normal = 0; normal < this->NList.size(); normal++) { // Legge normali globali
|
||||
*this->NList[normal] = t3dNORMAL(stream);
|
||||
}
|
||||
|
||||
for (uint16 i = 0; i < this->NumMeshes(); i++) { // Aggiorna normali mesh con normali globali
|
||||
t3dMESH &Mesh = this->MeshTable[i];
|
||||
#ifndef WMGEN
|
||||
Mesh.VBptr = Mesh.VertexBuffer;
|
||||
#endif
|
||||
Mesh.NList.reserve(Mesh.NumVerts); // Alloca normali mesh
|
||||
for (int k = 0; k < Mesh.NumVerts; k++) {
|
||||
Mesh.NList.push_back(Common::SharedPtr<t3dNORMAL>(new t3dNORMAL()));
|
||||
}
|
||||
|
||||
Mesh.NumNormals = 0;
|
||||
Mesh.NumVerticesNormals = Mesh.NumVerts; // Sono tutte normali ai vertici
|
||||
for (uint16 j = 0; j < Mesh.NumVerts; j++) {
|
||||
uint16 n = (uint16)Mesh.VBptr[j].diffuse;
|
||||
*Mesh.NList[j] = *this->NList[n]; // Copia normale globale in normale mesh
|
||||
Mesh.VBptr[j].diffuse = 0;
|
||||
}
|
||||
#ifndef WMGEN
|
||||
Mesh.VBptr = nullptr;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void t3dBODY::populatePortalLists() {
|
||||
t3dMESH *Mesh = &this->MeshTable[0];
|
||||
for (uint16 mesh = 0; mesh < this->NumMeshes(); mesh++) { // Cerca portali in tutte le mesh
|
||||
Mesh[mesh].PortalList = nullptr; // Azzera portale
|
||||
if (Mesh[mesh].portalName.empty()) // Se non ha portale
|
||||
continue; // continua
|
||||
if (Mesh[mesh].portalName == "castle") { // Aggiunge mesh che bloccano la vista
|
||||
// DebugFile("%s: %d %d",Mesh[mesh].Name,Mesh[mesh].NumVerts,Mesh[mesh].NumFaces);
|
||||
for (uint16 i = 0; i < T3D_MAX_BLOCK_MESHES; i++) {
|
||||
if (!this->BlockMeshes[i]) {
|
||||
this->BlockMeshes[i] = &Mesh[mesh];
|
||||
break;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
Common::String Name = Mesh[mesh].portalName + ".t3d"; // Crea nome del nuovo portale
|
||||
|
||||
Mesh[mesh].Flags |= T3D_MESH_PORTAL; // Mesh e' un portale
|
||||
Mesh[mesh].Flags |= T3D_MESH_NOBOUNDBOX; // Mesh non viene vista dal mouse
|
||||
//#ifndef VIEWER
|
||||
// Mesh[mesh].Flags|=T3D_MESH_NOPORTALCHECK; // Spegne portale
|
||||
//#endif
|
||||
// TODO: This should probably be upfactored.
|
||||
t3dBODY *rez = nullptr;
|
||||
if (((rez = _vm->_roomManager->checkIfAlreadyLoaded(Name)) == nullptr) && (!(LoaderFlags & T3D_NORECURSION))) { // Controlla se lo ha gia' caricato
|
||||
if (Name.equalsIgnoreCase("rxt.t3d"))
|
||||
_vm->_roomManager->addToLoadList(&Mesh[mesh], Name, (uint16)((LoaderFlags | T3D_NORECURSION) & ~T3D_RECURSIONLEVEL1)); // aggiunge e leva la ricorsione
|
||||
// Mesh[mesh].Flags|=T3D_MESH_NOPORTALCHECK;
|
||||
else {
|
||||
if (LoaderFlags & T3D_RECURSIONLEVEL1)
|
||||
_vm->_roomManager->addToLoadList(&Mesh[mesh], Name, (uint16)((LoaderFlags | T3D_NORECURSION) & ~T3D_RECURSIONLEVEL1)); // aggiunge e leva la ricorsione
|
||||
else
|
||||
_vm->_roomManager->addToLoadList(&Mesh[mesh], Name, (uint16)(LoaderFlags)); // altrimenti lo agggiunge alla lista
|
||||
}
|
||||
} else
|
||||
Mesh[mesh].PortalList = rez;
|
||||
}
|
||||
}
|
||||
|
||||
/* -----------------10/06/99 16.03-------------------
|
||||
* SetupWaterRipples
|
||||
* --------------------------------------------------*/
|
||||
void SetupWaterRipples(t3dMESH *m) {
|
||||
warning("TODO: Stubbed");
|
||||
return;
|
||||
}
|
||||
|
||||
/* -----------------10/06/99 16.02-------------------
|
||||
* LoadCameras
|
||||
* --------------------------------------------------*/
|
||||
void LoadCameras(WorkDirs &workDirs, const char *pname, t3dBODY *b) {
|
||||
uint8 ver;
|
||||
uint16 camera;
|
||||
|
||||
auto stream = workDirs.resolveFile(pname);
|
||||
if (!stream) {
|
||||
warning("File %s not found", pname);
|
||||
return ;
|
||||
}
|
||||
if ((ver = stream->readByte()) != CAMFILEVERSION) {
|
||||
warning("CAM File Version Error: loaded %d.\tRequired %d", ver, CAMFILEVERSION);
|
||||
return ;
|
||||
}
|
||||
|
||||
int numCameras = stream->readSint16LE();
|
||||
int numPaths = stream->readSint16LE();
|
||||
|
||||
b->CameraTable.clear();
|
||||
b->CameraTable.reserve(numCameras);
|
||||
for (camera = 0; camera < numCameras; camera++) {
|
||||
b->CameraTable.push_back(t3dCAMERA(*stream));
|
||||
}//__for_camera
|
||||
|
||||
b->CameraGrid.TopLeft.x = stream->readFloatLE() * SCALEFACTOR;
|
||||
b->CameraGrid.TopLeft.z = stream->readFloatLE() * SCALEFACTOR;
|
||||
b->CameraGrid.BottomRight.x = stream->readFloatLE() * SCALEFACTOR;
|
||||
b->CameraGrid.BottomRight.z = stream->readFloatLE() * SCALEFACTOR;
|
||||
|
||||
b->CameraGrid.Row = stream->readSint16LE();
|
||||
b->CameraGrid.Col = stream->readSint16LE();
|
||||
|
||||
b->CameraGrid.Grid.clear();
|
||||
b->CameraGrid.Grid.reserve(b->CameraGrid.Row * b->CameraGrid.Col);
|
||||
|
||||
for (int i = 0; i < (b->CameraGrid.Row * b->CameraGrid.Col); i++) {
|
||||
b->CameraGrid.Grid.push_back(stream->readByte());
|
||||
}
|
||||
|
||||
b->CameraPath.clear();
|
||||
b->CameraPath.reserve(numPaths);
|
||||
for (int i = 0; i < numPaths; i++) {
|
||||
b->CameraPath.push_back(t3dCAMERAPATH(*stream));
|
||||
}
|
||||
|
||||
b->CameraGrid.CellDim.x = (b->CameraGrid.BottomRight.x - b->CameraGrid.TopLeft.x) / b->CameraGrid.Col;
|
||||
b->CameraGrid.CellDim.z = (b->CameraGrid.BottomRight.z - b->CameraGrid.TopLeft.z) / b->CameraGrid.Row;
|
||||
}
|
||||
|
||||
/* -----------------10/06/99 16.03-------------------
|
||||
* loadBounds
|
||||
* --------------------------------------------------*/
|
||||
void loadBounds(WorkDirs &workDirs, const char *pname, t3dBODY *b) {
|
||||
for (int i = 0; i < T3D_MAX_LEVELS; i++)
|
||||
b->Panel[i] = nullptr;
|
||||
b->CurLevel = 0;
|
||||
|
||||
auto stream = workDirs.resolveFile(pname);
|
||||
if (!stream) {
|
||||
warning("File %s not found", pname);
|
||||
return ;
|
||||
}
|
||||
uint8 ver = stream->readByte();
|
||||
if (ver != BNDFILEVERSION) {
|
||||
warning("BND File Version Error: loaded %d.\tRequired %d", ver, BNDFILEVERSION);
|
||||
return;
|
||||
}
|
||||
uint16 nlev = stream->readSint16LE();
|
||||
b->NumLevels = nlev;
|
||||
if (nlev > T3D_MAX_LEVELS) {
|
||||
warning("Too much Floor Levels in %s: %d instead of %d", pname, b->NumLevels, T3D_MAX_LEVELS);
|
||||
b->NumLevels = nlev = T3D_MAX_LEVELS;
|
||||
}
|
||||
|
||||
for (int j = 0; j < nlev; j++) {
|
||||
uint16 npan = stream->readSint16LE();
|
||||
b->NumPanels[j] = npan;
|
||||
b->PanelHeight[j] = stream->readFloatLE() * SCALEFACTOR;
|
||||
b->Panel[j] = new t3dPAN[npan + 4 * T3D_MAX_CHARACTERS]; // also leave some space for any additions
|
||||
|
||||
for (int i = 0; i < npan; i++) {
|
||||
b->Panel[j][i].a.x = stream->readFloatLE() * SCALEFACTOR;
|
||||
b->Panel[j][i].a.z = stream->readFloatLE() * SCALEFACTOR;
|
||||
b->Panel[j][i].b.x = stream->readFloatLE() * SCALEFACTOR;
|
||||
b->Panel[j][i].b.z = stream->readFloatLE() * SCALEFACTOR;
|
||||
b->Panel[j][i].backA.x = stream->readFloatLE() * SCALEFACTOR;
|
||||
b->Panel[j][i].backA.z = stream->readFloatLE() * SCALEFACTOR;
|
||||
b->Panel[j][i].backB.x = stream->readFloatLE() * SCALEFACTOR;
|
||||
b->Panel[j][i].backB.z = stream->readFloatLE() * SCALEFACTOR;
|
||||
b->Panel[j][i].near1 = stream->readSint16LE();
|
||||
b->Panel[j][i].near2 = stream->readSint16LE();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* -----------------10/06/99 16.03-------------------
|
||||
* LoadLightmaps
|
||||
* --------------------------------------------------*/
|
||||
void LoadLightmaps(WGame &game, t3dBODY *b) {
|
||||
uint32 NumLightmaps;//, num;
|
||||
gVertex *gv;
|
||||
uint8 rr, gg, bb;
|
||||
int32 Map, alphaval1, alphaval2, alphaval3;
|
||||
WorkDirs &workDirs = game.workDirs;
|
||||
|
||||
Common::String Appo = setDirectoryAndName(workDirs._lightmapsDir, b->name);
|
||||
Appo = replaceExtension(Appo.c_str(), "map");
|
||||
|
||||
auto stream = workDirs.resolveFile(Appo);
|
||||
if (!stream) {
|
||||
warning("LoadLightmaps warning: File %s not found", Appo.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 lightMapVersion = stream->readSint32LE();
|
||||
if (lightMapVersion != LIGHT_MAPVERSION) {
|
||||
warning("LoadLightmaps error: File version error: found %d, required %d", lightMapVersion, LIGHT_MAPVERSION);
|
||||
return;
|
||||
}
|
||||
|
||||
b->NumLightmaps = NumLightmaps = stream->readSint32LE();
|
||||
b->LightmapTable = rCreateMaterialList(NumLightmaps);
|
||||
for (uint32 i = 0; i < NumLightmaps; i++) {
|
||||
Common::String root = setDirectoryAndName(workDirs._lightmapsDir, b->name);
|
||||
root = root.substr(0, root.size() - 4);
|
||||
Appo = Common::String::format("%s_%d.tga", root.c_str(), i);
|
||||
|
||||
/*num = */stream->readSint32LE();
|
||||
MaterialPtr mat(new gMaterial());
|
||||
assert(b->LightmapTable.size() == i);
|
||||
b->LightmapTable.push_back(mat);
|
||||
if (!game._renderer->addMaterial(*b->LightmapTable[i], Appo, 0, 0))
|
||||
return;
|
||||
|
||||
b->LightmapTable[i]->clear();
|
||||
}
|
||||
|
||||
for (uint32 i = 0; i < b->NumNormals; i++) {
|
||||
rr = (uint8)stream->readByte();
|
||||
gg = (uint8)stream->readByte();
|
||||
bb = (uint8)stream->readByte();
|
||||
Map = (int32)stream->readSint32LE();
|
||||
|
||||
Appo = setDirectoryAndName(workDirs._lightmapsDir.c_str(), b->name);
|
||||
Appo = Common::String::format("%s_%d.tga", Appo.c_str(), Map);
|
||||
|
||||
if (Map >= 0) {
|
||||
for (uint32 k = 0; k < b->NumMeshes(); k++) {
|
||||
t3dMESH &m = b->MeshTable[k];
|
||||
//f if (m->Flags&T3D_MESH_HIDDEN)
|
||||
//f continue;
|
||||
m.VBptr = m.VertexBuffer;
|
||||
gv = m.VBptr;
|
||||
|
||||
if (m.Flags & T3D_MESH_NOLIGHTMAP) {
|
||||
t3dFACE &f = m.FList[0];
|
||||
for (uint32 j = 0; j < m.NumFaces(); j++) {
|
||||
if (f.n == b->NList[i]) {
|
||||
f.lightmap = nullptr;
|
||||
}
|
||||
}
|
||||
m.VBptr = nullptr;
|
||||
continue;
|
||||
}
|
||||
t3dFACE &f = m.FList[0];
|
||||
for (uint32 j = 0; j < m.NumFaces(); j++) {
|
||||
// gMaterial *newmat;
|
||||
if (f.n == b->NList[i]) {
|
||||
// f->mat->Texture=f->mat->Lightmap;
|
||||
if ((!(f.hasMaterialFlag(T3D_MATERIAL_OPACITY))) &&
|
||||
(!(f.hasMaterialFlag(T3D_MATERIAL_CLIPMAP))) &&
|
||||
(!(f.hasMaterialFlag(T3D_MATERIAL_BOTTLE))) &&
|
||||
(!(f.hasMaterialFlag(T3D_MATERIAL_ADDITIVE))) &&
|
||||
(!(f.hasMaterialFlag(T3D_MATERIAL_GLASS)))) {
|
||||
alphaval1 = RGBA_GETALPHA(gv[f.VertexIndex[0]].diffuse);
|
||||
alphaval2 = RGBA_GETALPHA(gv[f.VertexIndex[1]].diffuse);
|
||||
alphaval3 = RGBA_GETALPHA(gv[f.VertexIndex[2]].diffuse);
|
||||
gv[f.VertexIndex[0]].diffuse = RGBA_MAKE(254, 254, 254, alphaval1);
|
||||
gv[f.VertexIndex[1]].diffuse = RGBA_MAKE(254, 254, 254, alphaval2);
|
||||
gv[f.VertexIndex[2]].diffuse = RGBA_MAKE(254, 254, 254, alphaval3);
|
||||
f.lightmap = b->LightmapTable[Map];
|
||||
f.getMaterial()->addNumFacesAdditionalMaterial(f.lightmap, 1);
|
||||
} else if (((f.hasMaterialFlag(T3D_MATERIAL_OPACITY))) ||
|
||||
((f.hasMaterialFlag(T3D_MATERIAL_CLIPMAP))) ||
|
||||
((f.hasMaterialFlag(T3D_MATERIAL_BOTTLE))) ||
|
||||
((f.hasMaterialFlag(T3D_MATERIAL_ADDITIVE))) ||
|
||||
((f.hasMaterialFlag(T3D_MATERIAL_GLASS)))) {
|
||||
f.lightmap = nullptr;
|
||||
}
|
||||
|
||||
// if (!f->mat->Lightmap)
|
||||
{
|
||||
//DebugLogWindow("Mesh %s: Face %d has not lightmap",m->Name,j);
|
||||
}
|
||||
}
|
||||
}
|
||||
m.VBptr = nullptr;
|
||||
}
|
||||
} else {
|
||||
for (uint32 k = 0; k < b->NumMeshes(); k++) {
|
||||
t3dMESH &m = b->MeshTable[k];
|
||||
// gMaterial *newmat;
|
||||
m.VBptr = m.VertexBuffer;
|
||||
gv = m.VBptr;
|
||||
|
||||
//f if (m->Flags&T3D_MESH_HIDDEN)
|
||||
//f continue;
|
||||
|
||||
if (m.Flags & T3D_MESH_NOLIGHTMAP) {
|
||||
t3dFACE &f = m.FList[0];
|
||||
for (uint32 j = 0; j < m.NumFaces(); j++) {
|
||||
if (f.n == b->NList[i]) {
|
||||
f.lightmap = nullptr;
|
||||
}
|
||||
}
|
||||
m.VBptr = nullptr;
|
||||
continue;
|
||||
}
|
||||
|
||||
t3dFACE &f = m.FList[0];
|
||||
for (uint32 j = 0; j < m.NumFaces(); j++) {
|
||||
// t3dU32 nr,ng,nb;
|
||||
if (f.n == b->NList[i]) {
|
||||
f.lightmap = nullptr;
|
||||
// if (Map==-1)
|
||||
if ((!(f.hasMaterialFlag(T3D_MATERIAL_OPACITY))) &&
|
||||
(!(f.hasMaterialFlag(T3D_MATERIAL_CLIPMAP))) &&
|
||||
(!(f.hasMaterialFlag(T3D_MATERIAL_BOTTLE))) &&
|
||||
(!(f.hasMaterialFlag(T3D_MATERIAL_ADDITIVE))) &&
|
||||
(!(f.hasMaterialFlag(T3D_MATERIAL_GLASS)))) {
|
||||
alphaval1 = RGBA_GETALPHA(gv[f.VertexIndex[0]].diffuse);
|
||||
alphaval2 = RGBA_GETALPHA(gv[f.VertexIndex[1]].diffuse);
|
||||
alphaval3 = RGBA_GETALPHA(gv[f.VertexIndex[2]].diffuse);
|
||||
gv[f.VertexIndex[0]].diffuse = RGBA_MAKE(rr, gg, bb, alphaval1);
|
||||
gv[f.VertexIndex[1]].diffuse = RGBA_MAKE(rr, gg, bb, alphaval2);
|
||||
gv[f.VertexIndex[2]].diffuse = RGBA_MAKE(rr, gg, bb, alphaval3);
|
||||
}
|
||||
}
|
||||
}
|
||||
// f->mat->Texture= nullptr;
|
||||
|
||||
m.VBptr = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32 i = 0; i < b->NumMeshes(); i++) {
|
||||
t3dMESH &m = b->MeshTable[i];
|
||||
m.VBptr = m.VertexBuffer;
|
||||
gv = m.VBptr;
|
||||
for (uint32 j = 0; j < m.NumVerts; j++) {
|
||||
t3dF32 u = stream->readFloatLE();
|
||||
t3dF32 v = stream->readFloatLE();
|
||||
|
||||
if ((RGBA_GETRED(gv[j].diffuse) == 254) &&
|
||||
(RGBA_GETGREEN(gv[j].diffuse) == 254) &&
|
||||
(RGBA_GETBLUE(gv[j].diffuse) == 254)) {
|
||||
gv[j].u2 = u;
|
||||
gv[j].v2 = v;
|
||||
gv[j].diffuse = RGBA_MAKE(255, 255, 255, RGBA_GETALPHA(gv[j].diffuse));
|
||||
|
||||
// gv[j].u2=(rand())%2;
|
||||
// gv[j].v2=(rand())%2;
|
||||
} else {
|
||||
gv[j].u2 = gv[j].u1;
|
||||
gv[j].v2 = gv[j].v1;
|
||||
}
|
||||
|
||||
// gv[j].diffuse=0xFFFFFFFF;
|
||||
// DebugLogWindow("%f %f",gv[j].u1,gv[j].v1);
|
||||
}
|
||||
m.VBptr = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/* -----------------10/06/99 16.04-------------------
|
||||
* t3dLoadSingleRoom
|
||||
* --------------------------------------------------*/
|
||||
t3dBODY *t3dBODY::loadFromStream(WGame &game, const Common::String &pname, Common::SeekableReadStream &stream, uint32 _LoaderFlags) {
|
||||
//decodeLoaderFlags(_LoaderFlags);
|
||||
//char /*t3dU8*/ Name[255];
|
||||
|
||||
uint16 light;
|
||||
t3dF32 minx, miny, minz, maxx, maxy, maxz;
|
||||
|
||||
WorkDirs &workdirs = game.workDirs;
|
||||
|
||||
this->name = pname;
|
||||
auto _name = constructPath(workdirs._t3dDir, pname);
|
||||
|
||||
this->NumTotVerts = 0;
|
||||
|
||||
this->AmbientLight = t3dV3F::fromStreamAsBytes(stream);
|
||||
int numMeshes = stream.readSint16LE(); // Legge globali del body
|
||||
int numMaterials = stream.readSint16LE();
|
||||
int numLights = stream.readSint16LE();
|
||||
int numPosLights = stream.readSint16LE();
|
||||
|
||||
this->NumNormals = stream.readSint32LE();
|
||||
this->NumVerticesNormals = stream.readSint32LE();
|
||||
this->allocateNormals();
|
||||
this->MatTable = rCreateMaterialList(numMaterials); // Crea Materiali Globali
|
||||
this->LightmapTable.clear();
|
||||
//-------------------LOADING MESHES--------------------------------------
|
||||
t3dMESH *ReceiveRipples = nullptr;
|
||||
uint8 Mirror = 0;
|
||||
t3dLoadMeshes(this, numMeshes, ReceiveRipples, Mirror, stream); // TODO: We probably don't need to pass ReceiveRipples, Mirror
|
||||
//-------------------END OF LOADING MESHES-------------------------------
|
||||
this->initNormals(stream);
|
||||
|
||||
//-------------------LOADING MATERIALS--------------------------------------
|
||||
t3dLoadMaterials(game, this, stream, numMaterials);
|
||||
//-------------------LOADING LIGHTS--------------------------------------
|
||||
this->LightTable.reserve(numLights); // Alloca spazio per le luci globali
|
||||
for (light = 0; light < numLights; light++) {
|
||||
this->LightTable.push_back(t3dLIGHT(game, this, workdirs, stream)); // Azzera luce
|
||||
}//__for_light
|
||||
//-------------------END OF LOADING LIGHTS-------------------------------
|
||||
|
||||
this->PosLightTable.clear();
|
||||
this->PosLightTable.reserve(numPosLights); // Alloca spazio per luci di posizione
|
||||
for (light = 0; light < numPosLights; light++) {
|
||||
this->PosLightTable.push_back(t3dPLIGHT(stream));
|
||||
}//__for_plight
|
||||
|
||||
//-------------------Extra optimization here-------------------------------
|
||||
#ifndef WMGEN
|
||||
if (ReceiveRipples) // Se c'era una mesh con i riples
|
||||
SetupWaterRipples(ReceiveRipples); // crea i buffers
|
||||
#endif
|
||||
|
||||
//-------------------Prelighting body-------------------------------
|
||||
for (uint16 i = 0; i < this->NumMeshes(); i++) { // Cerca in tutte le mesh
|
||||
this->MeshTable[i].preCalcLights(this->AmbientLight);
|
||||
}
|
||||
|
||||
#ifndef WMGEN
|
||||
t3dPrecalcLight(this, nullptr);
|
||||
#endif
|
||||
//----------------END OF VERTEX PRE-LIGHTING---------------------
|
||||
|
||||
populatePortalLists();
|
||||
|
||||
warning("LoaderFlags late = %08X", _LoaderFlags);
|
||||
//decodeLoaderFlags(_LoaderFlags);
|
||||
if (!(_LoaderFlags & T3D_NOBOUNDS)) { // Carica Bounds
|
||||
auto bndName = workdirs.join(workdirs._bndDir, pname, "bnd");
|
||||
loadBounds(game.workDirs, bndName.c_str(), this);
|
||||
}
|
||||
if (!(_LoaderFlags & T3D_NOCAMERAS)) { // Carica Camere
|
||||
auto cameraName = constructPath(workdirs._camDir, pname, "cam");
|
||||
LoadCameras(game.workDirs, cameraName.c_str(), this);
|
||||
}
|
||||
if (!(_LoaderFlags & T3D_NOLIGHTMAPS)) { // Carica le Lightmaps
|
||||
// TODO: This looks odd
|
||||
if (!pname.equalsIgnoreCase("rxt.t3d") || !pname.equalsIgnoreCase("rxt-b.t3d") || !pname.equalsIgnoreCase("rxt-c.t3d") ||
|
||||
!pname.equalsIgnoreCase("rxt-d.t3d") || !pname.equalsIgnoreCase("rxt-e.t3d") || !pname.equalsIgnoreCase("rxt.t3d-f"))
|
||||
LoadLightmaps(game, this);
|
||||
}
|
||||
if ((_LoaderFlags & T3D_OUTDOORLIGHTS)) { // Carica le luci per l'esterno
|
||||
if (pname.equalsIgnoreCase("rxt.t3d")) {
|
||||
auto outdoorLightsPath = constructPath(workdirs._lightmapsDir, pname);
|
||||
t3dLoadOutdoorLights(outdoorLightsPath.c_str(), this, t3dCurTime);
|
||||
}
|
||||
}
|
||||
if (!(_LoaderFlags & T3D_NOVOLUMETRICLIGHTS)) { // Carica le luci volumetriche
|
||||
auto volMapPath = constructPath(workdirs._lightmapsDir, pname, "vol");
|
||||
LoadVolumetricMap(workdirs, volMapPath.c_str(), this);
|
||||
}
|
||||
|
||||
GetBoundaries(this, &minx, &miny, &minz, &maxx, &maxy, &maxz); // Calcola occupazione stanza
|
||||
this->MinPos.x = minx; // Salva il minimo per le luci volumetriche
|
||||
this->MinPos.y = miny;
|
||||
this->MinPos.z = minz;
|
||||
|
||||
#ifndef WMGEN
|
||||
for (uint16 i = 0; i < this->NumMeshes(); i++) { // Scorre le mesh
|
||||
this->MeshTable[i].saveVertexBuffer();
|
||||
}
|
||||
#endif
|
||||
|
||||
t3dOptimizeMaterialList(this); // Ottimizza la lista dei metriali (evitando i doppi)
|
||||
#ifndef WMGEN
|
||||
t3dFinalizeMaterialList(this); // Crea VB e indici per materiali
|
||||
#endif
|
||||
|
||||
if (Mirror) { // Se c'era uno specchio
|
||||
this->MirrorMatTable = rCreateMaterialList(this->NumMaterials());
|
||||
rCopyMaterialList(this->MirrorMatTable, this->MatTable, this->NumMaterials());
|
||||
}
|
||||
|
||||
|
||||
//f
|
||||
#ifndef WMGEN
|
||||
for (uint16 i = 0; i < this->NumMeshes(); i++) { // Cancella le normali
|
||||
if (this->MeshTable[i].ModVertices.empty()) // dalle mesh con Smoothing groups
|
||||
continue;
|
||||
for (uint16 j = 0; j < this->MeshTable[i].NumFaces(); j++) {
|
||||
this->MeshTable[i].FList[j].n = nullptr;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
//f
|
||||
return this;
|
||||
}
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
108
engines/watchmaker/3d/t3d_body.h
Normal file
108
engines/watchmaker/3d/t3d_body.h
Normal file
@@ -0,0 +1,108 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef WATCHMAKER_T3D_BODY_H
|
||||
#define WATCHMAKER_T3D_BODY_H
|
||||
|
||||
#include "watchmaker/types.h"
|
||||
#include "watchmaker/t3d.h"
|
||||
#include "watchmaker/3d/t3d_mesh.h"
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
struct t3dBODY {
|
||||
Common::String name; // room name
|
||||
uint32 NumMeshes() {
|
||||
return MeshTable.size();
|
||||
}; // num meshes
|
||||
uint32 NumCameras() const {
|
||||
return CameraTable.size(); // num cameras
|
||||
}
|
||||
uint16 NumPaths() const {
|
||||
return CameraPath.size(); // num camera paths
|
||||
}
|
||||
uint32 NumLights() const {
|
||||
return LightTable.size(); // num lights
|
||||
}
|
||||
uint16 NumPanels[T3D_MAX_LEVELS] = {}; // num panels per level
|
||||
uint16 NumNormals = 0; // num face normals
|
||||
uint16 NumVerticesNormals = 0; // num vertex normals
|
||||
uint16 NumPosLights() const {
|
||||
return PosLightTable.size();
|
||||
}; // num positional lights
|
||||
uint16 NumLevels = 0; // num panel levels
|
||||
uint16 CurLevel = 0; // current level
|
||||
uint32 NumTotVerts = 0; // total number of verts in room
|
||||
t3dV3F AmbientLight; // room ambient color
|
||||
Common::Array<t3dMESH> MeshTable; // meshes list
|
||||
MaterialTable MatTable; // materials list
|
||||
uint32 NumMaterials() const {
|
||||
return MatTable.size(); // num materials
|
||||
}
|
||||
MaterialTable LightmapTable; // lightmap material list
|
||||
uint32 NumLightmaps = 0; // num lightmap materials
|
||||
MaterialTable MirrorMatTable; // material list (for mirrors)
|
||||
uint32 NumMirrorMaterials() const {
|
||||
return MirrorMatTable.size();
|
||||
}; // num materials (for mirror)
|
||||
private:
|
||||
Common::Array<Common::SharedPtr<VertexBuffer>> VBTable; // metrial vertex buffers list
|
||||
public:
|
||||
Common::SharedPtr<VertexBuffer> addVertexBuffer() {
|
||||
VBTable.push_back(Common::SharedPtr<VertexBuffer>(new VertexBuffer()));
|
||||
return VBTable.back();
|
||||
}
|
||||
void clearVBTable() {
|
||||
for (uint i = 0; i < VBTable.size(); i++) {
|
||||
rDeleteVertexBuffer(*VBTable[i]);
|
||||
}
|
||||
VBTable.clear();
|
||||
}
|
||||
uint32 NumVB() {
|
||||
return VBTable.size();
|
||||
}; // num vertex buffer
|
||||
public:
|
||||
Common::Array<t3dCAMERA> CameraTable; // camera list
|
||||
Common::Array<t3dLIGHT> LightTable; // light list
|
||||
Common::Array<t3dPLIGHT> PosLightTable; // positional light list
|
||||
NormalList NList; // normal list
|
||||
t3dCAMERAGRID CameraGrid; // camera grid
|
||||
Common::Array<t3dCAMERAPATH> CameraPath; // camer paths list
|
||||
t3dPAN *Panel[T3D_MAX_LEVELS] = {}; // room panels for level
|
||||
t3dF32 PanelHeight[T3D_MAX_LEVELS] = {}; // panel height for levels
|
||||
Common::SharedPtr<t3dVolLights> VolumetricLights; // volumetric lights
|
||||
t3dMESH *BlockMeshes[T3D_MAX_BLOCK_MESHES] = {}; // block mesh (for external rooms)
|
||||
t3dV3F MinPos; // min room position
|
||||
private:
|
||||
void allocateNormals();
|
||||
void initNormals(Common::SeekableReadStream &stream);
|
||||
public:
|
||||
t3dCAMERA *PickCamera(uint8 in);
|
||||
Common::Array<t3dPLIGHT> getPositionalLight(uint8 pos);
|
||||
|
||||
t3dBODY *loadFromStream(WGame &game, const Common::String &pname, Common::SeekableReadStream &stream, uint32 LoaderFlags);
|
||||
void populatePortalLists();
|
||||
};
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
|
||||
#endif // WATCHMAKER_T3D_BODY_H
|
||||
66
engines/watchmaker/3d/t3d_face.cpp
Normal file
66
engines/watchmaker/3d/t3d_face.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
/* 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 "common/stream.h"
|
||||
#include "watchmaker/3d/t3d_face.h"
|
||||
#include "watchmaker/3d/t3d_body.h"
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
t3dFACE::t3dFACE(t3dBODY *b, Common::SeekableReadStream &stream) {
|
||||
VertexIndex[0] = stream.readSint16LE(); // Legge VertexIndex0
|
||||
VertexIndex[1] = stream.readSint16LE(); // Legge VertexIndex1
|
||||
VertexIndex[2] = stream.readSint16LE(); // Legge VertexIndex2
|
||||
|
||||
this->n = b->NList[stream.readSint16LE()]; // Legge puntatore a normale
|
||||
|
||||
_materialIndex = stream.readSint16LE(); // Legge indice materiale
|
||||
_body = b;
|
||||
}
|
||||
|
||||
bool t3dFACE::isVisible() const {
|
||||
if (!n)
|
||||
return true;
|
||||
else if (n->flag != T3D_NORMAL_VISIBLE)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
MaterialPtr t3dFACE::getMaterial() {
|
||||
if (_mat) {
|
||||
return _mat;
|
||||
} else {
|
||||
_mat = _body->MatTable[_materialIndex];
|
||||
return _mat;
|
||||
}
|
||||
}
|
||||
|
||||
const gMaterial *t3dFACE::getMaterial() const {
|
||||
if (_mat) {
|
||||
return _mat.get();
|
||||
} else {
|
||||
error("t3dFACE::getMaterial(): No material loaded");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
78
engines/watchmaker/3d/t3d_face.h
Normal file
78
engines/watchmaker/3d/t3d_face.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WATCHMAKER_T3D_FACE_H
|
||||
#define WATCHMAKER_T3D_FACE_H
|
||||
|
||||
#include "watchmaker/3d/types3d.h"
|
||||
#include "watchmaker/3d/material.h"
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
struct t3dBODY;
|
||||
struct t3dFACE {
|
||||
uint32 flags = 0; // face status 4
|
||||
NormalPtr n; // pointer to the face normal 4
|
||||
private:
|
||||
int16 MatVertexIndex[3] = {}; // Vertices indices in material 6
|
||||
uint16 _materialIndex = 0;
|
||||
MaterialPtr _mat = nullptr; // pointer to material 4
|
||||
t3dBODY *_body = nullptr;
|
||||
public:
|
||||
int16 VertexIndex[3] = {}; // Vertices indices in mesh 6
|
||||
|
||||
void setMatVertexIndex(int index, int16 value) {
|
||||
MatVertexIndex[index] = value;
|
||||
}
|
||||
uint16 getMatVertexIndex(int index) {
|
||||
return MatVertexIndex[index];
|
||||
}
|
||||
public:
|
||||
MaterialPtr lightmap; // pointer to lightmap (or 2nd material) 4
|
||||
|
||||
t3dFACE(t3dBODY *b, Common::SeekableReadStream &stream);
|
||||
|
||||
bool hasMaterialFlag(uint32 flag) {
|
||||
return getMaterial()->hasFlag(flag);
|
||||
}
|
||||
MaterialPtr getMaterial();
|
||||
const gMaterial *getMaterial() const;
|
||||
uint16 getMaterialIndex() const {
|
||||
return _materialIndex;
|
||||
}
|
||||
void setMaterialIndex(uint32 index) {
|
||||
_materialIndex = index;
|
||||
_mat = nullptr;
|
||||
getMaterial();
|
||||
}
|
||||
|
||||
void checkVertices() {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
assert((int)getMaterial()->VertsList.size() > MatVertexIndex[i]);
|
||||
}
|
||||
}
|
||||
|
||||
bool isVisible() const;
|
||||
};
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
|
||||
#endif // SCUMMVM_T3D_FACE_H
|
||||
424
engines/watchmaker/3d/t3d_mesh.cpp
Normal file
424
engines/watchmaker/3d/t3d_mesh.cpp
Normal file
@@ -0,0 +1,424 @@
|
||||
/* 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/3d/t3d_mesh.h"
|
||||
#include "watchmaker/3d/t3d_body.h"
|
||||
#include "watchmaker/3d/math/llmath.h"
|
||||
#include "watchmaker/3d/loader.h"
|
||||
#include "watchmaker/ll/ll_system.h"
|
||||
#include "watchmaker/3d/geometry.h"
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
void t3dMESH::loadFaces(t3dBODY *b, Common::SeekableReadStream &stream, int numFaces) {
|
||||
//Mesh[mesh].FList = new t3dFACE[Mesh[mesh].NumFaces]{}; // Alloca facce
|
||||
|
||||
this->FList.reserve(numFaces); // Legge numero facce mesh
|
||||
for (uint16 face = 0; face < numFaces; face++) {
|
||||
FList.push_back(t3dFACE(b, stream));
|
||||
}//__for_face
|
||||
}
|
||||
|
||||
t3dMESH::t3dMESH(t3dBODY *b, Common::SeekableReadStream &stream, t3dMESH *&ReceiveRipples, uint8 &Mirror) {
|
||||
t3dMatIdentity(&Matrix); // Setta matrice identica
|
||||
|
||||
this->DefaultAnim.NumBones = this->DefaultAnim.NumFrames = 0;
|
||||
this->Anim.NumBones = this->Anim.NumFrames = 0;
|
||||
|
||||
char stringBuffer[T3D_NAMELEN + 1] = {};
|
||||
stream.read(stringBuffer, T3D_NAMELEN); // Legge nome mesh
|
||||
this->name = stringBuffer;
|
||||
stream.read(stringBuffer, T3D_NAMELEN); // Legge nome portale
|
||||
this->portalName = stringBuffer;
|
||||
|
||||
int numFaces = stream.readSint16LE(); // Legge numero facce mesh
|
||||
|
||||
t3dVectFill(&this->Trasl, 0.0f);
|
||||
this->Pos = t3dV3F(stream) * SCALEFACTOR;
|
||||
this->Radius = stream.readFloatLE() * SCALEFACTOR; // Legge raggio boundsphere
|
||||
|
||||
//this->LightmapDim=(t3dU16)t3dRead8();
|
||||
uint8 SaveMipStatus = stream.readByte(); // Legge dimensione lightmap
|
||||
this->LightmapDim = SaveMipStatus;
|
||||
if (this->LightmapDim == 255)
|
||||
this->LightmapDim = 256;
|
||||
if (this->LightmapDim == 0) { // Se non e' specificata
|
||||
if ((this->name[0] == 'o') || (this->name[0] == 'O')) // decide in base al nome
|
||||
this->LightmapDim = 8;
|
||||
else if ((this->name[0] == 'p') || (this->name[0] == 'P'))
|
||||
this->LightmapDim = 16;
|
||||
}
|
||||
if (this->LightmapDim > 256) { // Se > 256, errore
|
||||
this->LightmapDim = 256;
|
||||
warning("ATTENTION: Lightmap dim >256 on mesh %s!!!", this->name.c_str());
|
||||
warning("Check and verify .t3d");
|
||||
}
|
||||
|
||||
this->Flags = stream.readSint32LE(); // Legge flags
|
||||
// if ( !strcasecmp( "pxt-musoleoBUCO", this->Name ) );
|
||||
if (this->Flags & T3D_MESH_MIRROR) // Incrementa numero mirror
|
||||
Mirror++;
|
||||
// if( this->Flags&T3D_MESH_PORTAL)
|
||||
// this->Flags|=T3D_MESH_PORTAL;
|
||||
if ((this->Flags & T3D_MESH_RECEIVERIPPLES) || // Aggiunge buffer per le onde
|
||||
(this->Flags & T3D_MESH_POOLWATER))
|
||||
ReceiveRipples = this;
|
||||
if (this->Flags & T3D_MESH_WAVESTEXTURE) { // Legge informazioni sulle onde
|
||||
this->WavesSpeed = (t3dF32)stream.readSint32LE() / 10000.0f;
|
||||
this->YSpeed = (t3dF32)stream.readSint32LE() / 100.0f;
|
||||
}
|
||||
if (this->Flags & T3D_MESH_SOLARVARIATION) { // Legge informazioni sulla variazione solare
|
||||
this->SolarRGBVar[0].x = (t3dF32)stream.readSint16LE() / 100.0f;
|
||||
this->SolarRGBVar[0].y = (t3dF32)stream.readSint16LE() / 100.0f;
|
||||
this->SolarRGBVar[0].z = (t3dF32)stream.readSint16LE() / 100.0f;
|
||||
this->SolarRGBVar[1].x = 1.0f;
|
||||
this->SolarRGBVar[1].y = 1.0f;
|
||||
this->SolarRGBVar[1].z = 1.0f;
|
||||
this->SolarRGBVar[2].x = (t3dF32)stream.readSint16LE() / 100.0f;
|
||||
this->SolarRGBVar[2].y = (t3dF32)stream.readSint16LE() / 100.0f;
|
||||
this->SolarRGBVar[2].z = (t3dF32)stream.readSint16LE() / 100.0f;
|
||||
this->SolarRGBVar[3].x = (t3dF32)stream.readSint16LE() / 100.0f;
|
||||
this->SolarRGBVar[3].y = (t3dF32)stream.readSint16LE() / 100.0f;
|
||||
this->SolarRGBVar[3].z = (t3dF32)stream.readSint16LE() / 100.0f;
|
||||
}
|
||||
{
|
||||
uint16 n = stream.readSint32LE();
|
||||
if (n)
|
||||
this->XInc = 1.0f / (t3dF32) n; // Legge info su movimenti texture
|
||||
else this->XInc = 0.0f;
|
||||
n = stream.readSint32LE();
|
||||
if (n) this->YInc = 1.0f / (t3dF32) n;
|
||||
else this->YInc = 0.0f;
|
||||
}
|
||||
this->CurFrame = 0;
|
||||
|
||||
this->loadFaces(b, stream, numFaces);
|
||||
|
||||
this->NumVerts = stream.readSint16LE(); // Rilegge numero vertici
|
||||
b->NumTotVerts += this->NumVerts;
|
||||
|
||||
#ifndef WMGEN
|
||||
this->VertexBuffer = new gVertex[this->NumVerts](); // Crea un VertexBuffer
|
||||
this->VBptr = this->VertexBuffer;
|
||||
#else
|
||||
this->VBptr = (gVertex *)t3dMalloc(sizeof(gVertex) * this->NumVerts);
|
||||
#endif
|
||||
for (uint16 i = 0; i < this->NumVerts; i++) {
|
||||
this->VBptr[i].x = stream.readFloatLE(); // Legge X
|
||||
this->VBptr[i].y = stream.readFloatLE(); // Legge Y
|
||||
this->VBptr[i].z = stream.readFloatLE(); // Legge Z
|
||||
this->VBptr[i].u1 = stream.readFloatLE(); // Legge U
|
||||
this->VBptr[i].v1 = stream.readFloatLE(); // Legge V
|
||||
uint16 n = stream.readSint16LE(); // Legge indice normale
|
||||
this->VBptr[i].diffuse = n; //temporary storage for normal index
|
||||
}
|
||||
#ifndef WMGEN
|
||||
this->VBptr = nullptr;
|
||||
#endif
|
||||
this->NList = b->NList; // Lista di normali e' quella globale
|
||||
|
||||
int numMorphFrames = stream.readSint16LE(); // Legge frame di espressioni
|
||||
if (numMorphFrames) { // Se frame di espressioni
|
||||
this->MorphFrames.reserve(numMorphFrames); // Alloca spazio
|
||||
for (int i = 0; i < numMorphFrames; i++) {
|
||||
this->MorphFrames.push_back(t3dMORPH(stream));
|
||||
}
|
||||
}
|
||||
// Bounding box vertices
|
||||
//
|
||||
// 4 5
|
||||
// *-------*
|
||||
//0*-----1*/|
|
||||
// | 6 | |
|
||||
// |/*----+-*7
|
||||
// *------*/
|
||||
//2 3
|
||||
for (uint16 normal = 0; normal < 8; normal++) { // Legge BoundingBox
|
||||
this->BBox[normal].p = t3dV3F(stream) * SCALEFACTOR;
|
||||
}//__for_normal
|
||||
if ((this->BBox[0].p == this->BBox[4].p) && // Se non ha spessore
|
||||
(this->BBox[1].p == this->BBox[5].p) &&
|
||||
(this->BBox[2].p == this->BBox[6].p) &&
|
||||
(this->BBox[3].p == this->BBox[7].p)) {
|
||||
t3dV3F sub;
|
||||
sub.x = sub.y = sub.z = 5.0f;
|
||||
t3dVectSub(&this->BBox[0].p, &this->BBox[0].p, &sub); // Aggiunge 5 di spessore
|
||||
t3dVectSub(&this->BBox[1].p, &this->BBox[1].p, &sub);
|
||||
t3dVectSub(&this->BBox[2].p, &this->BBox[2].p, &sub);
|
||||
t3dVectSub(&this->BBox[3].p, &this->BBox[3].p, &sub);
|
||||
}
|
||||
|
||||
// Calcs the BBox normals
|
||||
t3dPlaneNormal(&this->BBoxNormal[0], &this->BBox[0].p, &this->BBox[2].p, &this->BBox[1].p); //front
|
||||
t3dPlaneNormal(&this->BBoxNormal[1], &this->BBox[4].p, &this->BBox[5].p, &this->BBox[6].p); //back
|
||||
t3dPlaneNormal(&this->BBoxNormal[2], &this->BBox[4].p, &this->BBox[0].p, &this->BBox[5].p); //Up
|
||||
t3dPlaneNormal(&this->BBoxNormal[3], &this->BBox[6].p, &this->BBox[7].p, &this->BBox[2].p); //Down
|
||||
t3dPlaneNormal(&this->BBoxNormal[4], &this->BBox[4].p, &this->BBox[6].p, &this->BBox[0].p); //Left
|
||||
t3dPlaneNormal(&this->BBoxNormal[5], &this->BBox[5].p, &this->BBox[1].p, &this->BBox[7].p); //Right
|
||||
this->BBoxAverageZ = 0; // Azzera distanza media
|
||||
uint32 numAniVerts = stream.readSint32LE();
|
||||
if (numAniVerts > 0) { // Se ci sono Smoothing Groups
|
||||
this->OldVertexBuffer = new gVertex[this->NumVerts]; // Crea un OldVertexBuffer
|
||||
this->SavedVertexBuffer = new gVertex[this->NumVerts]; // Crea un SavedVertexBuffer
|
||||
this->VertsInterpolants = t3dCalloc<t3dV3F>(this->NumVerts); // Crea spazio per interpolanti
|
||||
|
||||
this->ModVertices.reserve(numAniVerts);
|
||||
for (uint32 i = 0; i < numAniVerts; i++) {
|
||||
this->ModVertices.push_back(t3dMODVERTS(stream));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
t3dMESH &t3dMESH::operator=(t3dMESH rhs) {
|
||||
SWAP(name, rhs.name);
|
||||
SWAP(portalName, rhs.portalName);
|
||||
SWAP(NumVerts, rhs.NumVerts);
|
||||
SWAP(NumNormals, rhs.NumNormals);
|
||||
SWAP(NumVerticesNormals, rhs.NumVerticesNormals);
|
||||
SWAP(SavedVertexBuffer, rhs.SavedVertexBuffer);
|
||||
SWAP(VertexBuffer, rhs.VertexBuffer);
|
||||
SWAP(OldVertexBuffer, rhs.OldVertexBuffer);
|
||||
SWAP(VertsInterpolants, rhs.VertsInterpolants);
|
||||
SWAP(VBptr, rhs.VBptr);
|
||||
SWAP(MorphFrames, rhs.MorphFrames);
|
||||
SWAP(FList, rhs.FList);
|
||||
SWAP(NList, rhs.NList);
|
||||
SWAP(Pos, rhs.Pos);
|
||||
SWAP(Trasl, rhs.Trasl);
|
||||
SWAP(Radius, rhs.Radius);
|
||||
SWAP(BBoxAverageZ, rhs.BBoxAverageZ);
|
||||
SWAP(Intersection, rhs.Intersection);
|
||||
SWAP(Matrix, rhs.Matrix);
|
||||
SWAP(LightmapDim, rhs.LightmapDim);
|
||||
SWAP(ModVertices, rhs.ModVertices);
|
||||
SWAP(CurFrame, rhs.CurFrame);
|
||||
SWAP(LastFrame, rhs.LastFrame);
|
||||
SWAP(BlendPercent, rhs.BlendPercent);
|
||||
SWAP(LastBlendPercent, rhs.LastBlendPercent);
|
||||
SWAP(ExpressionFrame, rhs.ExpressionFrame);
|
||||
SWAP(LastExpressionFrame, rhs.LastExpressionFrame);
|
||||
SWAP(DefaultAnim, rhs.DefaultAnim);
|
||||
SWAP(Anim, rhs.Anim);
|
||||
SWAP(WaterBuffer1, rhs.WaterBuffer1);
|
||||
SWAP(WaterBuffer2, rhs.WaterBuffer2);
|
||||
SWAP(WavesSpeed, rhs.WavesSpeed);
|
||||
SWAP(YSpeed, rhs.YSpeed);
|
||||
SWAP(XInc, rhs.XInc);
|
||||
SWAP(YInc, rhs.YInc);
|
||||
SWAP(Flags, rhs.Flags);
|
||||
SWAP(PortalList, rhs.PortalList);
|
||||
SWAP(RejectedMeshes, rhs.RejectedMeshes);
|
||||
|
||||
Common::copy(rhs.BBox, rhs.BBox + 8, BBox);
|
||||
Common::copy(rhs.BBoxNormal, rhs.BBoxNormal + 6, BBoxNormal);
|
||||
Common::copy(rhs.SolarRGBVar, rhs.SolarRGBVar + 4, SolarRGBVar);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
t3dMESH::t3dMESH(const t3dMESH &other) :
|
||||
name(other.name),
|
||||
portalName(other.portalName),
|
||||
NumVerts(other.NumVerts),
|
||||
NumNormals(other.NumNormals),
|
||||
NumVerticesNormals(other.NumVerticesNormals),
|
||||
SavedVertexBuffer(nullptr),
|
||||
VertexBuffer(new gVertex[other.NumVerts]()),
|
||||
OldVertexBuffer(nullptr),
|
||||
VertsInterpolants(nullptr),
|
||||
VBptr(other.VBptr),
|
||||
MorphFrames(other.MorphFrames),
|
||||
FList(other.FList),
|
||||
NList(other.NList),
|
||||
Pos(other.Pos),
|
||||
Trasl(other.Trasl),
|
||||
Radius(other.Radius),
|
||||
BBoxAverageZ(other.BBoxAverageZ),
|
||||
Intersection(other.Intersection),
|
||||
Matrix(other.Matrix),
|
||||
LightmapDim(other.LightmapDim),
|
||||
ModVertices(other.ModVertices),
|
||||
CurFrame(other.CurFrame),
|
||||
LastFrame(other.LastFrame),
|
||||
BlendPercent(other.BlendPercent),
|
||||
LastBlendPercent(other.LastBlendPercent),
|
||||
ExpressionFrame(other.ExpressionFrame),
|
||||
LastExpressionFrame(other.LastExpressionFrame),
|
||||
DefaultAnim(other.DefaultAnim),
|
||||
Anim(other.Anim),
|
||||
WaterBuffer1(other.WaterBuffer1),
|
||||
WaterBuffer2(other.WaterBuffer2),
|
||||
WavesSpeed(other.WavesSpeed),
|
||||
YSpeed(other.YSpeed),
|
||||
XInc(other.XInc),
|
||||
YInc(other.YInc),
|
||||
Flags(other.Flags),
|
||||
PortalList(other.PortalList),
|
||||
RejectedMeshes(other.RejectedMeshes) {
|
||||
|
||||
Common::copy(other.VertexBuffer, other.VertexBuffer + NumVerts, VertexBuffer);
|
||||
if (other.SavedVertexBuffer) {
|
||||
SavedVertexBuffer = new gVertex[other.NumVerts]();
|
||||
Common::copy(other.SavedVertexBuffer, other.SavedVertexBuffer + NumVerts, SavedVertexBuffer);
|
||||
}
|
||||
if (other.OldVertexBuffer) {
|
||||
OldVertexBuffer = new gVertex[other.NumVerts]();
|
||||
Common::copy(other.OldVertexBuffer, other.OldVertexBuffer + NumVerts, OldVertexBuffer);
|
||||
}
|
||||
if (other.VertsInterpolants) {
|
||||
VertsInterpolants = t3dCalloc<t3dV3F>(NumVerts);
|
||||
Common::copy(other.VertsInterpolants, other.VertsInterpolants + NumVerts, VertsInterpolants);
|
||||
}
|
||||
Common::copy(other.BBox, other.BBox + 8, BBox);
|
||||
Common::copy(other.BBoxNormal, other.BBoxNormal + 6, BBoxNormal);
|
||||
Common::copy(other.SolarRGBVar, other.SolarRGBVar + 4, SolarRGBVar);
|
||||
}
|
||||
|
||||
|
||||
t3dMESH::t3dMESH(t3dMESH &&old) :
|
||||
name(Common::move(old.name)),
|
||||
portalName(Common::move(old.portalName)),
|
||||
NumVerts(old.NumVerts),
|
||||
NumNormals(old.NumNormals),
|
||||
NumVerticesNormals(old.NumVerticesNormals),
|
||||
SavedVertexBuffer(old.SavedVertexBuffer),
|
||||
VertexBuffer(old.VertexBuffer),
|
||||
OldVertexBuffer(old.OldVertexBuffer),
|
||||
VertsInterpolants(old.VertsInterpolants),
|
||||
VBptr(old.VBptr),
|
||||
MorphFrames(Common::move(old.MorphFrames)),
|
||||
FList(Common::move(old.FList)),
|
||||
NList(Common::move(old.NList)),
|
||||
Pos(Common::move(old.Pos)),
|
||||
Trasl(Common::move(old.Trasl)),
|
||||
Radius(old.Radius),
|
||||
BBoxAverageZ(old.BBoxAverageZ),
|
||||
Intersection(Common::move(old.Intersection)),
|
||||
Matrix(Common::move(old.Matrix)),
|
||||
LightmapDim(old.LightmapDim),
|
||||
ModVertices(Common::move(old.ModVertices)),
|
||||
CurFrame(old.CurFrame),
|
||||
LastFrame(old.LastFrame),
|
||||
BlendPercent(old.BlendPercent),
|
||||
LastBlendPercent(old.LastBlendPercent),
|
||||
ExpressionFrame(old.ExpressionFrame),
|
||||
LastExpressionFrame(old.LastExpressionFrame),
|
||||
DefaultAnim(Common::move(old.DefaultAnim)),
|
||||
Anim(Common::move(old.Anim)),
|
||||
WaterBuffer1(old.WaterBuffer1),
|
||||
WaterBuffer2(old.WaterBuffer2),
|
||||
WavesSpeed(old.WavesSpeed),
|
||||
YSpeed(old.YSpeed),
|
||||
XInc(old.XInc),
|
||||
YInc(old.YInc),
|
||||
Flags(old.Flags),
|
||||
PortalList(old.PortalList),
|
||||
RejectedMeshes(Common::move(old.RejectedMeshes)) {
|
||||
|
||||
old.SavedVertexBuffer = nullptr;
|
||||
old.VertexBuffer = nullptr;
|
||||
old.OldVertexBuffer = nullptr;
|
||||
old.VertsInterpolants = nullptr;
|
||||
old.VBptr = nullptr;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
BBox[i] = Common::move(old.BBox[i]);
|
||||
}
|
||||
for (int i = 0; i < 6; i++) {
|
||||
BBoxNormal[i] = Common::move(old.BBoxNormal[i]);
|
||||
}
|
||||
old.WaterBuffer1 = nullptr;
|
||||
old.WaterBuffer2 = nullptr;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
SolarRGBVar[i] = Common::move(old.SolarRGBVar[i]);
|
||||
}
|
||||
}
|
||||
|
||||
t3dMESH::~t3dMESH() {
|
||||
release();
|
||||
}
|
||||
|
||||
/* -----------------10/06/99 15.39-------------------
|
||||
* t3dReleaseAnim
|
||||
* --------------------------------------------------*/
|
||||
void t3dMESH::releaseAnim(uint8 flag) {
|
||||
t3dBONEANIM *ba;
|
||||
uint32 i;
|
||||
|
||||
if (flag & T3D_MESH_DEFAULTANIM)
|
||||
ba = &this->DefaultAnim;
|
||||
else
|
||||
ba = &this->Anim;
|
||||
|
||||
if (!ba)
|
||||
return ;
|
||||
|
||||
for (i = 0; i < ba->NumBones; i++) {
|
||||
if (ba->BoneTable && ba->BoneTable[i].Matrix) {
|
||||
t3dFree(ba->BoneTable[i].Matrix);
|
||||
ba->BoneTable[i].Matrix = nullptr;
|
||||
t3dFree(ba->BoneTable[i].Trasl);
|
||||
ba->BoneTable[i].Trasl = nullptr;
|
||||
ba->BoneTable[i].ModVertices.clear();
|
||||
}
|
||||
}
|
||||
|
||||
t3dFree(ba->BoneTable);
|
||||
ba->BoneTable = nullptr;
|
||||
delete[] ba->Dist;
|
||||
ba->Dist = nullptr;
|
||||
}
|
||||
|
||||
void t3dMESH::release() { // Will eventually be a destructor.
|
||||
this->FList.clear();
|
||||
|
||||
this->MorphFrames.clear();
|
||||
this->NList.clear();
|
||||
|
||||
releaseAnim(0);
|
||||
releaseAnim(T3D_MESH_DEFAULTANIM);
|
||||
|
||||
this->RejectedMeshes.clear();
|
||||
this->PortalList = nullptr;
|
||||
|
||||
delete[] this->WaterBuffer1;
|
||||
this->WaterBuffer1 = nullptr;
|
||||
|
||||
delete[] this->WaterBuffer2;
|
||||
this->WaterBuffer2 = nullptr;
|
||||
|
||||
delete[] this->VertexBuffer;
|
||||
this->VertexBuffer = nullptr;
|
||||
|
||||
delete[] this->OldVertexBuffer;
|
||||
this->OldVertexBuffer = nullptr;
|
||||
|
||||
delete[] this->SavedVertexBuffer;
|
||||
this->SavedVertexBuffer = nullptr;
|
||||
|
||||
t3dFree(this->VertsInterpolants);
|
||||
this->VertsInterpolants = nullptr;
|
||||
|
||||
// if(mt->VBptr)
|
||||
// t3dFree(mt->VBptr);
|
||||
this->VBptr = nullptr;
|
||||
}
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
170
engines/watchmaker/3d/t3d_mesh.h
Normal file
170
engines/watchmaker/3d/t3d_mesh.h
Normal file
@@ -0,0 +1,170 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WATCHMAKER_T3D_MESH_H
|
||||
#define WATCHMAKER_T3D_MESH_H
|
||||
|
||||
#include "watchmaker/3d/t3d_face.h"
|
||||
#include "watchmaker/t3d.h"
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
struct t3dMESH {
|
||||
Common::String name; // mesh name
|
||||
Common::String portalName; // dest room name (if portal)
|
||||
uint16 NumFaces() {
|
||||
return FList.size();
|
||||
}; // faces number
|
||||
uint16 NumVerts = 0; // verts number
|
||||
uint16 NumNormals = 0; // face normals number
|
||||
uint16 NumVerticesNormals = 0; // verts normals number
|
||||
gVertex *SavedVertexBuffer = nullptr; // saved vertices pos (original)
|
||||
gVertex *VertexBuffer = nullptr; // cur vertices pos
|
||||
gVertex *OldVertexBuffer = nullptr; // last vertices pos
|
||||
t3dV3F *VertsInterpolants = nullptr; // verts interpolants (for blending)
|
||||
gVertex *VBptr = nullptr; // temp pointer to vertexbuffer
|
||||
Common::Array<t3dMORPH> MorphFrames; // morph frames list
|
||||
Common::Array<t3dFACE> FList; // faces list
|
||||
NormalList NList; // normals list
|
||||
t3dV3F Pos; // mesh center
|
||||
t3dV3F Trasl; // mesh traslation (world)
|
||||
t3dF32 Radius = 0.0f; // radius for Bounding Sphere culling
|
||||
t3dVERTEX BBox[8] = {}; // Bounding box
|
||||
t3dNORMAL BBoxNormal[6] = {}; // bound box normals
|
||||
t3dF32 BBoxAverageZ = 0.0f; // average distance from eye
|
||||
t3dV3F Intersection; // intersecton form eye
|
||||
t3dM3X3F Matrix; // transformation matrix (useful only for 1st mesh in body)
|
||||
uint16 LightmapDim = 0; // lightmap texture dimensions
|
||||
Common::Array<t3dMODVERTS> ModVertices; // mod vertices list
|
||||
t3dBONEANIM DefaultAnim; // Default Animations
|
||||
t3dBONEANIM Anim; // Animations
|
||||
int16 CurFrame = 0; // current animation frames (0 no anim)
|
||||
int16 LastFrame = 0; // last animation frames
|
||||
uint8 BlendPercent = 0; // blend animation percentage
|
||||
uint8 LastBlendPercent = 0; // last blend animation percentage
|
||||
uint32 ExpressionFrame = 0; // current expression frames
|
||||
uint32 LastExpressionFrame = 0; // last expression frames
|
||||
int32 *WaterBuffer1 = nullptr; // pointers to ripple buffer
|
||||
int32 *WaterBuffer2 = nullptr; // pointers to ripple buffer
|
||||
t3dF32 WavesSpeed; // waves speed
|
||||
t3dF32 YSpeed; // waves y speed
|
||||
t3dF32 XInc, YInc; // waves movements
|
||||
|
||||
t3dV3F SolarRGBVar[4]; // Override ambient color variation for solar movement
|
||||
|
||||
uint32 Flags; // Flags
|
||||
t3dBODY *PortalList = nullptr; // Pointer to portal connected
|
||||
Common::Array<t3dMESH *> RejectedMeshes; // rejected mesh from portal
|
||||
|
||||
void saveVertexBuffer() { // Scorre le mesh
|
||||
this->VBptr = this->VertexBuffer;
|
||||
if (this->OldVertexBuffer)
|
||||
memcpy(this->OldVertexBuffer, this->VBptr, sizeof(gVertex)*this->NumVerts);
|
||||
if (this->SavedVertexBuffer)
|
||||
memcpy(this->SavedVertexBuffer, this->VBptr, sizeof(gVertex)*this->NumVerts);
|
||||
this->VBptr = nullptr;
|
||||
}
|
||||
|
||||
void preCalcLights(const t3dV3F &ambientLight) {
|
||||
#ifndef WMGEN
|
||||
this->VBptr = this->VertexBuffer;
|
||||
#endif
|
||||
for (uint16 j = 0; j < this->NumFaces(); j++) { // Scorre le facce
|
||||
t3dFACE &Face = this->FList[j];
|
||||
MaterialPtr Material = Face.getMaterial();
|
||||
uint32 alphaval = 2;
|
||||
uint32 rr = 0, gg = 0, bb = 0;
|
||||
|
||||
rr = Material->r; // Prende Ambient da materiale
|
||||
gg = Material->g;
|
||||
bb = Material->b;
|
||||
|
||||
if (Material->hasFlag(T3D_MATERIAL_CLIPMAP)) { // Se il materiale e' clipmap
|
||||
alphaval = 0xfe;
|
||||
Face.flags |= T3D_MATERIAL_CLIPMAP; // lo setta sulla faccia
|
||||
/* Face->flags&=~T3D_MATERIAL_OPACITY;
|
||||
Face->flags&=~T3D_MATERIAL_GLASS;
|
||||
Material->Flags&=~T3D_MATERIAL_OPACITY;
|
||||
Material->Flags&=~T3D_MATERIAL_GLASS;*/
|
||||
// r=g=b=0;
|
||||
}
|
||||
if (Material->hasFlag(T3D_MATERIAL_OPACITY)) { // Se il materiale e' opacity
|
||||
Face.flags |= T3D_MATERIAL_OPACITY; // lo setta sulla faccia
|
||||
alphaval = 0x88;
|
||||
rr = gg = bb = 0;
|
||||
}
|
||||
if (Material->hasFlag(T3D_MATERIAL_GLASS)) { // Se e' un glass
|
||||
Face.flags |= T3D_MATERIAL_GLASS; // lo setta sulla faccia
|
||||
alphaval = 0xfe;
|
||||
rr = gg = bb = 255;
|
||||
}
|
||||
if (Material->hasFlag(T3D_MATERIAL_BOTTLE)) { // Se e' un bottle
|
||||
Face.flags |= T3D_MATERIAL_BOTTLE; // sulla faccia
|
||||
alphaval = 0x88;
|
||||
rr = gg = bb = 255;
|
||||
}
|
||||
if (Material->hasFlag(T3D_MATERIAL_ADDITIVE)) { // Se e' un additivo
|
||||
Face.flags |= T3D_MATERIAL_ADDITIVE; // sulla faccia
|
||||
alphaval = 0x88;
|
||||
rr = gg = bb = 255;
|
||||
}
|
||||
if (rr < ambientLight.x) rr = (uint8)ambientLight.x;
|
||||
if (gg < ambientLight.y) gg = (uint8)ambientLight.y;
|
||||
if (bb < ambientLight.z) bb = (uint8)ambientLight.z;
|
||||
this->VBptr[Face.VertexIndex[0]].diffuse = RGBA_MAKE(rr, gg, bb, alphaval); // Cambia diffse dei vertici della mesh
|
||||
this->VBptr[Face.VertexIndex[1]].diffuse = RGBA_MAKE(rr, gg, bb, alphaval);
|
||||
this->VBptr[Face.VertexIndex[2]].diffuse = RGBA_MAKE(rr, gg, bb, alphaval);
|
||||
}
|
||||
#ifndef WMGEN
|
||||
this->VBptr = nullptr;
|
||||
#endif
|
||||
// rOptimizeVertexArray(Mesh->VertexBuffer);
|
||||
}
|
||||
|
||||
t3dMESH() = default;
|
||||
t3dMESH(t3dBODY *b, Common::SeekableReadStream &stream, t3dMESH *&ReceiveRipples, uint8 &Mirror);
|
||||
t3dMESH(const t3dMESH &other);
|
||||
t3dMESH(t3dMESH &&old);
|
||||
t3dMESH& operator=(t3dMESH rhs);
|
||||
~t3dMESH();
|
||||
void loadFaces(t3dBODY *b, Common::SeekableReadStream &stream, int numFaces);
|
||||
void release();
|
||||
void releaseAnim(uint8 flag);
|
||||
|
||||
bool hasFaceMaterial() const {
|
||||
return !this->FList.empty() && (bool)(this->FList[0].getMaterial());
|
||||
}
|
||||
|
||||
void setMovieFrame(uint32 dwCurrFrame) {
|
||||
// TODO: Could just inline rSetMovieFrame?
|
||||
if (!this->FList.empty() && this->FList[0].getMaterial()) {
|
||||
rSetMovieFrame(this->FList[0].getMaterial(), dwCurrFrame);
|
||||
}
|
||||
}
|
||||
uint32 getMovieFrame() {
|
||||
assert(!this->FList.empty() && this->FList[0].getMaterial());
|
||||
return rGetMovieFrame(this->FList[0].getMaterial());
|
||||
}
|
||||
};
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
|
||||
#endif // WATCHMAKER_T3D_MESH_H
|
||||
26
engines/watchmaker/3d/texture.cpp
Normal file
26
engines/watchmaker/3d/texture.cpp
Normal file
@@ -0,0 +1,26 @@
|
||||
/* 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/3d/texture.h"
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
69
engines/watchmaker/3d/texture.h
Normal file
69
engines/watchmaker/3d/texture.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WATCHMAKER_TEXTURE_H
|
||||
#define WATCHMAKER_TEXTURE_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/str.h"
|
||||
#include "common/textconsole.h"
|
||||
#include "watchmaker/3d/dds_header.h"
|
||||
#include "graphics/surface.h"
|
||||
#include "watchmaker/rect.h"
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
class WGame;
|
||||
// Texture structs
|
||||
struct gTexture {
|
||||
Common::String name;
|
||||
Texture *_texture = nullptr;
|
||||
int RealDimX = 0; // original dimensions
|
||||
int RealDimY = 0; // original dimensions
|
||||
int DimX = 0; // current dimensions
|
||||
int DimY = 0; // current dimensions
|
||||
int ID = 0; // id
|
||||
int Flags = 0; // Flags
|
||||
|
||||
bool isEmpty() {
|
||||
return _texture == nullptr;
|
||||
}
|
||||
void clear() {
|
||||
// TODO: This will only work for the back-surface
|
||||
warning("Clearing %d", _blitsOnTop.size());
|
||||
_blitsOnTop.clear();
|
||||
}
|
||||
void render(WGame &game, Common::Rect src, Common::Rect dst);
|
||||
void blitInto(gTexture *texture, Common::Rect src, Common::Rect dst) {
|
||||
_blitsOnTop.push_back({texture, src, dst});
|
||||
}
|
||||
private:
|
||||
struct Blit {
|
||||
gTexture *texture;
|
||||
Common::Rect src;
|
||||
Common::Rect dst;
|
||||
};
|
||||
Common::Array<Blit> _blitsOnTop;
|
||||
};
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
|
||||
#endif // WATCHMAKER_TEXTURE_H
|
||||
26
engines/watchmaker/3d/types3d.cpp
Normal file
26
engines/watchmaker/3d/types3d.cpp
Normal file
@@ -0,0 +1,26 @@
|
||||
/* 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/3d/types3d.h"
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
120
engines/watchmaker/3d/types3d.h
Normal file
120
engines/watchmaker/3d/types3d.h
Normal file
@@ -0,0 +1,120 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WATCHMAKER_TYPES3D_H
|
||||
#define WATCHMAKER_TYPES3D_H
|
||||
|
||||
#include "common/stream.h"
|
||||
#include "math/vector3d.h"
|
||||
#include "watchmaker/types.h"
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
struct t3dV2F {
|
||||
t3dF32 x = 0.0f, y = 0.0f; // 2d Vector
|
||||
public:
|
||||
constexpr t3dV2F() = default;
|
||||
constexpr t3dV2F(float _x, float _y, float z) : x(_x), y(_y) {}
|
||||
};
|
||||
|
||||
struct t3dV3F {
|
||||
t3dF32 x = 0.0f, y = 0.0f, z = 0.0f; // 3d vector
|
||||
public:
|
||||
constexpr t3dV3F() = default;
|
||||
constexpr t3dV3F(float _x, float _y, float _z) : x(_x), y(_y), z(_z) {}
|
||||
t3dV3F(const Math::Vector3d &vector) {
|
||||
x = vector.x();
|
||||
y = vector.y();
|
||||
z = vector.z();
|
||||
}
|
||||
t3dV3F(Common::SeekableReadStream &stream) {
|
||||
x = stream.readFloatLE(); // Legge Pos
|
||||
y = stream.readFloatLE();
|
||||
z = stream.readFloatLE();
|
||||
}
|
||||
static t3dV3F fromStreamAsBytes(Common::SeekableReadStream &stream) {
|
||||
t3dF32 x = stream.readByte();
|
||||
t3dF32 y = stream.readByte();
|
||||
t3dF32 z = stream.readByte();
|
||||
return t3dV3F(x, y, z);
|
||||
}
|
||||
t3dV3F operator+(const t3dV3F &rhs) const {
|
||||
return t3dV3F(
|
||||
x + rhs.x,
|
||||
y + rhs.y,
|
||||
z + rhs.z
|
||||
);
|
||||
}
|
||||
t3dV3F operator-(const t3dV3F &rhs) const {
|
||||
return t3dV3F(
|
||||
x + rhs.x,
|
||||
y + rhs.y,
|
||||
z + rhs.z
|
||||
);
|
||||
}
|
||||
t3dV3F operator-() const {
|
||||
return t3dV3F(
|
||||
-x,
|
||||
-y,
|
||||
-z
|
||||
);
|
||||
}
|
||||
t3dV3F operator*(float scalar) const {
|
||||
return t3dV3F(
|
||||
x * scalar,
|
||||
y * scalar,
|
||||
z * scalar
|
||||
);
|
||||
}
|
||||
t3dV3F &operator*=(float scalar) {
|
||||
this->x *= scalar;
|
||||
this->y *= scalar;
|
||||
this->z *= scalar;
|
||||
return *this;
|
||||
}
|
||||
bool operator==(const t3dV3F &rhs) const {
|
||||
return this->x == rhs.x && this->y == rhs.y && this->z == rhs.z;
|
||||
}
|
||||
bool operator!=(const t3dV3F &rhs) const {
|
||||
return !(*this == rhs);
|
||||
}
|
||||
};
|
||||
|
||||
struct t3dNORMAL {
|
||||
t3dV3F n; //normal coords 12
|
||||
t3dF32 tn = 0.0f; //normal coords in light space
|
||||
t3dF32 dist = 0.0f; //dist from plane 4
|
||||
t3dF32 tras_n = 0.0f; //transformed normal 4
|
||||
uint8 flag = 0; //flags 1
|
||||
public:
|
||||
constexpr t3dNORMAL() = default;
|
||||
t3dNORMAL(Common::SeekableReadStream &stream) {
|
||||
n = t3dV3F(stream); // Direzione
|
||||
dist = -stream.readFloatLE(); // Distanza-Dot
|
||||
}
|
||||
};
|
||||
|
||||
typedef Common::SharedPtr<t3dNORMAL> NormalPtr;
|
||||
typedef Common::Array<NormalPtr> NormalList; // TODO: Not necessarily the prettiest solution, but chosen to ensure that changes to copies are shared.
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
|
||||
#endif // WATCHMAKER_TYPES3D_H
|
||||
26
engines/watchmaker/3d/vertex.cpp
Normal file
26
engines/watchmaker/3d/vertex.cpp
Normal file
@@ -0,0 +1,26 @@
|
||||
/* 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/3d/vertex.h"
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
52
engines/watchmaker/3d/vertex.h
Normal file
52
engines/watchmaker/3d/vertex.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WATCHMAKER_VERTEX_H
|
||||
#define WATCHMAKER_VERTEX_H
|
||||
|
||||
|
||||
#include "watchmaker/types.h"
|
||||
#include "watchmaker/windows_hacks.h"
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
// VertexBuffer vertices definition
|
||||
#pragma pack(1)
|
||||
struct gVertex {
|
||||
float x; // untransformed vertex
|
||||
float y;
|
||||
float z;
|
||||
int32 diffuse; // diffuse color
|
||||
float u1; // texture set for primary texture
|
||||
float v1;
|
||||
float u2; // texture set for lightmaps
|
||||
float v2;
|
||||
};
|
||||
#pragma pack()
|
||||
|
||||
struct pVert {
|
||||
float x, y, z, rhw; // transformed vertex
|
||||
DWORD diffuse; // diffuse color
|
||||
} ;
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
|
||||
#endif // WATCHMAKER_VERTEX_H
|
||||
Reference in New Issue
Block a user