scummvm/engines/grim/emi/modelemi.cpp
2012-01-29 16:14:36 +01:00

247 lines
6.1 KiB
C++

/* ResidualVM - A 3D game interpreter
*
* ResidualVM 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 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"
#include "engines/grim/emi/modelemi.h"
namespace Grim {
struct Vector3int {
int _x;
int _y;
int _z;
void setVal(int x, int y, int z) {
_x = x; _y = y; _z = z;
}
};
Common::String readLAString(Common::ReadStream &ms) {
int strLength = ms.readUint32LE();
char* readString = new char[strLength];
ms.read(readString, strLength);
Common::String retVal(readString);
delete[] readString;
return retVal;
}
Math::Vector2d *readVector2d(Common::ReadStream &ms, int count = 1) {
Math::Vector2d *vec2d = new Math::Vector2d[count];
char buf[8];
for (int i = 0; i < count; i++) {
ms.read(buf, 8);
vec2d[i].setX(get_float(buf));
vec2d[i].setY(get_float(buf + 4));
}
return vec2d;
}
Math::Vector3d *readVector3d(Common::ReadStream &ms, int count = 1) {
Math::Vector3d *vec3d = new Math::Vector3d[count];
char buf[12];
for (int i = 0; i < count; i++) {
ms.read(buf, 12);
vec3d[i] = Math::Vector3d::get_vector3d(buf);
}
return vec3d;
}
Math::Vector4d *readVector4d(Common::ReadStream &ms) {
Math::Vector4d *vec4d = new Math::Vector4d();
char buf[16];
ms.read(buf, 16);
*vec4d = Math::Vector4d::get_vector4d(buf);
return vec4d;
}
void EMIMeshFace::loadFace(Common::SeekableReadStream *data) {
_flags = data->readUint32LE();
_hasTexture = data->readUint32LE();
if(_hasTexture)
_texID = data->readUint32LE();
_faceLength = data->readUint32LE();
_faceLength = _faceLength / 3;
int x = 0, y = 0, z = 0;
_indexes = new Vector3int[_faceLength];
int j = 0;
int readsize;
if (g_grim->getGamePlatform() == Common::kPlatformPS2) {
readsize = 4;
} else {
readsize = 2;
}
for (uint32 i = 0; i < _faceLength; i ++) {
data->read((char *)&x, readsize);
data->read((char *)&y, readsize);
data->read((char *)&z, readsize);
_indexes[j++].setVal(x,y,z);
}
}
EMIMeshFace::~EMIMeshFace() {
delete[] _indexes;
}
void EMIModel::setTex(int index) {
_mats[index]->select();
}
// 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);
}
void EMIModel::loadMesh(Common::SeekableReadStream *data) {
//int strLength = 0; // Usefull for PS2-strings
Common::String nameString = readLAString(*data);
_sphereData = readVector4d(*data);
_boxData = readVector3d(*data);
_boxData2 = readVector3d(*data);
_numTexSets = data->readUint32LE();
_setType = data->readUint32LE();
_numTextures = data->readUint32LE();
_texNames = new Common::String[_numTextures];
for(uint32 i = 0;i < _numTextures; i++) {
_texNames[i] = readLAString(*data);
// Every texname seems to be followed by 4 0-bytes (Ref mk1.mesh,
// this is intentional)
data->skip(4);
}
// 4 unknown bytes - usually with value 19
data->skip(4);
_numVertices = data->readUint32LE();
// Vertices
_vertices = readVector3d(*data, _numVertices);
_normals = readVector3d(*data, _numVertices);
_colorMap = new EMIColormap[_numVertices];
for (int i = 0; i < _numVertices; ++i) {
_colorMap[i].r = data->readByte();
_colorMap[i].g = data->readByte();
_colorMap[i].b = data->readByte();
_colorMap[i].a = data->readByte();
}
_texVerts = readVector2d(*data, _numVertices);
// Faces
_numFaces = data->readUint32LE();
// Handle the empty-faced fx/screen?.mesh-files
if (data->eos()) {
_numFaces = 0;
_faces = NULL;
return;
}
_faces = new EMIMeshFace[_numFaces];
for(uint32 j = 0;j < _numFaces; j++) {
_faces[j].setParent(this);
_faces[j].loadFace(data);
}
/*int hasBones = */data->readUint32LE();
// TODO add in the bone-stuff, as well as the skeleton
prepare(); // <- Initialize materials etc.
}
void EMIModel::prepareForRender() {
// TODO, this was intended to update the vertices from the skeleton.
}
void EMIModel::prepare() {
_mats = new Material*[_numTextures];
for (uint32 i = 0; i < _numTextures; i++) {
// 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);
}
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
for(uint32 i = 0; i < _numFaces; i++) {
_faces[i].render();
g_driver->drawEMIModelFace(this, &_faces[i]);
}
}
EMIModel::EMIModel(const Common::String &filename, Common::SeekableReadStream *data, EMIModel *parent) : _fname(filename) {
_numVertices = 0;
_vertices = NULL;
_normals = NULL;
_colorMap = NULL;
_texVerts = NULL;
_numFaces = 0;
_faces = NULL;
_numTextures = 0;
_texNames = NULL;
_mats = NULL;
_numBones = 0;
_sphereData = NULL;
_boxData = NULL;
_boxData2 = NULL;
_numTexSets = 0;
_setType = 0;
loadMesh(data);
}
EMIModel::~EMIModel() {
delete[] _vertices;
delete[] _normals;
delete[] _colorMap;
delete[] _texVerts;
delete[] _faces;
delete[] _texNames;
delete[] _mats;
delete _sphereData;
delete _boxData;
delete _boxData2;
}
} // end of namespace Grim