2012-01-06 22:29:45 +00:00
|
|
|
/* ResidualVM - A 3D game interpreter
|
2008-06-13 14:57:47 +00:00
|
|
|
*
|
2012-01-06 22:29:45 +00:00
|
|
|
* ResidualVM is the legal property of its developers, whose names
|
2011-04-16 12:12:44 +00:00
|
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
2008-06-13 14:57:47 +00:00
|
|
|
* file distributed with this source distribution.
|
2006-04-02 14:20:45 +00:00
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
* This library 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
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
|
|
*
|
|
|
|
*/
|
2003-08-15 18:00:22 +00:00
|
|
|
|
2008-06-12 12:08:15 +00:00
|
|
|
#include "common/endian.h"
|
2008-01-26 11:47:23 +00:00
|
|
|
|
2011-07-23 13:37:14 +00:00
|
|
|
#include "engines/grim/debug.h"
|
2009-06-18 11:52:26 +00:00
|
|
|
#include "engines/grim/grim.h"
|
2009-05-24 19:13:58 +00:00
|
|
|
#include "engines/grim/model.h"
|
|
|
|
#include "engines/grim/material.h"
|
|
|
|
#include "engines/grim/textsplit.h"
|
|
|
|
#include "engines/grim/gfx_base.h"
|
2011-05-14 00:55:14 +00:00
|
|
|
#include "engines/grim/resource.h"
|
2011-12-17 23:34:37 +00:00
|
|
|
#include "engines/grim/colormap.h"
|
2005-01-01 12:27:57 +00:00
|
|
|
|
2009-05-25 06:49:57 +00:00
|
|
|
namespace Grim {
|
|
|
|
|
2011-05-15 13:47:09 +00:00
|
|
|
void Sprite::draw() const {
|
|
|
|
if (!_visible)
|
|
|
|
return;
|
|
|
|
|
|
|
|
_material->select();
|
|
|
|
g_driver->drawSprite(this);
|
|
|
|
}
|
|
|
|
|
2011-07-22 20:20:48 +00:00
|
|
|
/**
|
|
|
|
* @class Model
|
|
|
|
*/
|
2011-12-19 17:26:48 +00:00
|
|
|
Model::Model(const Common::String &filename, Common::SeekableReadStream *data, CMap *cmap, Model *parent) :
|
2011-07-18 21:43:01 +00:00
|
|
|
Object(), _parent(parent), _numMaterials(0), _numGeosets(0), _cmap(cmap) {
|
2009-06-26 16:13:11 +00:00
|
|
|
_fname = filename;
|
2005-07-10 18:57:27 +00:00
|
|
|
|
2011-05-09 08:00:01 +00:00
|
|
|
if (g_grim->getGameType() == GType_MONKEY4) {
|
2011-12-19 17:26:48 +00:00
|
|
|
loadEMI(data);
|
|
|
|
} else if (data->readUint32BE() == MKTAG('L','D','O','M'))
|
2004-02-24 22:43:32 +00:00
|
|
|
loadBinary(data, cmap);
|
|
|
|
else {
|
2011-12-19 17:26:48 +00:00
|
|
|
data->seek(0, SEEK_SET);
|
|
|
|
TextSplitter ts(data);
|
2009-06-26 16:13:11 +00:00
|
|
|
loadText(&ts, cmap);
|
2004-02-24 22:43:32 +00:00
|
|
|
}
|
2011-08-01 20:16:15 +00:00
|
|
|
|
2011-09-10 15:46:07 +00:00
|
|
|
Math::Vector3d max;
|
2011-08-01 20:16:15 +00:00
|
|
|
|
2011-08-02 17:17:32 +00:00
|
|
|
_rootHierNode->update();
|
2011-08-01 20:16:15 +00:00
|
|
|
bool first = true;
|
2011-08-02 17:17:32 +00:00
|
|
|
for (int i = 0; i < _numHierNodes; ++i) {
|
|
|
|
ModelNode &node = _rootHierNode[i];
|
|
|
|
if (node._mesh) {
|
|
|
|
Mesh &mesh = *node._mesh;
|
2011-10-18 15:42:12 +00:00
|
|
|
Math::Vector3d p = mesh._matrix.getPosition();
|
2011-08-02 17:17:32 +00:00
|
|
|
float x = p.x();
|
|
|
|
float y = p.y();
|
|
|
|
float z = p.z();
|
|
|
|
for (int k = 0; k < mesh._numVertices * 3; k += 3) {
|
|
|
|
if (first || mesh._vertices[k] + x < _bboxPos.x())
|
|
|
|
_bboxPos.x() = mesh._vertices[k] + x;
|
2011-10-18 15:42:12 +00:00
|
|
|
if (first || mesh._vertices[k + 1] + y < _bboxPos.y())
|
2011-08-02 17:17:32 +00:00
|
|
|
_bboxPos.y() = mesh._vertices[k + 1] + y;
|
2011-10-18 15:42:12 +00:00
|
|
|
if (first || mesh._vertices[k + 2] + z < _bboxPos.z())
|
2011-08-02 17:17:32 +00:00
|
|
|
_bboxPos.z() = mesh._vertices[k + 2] + z;
|
|
|
|
|
|
|
|
if (first || mesh._vertices[k] + x > max.x())
|
|
|
|
max.x() = mesh._vertices[k] + x;
|
2011-10-18 15:42:12 +00:00
|
|
|
if (first || mesh._vertices[k + 1] + y > max.y())
|
2011-08-02 17:17:32 +00:00
|
|
|
max.y() = mesh._vertices[k + 1] + y;
|
2011-10-18 15:42:12 +00:00
|
|
|
if (first || mesh._vertices[k + 2] + z > max.z())
|
2011-08-02 17:17:32 +00:00
|
|
|
max.z() = mesh._vertices[k + 2] + z;
|
2011-08-01 20:16:15 +00:00
|
|
|
|
|
|
|
first = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_bboxSize = max - _bboxPos;
|
2003-08-15 18:00:22 +00:00
|
|
|
}
|
|
|
|
|
2011-07-22 20:20:48 +00:00
|
|
|
Model::~Model() {
|
2011-12-11 22:28:22 +00:00
|
|
|
for (int i = 0; i < _numMaterials; ++i) {
|
|
|
|
if (!_materialsShared[i]) {
|
|
|
|
delete _materials[i];
|
|
|
|
}
|
|
|
|
}
|
2011-07-22 20:20:48 +00:00
|
|
|
delete[] _materials;
|
|
|
|
delete[] _materialNames;
|
2011-12-11 22:28:22 +00:00
|
|
|
delete[] _materialsShared;
|
2011-07-22 20:20:48 +00:00
|
|
|
delete[] _geosets;
|
|
|
|
delete[] _rootHierNode;
|
|
|
|
g_resourceloader->uncacheModel(this);
|
2005-07-10 18:57:27 +00:00
|
|
|
}
|
|
|
|
|
2011-12-19 17:26:48 +00:00
|
|
|
void Model::loadEMI(Common::SeekableReadStream *data) {
|
2011-05-09 08:00:01 +00:00
|
|
|
char name[64];
|
|
|
|
|
2011-12-19 17:26:48 +00:00
|
|
|
int nameLength = data->readUint32LE();
|
2011-05-09 08:00:01 +00:00
|
|
|
assert(nameLength < 64);
|
|
|
|
|
2011-12-19 17:26:48 +00:00
|
|
|
data->read(name, nameLength);
|
2011-05-09 08:00:01 +00:00
|
|
|
|
2011-06-02 18:19:23 +00:00
|
|
|
// skip over some unkown floats
|
2011-12-19 17:26:48 +00:00
|
|
|
data->seek(48, SEEK_CUR);
|
2011-06-02 18:19:23 +00:00
|
|
|
|
2011-12-19 17:26:48 +00:00
|
|
|
_numMaterials = data->readUint32LE();
|
2011-07-18 20:16:40 +00:00
|
|
|
_materials = new Material*[_numMaterials];
|
2011-05-09 08:00:01 +00:00
|
|
|
_materialNames = new char[_numMaterials][32];
|
|
|
|
for (int i = 0; i < _numMaterials; i++) {
|
2011-12-19 17:26:48 +00:00
|
|
|
nameLength = data->readUint32LE();
|
2011-05-09 08:00:01 +00:00
|
|
|
assert(nameLength < 32);
|
|
|
|
|
2011-12-19 17:26:48 +00:00
|
|
|
data->read(_materialNames[i], nameLength);
|
2011-06-02 18:19:23 +00:00
|
|
|
// I'm not sure what specialty mateials are, but they are handled differently.
|
|
|
|
if (memcmp(_materialNames[i], "specialty", 9) == 0) {
|
|
|
|
_materials[i] = 0;
|
|
|
|
} else {
|
2011-07-18 21:43:01 +00:00
|
|
|
loadMaterial(i, 0);
|
2011-06-02 18:19:23 +00:00
|
|
|
}
|
2011-12-19 17:26:48 +00:00
|
|
|
data->seek(4, SEEK_CUR);
|
2011-05-09 08:00:01 +00:00
|
|
|
}
|
|
|
|
|
2011-12-19 17:26:48 +00:00
|
|
|
data->seek(4, SEEK_CUR);
|
2011-05-09 08:00:01 +00:00
|
|
|
|
|
|
|
|
|
|
|
}
|
2011-12-19 17:26:48 +00:00
|
|
|
void Model::loadBinary(Common::SeekableReadStream *data, CMap *cmap) {
|
|
|
|
char v3[4 * 3], f[4];
|
|
|
|
_numMaterials = data->readUint32LE();
|
2011-07-18 20:16:40 +00:00
|
|
|
_materials = new Material*[_numMaterials];
|
2005-07-10 18:57:27 +00:00
|
|
|
_materialNames = new char[_numMaterials][32];
|
2011-07-18 21:43:01 +00:00
|
|
|
_materialsShared = new bool[_numMaterials];
|
2004-12-09 23:55:43 +00:00
|
|
|
for (int i = 0; i < _numMaterials; i++) {
|
2011-12-19 17:26:48 +00:00
|
|
|
data->read(_materialNames[i], 32);
|
2011-07-18 21:43:01 +00:00
|
|
|
_materialsShared[i] = false;
|
|
|
|
_materials[i] = NULL;
|
|
|
|
loadMaterial(i, cmap);
|
2004-02-24 22:43:32 +00:00
|
|
|
}
|
2011-12-19 17:26:48 +00:00
|
|
|
data->seek(32, SEEK_CUR); // skip name
|
|
|
|
data->seek(4, SEEK_CUR);
|
|
|
|
_numGeosets = data->readUint32LE();
|
2004-12-09 23:55:43 +00:00
|
|
|
_geosets = new Geoset[_numGeosets];
|
|
|
|
for (int i = 0; i < _numGeosets; i++)
|
2011-07-18 20:16:40 +00:00
|
|
|
_geosets[i].loadBinary(data, _materials);
|
2011-12-19 17:26:48 +00:00
|
|
|
data->seek(4, SEEK_CUR);
|
|
|
|
_numHierNodes = data->readUint32LE();
|
2011-07-22 20:09:49 +00:00
|
|
|
_rootHierNode = new ModelNode[_numHierNodes];
|
2011-07-18 20:23:18 +00:00
|
|
|
for (int i = 0; i < _numHierNodes; i++) {
|
|
|
|
_rootHierNode[i].loadBinary(data, _rootHierNode, &_geosets[0]);
|
|
|
|
}
|
2011-12-19 17:26:48 +00:00
|
|
|
data->read(f, 4);
|
|
|
|
_radius = get_float(f);
|
|
|
|
data->seek(36, SEEK_CUR);
|
|
|
|
data->read(v3, 3 * 4);
|
|
|
|
_insertOffset = Math::Vector3d::get_vector3d(v3);
|
2003-08-15 18:00:22 +00:00
|
|
|
}
|
|
|
|
|
2011-03-20 21:16:27 +00:00
|
|
|
void Model::loadText(TextSplitter *ts, CMap *cmap) {
|
2009-06-26 16:13:11 +00:00
|
|
|
ts->expectString("section: header");
|
2004-02-24 22:43:32 +00:00
|
|
|
int major, minor;
|
2009-06-26 16:13:11 +00:00
|
|
|
ts->scanString("3do %d.%d", 2, &major, &minor);
|
|
|
|
ts->expectString("section: modelresource");
|
|
|
|
ts->scanString("materials %d", 1, &_numMaterials);
|
2011-07-18 20:16:40 +00:00
|
|
|
_materials = new Material*[_numMaterials];
|
2005-07-10 18:57:27 +00:00
|
|
|
_materialNames = new char[_numMaterials][32];
|
2011-07-18 21:43:01 +00:00
|
|
|
_materialsShared = new bool[_numMaterials];
|
2004-12-09 23:55:43 +00:00
|
|
|
for (int i = 0; i < _numMaterials; i++) {
|
2005-07-17 23:40:22 +00:00
|
|
|
char materialName[32];
|
2004-02-24 22:43:32 +00:00
|
|
|
int num;
|
2011-07-18 21:43:01 +00:00
|
|
|
_materialsShared[i] = false;
|
|
|
|
_materials[i] = NULL;
|
2008-07-30 07:04:32 +00:00
|
|
|
|
2009-06-26 16:13:11 +00:00
|
|
|
ts->scanString("%d: %32s", 2, &num, materialName);
|
2005-07-17 23:40:22 +00:00
|
|
|
strcpy(_materialNames[num], materialName);
|
2011-07-18 21:43:01 +00:00
|
|
|
loadMaterial(num, cmap);
|
2004-02-24 22:43:32 +00:00
|
|
|
}
|
|
|
|
|
2009-06-26 16:13:11 +00:00
|
|
|
ts->expectString("section: geometrydef");
|
|
|
|
ts->scanString("radius %f", 1, &_radius);
|
|
|
|
ts->scanString("insert offset %f %f %f", 3, &_insertOffset.x(), &_insertOffset.y(), &_insertOffset.z());
|
|
|
|
ts->scanString("geosets %d", 1, &_numGeosets);
|
2004-12-09 23:55:43 +00:00
|
|
|
_geosets = new Geoset[_numGeosets];
|
|
|
|
for (int i = 0; i < _numGeosets; i++) {
|
2004-02-24 22:43:32 +00:00
|
|
|
int num;
|
2009-06-26 16:13:11 +00:00
|
|
|
ts->scanString("geoset %d", 1, &num);
|
2011-07-18 20:16:40 +00:00
|
|
|
_geosets[num].loadText(ts, _materials);
|
2004-02-24 22:43:32 +00:00
|
|
|
}
|
|
|
|
|
2009-06-26 16:13:11 +00:00
|
|
|
ts->expectString("section: hierarchydef");
|
|
|
|
ts->scanString("hierarchy nodes %d", 1, &_numHierNodes);
|
2011-07-22 20:09:49 +00:00
|
|
|
_rootHierNode = new ModelNode[_numHierNodes];
|
2004-12-09 23:55:43 +00:00
|
|
|
for (int i = 0; i < _numHierNodes; i++) {
|
2009-06-07 14:34:48 +00:00
|
|
|
int num, mesh, parent, child, sibling, numChildren;
|
|
|
|
unsigned int flags, type;
|
2004-02-24 22:43:32 +00:00
|
|
|
float x, y, z, pitch, yaw, roll, pivotx, pivoty, pivotz;
|
|
|
|
char name[64];
|
2009-06-26 16:13:11 +00:00
|
|
|
ts->scanString(" %d: %x %x %d %d %d %d %d %f %f %f %f %f %f %f %f %f %64s",
|
2011-07-22 20:20:48 +00:00
|
|
|
18, &num, &flags, &type, &mesh, &parent, &child, &sibling,
|
|
|
|
&numChildren, &x, &y, &z, &pitch, &yaw, &roll, &pivotx, &pivoty, &pivotz, name);
|
2009-06-07 14:34:48 +00:00
|
|
|
_rootHierNode[num]._flags = (int)flags;
|
|
|
|
_rootHierNode[num]._type = (int)type;
|
2004-02-24 22:43:32 +00:00
|
|
|
if (mesh < 0)
|
2004-12-09 23:55:43 +00:00
|
|
|
_rootHierNode[num]._mesh = NULL;
|
2004-02-24 22:43:32 +00:00
|
|
|
else
|
2009-06-26 16:13:11 +00:00
|
|
|
_rootHierNode[num]._mesh = &_geosets[0]._meshes[mesh];
|
2004-02-24 22:43:32 +00:00
|
|
|
if (parent >= 0) {
|
2009-06-26 16:13:11 +00:00
|
|
|
_rootHierNode[num]._parent = &_rootHierNode[parent];
|
2004-12-09 23:55:43 +00:00
|
|
|
_rootHierNode[num]._depth = _rootHierNode[parent]._depth + 1;
|
2004-02-24 22:43:32 +00:00
|
|
|
} else {
|
2004-12-09 23:55:43 +00:00
|
|
|
_rootHierNode[num]._parent = NULL;
|
|
|
|
_rootHierNode[num]._depth = 0;
|
2004-02-24 22:43:32 +00:00
|
|
|
}
|
|
|
|
if (child >= 0)
|
2009-06-26 16:13:11 +00:00
|
|
|
_rootHierNode[num]._child = &_rootHierNode[child];
|
2004-02-24 22:43:32 +00:00
|
|
|
else
|
2004-12-09 23:55:43 +00:00
|
|
|
_rootHierNode[num]._child = NULL;
|
2004-02-24 22:43:32 +00:00
|
|
|
if (sibling >= 0)
|
2009-06-26 16:13:11 +00:00
|
|
|
_rootHierNode[num]._sibling = &_rootHierNode[sibling];
|
2004-02-24 22:43:32 +00:00
|
|
|
else
|
2004-12-09 23:55:43 +00:00
|
|
|
_rootHierNode[num]._sibling = NULL;
|
|
|
|
|
|
|
|
_rootHierNode[num]._numChildren = numChildren;
|
2011-09-10 15:46:07 +00:00
|
|
|
_rootHierNode[num]._pos = Math::Vector3d(x, y, z);
|
2004-12-09 23:55:43 +00:00
|
|
|
_rootHierNode[num]._pitch = pitch;
|
|
|
|
_rootHierNode[num]._yaw = yaw;
|
|
|
|
_rootHierNode[num]._roll = roll;
|
2011-09-10 15:46:07 +00:00
|
|
|
_rootHierNode[num]._pivot = Math::Vector3d(pivotx, pivoty, pivotz);
|
2004-12-09 23:55:43 +00:00
|
|
|
_rootHierNode[num]._meshVisible = true;
|
|
|
|
_rootHierNode[num]._hierVisible = true;
|
2011-05-15 20:57:08 +00:00
|
|
|
_rootHierNode[num]._sprite = NULL;
|
2004-02-24 22:43:32 +00:00
|
|
|
}
|
2004-04-19 09:56:34 +00:00
|
|
|
|
2011-10-07 21:05:20 +00:00
|
|
|
if (!ts->isEof())
|
|
|
|
Debug::warning(Debug::Models, "Unexpected junk at end of model text");
|
2003-08-15 18:00:22 +00:00
|
|
|
}
|
|
|
|
|
2011-07-22 20:20:48 +00:00
|
|
|
void Model::draw() const {
|
2011-12-12 17:57:17 +00:00
|
|
|
_rootHierNode->draw();
|
2011-07-22 20:20:48 +00:00
|
|
|
}
|
|
|
|
|
2011-12-12 18:18:33 +00:00
|
|
|
ModelNode *Model::getHierarchy() const {
|
|
|
|
return _rootHierNode;
|
2011-07-22 20:20:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Model::reload(CMap *cmap) {
|
|
|
|
// Load the new colormap
|
|
|
|
for (int i = 0; i < _numMaterials; i++) {
|
|
|
|
loadMaterial(i, cmap);
|
|
|
|
}
|
|
|
|
for (int i = 0; i < _numGeosets; i++)
|
|
|
|
_geosets[i].changeMaterials(_materials);
|
2011-07-24 15:40:50 +00:00
|
|
|
_cmap = cmap;
|
2011-07-22 20:20:48 +00:00
|
|
|
}
|
|
|
|
|
2011-07-18 21:43:01 +00:00
|
|
|
void Model::loadMaterial(int index, CMap *cmap) {
|
2011-07-24 15:40:50 +00:00
|
|
|
Material *mat = NULL;
|
2011-07-18 21:43:01 +00:00
|
|
|
if (!_materialsShared[index]) {
|
2011-07-24 15:40:50 +00:00
|
|
|
mat = _materials[index];
|
2011-07-18 21:43:01 +00:00
|
|
|
}
|
2011-07-24 15:40:50 +00:00
|
|
|
_materials[index] = NULL;
|
2011-07-18 21:43:01 +00:00
|
|
|
if (_parent) {
|
2011-07-27 16:07:35 +00:00
|
|
|
_materials[index] = _parent->findMaterial(_materialNames[index], cmap);
|
2011-07-24 15:40:50 +00:00
|
|
|
if (_materials[index]) {
|
|
|
|
_materialsShared[index] = true;
|
|
|
|
}
|
2011-07-18 21:43:01 +00:00
|
|
|
}
|
|
|
|
if (!_materials[index]) {
|
2011-07-27 16:07:35 +00:00
|
|
|
if (mat && cmap->getFilename() == _cmap->getFilename()) {
|
2011-07-24 15:40:50 +00:00
|
|
|
_materials[index] = mat;
|
|
|
|
} else {
|
|
|
|
_materials[index] = g_resourceloader->loadMaterial(_materialNames[index], cmap);
|
|
|
|
}
|
2011-07-18 21:43:01 +00:00
|
|
|
_materialsShared[index] = false;
|
|
|
|
}
|
2011-07-24 15:40:50 +00:00
|
|
|
if (mat != _materials[index]) {
|
|
|
|
delete mat;
|
|
|
|
}
|
2011-07-18 21:43:01 +00:00
|
|
|
}
|
|
|
|
|
2011-07-27 16:07:35 +00:00
|
|
|
Material *Model::findMaterial(const char *name, CMap *cmap) const {
|
2011-07-18 21:43:01 +00:00
|
|
|
for (int i = 0; i < _numMaterials; ++i) {
|
|
|
|
if (scumm_stricmp(name, _materialNames[i]) == 0) {
|
2011-07-27 16:07:35 +00:00
|
|
|
if (cmap->getFilename() != _cmap->getFilename())
|
|
|
|
_materials[i]->reload(cmap);
|
2011-07-18 21:43:01 +00:00
|
|
|
return _materials[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2011-07-22 20:20:48 +00:00
|
|
|
/**
|
|
|
|
* @class Model::Geoset
|
|
|
|
*/
|
|
|
|
Model::Geoset::~Geoset() {
|
|
|
|
delete[] _meshes;
|
|
|
|
}
|
|
|
|
|
2011-12-19 17:26:48 +00:00
|
|
|
void Model::Geoset::loadBinary(Common::SeekableReadStream *data, Material *materials[]) {
|
|
|
|
_numMeshes = data->readUint32LE();
|
2011-07-22 20:20:48 +00:00
|
|
|
_meshes = new Mesh[_numMeshes];
|
2005-07-10 18:57:27 +00:00
|
|
|
for (int i = 0; i < _numMeshes; i++)
|
2011-07-22 20:20:48 +00:00
|
|
|
_meshes[i].loadBinary(data, materials);
|
2005-07-10 18:57:27 +00:00
|
|
|
}
|
|
|
|
|
2009-08-27 19:01:09 +00:00
|
|
|
void Model::Geoset::loadText(TextSplitter *ts, Material *materials[]) {
|
2009-06-26 16:13:11 +00:00
|
|
|
ts->scanString("meshes %d", 1, &_numMeshes);
|
2004-12-09 23:55:43 +00:00
|
|
|
_meshes = new Mesh[_numMeshes];
|
|
|
|
for (int i = 0; i < _numMeshes; i++) {
|
2004-02-24 22:43:32 +00:00
|
|
|
int num;
|
2009-06-26 16:13:11 +00:00
|
|
|
ts->scanString("mesh %d", 1, &num);
|
2004-12-09 23:55:43 +00:00
|
|
|
_meshes[num].loadText(ts, materials);
|
2004-02-24 22:43:32 +00:00
|
|
|
}
|
2003-08-15 18:00:22 +00:00
|
|
|
}
|
|
|
|
|
2011-07-22 20:20:48 +00:00
|
|
|
void Model::Geoset::changeMaterials(Material *materials[]) {
|
|
|
|
for (int i = 0; i < _numMeshes; i++)
|
|
|
|
_meshes[i].changeMaterials(materials);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @class MeshFace
|
|
|
|
*/
|
|
|
|
MeshFace::~MeshFace() {
|
|
|
|
delete[] _vertices;
|
|
|
|
delete[] _texVertices;
|
|
|
|
}
|
|
|
|
|
2011-12-19 17:26:48 +00:00
|
|
|
int MeshFace::loadBinary(Common::SeekableReadStream *data, Material *materials[]) {
|
|
|
|
char v3[4 * 3], f[4];
|
|
|
|
data->seek(4, SEEK_CUR);
|
|
|
|
_type = data->readUint32LE();
|
|
|
|
_geo = data->readUint32LE();
|
|
|
|
_light = data->readUint32LE();
|
|
|
|
_tex = data->readUint32LE();
|
|
|
|
_numVertices = data->readUint32LE();
|
|
|
|
data->seek(4, SEEK_CUR);
|
|
|
|
int texPtr = data->readUint32LE();
|
|
|
|
int materialPtr = data->readUint32LE();
|
|
|
|
data->seek(12, SEEK_CUR);
|
|
|
|
data->read(f, 4);
|
|
|
|
_extraLight = get_float(f);
|
|
|
|
data->seek(12, SEEK_CUR);
|
|
|
|
data->read(v3, 4 * 3);
|
|
|
|
_normal = Math::Vector3d::get_vector3d(v3);
|
2011-07-22 20:20:48 +00:00
|
|
|
|
|
|
|
_vertices = new int[_numVertices];
|
2011-12-19 17:26:48 +00:00
|
|
|
for (int i = 0; i < _numVertices; i++)
|
|
|
|
_vertices[i] = data->readUint32LE();
|
2011-07-22 20:20:48 +00:00
|
|
|
if (texPtr == 0)
|
|
|
|
_texVertices = NULL;
|
|
|
|
else {
|
|
|
|
_texVertices = new int[_numVertices];
|
2011-12-19 17:26:48 +00:00
|
|
|
for (int i = 0; i < _numVertices; i++)
|
|
|
|
_texVertices[i] = data->readUint32LE();
|
2011-07-22 20:20:48 +00:00
|
|
|
}
|
|
|
|
if (materialPtr == 0)
|
|
|
|
_material = 0;
|
|
|
|
else {
|
2011-12-19 17:26:48 +00:00
|
|
|
materialPtr = data->readUint32LE();
|
|
|
|
_material = materials[materialPtr];
|
2011-07-22 20:20:48 +00:00
|
|
|
}
|
|
|
|
return materialPtr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MeshFace::changeMaterial(Material *material) {
|
|
|
|
_material = material;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MeshFace::draw(float *vertices, float *vertNormals, float *textureVerts) const {
|
|
|
|
_material->select();
|
|
|
|
g_driver->drawModelFace(this, vertices, vertNormals, textureVerts);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @class Mesh
|
|
|
|
*/
|
|
|
|
Mesh::~Mesh() {
|
|
|
|
delete[] _vertices;
|
|
|
|
delete[] _verticesI;
|
|
|
|
delete[] _vertNormals;
|
|
|
|
delete[] _textureVerts;
|
|
|
|
delete[] _faces;
|
|
|
|
delete[] _materialid;
|
|
|
|
}
|
|
|
|
|
2011-12-19 17:26:48 +00:00
|
|
|
void Mesh::loadBinary(Common::SeekableReadStream *data, Material *materials[]) {
|
|
|
|
char f[4];
|
|
|
|
data->read(_name, 32);
|
|
|
|
data->seek(4, SEEK_CUR);
|
|
|
|
_geometryMode = data->readUint32LE();
|
|
|
|
_lightingMode = data->readUint32LE();
|
|
|
|
_textureMode = data->readUint32LE();
|
|
|
|
_numVertices = data->readUint32LE();
|
|
|
|
_numTextureVerts = data->readUint32LE();
|
|
|
|
_numFaces = data->readUint32LE();
|
2011-07-22 20:20:48 +00:00
|
|
|
_vertices = new float[3 * _numVertices];
|
|
|
|
_verticesI = new float[_numVertices];
|
|
|
|
_vertNormals = new float[3 * _numVertices];
|
|
|
|
_textureVerts = new float[2 * _numTextureVerts];
|
|
|
|
_faces = new MeshFace[_numFaces];
|
|
|
|
_materialid = new int[_numFaces];
|
|
|
|
for (int i = 0; i < 3 * _numVertices; i++) {
|
2011-12-19 17:26:48 +00:00
|
|
|
data->read(f, 4);
|
|
|
|
_vertices[i] = get_float(f);
|
2011-07-22 20:20:48 +00:00
|
|
|
}
|
|
|
|
for (int i = 0; i < 2 * _numTextureVerts; i++) {
|
2011-12-19 17:26:48 +00:00
|
|
|
data->read(f, 4);
|
|
|
|
_textureVerts[i] = get_float(f);
|
2011-07-22 20:20:48 +00:00
|
|
|
}
|
|
|
|
for (int i = 0; i < _numVertices; i++) {
|
2011-12-19 17:26:48 +00:00
|
|
|
data->read(f, 4);
|
|
|
|
_verticesI[i] = get_float(f);
|
2011-07-22 20:20:48 +00:00
|
|
|
}
|
2011-12-19 17:26:48 +00:00
|
|
|
data->seek(_numVertices * 4, SEEK_CUR);
|
2005-07-10 18:57:27 +00:00
|
|
|
for (int i = 0; i < _numFaces; i++)
|
2011-07-22 20:20:48 +00:00
|
|
|
_materialid[i] = _faces[i].loadBinary(data, materials);
|
|
|
|
for (int i = 0; i < 3 * _numVertices; i++) {
|
2011-12-19 17:26:48 +00:00
|
|
|
data->read(f, 4);
|
|
|
|
_vertNormals[i] = get_float(f);
|
2011-07-22 20:20:48 +00:00
|
|
|
}
|
2011-12-19 17:26:48 +00:00
|
|
|
_shadow = data->readUint32LE();
|
|
|
|
data->seek(4, SEEK_CUR);
|
|
|
|
data->read(f, 4);
|
|
|
|
_radius = get_float(f);
|
|
|
|
data->seek(24, SEEK_CUR);
|
2005-07-10 18:57:27 +00:00
|
|
|
}
|
|
|
|
|
2011-07-22 20:09:49 +00:00
|
|
|
void Mesh::loadText(TextSplitter *ts, Material* materials[]) {
|
2009-06-26 16:13:11 +00:00
|
|
|
ts->scanString("name %32s", 1, _name);
|
|
|
|
ts->scanString("radius %f", 1, &_radius);
|
2004-02-24 22:43:32 +00:00
|
|
|
|
|
|
|
// In data001/rope_scale.3do, the shadow line is missing
|
2011-05-05 09:56:36 +00:00
|
|
|
if (sscanf(ts->getCurrentLine(), "shadow %d", &_shadow) < 1) {
|
2004-12-09 23:55:43 +00:00
|
|
|
_shadow = 0;
|
2004-02-24 22:43:32 +00:00
|
|
|
} else
|
2009-06-26 16:13:11 +00:00
|
|
|
ts->nextLine();
|
|
|
|
ts->scanString("geometrymode %d", 1, &_geometryMode);
|
|
|
|
ts->scanString("lightingmode %d", 1, &_lightingMode);
|
|
|
|
ts->scanString("texturemode %d", 1, &_textureMode);
|
|
|
|
ts->scanString("vertices %d", 1, &_numVertices);
|
2004-12-09 23:55:43 +00:00
|
|
|
_vertices = new float[3 * _numVertices];
|
|
|
|
_verticesI = new float[_numVertices];
|
|
|
|
_vertNormals = new float[3 * _numVertices];
|
|
|
|
|
|
|
|
for (int i = 0; i < _numVertices; i++) {
|
2004-02-24 22:43:32 +00:00
|
|
|
int num;
|
|
|
|
float x, y, z, ival;
|
2009-06-26 16:13:11 +00:00
|
|
|
ts->scanString(" %d: %f %f %f %f", 5, &num, &x, &y, &z, &ival);
|
2004-12-09 23:55:43 +00:00
|
|
|
_vertices[3 * num] = x;
|
|
|
|
_vertices[3 * num + 1] = y;
|
|
|
|
_vertices[3 * num + 2] = z;
|
|
|
|
_verticesI[num] = ival;
|
2004-02-24 22:43:32 +00:00
|
|
|
}
|
|
|
|
|
2009-06-26 16:13:11 +00:00
|
|
|
ts->scanString("texture vertices %d", 1, &_numTextureVerts);
|
2004-12-09 23:55:43 +00:00
|
|
|
_textureVerts = new float[2 * _numTextureVerts];
|
2004-02-24 22:43:32 +00:00
|
|
|
|
2004-12-09 23:55:43 +00:00
|
|
|
for (int i = 0; i < _numTextureVerts; i++) {
|
2004-02-24 22:43:32 +00:00
|
|
|
int num;
|
|
|
|
float x, y;
|
2009-06-26 16:13:11 +00:00
|
|
|
ts->scanString(" %d: %f %f", 3, &num, &x, &y);
|
2004-12-09 23:55:43 +00:00
|
|
|
_textureVerts[2 * num] = x;
|
|
|
|
_textureVerts[2 * num + 1] = y;
|
2004-02-24 22:43:32 +00:00
|
|
|
}
|
|
|
|
|
2009-06-26 16:13:11 +00:00
|
|
|
ts->expectString("vertex normals");
|
2004-12-09 23:55:43 +00:00
|
|
|
for (int i = 0; i < _numVertices; i++) {
|
2004-02-24 22:43:32 +00:00
|
|
|
int num;
|
|
|
|
float x, y, z;
|
2009-06-26 16:13:11 +00:00
|
|
|
ts->scanString(" %d: %f %f %f", 4, &num, &x, &y, &z);
|
2004-12-09 23:55:43 +00:00
|
|
|
_vertNormals[3 * num] = x;
|
|
|
|
_vertNormals[3 * num + 1] = y;
|
|
|
|
_vertNormals[3 * num + 2] = z;
|
2004-02-24 22:43:32 +00:00
|
|
|
}
|
|
|
|
|
2009-06-26 16:13:11 +00:00
|
|
|
ts->scanString("faces %d", 1, &_numFaces);
|
2011-07-22 20:09:49 +00:00
|
|
|
_faces = new MeshFace[_numFaces];
|
2005-07-10 18:57:27 +00:00
|
|
|
_materialid = new int[_numFaces];
|
2004-12-09 23:55:43 +00:00
|
|
|
for (int i = 0; i < _numFaces; i++) {
|
2009-06-07 14:34:48 +00:00
|
|
|
int num, materialid, geo, light, tex, verts;
|
|
|
|
unsigned int type;
|
2004-02-24 22:43:32 +00:00
|
|
|
float extralight;
|
|
|
|
int readlen;
|
2004-12-09 23:55:43 +00:00
|
|
|
|
2011-05-05 09:56:36 +00:00
|
|
|
if (ts->isEof())
|
2008-09-28 15:23:15 +00:00
|
|
|
error("Expected face data, got EOF");
|
2004-12-09 23:55:43 +00:00
|
|
|
|
2012-02-21 18:11:31 +00:00
|
|
|
ts->scanStringNoNewLine(" %d: %d %x %d %d %d %f %d%n", 8, &num, &materialid, &type, &geo, &light, &tex, &extralight, &verts, &readlen);
|
2004-12-09 23:55:43 +00:00
|
|
|
|
2009-06-07 15:45:00 +00:00
|
|
|
assert(materialid != -1);
|
2005-07-17 23:40:22 +00:00
|
|
|
_materialid[num] = materialid;
|
2009-08-27 19:01:09 +00:00
|
|
|
_faces[num]._material = materials[materialid];
|
2009-06-07 14:34:48 +00:00
|
|
|
_faces[num]._type = (int)type;
|
2004-12-09 23:55:43 +00:00
|
|
|
_faces[num]._geo = geo;
|
|
|
|
_faces[num]._light = light;
|
|
|
|
_faces[num]._tex = tex;
|
|
|
|
_faces[num]._extraLight = extralight;
|
|
|
|
_faces[num]._numVertices = verts;
|
|
|
|
_faces[num]._vertices = new int[verts];
|
|
|
|
_faces[num]._texVertices = new int[verts];
|
2004-02-24 22:43:32 +00:00
|
|
|
for (int j = 0; j < verts; j++) {
|
|
|
|
int readlen2;
|
2004-12-09 23:55:43 +00:00
|
|
|
|
2012-02-21 18:11:31 +00:00
|
|
|
ts->scanStringAtOffsetNoNewLine(readlen, " %d, %d%n", 2, &_faces[num]._vertices[j], &_faces[num]._texVertices[j], &readlen2);
|
2004-02-24 22:43:32 +00:00
|
|
|
readlen += readlen2;
|
|
|
|
}
|
2009-06-26 16:13:11 +00:00
|
|
|
ts->nextLine();
|
2004-02-24 22:43:32 +00:00
|
|
|
}
|
|
|
|
|
2009-06-26 16:13:11 +00:00
|
|
|
ts->expectString("face normals");
|
2004-12-09 23:55:43 +00:00
|
|
|
for (int i = 0; i < _numFaces; i++) {
|
2004-02-24 22:43:32 +00:00
|
|
|
int num;
|
|
|
|
float x, y, z;
|
2009-06-26 16:13:11 +00:00
|
|
|
ts->scanString(" %d: %f %f %f", 4, &num, &x, &y, &z);
|
2011-09-10 15:46:07 +00:00
|
|
|
_faces[num]._normal = Math::Vector3d(x, y, z);
|
2004-02-24 22:43:32 +00:00
|
|
|
}
|
2003-08-15 18:00:22 +00:00
|
|
|
}
|
|
|
|
|
2011-07-22 20:20:48 +00:00
|
|
|
void Mesh::update() {
|
|
|
|
}
|
|
|
|
|
|
|
|
void Mesh::changeMaterials(Material *materials[]) {
|
|
|
|
for (int i = 0; i < _numFaces; i++)
|
|
|
|
_faces[i].changeMaterial(materials[_materialid[i]]);
|
|
|
|
}
|
|
|
|
|
2011-12-12 17:57:17 +00:00
|
|
|
void Mesh::draw() const {
|
2011-07-22 20:20:48 +00:00
|
|
|
if (_lightingMode == 0)
|
|
|
|
g_driver->disableLights();
|
|
|
|
|
|
|
|
for (int i = 0; i < _numFaces; i++)
|
|
|
|
_faces[i].draw(_vertices, _vertNormals, _textureVerts);
|
|
|
|
|
|
|
|
if (_lightingMode == 0)
|
|
|
|
g_driver->enableLights();
|
|
|
|
}
|
|
|
|
|
2011-12-12 17:57:17 +00:00
|
|
|
void Mesh::getBoundingBox(int *x1, int *y1, int *x2, int *y2) const {
|
|
|
|
int winX1, winY1, winX2, winY2;
|
|
|
|
g_driver->getBoundingBoxPos(this, &winX1, &winY1, &winX2, &winY2);
|
|
|
|
if (winX1 != -1 && winY1 != -1 && winX2 != -1 && winY2 != -1) {
|
|
|
|
*x1 = MIN(*x1, winX1);
|
|
|
|
*y1 = MIN(*y1, winY1);
|
|
|
|
*x2 = MAX(*x2, winX2);
|
|
|
|
*y2 = MAX(*y2, winY2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-22 20:20:48 +00:00
|
|
|
/**
|
|
|
|
* @class ModelNode
|
|
|
|
*/
|
|
|
|
ModelNode::~ModelNode() {
|
|
|
|
ModelNode *child = _child;
|
|
|
|
while (child) {
|
|
|
|
child->_parent = NULL;
|
|
|
|
child = child->_sibling;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-19 17:26:48 +00:00
|
|
|
void ModelNode::loadBinary(Common::SeekableReadStream *data, ModelNode *hierNodes, const Model::Geoset *g) {
|
|
|
|
char v3[4 * 3], f[4];
|
|
|
|
data->read(_name, 64);
|
|
|
|
_flags = data->readUint32LE();
|
|
|
|
data->seek(4, SEEK_CUR);
|
|
|
|
_type = data->readUint32LE();
|
|
|
|
int meshNum = data->readUint32LE();
|
2011-07-22 20:20:48 +00:00
|
|
|
if (meshNum < 0)
|
|
|
|
_mesh = NULL;
|
|
|
|
else
|
|
|
|
_mesh = g->_meshes + meshNum;
|
2011-12-19 17:26:48 +00:00
|
|
|
_depth = data->readUint32LE();
|
|
|
|
int parentPtr = data->readUint32LE();
|
|
|
|
_numChildren = data->readUint32LE();
|
|
|
|
int childPtr = data->readUint32LE();
|
|
|
|
int siblingPtr = data->readUint32LE();
|
|
|
|
data->read(v3, 4 * 3);
|
|
|
|
_pivot = Math::Vector3d::get_vector3d(v3);
|
|
|
|
data->read(v3, 4 * 3);
|
|
|
|
_pos = Math::Vector3d::get_vector3d(v3);
|
|
|
|
data->read(f, 4);
|
|
|
|
_pitch = get_float(f);
|
|
|
|
data->read(f, 4);
|
|
|
|
_yaw = get_float(f);
|
|
|
|
data->read(f, 4);
|
|
|
|
_roll = get_float(f);
|
2011-07-22 20:20:48 +00:00
|
|
|
_animPos.set(0,0,0);
|
|
|
|
_animPitch = 0;
|
|
|
|
_animYaw = 0;
|
|
|
|
_animRoll = 0;
|
|
|
|
_sprite = NULL;
|
|
|
|
|
2011-12-19 17:26:48 +00:00
|
|
|
data->seek(48, SEEK_CUR);
|
2011-07-22 20:20:48 +00:00
|
|
|
|
2011-12-19 17:26:48 +00:00
|
|
|
if (parentPtr != 0)
|
|
|
|
_parent = hierNodes + data->readUint32LE();
|
|
|
|
else
|
2011-07-22 20:20:48 +00:00
|
|
|
_parent = NULL;
|
2011-12-19 17:26:48 +00:00
|
|
|
|
|
|
|
if (childPtr != 0)
|
|
|
|
_child = hierNodes + data->readUint32LE();
|
|
|
|
else
|
2011-07-22 20:20:48 +00:00
|
|
|
_child = NULL;
|
2011-12-19 17:26:48 +00:00
|
|
|
|
|
|
|
if (siblingPtr != 0)
|
|
|
|
_sibling = hierNodes + data->readUint32LE();
|
|
|
|
else
|
2011-07-22 20:20:48 +00:00
|
|
|
_sibling = NULL;
|
|
|
|
|
|
|
|
_meshVisible = true;
|
|
|
|
_hierVisible = true;
|
|
|
|
_initialized = true;
|
|
|
|
}
|
|
|
|
|
2011-12-12 17:57:17 +00:00
|
|
|
void ModelNode::draw() const {
|
|
|
|
translateViewpoint();
|
|
|
|
if (_hierVisible) {
|
|
|
|
g_driver->translateViewpointStart();
|
|
|
|
g_driver->translateViewpoint(_pivot);
|
|
|
|
|
|
|
|
if (!g_driver->isShadowModeActive()) {
|
|
|
|
Sprite *sprite = _sprite;
|
|
|
|
while (sprite) {
|
|
|
|
sprite->draw();
|
|
|
|
sprite = sprite->_next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_mesh && _meshVisible) {
|
|
|
|
_mesh->draw();
|
|
|
|
}
|
|
|
|
|
|
|
|
g_driver->translateViewpointFinish();
|
|
|
|
|
|
|
|
if (_child) {
|
|
|
|
_child->draw();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
translateViewpointBack();
|
|
|
|
|
|
|
|
if (_sibling) {
|
|
|
|
_sibling->draw();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ModelNode::getBoundingBox(int *x1, int *y1, int *x2, int *y2) const {
|
|
|
|
translateViewpoint();
|
|
|
|
if (_hierVisible) {
|
|
|
|
g_driver->translateViewpointStart();
|
|
|
|
g_driver->translateViewpoint(_pivot);
|
|
|
|
|
|
|
|
if (_mesh && _meshVisible) {
|
|
|
|
_mesh->getBoundingBox(x1, y1, x2, y2);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_driver->translateViewpointFinish();
|
|
|
|
|
|
|
|
if (_child) {
|
|
|
|
_child->getBoundingBox(x1, y1, x2, y2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
translateViewpointBack();
|
|
|
|
|
|
|
|
if (_sibling) {
|
|
|
|
_sibling->getBoundingBox(x1, y1, x2, y2);
|
|
|
|
}
|
2003-08-15 18:00:22 +00:00
|
|
|
}
|
|
|
|
|
2011-07-22 20:09:49 +00:00
|
|
|
void ModelNode::addChild(ModelNode *child) {
|
|
|
|
ModelNode **childPos = &_child;
|
2008-07-30 07:04:32 +00:00
|
|
|
while (*childPos)
|
2004-12-09 23:55:43 +00:00
|
|
|
childPos = &(*childPos)->_sibling;
|
2004-02-24 22:43:32 +00:00
|
|
|
*childPos = child;
|
2004-12-09 23:55:43 +00:00
|
|
|
child->_parent = this;
|
2003-08-15 18:00:22 +00:00
|
|
|
}
|
|
|
|
|
2011-07-22 20:09:49 +00:00
|
|
|
void ModelNode::removeChild(ModelNode *child) {
|
|
|
|
ModelNode **childPos = &_child;
|
2008-07-30 07:04:32 +00:00
|
|
|
while (*childPos && *childPos != child)
|
2004-12-09 23:55:43 +00:00
|
|
|
childPos = &(*childPos)->_sibling;
|
2008-07-30 07:04:32 +00:00
|
|
|
if (*childPos) {
|
2004-12-09 23:55:43 +00:00
|
|
|
*childPos = child->_sibling;
|
|
|
|
child->_parent = NULL;
|
2004-02-24 22:43:32 +00:00
|
|
|
}
|
2003-08-15 18:00:22 +00:00
|
|
|
}
|
|
|
|
|
2012-02-05 02:07:24 +00:00
|
|
|
void ModelNode::setMatrix(const Math::Matrix4 &matrix) {
|
2004-12-09 23:55:43 +00:00
|
|
|
_matrix = matrix;
|
2011-10-18 15:42:12 +00:00
|
|
|
if (_sibling)
|
|
|
|
_sibling->setMatrix(matrix);
|
2003-08-28 01:55:48 +00:00
|
|
|
}
|
|
|
|
|
2011-07-22 20:09:49 +00:00
|
|
|
void ModelNode::update() {
|
2005-07-21 15:16:35 +00:00
|
|
|
if (!_initialized)
|
|
|
|
return;
|
2009-05-09 17:47:28 +00:00
|
|
|
|
2011-10-18 15:42:12 +00:00
|
|
|
if (_hierVisible) {
|
|
|
|
Math::Vector3d animPos = _pos + _animPos;
|
|
|
|
Math::Angle animPitch = _pitch + _animPitch;
|
|
|
|
Math::Angle animYaw = _yaw + _animYaw;
|
|
|
|
Math::Angle animRoll = _roll + _animRoll;
|
2011-05-24 16:47:39 +00:00
|
|
|
|
2011-10-18 15:42:12 +00:00
|
|
|
_localMatrix.setPosition(animPos);
|
|
|
|
_localMatrix.buildFromPitchYawRoll(animPitch, animYaw, animRoll);
|
2003-08-28 01:55:48 +00:00
|
|
|
|
2011-10-18 15:42:12 +00:00
|
|
|
_matrix = _matrix * _localMatrix;
|
2003-08-28 01:55:48 +00:00
|
|
|
|
2011-10-18 15:42:12 +00:00
|
|
|
_pivotMatrix = _matrix;
|
|
|
|
_pivotMatrix.translate(_pivot);
|
2003-08-28 01:55:48 +00:00
|
|
|
|
2011-10-18 15:42:12 +00:00
|
|
|
if (_mesh) {
|
|
|
|
_mesh->_matrix = _pivotMatrix;
|
|
|
|
}
|
2005-01-11 19:46:47 +00:00
|
|
|
|
2011-10-18 15:42:12 +00:00
|
|
|
if (_child) {
|
|
|
|
_child->setMatrix(_matrix);
|
|
|
|
_child->update();
|
|
|
|
}
|
2005-01-11 19:46:47 +00:00
|
|
|
}
|
2003-08-28 01:55:48 +00:00
|
|
|
|
2011-10-18 15:42:12 +00:00
|
|
|
if (_sibling) {
|
|
|
|
_sibling->update();
|
2005-01-11 19:46:47 +00:00
|
|
|
}
|
2003-08-28 01:55:48 +00:00
|
|
|
}
|
|
|
|
|
2011-07-22 20:09:49 +00:00
|
|
|
void ModelNode::addSprite(Sprite *sprite) {
|
2011-05-15 13:47:09 +00:00
|
|
|
sprite->_next = _sprite;
|
|
|
|
_sprite = sprite;
|
|
|
|
}
|
|
|
|
|
2011-07-22 20:09:49 +00:00
|
|
|
void ModelNode::removeSprite(Sprite *sprite) {
|
2011-05-25 20:01:25 +00:00
|
|
|
Sprite* curr = _sprite;
|
|
|
|
Sprite* prev = NULL;
|
|
|
|
while (curr) {
|
|
|
|
if (curr == sprite) {
|
|
|
|
if (prev)
|
|
|
|
prev->_next = curr->_next;
|
|
|
|
else
|
|
|
|
_sprite = curr->_next;
|
2011-05-15 13:47:09 +00:00
|
|
|
}
|
2011-05-25 20:01:25 +00:00
|
|
|
prev = curr;
|
|
|
|
curr = curr->_next;
|
2011-05-15 13:47:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-12 17:57:17 +00:00
|
|
|
void ModelNode::translateViewpoint() const {
|
|
|
|
Math::Vector3d animPos = _pos + _animPos;
|
|
|
|
Math::Angle animPitch = _pitch + _animPitch;
|
|
|
|
Math::Angle animYaw = _yaw + _animYaw;
|
|
|
|
Math::Angle animRoll = _roll + _animRoll;
|
|
|
|
g_driver->translateViewpointStart();
|
|
|
|
|
|
|
|
g_driver->translateViewpoint(animPos);
|
|
|
|
g_driver->rotateViewpoint(animYaw, Math::Vector3d(0, 0, 1));
|
|
|
|
g_driver->rotateViewpoint(animPitch, Math::Vector3d(1, 0, 0));
|
|
|
|
g_driver->rotateViewpoint(animRoll, Math::Vector3d(0, 1, 0));
|
|
|
|
}
|
|
|
|
|
|
|
|
void ModelNode::translateViewpointBack() const {
|
|
|
|
g_driver->translateViewpointFinish();
|
|
|
|
}
|
|
|
|
|
2009-05-25 06:49:57 +00:00
|
|
|
} // end of namespace Grim
|