scummvm/engines/stark/formats/biffmesh.cpp
2021-12-26 21:19:38 +01:00

443 lines
12 KiB
C++

/* 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/formats/biffmesh.h"
#include "engines/stark/formats/biff.h"
#include "engines/stark/services/archiveloader.h"
#include "common/hashmap.h"
namespace Stark {
namespace Formats {
enum BiffMeshObjectType {
kMeshObjectSceneData = 0x5a4aa94,
kMeshObjectBase = 0x5a4aa89,
kMeshObjectTri = 0x5a4aa8d,
kMeshObjectMaterial = 0x5a4aa8e
};
class MeshObjectSceneData : public BiffObject {
public:
static const uint32 TYPE = kMeshObjectSceneData;
MeshObjectSceneData() :
BiffObject(),
_animStart(0),
_animEnd(0) {
_type = TYPE;
}
// BiffObject API
void readData(ArchiveReadStream *stream, uint32 dataLength) override {
_animStart = stream->readUint32LE();
_animEnd = stream->readUint32LE();
}
private:
uint32 _animStart;
uint32 _animEnd;
};
class MeshObjectBase : public BiffObject {
public:
static const uint32 TYPE = kMeshObjectBase;
MeshObjectBase() :
BiffObject() {
_type = TYPE;
}
// BiffObject API
void readData(ArchiveReadStream *stream, uint32 dataLength) override {
_name = stream->readString16();
}
private:
Common::String _name;
};
class MeshObjectTri : public BiffObject {
public:
static const uint32 TYPE = kMeshObjectTri;
MeshObjectTri() :
BiffObject(),
_hasPhysics(false) {
_type = TYPE;
}
struct KeyFrame {
uint32 time;
Math::Quaternion essentialRotation;
float determinant;
Math::Quaternion stretchRotation;
Math::Vector3d scale;
Math::Vector3d translation;
};
struct Vertex {
Common::String animName1;
Common::String animName2;
float animInfluence1;
float animInfluence2;
Math::Vector3d position;
};
struct RawFace {
uint32 vertexIndex[3];
uint32 normalIndex[3];
uint32 textureVertexIndex[3];
uint32 materialId;
uint32 smoothingGroup;
};
// BiffObject API
void readData(ArchiveReadStream *stream, uint32 dataLength) override {
_name = stream->readString16();
uint32 keyFrameCount = stream->readUint32LE();
for (uint i = 0; i < keyFrameCount; i++) {
KeyFrame keyFrame;
keyFrame.time = stream->readUint32LE();
keyFrame.essentialRotation = stream->readQuaternion();
keyFrame.determinant = stream->readFloatLE();
keyFrame.stretchRotation = stream->readQuaternion();
keyFrame.scale = stream->readVector3();
keyFrame.translation = stream->readVector3();
_keyFrames.push_back(keyFrame);
}
if (_version >= 2) {
uint32 uvKeyFrameCount = stream->readUint32LE();
assert(uvKeyFrameCount == 0); // Reading the uv keyframes is not implemented
uint32 attributeCount = stream->readUint32LE();
assert(attributeCount == 0); // Reading the attributes is not implemented
}
uint32 vertexCount = stream->readUint32LE();
for (uint i = 0; i < vertexCount; i++) {
Vertex vertex;
vertex.animName1 = stream->readString16();
vertex.animName2 = stream->readString16();
vertex.animInfluence1 = stream->readFloatLE();
vertex.animInfluence2 = stream->readFloatLE();
vertex.position = stream->readVector3();
_rawVertices.push_back(vertex);
}
uint32 normalCount = stream->readUint32LE();
for (uint i = 0; i < normalCount; i++) {
_rawNormals.push_back(stream->readVector3());
}
uint32 textureVertexCount = stream->readUint32LE();
for (uint i = 0; i < textureVertexCount; i++) {
_rawTexturePositions.push_back(stream->readVector3());
}
uint32 faceCount = stream->readUint32LE();
for (uint i = 0; i < faceCount; i++) {
RawFace face;
face.vertexIndex[0] = stream->readUint32LE();
face.vertexIndex[1] = stream->readUint32LE();
face.vertexIndex[2] = stream->readUint32LE();
face.normalIndex[0] = stream->readUint32LE();
face.normalIndex[1] = stream->readUint32LE();
face.normalIndex[2] = stream->readUint32LE();
face.textureVertexIndex[0] = stream->readUint32LE();
face.textureVertexIndex[1] = stream->readUint32LE();
face.textureVertexIndex[2] = stream->readUint32LE();
face.materialId = stream->readUint32LE();
face.smoothingGroup = stream->readUint32LE();
_rawFaces.push_back(face);
}
_hasPhysics = stream->readByte();
}
void reindex() {
// The raw data loaded from the BIFF archive needs to be split into faces of identical material.
// Reserve enough faces in our faces array
for (uint i = 0; i < _rawFaces.size(); i++) {
if (_rawFaces[i].materialId >= _faces.size()) {
_faces.resize(_rawFaces[i].materialId + 1);
}
_faces[_rawFaces[i].materialId].materialId = _rawFaces[i].materialId;
}
// The raw data loaded from the BIFF archive is multi-indexed, which is not simple to use to draw.
// Here, we reindex the data so that each vertex owns all of its related attributes, hence requiring
// a single index list.
Common::HashMap<VertexKey, uint32, VertexKey::Hash, VertexKey::EqualTo> vertexIndexMap;
for (uint i = 0; i < _rawFaces.size(); i++) {
for (uint j = 0; j < 3; j++) {
VertexKey vertexKey(_rawFaces[i].vertexIndex[j], _rawFaces[i].normalIndex[j], _rawFaces[i].textureVertexIndex[j]);
if (!vertexIndexMap.contains(vertexKey)) {
BiffMesh::Vertex vertex;
vertex.position = _rawVertices[_rawFaces[i].vertexIndex[j]].position;
vertex.normal = _rawNormals[_rawFaces[i].normalIndex[j]];
vertex.texturePosition = _rawTexturePositions[_rawFaces[i].textureVertexIndex[j]];
_vertices.push_back(vertex);
vertexIndexMap.setVal(vertexKey, _vertices.size() - 1);
}
uint32 vertexIndex = vertexIndexMap.getVal(vertexKey);
// Add the index to a face according to its material
_faces[_rawFaces[i].materialId].vertexIndices.push_back(vertexIndex);
}
}
// Clear the raw data
_rawVertices.clear();
_rawNormals.clear();
_rawTexturePositions.clear();
_rawFaces.clear();
}
Math::Matrix4 getTransform(uint keyframeIndex) const {
const KeyFrame &keyframe = _keyFrames[keyframeIndex];
Math::Matrix4 translation;
translation.setPosition(keyframe.translation);
Math::Matrix4 essentialRotation = keyframe.essentialRotation.toMatrix();
Math::Matrix4 determinant;
determinant.setValue(0, 0, keyframe.determinant);
determinant.setValue(1, 1, keyframe.determinant);
determinant.setValue(2, 2, keyframe.determinant);
Math::Matrix4 stretchRotation = keyframe.stretchRotation.toMatrix();
Math::Matrix4 stretchRotationTransposed = stretchRotation;
stretchRotationTransposed.transpose();
Math::Matrix4 scale;
scale.setValue(0, 0, keyframe.scale.x());
scale.setValue(1, 1, keyframe.scale.y());
scale.setValue(2, 2, keyframe.scale.z());
return translation * essentialRotation * determinant * stretchRotationTransposed * scale * stretchRotation;
}
const Common::Array<BiffMesh::Vertex> &getVertices() const {
return _vertices;
}
const Common::Array<Face> &getFaces() const {
return _faces;
}
private:
struct VertexKey {
uint32 _vertexIndex;
uint32 _normalIndex;
uint32 _textureVertexIndex;
VertexKey(uint32 vertexIndex, uint32 normalIndex, uint32 textureVertexIndex) {
_vertexIndex = vertexIndex;
_normalIndex = normalIndex;
_textureVertexIndex = textureVertexIndex;
}
struct Hash {
uint operator() (const VertexKey &x) const {
return x._vertexIndex + x._normalIndex + x._textureVertexIndex;
}
};
struct EqualTo {
bool operator() (const VertexKey &x, const VertexKey &y) const {
return x._vertexIndex == y._vertexIndex &&
x._normalIndex == y._normalIndex &&
x._textureVertexIndex == y._textureVertexIndex;
}
};
};
Common::String _name;
Common::Array<KeyFrame> _keyFrames;
Common::Array<Vertex> _rawVertices;
Common::Array<RawFace> _rawFaces;
Common::Array<Math::Vector3d> _rawNormals;
Common::Array<Math::Vector3d> _rawTexturePositions;
Common::Array<BiffMesh::Vertex> _vertices;
Common::Array<Face> _faces;
bool _hasPhysics;
};
class MeshObjectMaterial : public BiffObject {
public:
static const uint32 TYPE = kMeshObjectMaterial;
MeshObjectMaterial() :
BiffObject(),
_shading(0),
_shininess(0),
_opacity(1),
_doubleSided(false),
_textureTiling(0),
_alphaTiling(0),
_environementTiling(0),
_isColorKey(false),
_colorKey(0) {
_type = TYPE;
}
// BiffObject API
void readData(ArchiveReadStream *stream, uint32 dataLength) override {
_name = stream->readString16();
_texture = stream->readString16();
_alpha = stream->readString16();
_environment = stream->readString16();
_shading = stream->readUint32LE();
_ambiant = stream->readVector3();
_diffuse = stream->readVector3();
_specular = stream->readVector3();
_shininess = stream->readFloatLE();
_opacity = stream->readFloatLE();
_doubleSided = stream->readByte();
_textureTiling = stream->readUint32LE();
_alphaTiling = stream->readUint32LE();
_environementTiling = stream->readUint32LE();
_isColorKey = stream->readByte();
_colorKey = stream->readUint32LE();
uint32 attributeCount = stream->readUint32LE();
assert(attributeCount == 0); // Reading the attributes is not implemented
}
Material toMaterial() const {
Material material;
material.name = _name;
material.texture = _texture;
material.r = _diffuse.x();
material.g = _diffuse.y();
material.b = _diffuse.z();
material.doubleSided = _doubleSided;
return material;
}
private:
Common::String _name;
Common::String _texture;
Common::String _alpha;
Common::String _environment;
uint32 _shading;
Math::Vector3d _ambiant;
Math::Vector3d _diffuse;
Math::Vector3d _specular;
float _shininess;
float _opacity;
bool _doubleSided;
uint32 _textureTiling;
uint32 _alphaTiling;
uint32 _environementTiling;
bool _isColorKey;
uint32 _colorKey;
};
BiffMesh *BiffMeshReader::read(ArchiveReadStream *stream) {
BiffArchive archive = BiffArchive(stream, &biffObjectBuilder);
Common::Array<MeshObjectTri *> tris = archive.listObjectsRecursive<MeshObjectTri>();
Common::Array<MeshObjectMaterial *> materialObjects = archive.listObjectsRecursive<MeshObjectMaterial>();
if (tris.size() != 1) {
error("Unexpected tri count in BIFF archive: '%d'", tris.size());
}
tris[0]->reindex();
Common::Array<Material> materials;
for (uint i = 0; i < materialObjects.size(); i++) {
materials.push_back(materialObjects[i]->toMaterial());
}
BiffMesh *mesh = new BiffMesh(tris[0]->getVertices(), tris[0]->getFaces(), materials);
mesh->setTransform(tris[0]->getTransform(0));
return mesh;
}
BiffObject *BiffMeshReader::biffObjectBuilder(uint32 type) {
switch (type) {
case kMeshObjectSceneData:
return new MeshObjectSceneData();
case kMeshObjectBase:
return new MeshObjectBase();
case kMeshObjectTri:
return new MeshObjectTri();
case kMeshObjectMaterial:
return new MeshObjectMaterial();
default:
return nullptr;
}
}
BiffMesh::BiffMesh(const Common::Array<Vertex> &vertices, const Common::Array<Face> &faces,
const Common::Array<Material> &materials) :
_vertices(vertices),
_faces(faces),
_materials(materials) {
}
const Common::Array<BiffMesh::Vertex> &BiffMesh::getVertices() const {
return _vertices;
}
const Common::Array<Face> &BiffMesh::getFaces() const {
return _faces;
}
const Common::Array<Material> &BiffMesh::getMaterials() const {
return _materials;
}
void BiffMesh::setTransform(const Math::Matrix4 &transform) {
_transform = transform;
}
Math::Matrix4 BiffMesh::getTransform() const {
return _transform;
}
} // End of namespace Formats
} // End of namespace Stark