ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

grim/model.cpp

Go to the documentation of this file.
00001 /* ResidualVM - A 3D game interpreter
00002  *
00003  * ResidualVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "common/algorithm.h"
00024 #include "common/endian.h"
00025 #include "common/func.h"
00026 
00027 #include "engines/grim/debug.h"
00028 #include "engines/grim/grim.h"
00029 #include "engines/grim/model.h"
00030 #include "engines/grim/material.h"
00031 #include "engines/grim/textsplit.h"
00032 #include "engines/grim/gfx_base.h"
00033 #include "engines/grim/resource.h"
00034 #include "engines/grim/colormap.h"
00035 #include "engines/grim/sprite.h"
00036 
00037 namespace Grim {
00038 
00039 
00043 Model::Model(const Common::String &filename, Common::SeekableReadStream *data, CMap *cmap, Model *parent) :
00044         Object(), _parent(parent), _numMaterials(0), _numGeosets(0), _cmap(cmap), _fname(filename) {
00045 
00046     if (data->readUint32BE() == MKTAG('L','D','O','M'))
00047         loadBinary(data);
00048     else {
00049         data->seek(0, SEEK_SET);
00050         TextSplitter ts(_fname, data);
00051         loadText(&ts);
00052     }
00053 
00054     Math::Vector3d max;
00055 
00056     _rootHierNode->update();
00057     bool first = true;
00058     for (int i = 0; i < _numHierNodes; ++i) {
00059         ModelNode &node = _rootHierNode[i];
00060         if (node._mesh) {
00061             g_driver->createMesh(node._mesh);
00062             Mesh &mesh = *node._mesh;
00063             Math::Vector3d p = mesh._matrix.getPosition();
00064             float x = p.x();
00065             float y = p.y();
00066             float z = p.z();
00067             for (int k = 0; k < mesh._numVertices * 3; k += 3) {
00068                 if (first || mesh._vertices[k] + x < _bboxPos.x())
00069                     _bboxPos.x() = mesh._vertices[k] + x;
00070                 if (first || mesh._vertices[k + 1] + y < _bboxPos.y())
00071                     _bboxPos.y() = mesh._vertices[k + 1] + y;
00072                 if (first || mesh._vertices[k + 2] + z < _bboxPos.z())
00073                     _bboxPos.z() = mesh._vertices[k + 2] + z;
00074 
00075                 if (first || mesh._vertices[k] + x > max.x())
00076                     max.x() = mesh._vertices[k] + x;
00077                 if (first || mesh._vertices[k + 1] + y > max.y())
00078                     max.y() = mesh._vertices[k + 1] + y;
00079                 if (first || mesh._vertices[k + 2] + z > max.z())
00080                     max.z() = mesh._vertices[k + 2] + z;
00081 
00082                 first = false;
00083             }
00084         }
00085     }
00086 
00087     _bboxSize = max - _bboxPos;
00088 }
00089 
00090 Model::~Model() {
00091     for (int i = 0; i < _numMaterials; ++i) {
00092         if (!_materialsShared[i]) {
00093             delete _materials[i];
00094         }
00095     }
00096     delete[] _materials;
00097     delete[] _materialNames;
00098     delete[] _materialsShared;
00099     delete[] _geosets;
00100     delete[] _rootHierNode;
00101     g_resourceloader->uncacheModel(this);
00102 }
00103 
00104 void Model::loadBinary(Common::SeekableReadStream *data) {
00105     _numMaterials = data->readUint32LE();
00106     _materials = new Material*[_numMaterials];
00107     _materialNames = new char[_numMaterials][32];
00108     _materialsShared = new bool[_numMaterials];
00109     for (int i = 0; i < _numMaterials; i++) {
00110         data->read(_materialNames[i], 32);
00111         _materialsShared[i] = false;
00112         _materials[i] = nullptr;
00113         loadMaterial(i, _cmap);
00114     }
00115     data->seek(32, SEEK_CUR); // skip name
00116     data->seek(4, SEEK_CUR);
00117     _numGeosets = data->readUint32LE();
00118     _geosets = new Geoset[_numGeosets];
00119     for (int i = 0; i < _numGeosets; i++)
00120         _geosets[i].loadBinary(data, _materials);
00121     data->seek(4, SEEK_CUR);
00122     _numHierNodes = data->readUint32LE();
00123     _rootHierNode = new ModelNode[_numHierNodes];
00124     for (int i = 0; i < _numHierNodes; i++) {
00125         _rootHierNode[i].loadBinary(data, _rootHierNode, &_geosets[0]);
00126     }
00127     _radius = data->readFloatLE();
00128     data->seek(36, SEEK_CUR);
00129     _insertOffset.readFromStream(data);
00130 }
00131 
00132 void Model::loadText(TextSplitter *ts) {
00133     ts->expectString("section: header");
00134     int major, minor;
00135     ts->scanString("3do %d.%d", 2, &major, &minor);
00136     ts->expectString("section: modelresource");
00137     ts->scanString("materials %d", 1, &_numMaterials);
00138     _materials = new Material*[_numMaterials];
00139     _materialNames = new char[_numMaterials][32];
00140     _materialsShared = new bool[_numMaterials];
00141     for (int i = 0; i < _numMaterials; i++) {
00142         char materialName[32];
00143         int num;
00144         _materialsShared[i] = false;
00145         _materials[i] = nullptr;
00146 
00147         ts->scanString("%d: %32s", 2, &num, materialName);
00148         strcpy(_materialNames[num], materialName);
00149         loadMaterial(num, _cmap);
00150     }
00151 
00152     ts->expectString("section: geometrydef");
00153     ts->scanString("radius %f", 1, &_radius);
00154     ts->scanString("insert offset %f %f %f", 3, &_insertOffset.x(), &_insertOffset.y(), &_insertOffset.z());
00155     ts->scanString("geosets %d", 1, &_numGeosets);
00156     _geosets = new Geoset[_numGeosets];
00157     for (int i = 0; i < _numGeosets; i++) {
00158         int num;
00159         ts->scanString("geoset %d", 1, &num);
00160         _geosets[num].loadText(ts, _materials);
00161     }
00162 
00163     ts->expectString("section: hierarchydef");
00164     ts->scanString("hierarchy nodes %d", 1, &_numHierNodes);
00165     _rootHierNode = new ModelNode[_numHierNodes];
00166     for (int i = 0; i < _numHierNodes; i++) {
00167         int num, mesh, parent, child, sibling, numChildren;
00168         unsigned int flags, type;
00169         float x, y, z, pitch, yaw, roll, pivotx, pivoty, pivotz;
00170         char name[64];
00171         ts->scanString(" %d: %x %x %d %d %d %d %d %f %f %f %f %f %f %f %f %f %64s",
00172                        18, &num, &flags, &type, &mesh, &parent, &child, &sibling,
00173                  &numChildren, &x, &y, &z, &pitch, &yaw, &roll, &pivotx, &pivoty, &pivotz, name);
00174         _rootHierNode[num]._flags = (int)flags;
00175         _rootHierNode[num]._type = (int)type;
00176         if (mesh < 0)
00177             _rootHierNode[num]._mesh = nullptr;
00178         else
00179             _rootHierNode[num]._mesh = &_geosets[0]._meshes[mesh];
00180         if (parent >= 0) {
00181             _rootHierNode[num]._parent = &_rootHierNode[parent];
00182             _rootHierNode[num]._depth = _rootHierNode[parent]._depth + 1;
00183         } else {
00184             _rootHierNode[num]._parent = nullptr;
00185             _rootHierNode[num]._depth = 0;
00186         }
00187         if (child >= 0)
00188             _rootHierNode[num]._child = &_rootHierNode[child];
00189         else
00190             _rootHierNode[num]._child = nullptr;
00191         if (sibling >= 0)
00192             _rootHierNode[num]._sibling = &_rootHierNode[sibling];
00193         else
00194             _rootHierNode[num]._sibling = nullptr;
00195 
00196         _rootHierNode[num]._numChildren = numChildren;
00197         _rootHierNode[num]._pos = Math::Vector3d(x, y, z);
00198         _rootHierNode[num]._rot = Math::Quaternion::fromEuler(yaw, pitch, roll, Math::EO_ZXY);
00199         _rootHierNode[num]._animRot = _rootHierNode[num]._rot;
00200         _rootHierNode[num]._animPos = _rootHierNode[num]._pos;
00201         _rootHierNode[num]._pivot = Math::Vector3d(pivotx, pivoty, pivotz);
00202         _rootHierNode[num]._meshVisible = true;
00203         _rootHierNode[num]._hierVisible = true;
00204         _rootHierNode[num]._sprite = nullptr;
00205         _rootHierNode[num]._initialized = true;
00206     }
00207 
00208     if (!ts->isEof())
00209         Debug::warning(Debug::Models, "Unexpected junk at end of model text");
00210 }
00211 
00212 void Model::draw() const {
00213     _rootHierNode->draw();
00214 }
00215 
00216 ModelNode *Model::getHierarchy() const {
00217     return _rootHierNode;
00218 }
00219 
00220 void Model::reload(CMap *cmap) {
00221     // Load the new colormap
00222     for (int i = 0; i < _numMaterials; i++) {
00223         loadMaterial(i, cmap);
00224     }
00225     for (int i = 0; i < _numGeosets; i++)
00226         _geosets[i].changeMaterials(_materials);
00227     _cmap = cmap;
00228 }
00229 
00230 void Model::loadMaterial(int index, CMap *cmap) {
00231     Material *mat = nullptr;
00232     if (!_materialsShared[index]) {
00233         mat = _materials[index];
00234     }
00235     _materials[index] = nullptr;
00236     if (_parent) {
00237         _materials[index] = _parent->findMaterial(_materialNames[index], cmap);
00238         if (_materials[index]) {
00239             _materialsShared[index] = true;
00240         }
00241     }
00242     if (!_materials[index]) {
00243         if (mat && cmap->getFilename() == _cmap->getFilename()) {
00244             _materials[index] = mat;
00245         } else {
00246             _materials[index] = g_resourceloader->loadMaterial(_materialNames[index], cmap, false);
00247         }
00248         _materialsShared[index] = false;
00249     }
00250     if (mat != _materials[index]) {
00251         delete mat;
00252     }
00253 }
00254 
00255 Material *Model::findMaterial(const char *name, CMap *cmap) const {
00256     for (int i = 0; i < _numMaterials; ++i) {
00257         if (scumm_stricmp(name, _materialNames[i]) == 0) {
00258             if (cmap->getFilename() != _cmap->getFilename())
00259                 _materials[i]->reload(cmap);
00260             return _materials[i];
00261         }
00262     }
00263 
00264     return nullptr;
00265 }
00266 
00270 Model::Geoset::~Geoset() {
00271     delete[] _meshes;
00272 }
00273 
00274 void Model::Geoset::loadBinary(Common::SeekableReadStream *data, Material *materials[]) {
00275     _numMeshes =  data->readUint32LE();
00276     _meshes = new Mesh[_numMeshes];
00277     for (int i = 0; i < _numMeshes; i++)
00278         _meshes[i].loadBinary(data, materials);
00279 }
00280 
00281 void Model::Geoset::loadText(TextSplitter *ts, Material *materials[]) {
00282     ts->scanString("meshes %d", 1, &_numMeshes);
00283     _meshes = new Mesh[_numMeshes];
00284     for (int i = 0; i < _numMeshes; i++) {
00285         int num;
00286         ts->scanString("mesh %d", 1, &num);
00287         _meshes[num].loadText(ts, materials);
00288     }
00289 }
00290 
00291 void Model::Geoset::changeMaterials(Material *materials[]) {
00292     for (int i = 0; i < _numMeshes; i++)
00293         _meshes[i].changeMaterials(materials);
00294 }
00295 
00299 MeshFace::MeshFace() :
00300         _material(nullptr), _type(0), _geo(0), _light(0), _tex(0),
00301         _extraLight(0), _numVertices(0), _vertices(nullptr),
00302         _texVertices(nullptr), _userData(nullptr) {
00303 }
00304 
00305 MeshFace::~MeshFace() {
00306     delete[] _vertices;
00307     delete[] _texVertices;
00308 }
00309 
00310 void MeshFace::stealData(MeshFace &other) {
00311     *this = other;
00312     other._vertices = nullptr;
00313     other._texVertices = nullptr;
00314 }
00315 
00316 int MeshFace::loadBinary(Common::SeekableReadStream *data, Material *materials[]) {
00317     data->seek(4, SEEK_CUR);
00318     _type = data->readUint32LE();
00319     _geo = data->readUint32LE();
00320     _light = data->readUint32LE();
00321     _tex = data->readUint32LE();
00322     _numVertices = data->readUint32LE();
00323     data->seek(4, SEEK_CUR);
00324     int texPtr = data->readUint32LE();
00325     int materialPtr = data->readUint32LE();
00326     data->seek(12, SEEK_CUR);
00327     _extraLight = data->readFloatLE();
00328     data->seek(12, SEEK_CUR);
00329     _normal.readFromStream(data);
00330 
00331     _vertices = new int[_numVertices];
00332     for (int i = 0; i < _numVertices; i++) {
00333         _vertices[i] = data->readUint32LE();
00334     }
00335 
00336     if (texPtr != 0) {
00337         _texVertices = new int[_numVertices];
00338         for (int i = 0; i < _numVertices; i++) {
00339             _texVertices[i] = data->readUint32LE();
00340         }
00341     }
00342 
00343     if (materialPtr != 0) {
00344         materialPtr = data->readUint32LE();
00345         _material = materials[materialPtr];
00346     }
00347 
00348     return materialPtr;
00349 }
00350 
00351 int MeshFace::loadText(TextSplitter *ts, Material *materials[], int offset) {
00352     int readlen, materialid;
00353 
00354     if (ts->isEof())
00355         error("Expected face data, got EOF");
00356 
00357     ts->scanStringAtOffsetNoNewLine(offset, "%d %x %d %d %d %f %d%n", 7, &materialid, &_type, &_geo, &_light, &_tex, &_extraLight, &_numVertices, &readlen);
00358     readlen += offset;
00359 
00360     assert(materialid != -1);
00361     _material = materials[materialid];
00362     _vertices = new int[_numVertices];
00363     _texVertices = new int[_numVertices];
00364     for (int i = 0; i < _numVertices; ++i) {
00365         int readlen2;
00366 
00367         ts->scanStringAtOffsetNoNewLine(readlen, " %d, %d%n", 2, &_vertices[i], &_texVertices[i], &readlen2);
00368         readlen += readlen2;
00369     }
00370     ts->nextLine();
00371 
00372     return materialid;
00373 }
00374 
00375 void MeshFace::changeMaterial(Material *material) {
00376     _material = material;
00377 }
00378 
00379 void MeshFace::draw(const Mesh *mesh) const {
00380     if (_light == 0 && !g_driver->isShadowModeActive())
00381         g_driver->disableLights();
00382 
00383     _material->select();
00384     g_driver->drawModelFace(mesh, this);
00385 
00386     if (_light == 0 && !g_driver->isShadowModeActive())
00387         g_driver->enableLights();
00388 }
00389 
00393 Mesh::Mesh() :
00394         _numFaces(0), _radius(0.0f), _shadow(0), _geometryMode(0),
00395         _lightingMode(0), _textureMode(0), _numVertices(0), _materialid(nullptr),
00396         _vertices(nullptr), _verticesI(nullptr), _vertNormals(nullptr),
00397         _numTextureVerts(0), _textureVerts(nullptr), _faces(nullptr), _userData(nullptr) {
00398     _name[0] = '\0';
00399 
00400 }
00401 
00402 
00403 Mesh::~Mesh() {
00404     g_driver->destroyMesh(this);
00405 
00406     delete[] _vertices;
00407     delete[] _verticesI;
00408     delete[] _vertNormals;
00409     delete[] _textureVerts;
00410     delete[] _faces;
00411     delete[] _materialid;
00412 }
00413 
00414 void Mesh::loadBinary(Common::SeekableReadStream *data, Material *materials[]) {
00415     data->read(_name, 32);
00416     data->seek(4, SEEK_CUR);
00417     _geometryMode = data->readUint32LE();
00418     _lightingMode = data->readUint32LE();
00419     _textureMode = data->readUint32LE();
00420     _numVertices = data->readUint32LE();
00421     _numTextureVerts = data->readUint32LE();
00422     _numFaces =  data->readUint32LE();
00423     _vertices = new float[3 * _numVertices];
00424     _verticesI = new float[_numVertices];
00425     _vertNormals = new float[3 * _numVertices];
00426     _textureVerts = new float[2 * _numTextureVerts];
00427     _faces = new MeshFace[_numFaces];
00428     _materialid = new int[_numFaces];
00429     for (int i = 0; i < 3 * _numVertices; i++) {
00430         _vertices[i] = data->readFloatLE();
00431     }
00432     for (int i = 0; i < 2 * _numTextureVerts; i++) {
00433         _textureVerts[i] = data->readFloatLE();
00434     }
00435     for (int i = 0; i < _numVertices; i++) {
00436         _verticesI[i] = data->readFloatLE();
00437     }
00438     data->seek(_numVertices * 4, SEEK_CUR);
00439     for (int i = 0; i < _numFaces; i++)
00440         _materialid[i] = _faces[i].loadBinary(data, materials);
00441     for (int i = 0; i < 3 * _numVertices; i++) {
00442         _vertNormals[i] = data->readFloatLE();
00443     }
00444     _shadow = data->readUint32LE();
00445     data->seek(4, SEEK_CUR);
00446     _radius = data->readFloatLE();
00447     data->seek(24, SEEK_CUR);
00448     sortFaces();
00449 }
00450 
00451 void Mesh::loadText(TextSplitter *ts, Material *materials[]) {
00452     ts->scanString("name %32s", 1, _name);
00453     ts->scanString("radius %f", 1, &_radius);
00454 
00455     // In data001/rope_scale.3do, the shadow line is missing
00456     if (sscanf(ts->getCurrentLine(), "shadow %d", &_shadow) < 1) {
00457         _shadow = 0;
00458     } else
00459         ts->nextLine();
00460     ts->scanString("geometrymode %d", 1, &_geometryMode);
00461     ts->scanString("lightingmode %d", 1, &_lightingMode);
00462     ts->scanString("texturemode %d", 1, &_textureMode);
00463     ts->scanString("vertices %d", 1, &_numVertices);
00464     _vertices = new float[3 * _numVertices];
00465     _verticesI = new float[_numVertices];
00466     _vertNormals = new float[3 * _numVertices];
00467 
00468     for (int i = 0; i < _numVertices; i++) {
00469         int num;
00470         float x, y, z, ival;
00471         ts->scanString(" %d: %f %f %f %f", 5, &num, &x, &y, &z, &ival);
00472         _vertices[3 * num] = x;
00473         _vertices[3 * num + 1] = y;
00474         _vertices[3 * num + 2] = z;
00475         _verticesI[num] = ival;
00476     }
00477 
00478     ts->scanString("texture vertices %d", 1, &_numTextureVerts);
00479     _textureVerts = new float[2 * _numTextureVerts];
00480 
00481     for (int i = 0; i < _numTextureVerts; i++) {
00482         int num;
00483         float x, y;
00484         ts->scanString(" %d: %f %f", 3, &num, &x, &y);
00485         _textureVerts[2 * num] = x;
00486         _textureVerts[2 * num + 1] = y;
00487     }
00488 
00489     ts->expectString("vertex normals");
00490     for (int i = 0; i < _numVertices; i++) {
00491         int num;
00492         float x, y, z;
00493         ts->scanString(" %d: %f %f %f", 4, &num, &x, &y, &z);
00494         _vertNormals[3 * num] = x;
00495         _vertNormals[3 * num + 1] = y;
00496         _vertNormals[3 * num + 2] = z;
00497     }
00498 
00499     ts->scanString("faces %d", 1, &_numFaces);
00500     _faces = new MeshFace[_numFaces];
00501     _materialid = new int[_numFaces];
00502     for (int i = 0; i < _numFaces; i++) {
00503         int num, readlen;
00504         ts->scanStringNoNewLine(" %d:%n ", 1, &num, &readlen);
00505         _materialid[num] = _faces[num].loadText(ts, materials, readlen);
00506     }
00507 
00508     ts->expectString("face normals");
00509     for (int i = 0; i < _numFaces; i++) {
00510         int num;
00511         float x, y, z;
00512         ts->scanString(" %d: %f %f %f", 4, &num, &x, &y, &z);
00513         _faces[num].setNormal(Math::Vector3d(x, y, z));
00514     }
00515     sortFaces();
00516 }
00517 
00518 void Mesh::sortFaces() {
00519     if (_numFaces < 2)
00520         return;
00521 
00522     MeshFace *newFaces = new MeshFace[_numFaces];
00523     int *newMaterialid = new int[_numFaces];
00524     bool *copied = new bool[_numFaces];
00525     for (int i = 0; i < _numFaces; ++i)
00526         copied[i] = false;
00527 
00528     for (int cur = 0, writeIdx = 0; cur < _numFaces; ++cur) {
00529         if (copied[cur])
00530             continue;
00531 
00532         for (int other = cur; other < _numFaces; ++other) {
00533             if (_faces[cur].getMaterial() == _faces[other].getMaterial() && !copied[other]) {
00534                 copied[other] = true;
00535                 newFaces[writeIdx].stealData(_faces[other]);
00536                 newMaterialid[writeIdx] = _materialid[other];
00537                 writeIdx++;
00538             }
00539         }
00540     }
00541 
00542     delete[] _faces;
00543     _faces = newFaces;
00544     delete[] _materialid;
00545     _materialid = newMaterialid;
00546     delete[] copied;
00547 }
00548 
00549 void Mesh::update() {
00550 }
00551 
00552 void Mesh::changeMaterials(Material *materials[]) {
00553     for (int i = 0; i < _numFaces; i++)
00554         _faces[i].changeMaterial(materials[_materialid[i]]);
00555 }
00556 
00557 void Mesh::draw() const {
00558     if (_lightingMode == 0)
00559         g_driver->disableLights();
00560 
00561     g_driver->drawMesh(this);
00562 
00563     if (_lightingMode == 0)
00564         g_driver->enableLights();
00565 }
00566 
00567 void Mesh::getBoundingBox(int *x1, int *y1, int *x2, int *y2) const {
00568     int winX1, winY1, winX2, winY2;
00569     g_driver->getScreenBoundingBox(this, &winX1, &winY1, &winX2, &winY2);
00570     if (winX1 != -1 && winY1 != -1 && winX2 != -1 && winY2 != -1) {
00571         *x1 = MIN(*x1, winX1);
00572         *y1 = MIN(*y1, winY1);
00573         *x2 = MAX(*x2, winX2);
00574         *y2 = MAX(*y2, winY2);
00575     }
00576 }
00577 
00581 ModelNode::ModelNode() :
00582         _initialized(false), _needsUpdate(true), _mesh(nullptr), _flags(0), _type(0),
00583         _depth(0), _numChildren(0), _parent(nullptr), _child(nullptr), _sprite(nullptr),
00584         _sibling(nullptr), _meshVisible(false), _hierVisible(false) {
00585     _name[0] = '\0';
00586 }
00587 
00588 ModelNode::~ModelNode() {
00589     ModelNode *child = _child;
00590     while (child) {
00591         child->_parent = nullptr;
00592         child = child->_sibling;
00593     }
00594 }
00595 
00596 void ModelNode::loadBinary(Common::SeekableReadStream *data, ModelNode *hierNodes, const Model::Geoset *g) {
00597     data->read(_name, 64);
00598     _flags = data->readUint32LE();
00599     data->seek(4, SEEK_CUR);
00600     _type = data->readUint32LE();
00601     int meshNum = data->readUint32LE();
00602     if (meshNum < 0)
00603         _mesh = nullptr;
00604     else
00605         _mesh = g->_meshes + meshNum;
00606     _depth = data->readUint32LE();
00607     int parentPtr = data->readUint32LE();
00608     _numChildren = data->readUint32LE();
00609     int childPtr = data->readUint32LE();
00610     int siblingPtr = data->readUint32LE();
00611     _pivot.readFromStream(data);
00612     _pos.readFromStream(data);
00613     float pitch = data->readFloatLE();
00614     float yaw = data->readFloatLE();
00615     float roll = data->readFloatLE();
00616     _rot = Math::Quaternion::fromEuler(yaw, pitch, roll, Math::EO_ZXY);
00617     _animRot = _rot;
00618     _animPos = _pos;
00619     _sprite = nullptr;
00620 
00621     data->seek(48, SEEK_CUR);
00622 
00623     if (parentPtr != 0)
00624         _parent = hierNodes + data->readUint32LE();
00625     else
00626         _parent = nullptr;
00627 
00628     if (childPtr != 0)
00629         _child = hierNodes + data->readUint32LE();
00630     else
00631         _child = nullptr;
00632 
00633     if (siblingPtr != 0)
00634         _sibling = hierNodes + data->readUint32LE();
00635     else
00636         _sibling = nullptr;
00637 
00638     _meshVisible = true;
00639     _hierVisible = true;
00640     _initialized = true;
00641 }
00642 
00643 void ModelNode::draw() const {
00644     if (_sibling || _child) {
00645         translateViewpointStart();
00646     }
00647     translateViewpoint();
00648     if (_hierVisible) {
00649         if (_child) {
00650             translateViewpointStart();
00651         }
00652         g_driver->translateViewpoint(_pivot);
00653 
00654         if (!g_driver->isShadowModeActive()) {
00655             Sprite *sprite = _sprite;
00656             while (sprite) {
00657                 sprite->draw();
00658                 sprite = sprite->_next;
00659             }
00660         }
00661 
00662         if (_mesh && _meshVisible) {
00663             _mesh->draw();
00664         }
00665 
00666         if (_child) {
00667             translateViewpointFinish();
00668             _child->draw();
00669         }
00670     }
00671 
00672     if (_sibling || _child) {
00673         translateViewpointFinish();
00674     }
00675     if (_sibling) {
00676         _sibling->draw();
00677     }
00678 }
00679 
00680 void ModelNode::getBoundingBox(int *x1, int *y1, int *x2, int *y2) const {
00681     if (_sibling || _child) {
00682         translateViewpointStart();
00683     }
00684     translateViewpoint();
00685     if (_hierVisible) {
00686         if (_child) {
00687             translateViewpointStart();
00688         }
00689         g_driver->translateViewpoint(_pivot);
00690 
00691         if (_mesh && _meshVisible) {
00692             _mesh->getBoundingBox(x1, y1, x2, y2);
00693         }
00694 
00695         if (_child) {
00696             translateViewpointFinish();
00697             _child->getBoundingBox(x1, y1, x2, y2);
00698         }
00699     }
00700 
00701     if (_sibling || _child) {
00702         translateViewpointFinish();
00703     }
00704     if (_sibling) {
00705         _sibling->getBoundingBox(x1, y1, x2, y2);
00706     }
00707 }
00708 
00709 void ModelNode::addChild(ModelNode *child) {
00710     ModelNode **childPos = &_child;
00711     while (*childPos)
00712         childPos = &(*childPos)->_sibling;
00713     *childPos = child;
00714     child->_parent = this;
00715 }
00716 
00717 void ModelNode::removeChild(ModelNode *child) {
00718     ModelNode **childPos = &_child;
00719     while (*childPos && *childPos != child)
00720         childPos = &(*childPos)->_sibling;
00721     if (*childPos) {
00722         *childPos = child->_sibling;
00723         child->_parent = nullptr;
00724     }
00725 }
00726 
00727 void ModelNode::setMatrix(const Math::Matrix4 &matrix) {
00728     _matrix = matrix;
00729     if (_sibling)
00730         _sibling->setMatrix(matrix);
00731 }
00732 
00733 void ModelNode::update() {
00734     if (!_initialized)
00735         return;
00736 
00737     if (_hierVisible && _needsUpdate) {
00738         _localMatrix = _animRot.toMatrix();
00739         _localMatrix.setPosition(_animPos);
00740 
00741         _matrix = _matrix * _localMatrix;
00742 
00743         _pivotMatrix = _matrix;
00744         _pivotMatrix.translate(_pivot);
00745 
00746         if (_mesh) {
00747             _mesh->_matrix = _pivotMatrix;
00748         }
00749 
00750         if (_child) {
00751             _child->setMatrix(_matrix);
00752             _child->update();
00753         }
00754 
00755         _needsUpdate = false;
00756     }
00757 
00758     if (_sibling) {
00759         _sibling->update();
00760     }
00761 }
00762 
00763 void ModelNode::addSprite(Sprite *sprite) {
00764     sprite->_next = _sprite;
00765     _sprite = sprite;
00766 }
00767 
00768 void ModelNode::removeSprite(const Sprite *sprite) {
00769     Sprite *curr = _sprite;
00770     Sprite *prev = nullptr;
00771     while (curr) {
00772         if (curr == sprite) {
00773             if (prev)
00774                 prev->_next = curr->_next;
00775             else
00776                 _sprite = curr->_next;
00777         }
00778         prev = curr;
00779         curr = curr->_next;
00780     }
00781 }
00782 
00783 void ModelNode::translateViewpoint() const {
00784     g_driver->translateViewpoint(_animPos);
00785 
00786     Math::Matrix4 rot = _animRot.toMatrix();
00787     rot.transpose();
00788     g_driver->rotateViewpoint(rot);
00789 }
00790 
00791 void ModelNode::translateViewpointStart() const {
00792     g_driver->translateViewpointStart();
00793 }
00794 
00795 void ModelNode::translateViewpointFinish() const {
00796     g_driver->translateViewpointFinish();
00797 }
00798 
00799 } // end of namespace Grim


Generated on Sat May 18 2019 05:01:09 for ResidualVM by doxygen 1.7.1
curved edge   curved edge