Initial commit
This commit is contained in:
233
engines/stark/model/model.cpp
Normal file
233
engines/stark/model/model.cpp
Normal file
@@ -0,0 +1,233 @@
|
||||
/* 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 "engines/stark/model/model.h"
|
||||
|
||||
#include "engines/stark/services/archiveloader.h"
|
||||
#include "engines/stark/model/animhandler.h"
|
||||
#include "engines/stark/gfx/texture.h"
|
||||
|
||||
#include "math/aabb.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
Model::Model() :
|
||||
_u1(0),
|
||||
_u2(0.0) {
|
||||
|
||||
}
|
||||
|
||||
Model::~Model() {
|
||||
for (Common::Array<VertNode *>::iterator it = _vertices.begin(); it != _vertices.end(); ++it)
|
||||
delete *it;
|
||||
|
||||
for (Common::Array<Material *>::iterator it = _materials.begin(); it != _materials.end(); ++it)
|
||||
delete *it;
|
||||
|
||||
for (Common::Array<Face *>::iterator it = _faces.begin(); it != _faces.end(); ++it)
|
||||
delete *it;
|
||||
|
||||
for (Common::Array<BoneNode *>::iterator it = _bones.begin(); it != _bones.end(); ++it)
|
||||
delete *it;
|
||||
}
|
||||
|
||||
void Model::readFromStream(ArchiveReadStream *stream) {
|
||||
uint32 id = stream->readUint32LE();
|
||||
if (id != 4) {
|
||||
error("Wrong magic 1 while reading actor '%d'", id);
|
||||
}
|
||||
|
||||
uint32 format = stream->readUint32LE();
|
||||
if (format == 256) {
|
||||
_u1 = stream->readUint32LE();
|
||||
} else if (format == 16) {
|
||||
_u1 = 0;
|
||||
} else {
|
||||
error("Wrong format while reading actor '%d'", format);
|
||||
}
|
||||
|
||||
uint32 id2 = stream->readUint32LE();
|
||||
if (id2 != 0xDEADBABE) {
|
||||
error("Wrong magic 2 while reading actor '%d'", id2);
|
||||
}
|
||||
|
||||
_u2 = stream->readFloatLE();
|
||||
|
||||
uint32 numMaterials = stream->readUint32LE();
|
||||
|
||||
for (uint i = 0; i < numMaterials; ++i) {
|
||||
Material *node = new Material();
|
||||
node->name = stream->readString();
|
||||
stream->readUint32LE(); // CHECKME: Unknown data
|
||||
node->texture = stream->readString();
|
||||
node->r = stream->readFloatLE();
|
||||
node->g = stream->readFloatLE();
|
||||
node->b = stream->readFloatLE();
|
||||
_materials.push_back(node);
|
||||
}
|
||||
|
||||
uint32 numUnknowns = stream->readUint32LE();
|
||||
if (numUnknowns != 0) {
|
||||
error("Found a mesh with numUnknowns != 0");
|
||||
}
|
||||
|
||||
readBones(stream);
|
||||
|
||||
uint32 numMeshes = stream->readUint32LE();
|
||||
if (numMeshes != 1) {
|
||||
error("Found a mesh with numMeshes != 1 (%d)", numMeshes);
|
||||
}
|
||||
|
||||
_name = stream->readString();
|
||||
|
||||
uint32 numFaces = stream->readUint32LE();
|
||||
for (uint32 j = 0; j < numFaces; ++j) {
|
||||
uint faceVertexIndexOffset = _vertices.size();
|
||||
|
||||
Face *face = new Face();
|
||||
face->materialId = stream->readUint32LE();
|
||||
|
||||
uint32 numVertices = stream->readUint32LE();
|
||||
for (uint32 k = 0; k < numVertices; ++k) {
|
||||
VertNode *vert = new VertNode();
|
||||
vert->_pos1 = stream->readVector3();
|
||||
vert->_pos2 = stream->readVector3();
|
||||
vert->_normal = stream->readVector3();
|
||||
vert->_texS = stream->readFloatLE();
|
||||
vert->_texT = stream->readFloatLE();
|
||||
vert->_bone1 = stream->readUint32LE();
|
||||
vert->_bone2 = stream->readUint32LE();
|
||||
vert->_boneWeight = stream->readFloatLE();
|
||||
_vertices.push_back(vert);
|
||||
}
|
||||
|
||||
uint32 numTriangles = stream->readUint32LE();
|
||||
face->vertexIndices.resize(numTriangles * 3); // 3 vertex indices per triangle
|
||||
for (uint32 k = 0; k < numTriangles; ++k) {
|
||||
face->vertexIndices[k * 3 + 0] = stream->readUint32LE() + faceVertexIndexOffset;
|
||||
face->vertexIndices[k * 3 + 1] = stream->readUint32LE() + faceVertexIndexOffset;
|
||||
face->vertexIndices[k * 3 + 2] = stream->readUint32LE() + faceVertexIndexOffset;
|
||||
}
|
||||
|
||||
_faces.push_back(face);
|
||||
}
|
||||
|
||||
buildBonesBoundingBoxes();
|
||||
}
|
||||
|
||||
void Model::readBones(ArchiveReadStream *stream) {
|
||||
uint32 numBones = stream->readUint32LE();
|
||||
for (uint32 i = 0; i < numBones; ++i) {
|
||||
BoneNode *node = new BoneNode();
|
||||
node->_name = stream->readString();
|
||||
node->_u1 = stream->readFloatLE();
|
||||
|
||||
uint32 len = stream->readUint32LE();
|
||||
for (uint32 j = 0; j < len; ++j)
|
||||
node->_children.push_back(stream->readUint32LE());
|
||||
|
||||
node->_idx = _bones.size();
|
||||
_bones.push_back(node);
|
||||
}
|
||||
|
||||
for (uint32 i = 0; i < numBones; ++i) {
|
||||
BoneNode *node = _bones[i];
|
||||
for (uint j = 0; j < node->_children.size(); ++j) {
|
||||
_bones[node->_children[j]]->_parent = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Model::buildBonesBoundingBoxes() {
|
||||
for (uint i = 0; i < _bones.size(); i++) {
|
||||
buildBoneBoundingBox(_bones[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void Model::buildBoneBoundingBox(BoneNode *bone) const {
|
||||
bone->_boundingBox.reset();
|
||||
|
||||
// Add all the vertices with a non zero weight for the bone to the bone's bounding box
|
||||
for (uint k = 0; k < _vertices.size(); k++) {
|
||||
VertNode *vert = _vertices[k];
|
||||
|
||||
if (vert->_bone1 == bone->_idx) {
|
||||
bone->_boundingBox.expand(vert->_pos1);
|
||||
}
|
||||
|
||||
if (vert->_bone2 == bone->_idx) {
|
||||
bone->_boundingBox.expand(vert->_pos2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Model::intersectRay(const Math::Ray &ray) const {
|
||||
for (uint i = 0; i < _bones.size(); i++) {
|
||||
if (_bones[i]->intersectRay(ray)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Model::updateBoundingBox() {
|
||||
_boundingBox.reset();
|
||||
for (uint i = 0; i < _bones.size(); i++) {
|
||||
_bones[i]->expandModelSpaceBB(_boundingBox);
|
||||
}
|
||||
}
|
||||
|
||||
Math::AABB Model::getBoundingBox() const {
|
||||
return _boundingBox;
|
||||
}
|
||||
|
||||
bool BoneNode::intersectRay(const Math::Ray &ray) const {
|
||||
Math::Ray localRay = ray;
|
||||
localRay.translate(-_animPos);
|
||||
localRay.rotate(_animRot.inverse());
|
||||
|
||||
return localRay.intersectAABB(_boundingBox);
|
||||
}
|
||||
|
||||
void BoneNode::expandModelSpaceBB(Math::AABB &aabb) const {
|
||||
// Transform the bounding box
|
||||
Math::Vector3d min = _boundingBox.getMin();
|
||||
Math::Vector3d max = _boundingBox.getMax();
|
||||
|
||||
Math::Vector3d verts[8];
|
||||
verts[0].set(min.x(), min.y(), min.z());
|
||||
verts[1].set(max.x(), min.y(), min.z());
|
||||
verts[2].set(min.x(), max.y(), min.z());
|
||||
verts[3].set(min.x(), min.y(), max.z());
|
||||
verts[4].set(max.x(), max.y(), min.z());
|
||||
verts[5].set(max.x(), min.y(), max.z());
|
||||
verts[6].set(min.x(), max.y(), max.z());
|
||||
verts[7].set(max.x(), max.y(), max.z());
|
||||
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
_animRot.transform(verts[i]);
|
||||
verts[i] += _animPos;
|
||||
aabb.expand(verts[i]);
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Stark
|
||||
Reference in New Issue
Block a user