2012-01-06 23:29:45 +01:00
|
|
|
/* ResidualVM - A 3D game interpreter
|
2011-12-30 12:39:45 +01:00
|
|
|
*
|
2012-01-06 23:29:45 +01:00
|
|
|
* ResidualVM is the legal property of its developers, whose names
|
2011-12-30 12:39:45 +01:00
|
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
|
|
* file distributed with this source distribution.
|
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "common/endian.h"
|
|
|
|
#include "engines/grim/debug.h"
|
|
|
|
#include "engines/grim/grim.h"
|
|
|
|
#include "engines/grim/material.h"
|
|
|
|
#include "engines/grim/gfx_base.h"
|
|
|
|
#include "engines/grim/resource.h"
|
2012-01-29 16:14:36 +01:00
|
|
|
#include "engines/grim/emi/modelemi.h"
|
2012-01-30 22:59:18 +01:00
|
|
|
#include "engines/grim/emi/animationemi.h"
|
|
|
|
#include "engines/grim/emi/skeleton.h"
|
2011-12-30 12:39:45 +01:00
|
|
|
|
|
|
|
namespace Grim {
|
|
|
|
|
|
|
|
struct Vector3int {
|
|
|
|
int _x;
|
|
|
|
int _y;
|
|
|
|
int _z;
|
|
|
|
void setVal(int x, int y, int z) {
|
|
|
|
_x = x; _y = y; _z = z;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2012-01-30 22:59:18 +01:00
|
|
|
struct BoneInfo {
|
|
|
|
int _incFac;
|
|
|
|
int _joint;
|
|
|
|
float _weight;
|
|
|
|
};
|
|
|
|
|
2012-01-30 22:24:09 +01:00
|
|
|
Common::String readLAString(Common::ReadStream *ms) {
|
|
|
|
int strLength = ms->readUint32LE();
|
2011-12-30 12:39:45 +01:00
|
|
|
char* readString = new char[strLength];
|
2012-01-30 22:24:09 +01:00
|
|
|
ms->read(readString, strLength);
|
2011-12-30 12:39:45 +01:00
|
|
|
|
|
|
|
Common::String retVal(readString);
|
|
|
|
delete[] readString;
|
|
|
|
|
|
|
|
return retVal;
|
|
|
|
}
|
2011-12-30 16:41:52 +01:00
|
|
|
|
|
|
|
void EMIMeshFace::loadFace(Common::SeekableReadStream *data) {
|
|
|
|
_flags = data->readUint32LE();
|
|
|
|
_hasTexture = data->readUint32LE();
|
2012-01-14 18:05:19 +01:00
|
|
|
|
2011-12-30 12:39:45 +01:00
|
|
|
if(_hasTexture)
|
2011-12-30 16:41:52 +01:00
|
|
|
_texID = data->readUint32LE();
|
|
|
|
_faceLength = data->readUint32LE();
|
2011-12-30 12:39:45 +01:00
|
|
|
_faceLength = _faceLength / 3;
|
2012-01-14 12:52:54 +01:00
|
|
|
int x = 0, y = 0, z = 0;
|
2011-12-30 12:39:45 +01:00
|
|
|
_indexes = new Vector3int[_faceLength];
|
|
|
|
int j = 0;
|
2012-01-14 12:52:54 +01:00
|
|
|
int readsize;
|
|
|
|
if (g_grim->getGamePlatform() == Common::kPlatformPS2) {
|
|
|
|
readsize = 4;
|
|
|
|
} else {
|
|
|
|
readsize = 2;
|
|
|
|
}
|
2011-12-31 14:51:43 +01:00
|
|
|
for (uint32 i = 0; i < _faceLength; i ++) {
|
2012-01-14 12:52:54 +01:00
|
|
|
data->read((char *)&x, readsize);
|
|
|
|
data->read((char *)&y, readsize);
|
|
|
|
data->read((char *)&z, readsize);
|
2011-12-30 12:39:45 +01:00
|
|
|
_indexes[j++].setVal(x,y,z);
|
|
|
|
}
|
|
|
|
}
|
2011-12-30 16:41:52 +01:00
|
|
|
|
2012-01-26 07:49:33 +01:00
|
|
|
EMIMeshFace::~EMIMeshFace() {
|
|
|
|
delete[] _indexes;
|
|
|
|
}
|
|
|
|
|
2011-12-30 12:39:45 +01:00
|
|
|
void EMIModel::setTex(int index) {
|
|
|
|
_mats[index]->select();
|
2011-12-30 16:41:52 +01:00
|
|
|
}
|
2011-12-30 12:39:45 +01:00
|
|
|
|
|
|
|
// May be removed when I get through the conversion
|
|
|
|
void EMIMeshFace::render() {
|
|
|
|
if(_hasTexture) {
|
|
|
|
_parent->setTex(_texID);
|
|
|
|
}
|
|
|
|
//glDrawElements(GL_TRIANGLES, _faceLength * 3, GL_UNSIGNED_INT, _indexes);
|
|
|
|
}
|
2011-12-30 16:41:52 +01:00
|
|
|
|
|
|
|
void EMIModel::loadMesh(Common::SeekableReadStream *data) {
|
2012-01-27 12:02:03 +01:00
|
|
|
//int strLength = 0; // Usefull for PS2-strings
|
2011-12-30 12:39:45 +01:00
|
|
|
|
2012-01-30 22:24:09 +01:00
|
|
|
Common::String nameString = readLAString(data);
|
2011-12-30 12:39:45 +01:00
|
|
|
|
2012-01-30 22:32:28 +01:00
|
|
|
_sphereData->readFromStream(data);
|
|
|
|
|
|
|
|
_boxData->readFromStream(data);
|
|
|
|
_boxData2->readFromStream(data);
|
2011-12-31 14:51:43 +01:00
|
|
|
|
2011-12-30 16:41:52 +01:00
|
|
|
_numTexSets = data->readUint32LE();
|
|
|
|
_setType = data->readUint32LE();
|
|
|
|
_numTextures = data->readUint32LE();
|
2011-12-31 14:51:43 +01:00
|
|
|
|
2011-12-30 12:39:45 +01:00
|
|
|
_texNames = new Common::String[_numTextures];
|
2011-12-31 14:51:43 +01:00
|
|
|
|
|
|
|
for(uint32 i = 0;i < _numTextures; i++) {
|
2012-01-30 22:24:09 +01:00
|
|
|
_texNames[i] = readLAString(data);
|
2011-12-30 12:39:45 +01:00
|
|
|
// Every texname seems to be followed by 4 0-bytes (Ref mk1.mesh,
|
|
|
|
// this is intentional)
|
2011-12-30 16:41:52 +01:00
|
|
|
data->skip(4);
|
2011-12-30 12:39:45 +01:00
|
|
|
}
|
2011-12-31 14:51:43 +01:00
|
|
|
|
2011-12-30 12:39:45 +01:00
|
|
|
// 4 unknown bytes - usually with value 19
|
2011-12-30 16:41:52 +01:00
|
|
|
data->skip(4);
|
2011-12-31 14:51:43 +01:00
|
|
|
|
2011-12-30 16:41:52 +01:00
|
|
|
_numVertices = data->readUint32LE();
|
2011-12-31 14:51:43 +01:00
|
|
|
|
2011-12-30 12:39:45 +01:00
|
|
|
// Vertices
|
2012-01-30 22:32:28 +01:00
|
|
|
_vertices = new Math::Vector3d[_numVertices];
|
2012-01-31 00:14:26 +01:00
|
|
|
_drawVertices = new Math::Vector3d[_numVertices];
|
2012-01-30 22:32:28 +01:00
|
|
|
for (int i = 0; i < _numVertices; i++) {
|
|
|
|
_vertices[i].readFromStream(data);
|
2012-01-31 00:14:26 +01:00
|
|
|
_drawVertices[i] = _vertices[i];
|
2012-01-30 22:32:28 +01:00
|
|
|
}
|
|
|
|
_normals = new Math::Vector3d[_numVertices];
|
|
|
|
for (int i = 0; i < _numVertices; i++) {
|
|
|
|
_normals[i].readFromStream(data);
|
|
|
|
}
|
2011-12-30 12:39:45 +01:00
|
|
|
_colorMap = new EMIColormap[_numVertices];
|
|
|
|
for (int i = 0; i < _numVertices; ++i) {
|
2011-12-30 16:41:52 +01:00
|
|
|
_colorMap[i].r = data->readByte();
|
|
|
|
_colorMap[i].g = data->readByte();
|
|
|
|
_colorMap[i].b = data->readByte();
|
|
|
|
_colorMap[i].a = data->readByte();
|
2011-12-30 12:39:45 +01:00
|
|
|
}
|
2012-01-30 22:32:28 +01:00
|
|
|
_texVerts = new Math::Vector2d[_numVertices];
|
|
|
|
for (int i = 0; i < _numVertices; i++) {
|
|
|
|
_texVerts[i].readFromStream(data);
|
|
|
|
}
|
2011-12-31 14:51:43 +01:00
|
|
|
|
2011-12-30 12:39:45 +01:00
|
|
|
// Faces
|
2011-12-31 14:51:43 +01:00
|
|
|
|
2011-12-30 16:41:52 +01:00
|
|
|
_numFaces = data->readUint32LE();
|
2011-12-30 12:39:45 +01:00
|
|
|
|
2011-12-31 14:51:43 +01:00
|
|
|
// Handle the empty-faced fx/screen?.mesh-files
|
|
|
|
if (data->eos()) {
|
|
|
|
_numFaces = 0;
|
|
|
|
_faces = NULL;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-12-30 12:39:45 +01:00
|
|
|
_faces = new EMIMeshFace[_numFaces];
|
2011-12-31 14:51:43 +01:00
|
|
|
|
|
|
|
for(uint32 j = 0;j < _numFaces; j++) {
|
2011-12-30 12:39:45 +01:00
|
|
|
_faces[j].setParent(this);
|
2011-12-30 16:41:52 +01:00
|
|
|
_faces[j].loadFace(data);
|
2011-12-30 12:39:45 +01:00
|
|
|
}
|
2011-12-31 14:51:43 +01:00
|
|
|
|
2012-01-30 22:59:18 +01:00
|
|
|
int hasBones = data->readUint32LE();
|
|
|
|
|
|
|
|
if (hasBones == 1) {
|
|
|
|
_numBones = data->readUint32LE();
|
|
|
|
_bones = new Bone[_numBones];
|
|
|
|
_boneNames = new Common::String[_numBones];
|
|
|
|
for(int i = 0;i < _numBones; i++) {
|
|
|
|
_bones[i]._boneName = readLAString(data);
|
|
|
|
_boneNames[i] = _bones[i]._boneName;
|
|
|
|
}
|
|
|
|
|
|
|
|
_numBoneInfos = data->readUint32LE();
|
|
|
|
_boneInfos = new BoneInfo[_numBoneInfos];
|
|
|
|
|
|
|
|
for(int i = 0;i < _numBoneInfos; i++) {
|
|
|
|
_boneInfos[i]._incFac = data->readUint32LE();
|
|
|
|
_boneInfos[i]._joint = data->readUint32LE();
|
|
|
|
_boneInfos[i]._weight = data->readUint32LE();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
_numBones = 0;
|
|
|
|
_numBoneInfos = 0;
|
|
|
|
}
|
2012-01-02 14:00:05 +01:00
|
|
|
prepare(); // <- Initialize materials etc.
|
2011-12-30 12:39:45 +01:00
|
|
|
}
|
|
|
|
|
2012-01-30 22:59:18 +01:00
|
|
|
void EMIModel::setSkeleton(Skeleton *skel) {
|
2012-01-31 17:12:59 -08:00
|
|
|
if (_skeleton == skel) {
|
|
|
|
return;
|
|
|
|
}
|
2012-01-30 22:59:18 +01:00
|
|
|
_skeleton = skel;
|
2012-01-31 17:12:59 -08:00
|
|
|
if (!skel || !_numBoneInfos) {
|
|
|
|
return;
|
|
|
|
}
|
2012-01-30 22:59:18 +01:00
|
|
|
int boneVert = 0;
|
|
|
|
delete[] _vertexBoneInfo; _vertexBoneInfo = NULL;
|
|
|
|
delete[] _vertexBone; _vertexBone = NULL;
|
|
|
|
_vertexBoneInfo = new int[_numBoneInfos];
|
|
|
|
_vertexBone = new int[_numBoneInfos]; // Oversized, but yeah.
|
|
|
|
|
|
|
|
for (int i = 0; i < _numBoneInfos; i++) {
|
|
|
|
_vertexBoneInfo[i] = _skeleton->findJointIndex(_boneNames[_boneInfos[i]._joint], _skeleton->_numJoints);
|
|
|
|
|
|
|
|
if (_boneInfos[i]._incFac == 1) {
|
|
|
|
_vertexBone[boneVert] = i;
|
|
|
|
boneVert++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Math::Vector3d vertex;
|
|
|
|
Math::Matrix4 mat;
|
|
|
|
for (int i = 0; i < _numVertices; i++) {
|
|
|
|
vertex = _vertices[i];
|
|
|
|
if (_vertexBoneInfo[_vertexBone[i]] != -1) {
|
|
|
|
mat = _skeleton->_joints[_vertexBoneInfo[_vertexBone[i]]]._absMatrix;
|
2012-01-31 16:59:29 +01:00
|
|
|
mat.inverseTranslate(&vertex);
|
|
|
|
mat.inverseRotate(&vertex);
|
2012-01-30 22:59:18 +01:00
|
|
|
}
|
|
|
|
_vertices[i] = vertex;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-30 12:39:45 +01:00
|
|
|
void EMIModel::prepareForRender() {
|
2012-01-31 17:12:59 -08:00
|
|
|
if (!_skeleton || !_vertexBoneInfo)
|
2012-01-31 00:14:26 +01:00
|
|
|
return;
|
|
|
|
for (int i = 0; i < _numVertices; i++) {
|
|
|
|
_drawVertices[i] = _vertices[i];
|
|
|
|
int animIndex = _vertexBoneInfo[_vertexBone[i]];
|
|
|
|
_skeleton->_joints[animIndex]._finalMatrix.transform(_drawVertices + i, true);
|
|
|
|
}
|
2011-12-30 12:39:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void EMIModel::prepare() {
|
|
|
|
_mats = new Material*[_numTextures];
|
2011-12-31 14:51:43 +01:00
|
|
|
for (uint32 i = 0; i < _numTextures; i++) {
|
2012-01-09 19:07:22 +01:00
|
|
|
// HACK: As we dont know what specialty-textures are yet, we skip loading them
|
|
|
|
if (!_texNames[i].contains("specialty"))
|
|
|
|
_mats[i] = g_resourceloader->loadMaterial(_texNames[i].c_str(), NULL);
|
2011-12-30 12:39:45 +01:00
|
|
|
}
|
|
|
|
prepareForRender();
|
|
|
|
}
|
|
|
|
|
|
|
|
void EMIModel::draw() {
|
|
|
|
prepareForRender();
|
|
|
|
// We will need to add a call to the skeleton, to get the modified vertices, but for now,
|
|
|
|
// I'll be happy with just static drawing
|
2011-12-31 14:51:43 +01:00
|
|
|
for(uint32 i = 0; i < _numFaces; i++) {
|
2012-01-07 03:16:55 +01:00
|
|
|
_faces[i].render();
|
2011-12-30 12:53:49 +01:00
|
|
|
g_driver->drawEMIModelFace(this, &_faces[i]);
|
2011-12-30 12:39:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-31 14:51:43 +01:00
|
|
|
EMIModel::EMIModel(const Common::String &filename, Common::SeekableReadStream *data, EMIModel *parent) : _fname(filename) {
|
2012-01-26 07:49:33 +01:00
|
|
|
_numVertices = 0;
|
|
|
|
_vertices = NULL;
|
2012-01-31 00:14:26 +01:00
|
|
|
_drawVertices = NULL;
|
2012-01-26 07:49:33 +01:00
|
|
|
_normals = NULL;
|
|
|
|
_colorMap = NULL;
|
|
|
|
_texVerts = NULL;
|
|
|
|
_numFaces = 0;
|
|
|
|
_faces = NULL;
|
|
|
|
_numTextures = 0;
|
|
|
|
_texNames = NULL;
|
|
|
|
_mats = NULL;
|
|
|
|
_numBones = 0;
|
2012-01-30 22:59:18 +01:00
|
|
|
_bones = NULL;
|
|
|
|
_boneInfos = NULL;
|
|
|
|
_numBoneInfos = 0;
|
|
|
|
_vertexBoneInfo = NULL;
|
|
|
|
_vertexBone = NULL;
|
2012-01-31 00:14:26 +01:00
|
|
|
_skeleton = NULL;
|
2012-01-30 22:32:28 +01:00
|
|
|
_sphereData = new Math::Vector4d();
|
|
|
|
_boxData = new Math::Vector3d();
|
|
|
|
_boxData2 = new Math::Vector3d();
|
2012-01-26 07:49:33 +01:00
|
|
|
_numTexSets = 0;
|
|
|
|
_setType = 0;
|
|
|
|
|
2011-12-30 16:41:52 +01:00
|
|
|
loadMesh(data);
|
2011-12-30 12:39:45 +01:00
|
|
|
}
|
2012-01-26 07:49:33 +01:00
|
|
|
|
|
|
|
EMIModel::~EMIModel() {
|
|
|
|
delete[] _vertices;
|
2012-01-31 00:14:26 +01:00
|
|
|
delete[] _drawVertices;
|
2012-01-26 07:49:33 +01:00
|
|
|
delete[] _normals;
|
|
|
|
delete[] _colorMap;
|
|
|
|
delete[] _texVerts;
|
|
|
|
delete[] _faces;
|
|
|
|
delete[] _texNames;
|
|
|
|
delete[] _mats;
|
2012-01-30 22:59:18 +01:00
|
|
|
delete[] _bones;
|
|
|
|
delete[] _boneInfos;
|
|
|
|
delete[] _vertexBone;
|
|
|
|
delete[] _vertexBoneInfo;
|
2012-01-26 07:49:33 +01:00
|
|
|
delete _sphereData;
|
|
|
|
delete _boxData;
|
|
|
|
delete _boxData2;
|
|
|
|
}
|
|
|
|
|
2011-12-30 12:39:45 +01:00
|
|
|
} // end of namespace Grim
|