[Scummvm-git-logs] scummvm master -> 9d26cb597d23975fae9326ef019520032c283b4c
aquadran
noreply at scummvm.org
Wed Oct 2 19:44:57 UTC 2024
This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
9d26cb597d WINTERMUTE: WME3D: Switch skin and mesh code from core to behind API
Commit: 9d26cb597d23975fae9326ef019520032c283b4c
https://github.com/scummvm/scummvm/commit/9d26cb597d23975fae9326ef019520032c283b4c
Author: PaweÅ KoÅodziejski (aquadran at gmail.com)
Date: 2024-10-02T21:44:52+02:00
Commit Message:
WINTERMUTE: WME3D: Switch skin and mesh code from core to behind API
Changed paths:
A engines/wintermute/base/gfx/xbuffer.h
A engines/wintermute/base/gfx/xmath.cpp
A engines/wintermute/base/gfx/xmath.h
A engines/wintermute/base/gfx/xskinmesh.cpp
A engines/wintermute/base/gfx/xskinmesh.h
engines/wintermute/base/gfx/opengl/meshx_opengl.cpp
engines/wintermute/base/gfx/opengl/meshx_opengl_shader.cpp
engines/wintermute/base/gfx/skin_mesh_helper.cpp
engines/wintermute/base/gfx/skin_mesh_helper.h
engines/wintermute/base/gfx/xfile_loader.cpp
engines/wintermute/base/gfx/xfile_loader.h
engines/wintermute/base/gfx/xframe_node.cpp
engines/wintermute/base/gfx/xmaterial.cpp
engines/wintermute/base/gfx/xmaterial.h
engines/wintermute/base/gfx/xmesh.cpp
engines/wintermute/base/gfx/xskinmesh_loader.cpp
engines/wintermute/base/gfx/xskinmesh_loader.h
engines/wintermute/module.mk
diff --git a/engines/wintermute/base/gfx/opengl/meshx_opengl.cpp b/engines/wintermute/base/gfx/opengl/meshx_opengl.cpp
index 35620f66908..fe531eb34e3 100644
--- a/engines/wintermute/base/gfx/opengl/meshx_opengl.cpp
+++ b/engines/wintermute/base/gfx/opengl/meshx_opengl.cpp
@@ -58,11 +58,11 @@ bool XMeshOpenGL::render(XModel *model) {
for (uint32 i = 0; i < _numAttrs; i++) {
int materialIndex = materialIndices[i];
- glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, _materials[materialIndex]->_diffuse.data);
- glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, _materials[materialIndex]->_diffuse.data);
- glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, _materials[materialIndex]->_specular.data);
- glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, _materials[materialIndex]->_emissive.data);
- glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, _materials[materialIndex]->_shininess);
+ glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, _materials[materialIndex]->_material._diffuse._data);
+ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, _materials[materialIndex]->_material._diffuse._data);
+ glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, _materials[materialIndex]->_material._specular._data);
+ glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, _materials[materialIndex]->_material._emissive._data);
+ glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, _materials[materialIndex]->_material._power);
bool textureEnable = false;
if (_materials[materialIndex]->getSurface()) {
diff --git a/engines/wintermute/base/gfx/opengl/meshx_opengl_shader.cpp b/engines/wintermute/base/gfx/opengl/meshx_opengl_shader.cpp
index 205ab05ec28..a09605cd3ff 100644
--- a/engines/wintermute/base/gfx/opengl/meshx_opengl_shader.cpp
+++ b/engines/wintermute/base/gfx/opengl/meshx_opengl_shader.cpp
@@ -98,7 +98,7 @@ bool XMeshOpenGLShader::render(XModel *model) {
}
// wme does not seem to care about specular or emissive light values
- Math::Vector4d diffuse(_materials[materialIndex]->_diffuse.data);
+ Math::Vector4d diffuse(_materials[materialIndex]->_material._diffuse._data);
_shader->setUniform("diffuse", diffuse);
_shader->setUniform("ambient", diffuse);
diff --git a/engines/wintermute/base/gfx/skin_mesh_helper.cpp b/engines/wintermute/base/gfx/skin_mesh_helper.cpp
index 16996230d4d..6bd472ba056 100644
--- a/engines/wintermute/base/gfx/skin_mesh_helper.cpp
+++ b/engines/wintermute/base/gfx/skin_mesh_helper.cpp
@@ -28,23 +28,28 @@
#include "engines/wintermute/dcgf.h"
#include "engines/wintermute/base/gfx/skin_mesh_helper.h"
#include "engines/wintermute/base/gfx/xskinmesh_loader.h"
+#include "engines/wintermute/base/gfx/xskinmesh.h"
#include "engines/wintermute/base/gfx/xfile_loader.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////////
-SkinMeshHelper::SkinMeshHelper(XSkinMeshLoader *mesh) {
- _mesh = mesh;
+SkinMeshHelper::SkinMeshHelper(XSkinMeshLoader *meshLoader, DXMesh *mesh, DXSkinInfo *skinInfo) {
+ _mesh = meshLoader;
+ _dxmesh = mesh;
+ _skinInfo = skinInfo;
}
//////////////////////////////////////////////////////////////////////////
SkinMeshHelper::~SkinMeshHelper() {
delete _mesh;
+ delete _dxmesh;
+ delete _skinInfo;
}
//////////////////////////////////////////////////////////////////////////
uint SkinMeshHelper::getNumFaces() {
- return _mesh->_meshObject->_numFaces;
+ return _dxmesh->getNumFaces();
}
//////////////////////////////////////////////////////////////////////////
diff --git a/engines/wintermute/base/gfx/skin_mesh_helper.h b/engines/wintermute/base/gfx/skin_mesh_helper.h
index a8e847bd034..275d7c5723e 100644
--- a/engines/wintermute/base/gfx/skin_mesh_helper.h
+++ b/engines/wintermute/base/gfx/skin_mesh_helper.h
@@ -37,6 +37,8 @@ class XSkinMeshLoader;
class XMesh;
class XMeshOpenGL;
class XMeshOpenGLShader;
+class DXMesh;
+class DXSkinInfo;
class SkinMeshHelper {
friend class XMesh;
@@ -44,9 +46,9 @@ class SkinMeshHelper {
friend class XMeshOpenGLShader;
public:
- SkinMeshHelper(XSkinMeshLoader *mesh);
+ SkinMeshHelper(XSkinMeshLoader *meshLoader, DXMesh *mesh, DXSkinInfo *skinInfo);
virtual ~SkinMeshHelper();
-
+
uint getNumFaces();
uint getNumBones();
bool getOriginalMesh(XSkinMeshLoader **mesh);
@@ -57,6 +59,8 @@ public:
private:
XSkinMeshLoader *_mesh;
+ DXMesh *_dxmesh;
+ DXSkinInfo *_skinInfo;
};
} // namespace Wintermute
diff --git a/engines/wintermute/base/gfx/xbuffer.h b/engines/wintermute/base/gfx/xbuffer.h
new file mode 100644
index 00000000000..486ea2bdd04
--- /dev/null
+++ b/engines/wintermute/base/gfx/xbuffer.h
@@ -0,0 +1,79 @@
+/* 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/>.
+ *
+ */
+
+#ifndef WINTERMUTE_XBUFFER_H
+#define WINTERMUTE_XBUFFER_H
+
+#include <common/types.h>
+#include <common/util.h>
+
+namespace Wintermute {
+
+struct DXBuffer {
+private:
+
+ byte *_ptr;
+ uint64 _size;
+
+public:
+
+ DXBuffer() {
+ _ptr = nullptr;
+ _size = 0;
+ }
+
+ DXBuffer(uint64 size) {
+ _ptr = new uint8_t[size];
+ if (_ptr == nullptr) {
+ size = 0;
+ return;
+ }
+ _size = size;
+ }
+
+ DXBuffer(const uint8 *ptr, uint64 size) {
+ _ptr = new uint8[size];
+ if (_ptr == nullptr) {
+ size = 0;
+ return;
+ }
+ memcpy(_ptr, ptr, size);
+ _size = size;
+ }
+
+ void free() {
+ delete[] _ptr;
+ _ptr = nullptr;
+ _size = 0;
+ }
+
+ byte *ptr() const {
+ return _ptr;
+ }
+
+ uint64 size() const {
+ return _size;
+ }
+};
+
+} // namespace Wintermute
+
+#endif
diff --git a/engines/wintermute/base/gfx/xfile_loader.cpp b/engines/wintermute/base/gfx/xfile_loader.cpp
index 08bf5ea9733..7fb4836dc25 100644
--- a/engines/wintermute/base/gfx/xfile_loader.cpp
+++ b/engines/wintermute/base/gfx/xfile_loader.cpp
@@ -966,7 +966,7 @@ bool XFileLoader::parseObjectParts(XObject *object) {
return false;
}
- objClass->_vertices = new XVector[objClass->_numVertices];
+ objClass->_vertices = new XVector3[objClass->_numVertices];
for (uint n = 0; n < objClass->_numVertices; n++) {
if (!getFloat(objClass->_vertices[n]._x) ||
!getFloat(objClass->_vertices[n]._y) ||
@@ -1016,7 +1016,7 @@ bool XFileLoader::parseObjectParts(XObject *object) {
return false;
}
- objClass->_normals = new XVector[objClass->_numNormals];
+ objClass->_normals = new XVector3[objClass->_numNormals];
for (uint n = 0; n < objClass->_numNormals; n++) {
if (!getFloat(objClass->_normals[n]._x) ||
!getFloat(objClass->_normals[n]._y) ||
diff --git a/engines/wintermute/base/gfx/xfile_loader.h b/engines/wintermute/base/gfx/xfile_loader.h
index aa19a9fae46..147a67293ca 100644
--- a/engines/wintermute/base/gfx/xfile_loader.h
+++ b/engines/wintermute/base/gfx/xfile_loader.h
@@ -78,12 +78,19 @@ struct XToken {
float _floatVal;
};
-struct XVector {
+struct XVector3 {
float _x;
float _y;
float _z;
};
+struct XVector4 {
+ float _x;
+ float _y;
+ float _z;
+ float _w;
+};
+
struct XCoords2d {
float _u;
float _v;
@@ -157,7 +164,7 @@ struct XSkinWeightsObject {
struct XMeshObject {
uint32 _numVertices;
- XVector *_vertices{};
+ XVector3 *_vertices{};
uint32 _numFaces;
XMeshFace *_faces{};
@@ -169,7 +176,7 @@ struct XMeshObject {
struct XMeshNormalsObject {
uint32 _numNormals;
- XVector *_normals{};
+ XVector3 *_normals{};
uint32 _numFaceNormals;
XMeshFace *_faceNormals{};
diff --git a/engines/wintermute/base/gfx/xframe_node.cpp b/engines/wintermute/base/gfx/xframe_node.cpp
index 0655a8e6a42..cf0d95c8e57 100644
--- a/engines/wintermute/base/gfx/xframe_node.cpp
+++ b/engines/wintermute/base/gfx/xframe_node.cpp
@@ -182,13 +182,6 @@ bool FrameNode::loadFromXData(const Common::String &filename, XModel *model, XFi
model->_ticksPerSecond = xobj->getXAnimTicksPerSecondObject()->_animTicksPerSecond;
return true;
}
- } else if (objectType == kXClassMaterial) {
- MaterialReference materialReference;
- xobj->getName(materialReference._name);
- materialReference._material = new Material(_gameRef);
- materialReference._material->loadFromX(xobj, filename);
- materialReferences.push_back(materialReference);
- return true;
}
return true;
diff --git a/engines/wintermute/base/gfx/xmaterial.cpp b/engines/wintermute/base/gfx/xmaterial.cpp
index 6f57b4f2fe0..9f07d04c653 100644
--- a/engines/wintermute/base/gfx/xmaterial.cpp
+++ b/engines/wintermute/base/gfx/xmaterial.cpp
@@ -43,6 +43,7 @@ namespace Wintermute {
//////////////////////////////////////////////////////////////////////////
Material::Material(BaseGame *inGame) : BaseNamedObject(inGame) {
+ memset(&_material, 0, sizeof(_material));
_surface = nullptr;
_ownedSurface = false;
_sprite = nullptr;
@@ -141,45 +142,4 @@ BaseSurface *Material::getSurface() {
}
}
-bool Material::loadFromX(XFileData *xobj, const Common::String &filename) {
- XMaterialObject *material = xobj->getXMaterialObject();
- if (!material)
- return false;
-
- _diffuse.r() = material->_colorR;
- _diffuse.g() = material->_colorG;
- _diffuse.b() = material->_colorB;
- _diffuse.a() = material->_colorA;
-
- _shininess = material->_power;
-
- _specular.r() = material->_specularR;
- _specular.g() = material->_specularG;
- _specular.b() = material->_specularB;
- _specular.a() = 1.0f;
-
- _emissive.r() = material->_emissiveR;
- _emissive.g() = material->_emissiveG;
- _emissive.b() = material->_emissiveB;
- _emissive.a() = 1.0f;
-
- uint numChildren = 0;
- xobj->getChildren(numChildren);
-
- for (uint32 i = 0; i < numChildren; i++) {
- XFileData xchildData;
- XClassType objectType;
- bool res = xobj->getChild(i, xchildData);
- if (res) {
- res = xchildData.getType(objectType);
- if (res && objectType == kXClassTextureFilename) {
- Common::String textureFilename = xchildData.getXTextureFilenameObject()->_filename;
- setTexture(PathUtil::getDirectoryName(filename) + textureFilename);
- }
- }
- }
-
- return true;
-}
-
} // namespace Wintermute
diff --git a/engines/wintermute/base/gfx/xmaterial.h b/engines/wintermute/base/gfx/xmaterial.h
index 540399291ec..87a217c6909 100644
--- a/engines/wintermute/base/gfx/xmaterial.h
+++ b/engines/wintermute/base/gfx/xmaterial.h
@@ -29,6 +29,7 @@
#define WINTERMUTE_XMATERIAL_H
#include "engines/wintermute/base/base_named_object.h"
+#include "engines/wintermute/base/gfx/xskinmesh.h"
namespace Wintermute {
@@ -78,19 +79,13 @@ public:
Material(BaseGame *inGame);
virtual ~Material();
- ColorValue _diffuse;
- ColorValue _ambient;
- ColorValue _specular;
- ColorValue _emissive;
- float _shininess;
+ DXMaterial _material;
bool setTexture(const Common::String &filename, bool adoptName = false);
bool setSprite(BaseSprite *sprite, bool adoptName = false);
bool setTheora(VideoTheoraPlayer *theora, bool adoptName = false);
BaseSurface *getSurface();
- bool loadFromX(XFileData *xobj, const Common::String &filename);
-
bool invalidateDeviceObjects();
bool restoreDeviceObjects();
diff --git a/engines/wintermute/base/gfx/xmath.cpp b/engines/wintermute/base/gfx/xmath.cpp
new file mode 100644
index 00000000000..e906f623278
--- /dev/null
+++ b/engines/wintermute/base/gfx/xmath.cpp
@@ -0,0 +1,460 @@
+/* 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/>.
+ *
+ */
+
+/*
+ * Code originated from Wine sources.
+ * Copyright (C) 2008 David Adam
+ * Copyright (C) 2008 Luis Busquets
+ * Copyright (C) 2008 Jérôme Gardou
+ * Copyright (C) 2008 Philip Nilsson
+ * Copyright (C) 2008 Henri Verbeet
+ */
+
+#include "engines/wintermute/base/gfx/xmath.h"
+
+namespace Wintermute {
+
+DXQuaternion *DXQuaternionRotationMatrix(DXQuaternion *out, const DXMatrix *m) {
+ float s, trace;
+
+ trace = m->_m[0][0] + m->_m[1][1] + m->_m[2][2] + 1.0f;
+ if (trace > 1.0f) {
+ s = 2.0f * sqrtf(trace);
+ out->_x = (m->_m[1][2] - m->_m[2][1]) / s;
+ out->_y = (m->_m[2][0] - m->_m[0][2]) / s;
+ out->_z = (m->_m[0][1] - m->_m[1][0]) / s;
+ out->_w = 0.25f * s;
+ } else {
+ int i, maxi = 0;
+
+ for (i = 1; i < 3; i++) {
+ if (m->_m[i][i] > m->_m[maxi][maxi])
+ maxi = i;
+ }
+
+ switch (maxi) {
+ case 0:
+ s = 2.0f * sqrtf(1.0f + m->_m[0][0] - m->_m[1][1] - m->_m[2][2]);
+ out->_x = 0.25f * s;
+ out->_y = (m->_m[0][1] + m->_m[1][0]) / s;
+ out->_z = (m->_m[0][2] + m->_m[2][0]) / s;
+ out->_w = (m->_m[1][2] - m->_m[2][1]) / s;
+ break;
+
+ case 1:
+ s = 2.0f * sqrtf(1.0f + m->_m[1][1] - m->_m[0][0] - m->_m[2][2]);
+ out->_x = (m->_m[0][1] + m->_m[1][0]) / s;
+ out->_y = 0.25f * s;
+ out->_z = (m->_m[1][2] + m->_m[2][1]) / s;
+ out->_w = (m->_m[2][0] - m->_m[0][2]) / s;
+ break;
+
+ case 2:
+ s = 2.0f * sqrtf(1.0f + m->_m[2][2] - m->_m[0][0] - m->_m[1][1]);
+ out->_x = (m->_m[0][2] + m->_m[2][0]) / s;
+ out->_y = (m->_m[1][2] + m->_m[2][1]) / s;
+ out->_z = 0.25f * s;
+ out->_w = (m->_m[0][1] - m->_m[1][0]) / s;
+ break;
+ }
+ }
+
+ return out;
+}
+
+DXMatrix *DXMatrixPerspectiveFovLH(DXMatrix *pout,float fovy, float aspect, float zn, float zf) {
+ DXMatrixIdentity(pout);
+ pout->_m[0][0] = 1.0f / (aspect * tanf(fovy/2.0f));
+ pout->_m[1][1] = 1.0f / tanf(fovy/2.0f);
+ pout->_m[2][2] = zf / (zf - zn);
+ pout->_m[2][3] = 1.0f;
+ pout->_m[3][2] = (zf * zn) / (zn - zf);
+ pout->_m[3][3] = 0.0f;
+ return pout;
+}
+
+DXMatrix *DXMatrixPerspectiveFovRH(DXMatrix *pout, float fovy, float aspect, float zn, float zf) {
+ DXMatrixIdentity(pout);
+ pout->_m[0][0] = 1.0f / (aspect * tanf(fovy / 2.0f));
+ pout->_m[1][1] = 1.0f / tanf(fovy / 2.0f);
+ pout->_m[2][2] = zf / (zn - zf);
+ pout->_m[2][3] = -1.0f;
+ pout->_m[3][2] = (zf * zn) / (zn - zf);
+ pout->_m[3][3] = 0.0f;
+ return pout;
+}
+
+DXMatrix *DXMatrixInverse(DXMatrix *pout, float *pdeterminant, const DXMatrix *pm) {
+ float det, t[3], v[16];
+ int i, j;
+
+ t[0] = pm->_m[2][2] * pm->_m[3][3] - pm->_m[2][3] * pm->_m[3][2];
+ t[1] = pm->_m[1][2] * pm->_m[3][3] - pm->_m[1][3] * pm->_m[3][2];
+ t[2] = pm->_m[1][2] * pm->_m[2][3] - pm->_m[1][3] * pm->_m[2][2];
+ v[0] = pm->_m[1][1] * t[0] - pm->_m[2][1] * t[1] + pm->_m[3][1] * t[2];
+ v[4] = -pm->_m[1][0] * t[0] + pm->_m[2][0] * t[1] - pm->_m[3][0] * t[2];
+
+ t[0] = pm->_m[1][0] * pm->_m[2][1] - pm->_m[2][0] * pm->_m[1][1];
+ t[1] = pm->_m[1][0] * pm->_m[3][1] - pm->_m[3][0] * pm->_m[1][1];
+ t[2] = pm->_m[2][0] * pm->_m[3][1] - pm->_m[3][0] * pm->_m[2][1];
+ v[8] = pm->_m[3][3] * t[0] - pm->_m[2][3] * t[1] + pm->_m[1][3] * t[2];
+ v[12] = -pm->_m[3][2] * t[0] + pm->_m[2][2] * t[1] - pm->_m[1][2] * t[2];
+
+ det = pm->_m[0][0] * v[0] + pm->_m[0][1] * v[4] + pm->_m[0][2] * v[8] + pm->_m[0][3] * v[12];
+ if (det == 0.0f)
+ return nullptr;
+ if (pdeterminant)
+ *pdeterminant = det;
+
+ t[0] = pm->_m[2][2] * pm->_m[3][3] - pm->_m[2][3] * pm->_m[3][2];
+ t[1] = pm->_m[0][2] * pm->_m[3][3] - pm->_m[0][3] * pm->_m[3][2];
+ t[2] = pm->_m[0][2] * pm->_m[2][3] - pm->_m[0][3] * pm->_m[2][2];
+ v[1] = -pm->_m[0][1] * t[0] + pm->_m[2][1] * t[1] - pm->_m[3][1] * t[2];
+ v[5] = pm->_m[0][0] * t[0] - pm->_m[2][0] * t[1] + pm->_m[3][0] * t[2];
+
+ t[0] = pm->_m[0][0] * pm->_m[2][1] - pm->_m[2][0] * pm->_m[0][1];
+ t[1] = pm->_m[3][0] * pm->_m[0][1] - pm->_m[0][0] * pm->_m[3][1];
+ t[2] = pm->_m[2][0] * pm->_m[3][1] - pm->_m[3][0] * pm->_m[2][1];
+ v[9] = -pm->_m[3][3] * t[0] - pm->_m[2][3] * t[1]- pm->_m[0][3] * t[2];
+ v[13] = pm->_m[3][2] * t[0] + pm->_m[2][2] * t[1] + pm->_m[0][2] * t[2];
+
+ t[0] = pm->_m[1][2] * pm->_m[3][3] - pm->_m[1][3] * pm->_m[3][2];
+ t[1] = pm->_m[0][2] * pm->_m[3][3] - pm->_m[0][3] * pm->_m[3][2];
+ t[2] = pm->_m[0][2] * pm->_m[1][3] - pm->_m[0][3] * pm->_m[1][2];
+ v[2] = pm->_m[0][1] * t[0] - pm->_m[1][1] * t[1] + pm->_m[3][1] * t[2];
+ v[6] = -pm->_m[0][0] * t[0] + pm->_m[1][0] * t[1] - pm->_m[3][0] * t[2];
+
+ t[0] = pm->_m[0][0] * pm->_m[1][1] - pm->_m[1][0] * pm->_m[0][1];
+ t[1] = pm->_m[3][0] * pm->_m[0][1] - pm->_m[0][0] * pm->_m[3][1];
+ t[2] = pm->_m[1][0] * pm->_m[3][1] - pm->_m[3][0] * pm->_m[1][1];
+ v[10] = pm->_m[3][3] * t[0] + pm->_m[1][3] * t[1] + pm->_m[0][3] * t[2];
+
+ t[0] = pm->_m[1][2] * pm->_m[2][3] - pm->_m[1][3] * pm->_m[2][2];
+ t[1] = pm->_m[0][2] * pm->_m[2][3] - pm->_m[0][3] * pm->_m[2][2];
+ t[2] = pm->_m[0][2] * pm->_m[1][3] - pm->_m[0][3] * pm->_m[1][2];
+ v[3] = -pm->_m[0][1] * t[0] + pm->_m[1][1] * t[1] - pm->_m[2][1] * t[2];
+ v[7] = pm->_m[0][0] * t[0] - pm->_m[1][0] * t[1] + pm->_m[2][0] * t[2];
+
+ v[11] = -pm->_m[0][0] * (pm->_m[1][1] * pm->_m[2][3] - pm->_m[1][3] * pm->_m[2][1]) +
+ pm->_m[1][0] * (pm->_m[0][1] * pm->_m[2][3] - pm->_m[0][3] * pm->_m[2][1]) -
+ pm->_m[2][0] * (pm->_m[0][1] * pm->_m[1][3] - pm->_m[0][3] * pm->_m[1][1]);
+
+ v[15] = pm->_m[0][0] * (pm->_m[1][1] * pm->_m[2][2] - pm->_m[1][2] * pm->_m[2][1]) -
+ pm->_m[1][0] * (pm->_m[0][1] * pm->_m[2][2] - pm->_m[0][2] * pm->_m[2][1]) +
+ pm->_m[2][0] * (pm->_m[0][1] * pm->_m[1][2] - pm->_m[0][2] * pm->_m[1][1]);
+
+ det = 1.0f / det;
+
+ for (i = 0; i < 4; i++)
+ for (j = 0; j < 4; j++)
+ pout->_m[i][j] = v[4 * i + j] * det;
+
+ return pout;
+}
+
+DXPlane *DXPlaneFromPointNormal(DXPlane *pout, const DXVector3 *pvpoint, const DXVector3 *pvnormal) {
+ pout->_a = pvnormal->_x;
+ pout->_b = pvnormal->_y;
+ pout->_c = pvnormal->_z;
+ pout->_d = -DXVec3Dot(pvpoint, pvnormal);
+ return pout;
+}
+
+DXPlane *D3DXPlaneFromPoints(DXPlane *pout, const DXVector3 *pv1, const DXVector3 *pv2, const DXVector3 *pv3) {
+ DXVector3 edge1, edge2, normal, Nnormal;
+
+ edge1._x = 0.0f; edge1._y = 0.0f; edge1._z = 0.0f;
+ edge2._x = 0.0f; edge2._y = 0.0f; edge2._z = 0.0f;
+ DXVec3Subtract(&edge1, pv2, pv1);
+ DXVec3Subtract(&edge2, pv3, pv1);
+ DXVec3Cross(&normal, &edge1, &edge2);
+ DXVec3Normalize(&Nnormal, &normal);
+ DXPlaneFromPointNormal(pout, pv1, &Nnormal);
+ return pout;
+}
+
+DXVector3 *DXPlaneIntersectLine(DXVector3 *pout, const DXPlane *pp, const DXVector3 *pv1, const DXVector3 *pv2) {
+ DXVector3 direction, normal;
+ float dot, temp;
+
+ normal._x = pp->_a;
+ normal._y = pp->_b;
+ normal._z = pp->_c;
+ direction._x = pv2->_x - pv1->_x;
+ direction._y = pv2->_y - pv1->_y;
+ direction._z = pv2->_z - pv1->_z;
+ dot = DXVec3Dot(&normal, &direction);
+ if (!dot)
+ return nullptr;
+ temp = (pp->_d + DXVec3Dot(&normal, pv1) ) / dot;
+ pout->_x = pv1->_x - temp * direction._x;
+ pout->_y = pv1->_y - temp * direction._y;
+ pout->_z = pv1->_z - temp * direction._z;
+ return pout;
+}
+
+DXVector3 *DXVec3Normalize(DXVector3 *pout, const DXVector3 *pv) {
+ float norm;
+
+ norm = DXVec3Length(pv);
+ if (!norm) {
+ pout->_x = 0.0f;
+ pout->_y = 0.0f;
+ pout->_z = 0.0f;
+ } else {
+ pout->_x = pv->_x / norm;
+ pout->_y = pv->_y / norm;
+ pout->_z = pv->_z / norm;
+ }
+
+ return pout;
+}
+
+DXMatrix *DXMatrixTranslation(DXMatrix *pout, float x, float y, float z) {
+ DXMatrixIdentity(pout);
+ pout->_m[3][0] = x;
+ pout->_m[3][1] = y;
+ pout->_m[3][2] = z;
+ return pout;
+}
+
+DXMatrix *D3DXMatrixScaling(DXMatrix *pout, float sx, float sy, float sz) {
+ DXMatrixIdentity(pout);
+ pout->_m[0][0] = sx;
+ pout->_m[1][1] = sy;
+ pout->_m[2][2] = sz;
+ return pout;
+}
+
+DXMatrix *D3DXMatrixRotationZ(DXMatrix *pout, float angle) {
+ DXMatrixIdentity(pout);
+ pout->_m[0][0] = cosf(angle);
+ pout->_m[1][1] = cosf(angle);
+ pout->_m[0][1] = sinf(angle);
+ pout->_m[1][0] = -sinf(angle);
+ return pout;
+}
+
+DXMatrix *DXMatrixRotationYawPitchRoll(DXMatrix *out, float yaw, float pitch, float roll) {
+ float sroll, croll, spitch, cpitch, syaw, cyaw;
+
+ sroll = sinf(roll);
+ croll = cosf(roll);
+ spitch = sinf(pitch);
+ cpitch = cosf(pitch);
+ syaw = sinf(yaw);
+ cyaw = cosf(yaw);
+
+ out->_m[0][0] = sroll * spitch * syaw + croll * cyaw;
+ out->_m[0][1] = sroll * cpitch;
+ out->_m[0][2] = sroll * spitch * cyaw - croll * syaw;
+ out->_m[0][3] = 0.0f;
+ out->_m[1][0] = croll * spitch * syaw - sroll * cyaw;
+ out->_m[1][1] = croll * cpitch;
+ out->_m[1][2] = croll * spitch * cyaw + sroll * syaw;
+ out->_m[1][3] = 0.0f;
+ out->_m[2][0] = cpitch * syaw;
+ out->_m[2][1] = -spitch;
+ out->_m[2][2] = cpitch * cyaw;
+ out->_m[2][3] = 0.0f;
+ out->_m[3][0] = 0.0f;
+ out->_m[3][1] = 0.0f;
+ out->_m[3][2] = 0.0f;
+ out->_m[3][3] = 1.0f;
+
+ return out;
+}
+
+DXMatrix *DXMatrixRotationQuaternion(DXMatrix *pout, const DXQuaternion *pq) {
+ DXMatrixIdentity(pout);
+ pout->_m[0][0] = 1.0f - 2.0f * (pq->_y * pq->_y + pq->_z * pq->_z);
+ pout->_m[0][1] = 2.0f * (pq->_x *pq->_y + pq->_z * pq->_w);
+ pout->_m[0][2] = 2.0f * (pq->_x * pq->_z - pq->_y * pq->_w);
+ pout->_m[1][0] = 2.0f * (pq->_x * pq->_y - pq->_z * pq->_w);
+ pout->_m[1][1] = 1.0f - 2.0f * (pq->_x * pq->_x + pq->_z * pq->_z);
+ pout->_m[1][2] = 2.0f * (pq->_y *pq->_z + pq->_x *pq->_w);
+ pout->_m[2][0] = 2.0f * (pq->_x * pq->_z + pq->_y * pq->_w);
+ pout->_m[2][1] = 2.0f * (pq->_y *pq->_z - pq->_x *pq->_w);
+ pout->_m[2][2] = 1.0f - 2.0f * (pq->_x * pq->_x + pq->_y * pq->_y);
+ return pout;
+}
+
+DXQuaternion *DXQuaternionSlerp(DXQuaternion *out, const DXQuaternion *q1, const DXQuaternion *q2, float t) {
+ float dot, temp;
+
+ temp = 1.0f - t;
+ dot = DXQuaternionDot(q1, q2);
+ if (dot < 0.0f) {
+ t = -t;
+ dot = -dot;
+ }
+
+ if (1.0f - dot > 0.001f) {
+ float theta = acosf(dot);
+ temp = sinf(theta * temp) / sinf(theta);
+ t = sinf(theta * t) / sinf(theta);
+ }
+
+ out->_x = temp * q1->_x + t * q2->_x;
+ out->_y = temp * q1->_y + t * q2->_y;
+ out->_z = temp * q1->_z + t * q2->_z;
+ out->_w = temp * q1->_w + t * q2->_w;
+
+ return out;
+}
+
+float D3DXQuaternionDot(const DXVector4 *pq1, const DXVector4 *pq2) {
+ return (pq1->_x) * (pq2->_x) + (pq1->_y) * (pq2->_y) + (pq1->_z) * (pq2->_z) + (pq1->_w) * (pq2->_w);
+}
+
+DXVector4 *D3DXVec3Transform(DXVector4 *pout, const DXVector3 *pv, const DXMatrix *pm) {
+ DXVector4 out;
+
+ out._x = pm->_m[0][0] * pv->_x + pm->_m[1][0] * pv->_y + pm->_m[2][0] * pv->_z + pm->_m[3][0];
+ out._y = pm->_m[0][1] * pv->_x + pm->_m[1][1] * pv->_y + pm->_m[2][1] * pv->_z + pm->_m[3][1];
+ out._z = pm->_m[0][2] * pv->_x + pm->_m[1][2] * pv->_y + pm->_m[2][2] * pv->_z + pm->_m[3][2];
+ out._w = pm->_m[0][3] * pv->_x + pm->_m[1][3] * pv->_y + pm->_m[2][3] * pv->_z + pm->_m[3][3];
+ *pout = out;
+ return pout;
+}
+
+DXVector3 *DXVec3TransformCoord(DXVector3 *pout, const DXVector3 *pv, const DXMatrix *pm) {
+ DXVector3 out;
+
+ float norm = pm->_m[0][3] * pv->_x + pm->_m[1][3] * pv->_y + pm->_m[2][3] *pv->_z + pm->_m[3][3];
+
+ out._x = (pm->_m[0][0] * pv->_x + pm->_m[1][0] * pv->_y + pm->_m[2][0] * pv->_z + pm->_m[3][0]) / norm;
+ out._y = (pm->_m[0][1] * pv->_x + pm->_m[1][1] * pv->_y + pm->_m[2][1] * pv->_z + pm->_m[3][1]) / norm;
+ out._z = (pm->_m[0][2] * pv->_x + pm->_m[1][2] * pv->_y + pm->_m[2][2] * pv->_z + pm->_m[3][2]) / norm;
+
+ *pout = out;
+
+ return pout;
+}
+
+DXVector3 *DXVec3TransformNormal(DXVector3 *pout, const DXVector3 *pv, const DXMatrix *pm) {
+ const DXVector3 v = *pv;
+
+ pout->_x = pm->_m[0][0] * v._x + pm->_m[1][0] * v._y + pm->_m[2][0] * v._z;
+ pout->_y = pm->_m[0][1] * v._x + pm->_m[1][1] * v._y + pm->_m[2][1] * v._z;
+ pout->_z = pm->_m[0][2] * v._x + pm->_m[1][2] * v._y + pm->_m[2][2] * v._z;
+ return pout;
+}
+
+DXMatrix *DXMatrixMultiply(DXMatrix *pout, const DXMatrix *pm1, const DXMatrix *pm2) {
+ DXMatrix out;
+
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ out._m[i][j] = pm1->_m[i][0] * pm2->_m[0][j] + pm1->_m[i][1] * pm2->_m[1][j] + pm1->_m[i][2] * pm2->_m[2][j] + pm1->_m[i][3] * pm2->_m[3][j];
+ }
+ }
+
+ *pout = out;
+ return pout;
+}
+
+DXVector3 *DXVec3Project(DXVector3 *pout, const DXVector3 *pv, const Rect32 *pviewport,
+ const DXMatrix *pprojection, const DXMatrix *pview, const DXMatrix *pworld) {
+ DXMatrix m;
+
+ DXMatrixIdentity(&m);
+ if (pworld)
+ DXMatrixMultiply(&m, &m, pworld);
+ if (pview)
+ DXMatrixMultiply(&m, &m, pview);
+ if (pprojection)
+ DXMatrixMultiply(&m, &m, pprojection);
+
+ DXVec3TransformCoord(pout, pv, &m);
+
+ if (pviewport) {
+ pout->_x = pviewport->left + (1.0f + pout->_x) * pviewport->width() / 2.0f;
+ pout->_y = pviewport->top + (1.0f - pout->_y) * pviewport->height() / 2.0f;
+ pout->_z = (1.0f + pout->_z) / 2.0f;
+ }
+ return pout;
+}
+
+float D3DXVec3Length(const DXVector3 *pv) {
+ return sqrtf(pv->_x * pv->_x + pv->_y * pv->_y + pv->_z * pv->_z);
+}
+
+DXMatrix *DXMatrixLookAtLH(DXMatrix *out, const DXVector3 *eye, const DXVector3 *at, const DXVector3 *up) {
+ DXVector3 right, upn, vec;
+
+ DXVec3Subtract(&vec, at, eye);
+ DXVec3Normalize(&vec, &vec);
+ DXVec3Cross(&right, up, &vec);
+ DXVec3Cross(&upn, &vec, &right);
+ DXVec3Normalize(&right, &right);
+ DXVec3Normalize(&upn, &upn);
+ out->_m[0][0] = right._x;
+ out->_m[1][0] = right._y;
+ out->_m[2][0] = right._z;
+ out->_m[3][0] = -DXVec3Dot(&right, eye);
+ out->_m[0][1] = upn._x;
+ out->_m[1][1] = upn._y;
+ out->_m[2][1] = upn._z;
+ out->_m[3][1] = -DXVec3Dot(&upn, eye);
+ out->_m[0][2] = vec._x;
+ out->_m[1][2] = vec._y;
+ out->_m[2][2] = vec._z;
+ out->_m[3][2] = -DXVec3Dot(&vec, eye);
+ out->_m[0][3] = 0.0f;
+ out->_m[1][3] = 0.0f;
+ out->_m[2][3] = 0.0f;
+ out->_m[3][3] = 1.0f;
+
+ return out;
+}
+
+
+DXMatrix *DXMatrixLookAtRH(DXMatrix *out, const DXVector3 *eye, const DXVector3 *at, const DXVector3 *up) {
+ DXVector3 right, upn, vec;
+
+ DXVec3Subtract(&vec, at, eye);
+ DXVec3Normalize(&vec, &vec);
+ DXVec3Cross(&right, up, &vec);
+ DXVec3Cross(&upn, &vec, &right);
+ DXVec3Normalize(&right, &right);
+ DXVec3Normalize(&upn, &upn);
+ out->_m[0][0] = -right._x;
+ out->_m[1][0] = -right._y;
+ out->_m[2][0] = -right._z;
+ out->_m[3][0] = DXVec3Dot(&right, eye);
+ out->_m[0][1] = upn._x;
+ out->_m[1][1] = upn._y;
+ out->_m[2][1] = upn._z;
+ out->_m[3][1] = -DXVec3Dot(&upn, eye);
+ out->_m[0][2] = -vec._x;
+ out->_m[1][2] = -vec._y;
+ out->_m[2][2] = -vec._z;
+ out->_m[3][2] = DXVec3Dot(&vec, eye);
+ out->_m[0][3] = 0.0f;
+ out->_m[1][3] = 0.0f;
+ out->_m[2][3] = 0.0f;
+ out->_m[3][3] = 1.0f;
+
+ return out;
+}
+
+} // End of namespace Wintermute
diff --git a/engines/wintermute/base/gfx/xmath.h b/engines/wintermute/base/gfx/xmath.h
new file mode 100644
index 00000000000..4f88ff80c7b
--- /dev/null
+++ b/engines/wintermute/base/gfx/xmath.h
@@ -0,0 +1,170 @@
+/* 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/>.
+ *
+ */
+
+/*
+ * Code originated from Wine sources.
+ * Copyright (C) 2008 David Adam
+ * Copyright (C) 2008 Luis Busquets
+ * Copyright (C) 2008 Jérôme Gardou
+ * Copyright (C) 2008 Philip Nilsson
+ * Copyright (C) 2008 Henri Verbeet
+ */
+
+#ifndef WINTERMUTE_XMATH_H
+#define WINTERMUTE_XMATH_H
+
+#include "engines/wintermute/math/rect32.h"
+
+namespace Wintermute {
+
+#if defined(SCUMMVM_USE_PRAGMA_PACK)
+#pragma pack(4)
+#endif
+
+struct DXVector2 {
+ float _x;
+ float _y;
+};
+
+struct DXVector3 {
+ float _x;
+ float _y;
+ float _z;
+};
+
+struct DXVector4 {
+ float _x;
+ float _y;
+ float _z;
+ float _w;
+};
+
+struct DXQuaternion {
+ float _x;
+ float _y;
+ float _z;
+ float _w;
+};
+
+struct DXPlane {
+ float _a;
+ float _b;
+ float _c;
+ float _d;
+};
+
+union DXMatrix {
+ struct {
+ float _11, _12, _13, _14;
+ float _21, _22, _23, _24;
+ float _31, _32, _33, _34;
+ float _41, _42, _43, _44;
+ } matrix;
+ float _m[4][4];
+ float _m4x4[16];
+};
+
+#if defined(SCUMMVM_USE_PRAGMA_PACK)
+#pragma pack()
+#endif
+
+DXQuaternion *DXQuaternionRotationMatrix(DXQuaternion *out,const DXMatrix *m);
+DXMatrix *DXMatrixPerspectiveFovLH(DXMatrix *pout,float fovy, float aspect, float zn, float zf);
+DXMatrix *DXMatrixPerspectiveFovRH(DXMatrix *pout, float fovy, float aspect, float zn, float zf);
+DXMatrix *DXMatrixLookAtLH(DXMatrix *out, const DXVector3 *eye, const DXVector3 *at, const DXVector3 *up);
+DXMatrix *DXMatrixLookAtRH(DXMatrix *out, const DXVector3 *eye, const DXVector3 *at, const DXVector3 *up);
+DXMatrix *DXMatrixInverse(DXMatrix *pout, float *pdeterminant, const DXMatrix *pm);
+DXPlane *DXPlaneFromPointNormal(DXPlane *pout, const DXVector3 *pvpoint, const DXVector3 *pvnormal);
+DXPlane *DXPlaneFromPoints(DXPlane *pout, const DXVector3 *pv1, const DXVector3 *pv2, const DXVector3 *pv3);
+DXVector3 *DXPlaneIntersectLine(DXVector3 *pout, const DXPlane *pp, const DXVector3 *pv1, const DXVector3 *pv2);
+DXVector3 *DXVec3Normalize(DXVector3 *pout, const DXVector3 *pv);
+DXMatrix *DXMatrixTranslation(DXMatrix *pout, float x, float y, float z);
+DXMatrix *DXMatrixScaling(DXMatrix *pout, float sx, float sy, float sz);
+DXMatrix *DXMatrixRotationZ(DXMatrix *pout, float angle);
+DXMatrix *DXMatrixRotationYawPitchRoll(DXMatrix *out, float yaw, float pitch, float roll);
+DXMatrix *DXMatrixRotationQuaternion(DXMatrix *pout, const DXQuaternion *pq);
+DXQuaternion *DXQuaternionSlerp(DXQuaternion *out, const DXQuaternion *q1, const DXQuaternion *q2, float t);
+DXVector4 *DXVec3Transform(DXVector4 *pout, const DXVector3 *pv, const DXMatrix *pm);
+DXVector3 *DXVec3TransformCoord(DXVector3 *pout, const DXVector3 *pv, const DXMatrix *pm);
+DXVector3 *DXVec3TransformNormal(DXVector3 *pout, const DXVector3 *pv, const DXMatrix *pm);
+DXMatrix *DXMatrixMultiply(DXMatrix *pout, const DXMatrix *pm1, const DXMatrix *pm2);
+DXVector3 *DXVec3Project(DXVector3 *pout, const DXVector3 *pv, const Rect32 *pviewport,
+ const DXVector3 *pprojection, const DXMatrix *pview, const DXMatrix *pworld);
+
+static inline DXMatrix *DXMatrixIdentity(DXMatrix *pout) {
+ (*pout)._m[0][1] = 0.0f;
+ (*pout)._m[0][2] = 0.0f;
+ (*pout)._m[0][3] = 0.0f;
+ (*pout)._m[1][0] = 0.0f;
+ (*pout)._m[1][2] = 0.0f;
+ (*pout)._m[1][3] = 0.0f;
+ (*pout)._m[2][0] = 0.0f;
+ (*pout)._m[2][1] = 0.0f;
+ (*pout)._m[2][3] = 0.0f;
+ (*pout)._m[3][0] = 0.0f;
+ (*pout)._m[3][1] = 0.0f;
+ (*pout)._m[3][2] = 0.0f;
+ (*pout)._m[0][0] = 1.0f;
+ (*pout)._m[1][1] = 1.0f;
+ (*pout)._m[2][2] = 1.0f;
+ (*pout)._m[3][3] = 1.0f;
+ return pout;
+}
+
+static inline DXVector3 *DXVec3Lerp(DXVector3 *pout, const DXVector3 *pv1, const DXVector3 *pv2, float s) {
+ pout->_x = (1-s) * (pv1->_x) + s * (pv2->_x);
+ pout->_y = (1-s) * (pv1->_y) + s * (pv2->_y);
+ pout->_z = (1-s) * (pv1->_z) + s * (pv2->_z);
+ return pout;
+}
+
+static inline float DXQuaternionDot(const DXQuaternion *pq1, const DXQuaternion *pq2) {
+ return (pq1->_x) * (pq2->_x) + (pq1->_y) * (pq2->_y) + (pq1->_z) * (pq2->_z) + (pq1->_w) * (pq2->_w);
+}
+
+static inline DXVector3 *DXVec3Cross(DXVector3 *pout, const DXVector3 *pv1, const DXVector3 *pv2) {
+ DXVector3 temp;
+
+ temp._x = (pv1->_y) * (pv2->_z) - (pv1->_z) * (pv2->_y);
+ temp._y = (pv1->_z) * (pv2->_x) - (pv1->_x) * (pv2->_z);
+ temp._z = (pv1->_x) * (pv2->_y) - (pv1->_y) * (pv2->_x);
+ *pout = temp;
+ return pout;
+}
+
+static inline float DXVec3Dot(const DXVector3 *pv1, const DXVector3 *pv2) {
+ return (pv1->_x) * (pv2->_x) + (pv1->_y) * (pv2->_y) + (pv1->_z) * (pv2->_z);
+}
+
+static inline DXVector3 *DXVec3Subtract(DXVector3 *pout, const DXVector3 *pv1, const DXVector3 *pv2) {
+ pout->_x = pv1->_x - pv2->_x;
+ pout->_y = pv1->_y - pv2->_y;
+ pout->_z = pv1->_z - pv2->_z;
+ return pout;
+}
+
+static inline float DXVec3Length(const DXVector3 *pv) {
+ return sqrtf(pv->_x * pv->_x + pv->_y * pv->_y + pv->_z * pv->_z);
+}
+
+} // End of namespace Wintermute
+
+#endif
diff --git a/engines/wintermute/base/gfx/xmesh.cpp b/engines/wintermute/base/gfx/xmesh.cpp
index 1ae0f669cbc..3aa52199065 100644
--- a/engines/wintermute/base/gfx/xmesh.cpp
+++ b/engines/wintermute/base/gfx/xmesh.cpp
@@ -33,8 +33,11 @@
#include "engines/wintermute/base/gfx/xframe_node.h"
#include "engines/wintermute/base/gfx/xfile_loader.h"
#include "engines/wintermute/base/gfx/xmodel.h"
+#include "engines/wintermute/base/gfx/xbuffer.h"
+#include "engines/wintermute/base/gfx/xskinmesh.h"
#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/math/math_util.h"
+#include "engines/wintermute/utils/path_util.h"
namespace Wintermute {
@@ -63,13 +66,120 @@ bool XMesh::loadFromXData(const Common::String &filename, XFileData *xobj, Commo
XMeshObject *meshObject = xobj->getXMeshObject();
if (!meshObject) {
+ BaseEngine::LOG(0, "Error loading mesh");
+ return false;
+ }
+
+ // load mesh
+ DXBuffer bufMaterials;
+ DXBuffer bufAdjacency;
+ //DXBuffer bufBoneOffset;
+ //uint32 numFaces;
+ uint32 numMaterials;
+ DXMesh *mesh;
+ DXSkinInfo *skinInfo = nullptr;
+
+ auto res = DXLoadSkinMesh(xobj, bufAdjacency, bufMaterials, numMaterials, &skinInfo, &mesh);
+ if (!res) {
BaseEngine::LOG(0, "Error loading skin mesh");
return false;
}
- XSkinMeshLoader *mesh = new XSkinMeshLoader(this, meshObject);
- _skinMesh = new SkinMeshHelper(mesh);
- mesh->loadMesh(filename, xobj, materialReferences);
+ XSkinMeshLoader *meshLoader = new XSkinMeshLoader(this, meshObject, mesh, skinInfo);
+ meshLoader->loadMesh(filename, xobj, materialReferences);
+
+ _skinMesh = new SkinMeshHelper(meshLoader, mesh, skinInfo);
+
+
+ // check for materials
+ if ((bufMaterials.ptr() == nullptr) || (numMaterials == 0)) {
+ // no materials are found, create default material
+ Material *mat = new Material(_gameRef);
+ mat->_material._diffuse.color._r = 0.5f;
+ mat->_material._diffuse.color._g = 0.5f;
+ mat->_material._diffuse.color._b = 0.5f;
+ mat->_material._specular = mat->_material._diffuse;
+ mat->_material._ambient = mat->_material._diffuse;
+
+ _materials.add(mat);
+ _numAttrs = 1;
+
+ meshLoader->_indexRanges.push_back(0);
+ meshLoader->_indexRanges.push_back(meshLoader->_indexData.size());
+ } else {
+ // load the materials
+ DXMaterial *fileMats = (DXMaterial *)bufMaterials.ptr();
+ for (uint i = 0; i < numMaterials; i++) {
+ Material *mat = new Material(_gameRef);
+ mat->_material = fileMats[i];
+ mat->_material._ambient = mat->_material._diffuse;
+ if (fileMats[i]._textureFilename[0] != '\0') {
+ mat->setTexture(PathUtil::getDirectoryName(filename) + fileMats[i]._textureFilename, true);
+ }
+
+ _materials.add(mat);
+ }
+
+ auto atribTable = mesh->getAttributeTable();
+ assert (atribTable);
+ _numAttrs = atribTable->_size;
+
+ for (uint i = 0; i < atribTable->_size; i++) {
+ meshLoader->_materialIndices.push_back(atribTable->_ptr[i]._attribId);
+ meshLoader->_indexRanges.push_back(atribTable->_ptr[i]._faceStart * 3);
+ }
+
+ meshLoader->_indexRanges.push_back((atribTable->_ptr[atribTable->_size - 1]._faceStart + atribTable->_ptr[atribTable->_size - 1]._faceCount) * 3);
+
+ }
+
+ _skinnedMesh = false;
+
+ if (skinInfo) {
+ _skinnedMesh = skinInfo->getNumBones() > 0;
+ for (uint index = 0; index < skinInfo->getNumBones(); index++) {
+ SkinWeights currSkinWeights;
+ DXBone *bone = skinInfo->getBone(index);
+ currSkinWeights._boneName = bone->_name;
+
+ int weightCount = bone->_numInfluences;
+ currSkinWeights._vertexIndices.resize(weightCount);
+ currSkinWeights._vertexWeights.resize(weightCount);
+
+ for (int i = 0; i < weightCount; ++i) {
+ currSkinWeights._vertexIndices[i] = bone->_vertices[i];
+ }
+
+ for (int i = 0; i < weightCount; ++i) {
+ currSkinWeights._vertexWeights[i] = bone->_weights[i];
+ }
+
+ for (int r = 0; r < 4; ++r) {
+ for (int c = 0; c < 4; ++c) {
+ currSkinWeights._offsetMatrix(c, r) = bone->_transform._m4x4[r * 4 + c];
+ }
+ }
+
+ // mirror at orign
+ currSkinWeights._offsetMatrix(2, 3) *= -1.0f;
+
+ // mirror base vectors
+ currSkinWeights._offsetMatrix(2, 0) *= -1.0f;
+ currSkinWeights._offsetMatrix(2, 1) *= -1.0f;
+
+ // change handedness
+ currSkinWeights._offsetMatrix(0, 2) *= -1.0f;
+ currSkinWeights._offsetMatrix(1, 2) *= -1.0f;
+
+ meshLoader->_skinWeightsList.push_back(currSkinWeights);
+ }
+ }
+
+ meshLoader->generateAdjacency(_adjacency);
+
+ bufAdjacency.free();
+ bufMaterials.free();
+ //bufBoneOffset.free();
return true;
}
@@ -90,7 +200,7 @@ bool XMesh::findBones(FrameNode *rootFrame) {
if (frame) {
_boneMatrices[i] = frame->getCombinedMatrix();
} else {
- warning("XMeshOpenGL::findBones could not find bone %s", skinWeightsList[i]._boneName.c_str());
+ warning("XMesh::findBones could not find bone %s", skinWeightsList[i]._boneName.c_str());
}
}
diff --git a/engines/wintermute/base/gfx/xskinmesh.cpp b/engines/wintermute/base/gfx/xskinmesh.cpp
new file mode 100644
index 00000000000..d7d4ca5267f
--- /dev/null
+++ b/engines/wintermute/base/gfx/xskinmesh.cpp
@@ -0,0 +1,1167 @@
+/* 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/>.
+ *
+ */
+
+/*
+ * Based on skin and mesh code from Wine sources.
+ * Copyright (C) 2005 Henri Verbeet
+ * Copyright (C) 2006 Ivan Gyurdiev
+ * Copyright (C) 2009 David Adam
+ * Copyright (C) 2010 Tony Wasserka
+ * Copyright (C) 2011 Dylan Smith
+ * Copyright (C) 2011 Michael Mc Donnell
+ * Copyright (C) 2013 Christian Costa
+ */
+
+#include "engines/wintermute/base/gfx/xskinmesh.h"
+#include "engines/wintermute/base/gfx/xmath.h"
+
+namespace Wintermute {
+
+struct MeshData {
+ uint32 _numVertices;
+ uint32 _numPolyFaces;
+ uint32 _numTriFaces;
+ DXVector3 *_vertices;
+ uint32 *_numTriPerFace;
+ uint32 *_indices;
+ uint32 _fvf;
+ uint32 _numNormals;
+ DXVector3 *_normals;
+ uint32 *_normalIndices;
+ DXVector3 *_vertexNormals;
+ DXVector2 *_texCoords;
+ DXColorValue *_vertexColors;
+ uint32 _numMaterials;
+ DXMaterial *_materials;
+ uint32 *_materialIndices;
+ DXSkinInfo *_skinInfo;
+ uint32 _boneCount;
+ uint32 _skinWeightsInfoCount;
+};
+
+uint32 DXGetFVFVertexSize(uint32 fvf) {
+ uint32 size = 0;
+
+ if (fvf & DXFVF_XYZ)
+ size += sizeof(DXVector3);
+ if (fvf & DXFVF_NORMAL)
+ size += sizeof(DXVector3);
+ if (fvf & DXFVF_DIFFUSE)
+ size += sizeof(DXVector4);
+ if (fvf & DXFVF_TEX1)
+ size += sizeof(DXVector2);
+
+ return size;
+}
+
+static bool createMesh(uint32 numFaces, uint32 numVertices, uint32 fvf, DXMesh **mesh) {
+ if (!mesh)
+ return false;
+
+ auto object = new DXMesh;
+ if (!object)
+ return false;
+
+ if (!object->create(numFaces, numVertices, fvf)) {
+ delete object;
+ return false;
+ }
+
+ *mesh = object;
+
+ return true;
+}
+
+static bool createSkinInfo(uint32 vertexCount, uint32 boneCount, DXSkinInfo **skinInfo) {
+ if (!skinInfo)
+ return false;
+
+ auto skin = new DXSkinInfo();
+ if (!skin)
+ return false;
+
+ if (!skin->create(vertexCount, boneCount)) {
+ delete skin;
+ return false;
+ }
+
+ *skinInfo = skin;
+
+ return true;
+}
+
+bool DXMesh::create(uint32 numFaces, uint32 numVertices, uint32 fvf) {
+ _numFaces = numFaces;
+ _numVertices = numVertices;
+ _fvf = fvf;
+ _vertexSize = DXGetFVFVertexSize(fvf);
+ _attribTable._size = 0;
+ _attribTable._ptr = nullptr;
+ _vertexBuffer = DXBuffer(numVertices * _vertexSize);
+ _indexBuffer = DXBuffer(numFaces * 3 * sizeof(uint32));
+ _attribBuffer = DXBuffer(numFaces * sizeof(uint32));
+ if (!_vertexBuffer.ptr() || !_indexBuffer.ptr() || !_attribBuffer.ptr()) {
+ destroy();
+ return false;
+ }
+
+ return true;
+}
+
+void DXMesh::destroy() {
+ _numFaces = 0;
+ _numVertices = 0;
+ _fvf = 0;
+ _vertexSize = 0;
+ _attribTable._size = 0;
+ _vertexBuffer.free();
+ _indexBuffer.free();
+ _attribBuffer.free();
+ delete[] _attribTable._ptr;
+ _attribTable._ptr = nullptr;
+}
+
+int DXMesh::compareVertexKeys(const void *a, const void *b) {
+ const DXVertexMetadata *left = static_cast<const DXVertexMetadata *>(a);
+ const DXVertexMetadata *right = static_cast<const DXVertexMetadata *>(b);
+ if (left->_key == right->_key)
+ return 0;
+ return left->_key < right->_key ? -1 : 1;
+}
+
+bool DXMesh::generateAdjacency(uint32 *adjacency) {
+ uint32 i;
+
+ if (!adjacency)
+ return false;
+
+ byte *vertices = const_cast<byte *>(_vertexBuffer.ptr());
+ const uint32 *indices = (const uint32 *)_indexBuffer.ptr();
+
+ uint32 bufferSize = _numFaces * 3 * sizeof(uint32) + _numVertices * sizeof(DXVertexMetadata);
+ uint32 *sharedIndices = new uint32[bufferSize];
+ if (!sharedIndices)
+ return false;
+ DXVertexMetadata *sortedVertices = (DXVertexMetadata *)(sharedIndices + _numFaces * 3);
+
+ for (i = 0; i < _numVertices; i++) {
+ DXVector3 *vertex = (DXVector3 *)(vertices + _vertexSize * i);
+ sortedVertices[i]._firstSharedIndex = -1;
+ sortedVertices[i]._key = vertex->_x + vertex->_y + vertex->_z;
+ sortedVertices[i]._vertexIndex = i;
+ }
+ for (i = 0; i < _numFaces * 3; i++) {
+ uint32 *firstSharedIndex = &sortedVertices[indices[i]]._firstSharedIndex;
+ sharedIndices[i] = *firstSharedIndex;
+ *firstSharedIndex = i;
+ adjacency[i] = -1;
+ }
+ qsort(sortedVertices, _numVertices, sizeof(DXVertexMetadata), compareVertexKeys);
+
+ for (i = 0; i < _numVertices; i++) {
+ DXVertexMetadata *sortedVertexA = &sortedVertices[i];
+ DXVector3 *vertex_a = (DXVector3 *)(vertices + sortedVertexA->_vertexIndex * _vertexSize);
+ uint32 sharedIndexA = sortedVertexA->_firstSharedIndex;
+
+ while (sharedIndexA != (uint32)-1) {
+ uint32 j = i;
+ uint32 sharedIndexB = sharedIndices[sharedIndexA];
+ struct DXVertexMetadata *sortedVertexB = sortedVertexA;
+
+ while (true) {
+ while (sharedIndexB != (uint32)-1) {
+ uint32 baseA = (sharedIndexA / 3) * 3;
+ uint32 baseB = (sharedIndexB / 3) * 3;
+ bool adjacent = true;
+ int k;
+
+ for (k = 0; k < 3; k++) {
+ if (adjacency[baseB + k] == sharedIndexA / 3) {
+ adjacent = true;
+ break;
+ }
+ }
+ if (!adjacent) {
+ for (k = 1; k <= 2; k++) {
+ uint32 vertex_index_a = baseA + (sharedIndexA + k) % 3;
+ uint32 vertex_index_b = baseB + (sharedIndexB + (3 - k)) % 3;
+ adjacent = indices[vertex_index_a] == indices[vertex_index_b];
+ if (!adjacent) {
+ DXVector3 delta = {0.0f, 0.0f, 0.0f};
+ float lengthSq;
+
+ DXVec3Subtract(&delta, (DXVector3 *)(vertices + indices[vertex_index_a] * _vertexSize), (DXVector3 *)(vertices + indices[vertex_index_b] * _vertexSize));
+ lengthSq = DXVec3Length(&delta);
+ adjacent = lengthSq == 0.0f;
+ }
+ if (adjacent) {
+ uint32 adjA = baseA + 2 - (vertex_index_a + sharedIndexA + 1) % 3;
+ uint32 adjB = baseB + 2 - (vertex_index_b + sharedIndexB + 1) % 3;
+ if (adjacency[adjA] == (uint32)-1 && adjacency[adjB] == (uint32)-1) {
+ adjacency[adjA] = baseB / 3;
+ adjacency[adjB] = baseA / 3;
+ break;
+ }
+ }
+ }
+ }
+
+ sharedIndexB = sharedIndices[sharedIndexB];
+ }
+ while (++j < _numVertices) {
+ DXVector3 *vertexB;
+
+ sortedVertexB++;
+ if (sortedVertexB->_key - sortedVertexA->_key > 0.0f) {
+ j = _numVertices;
+ break;
+ }
+ vertexB = (DXVector3 *)(vertices + sortedVertexB->_vertexIndex * _vertexSize);
+ if (fabsf(vertex_a->_x - vertexB->_x) <= 0.0f &&
+ fabsf(vertex_a->_y - vertexB->_y) <= 0.0f &&
+ fabsf(vertex_a->_z - vertexB->_z) <= 0.0f) {
+ break;
+ }
+ }
+ if (j >= _numVertices)
+ break;
+ sharedIndexB = sortedVertexB->_firstSharedIndex;
+ }
+
+ sortedVertexA->_firstSharedIndex = sharedIndices[sortedVertexA->_firstSharedIndex];
+ sharedIndexA = sortedVertexA->_firstSharedIndex;
+ }
+ }
+
+ delete[] sharedIndices;
+ return true;
+}
+
+bool DXMesh::cloneMesh(DXMesh **cloneMeshOut) {
+ DXMesh *clonedMesh;
+
+ if (!cloneMeshOut)
+ return false;
+
+ if (!createMesh(_numFaces, _numVertices, _fvf, &clonedMesh))
+ return false;
+
+ memcpy(clonedMesh->_vertexBuffer.ptr(), _vertexBuffer.ptr(), _vertexBuffer.size());
+ memcpy(clonedMesh->_indexBuffer.ptr(), _indexBuffer.ptr(), _indexBuffer.size());
+ memcpy(clonedMesh->_attribBuffer.ptr(), _attribBuffer.ptr(), _attribBuffer.size());
+
+ if (_attribTable._size) {
+ clonedMesh->_attribTable._size = _attribTable._size;
+ clonedMesh->_attribTable._ptr = new DXAttributeRange[_attribTable._size];
+ if (!clonedMesh->_attribTable._ptr) {
+ delete clonedMesh;
+ return false;
+ }
+ memcpy(clonedMesh->_attribTable._ptr, _attribTable._ptr, _attribTable._size * sizeof(DXAttributeRange));
+ }
+
+ *cloneMeshOut = clonedMesh;
+
+ return true;
+}
+
+static uint32 countAttributes(const uint32 *attribBuffer, uint32 numFaces) {
+ uint32 last_attribute = attribBuffer[0];
+ uint32 attribTableSize = 1;
+ for (uint32 i = 1; i < numFaces; i++) {
+ if (attribBuffer[i] != last_attribute) {
+ last_attribute = attribBuffer[i];
+ attribTableSize++;
+ }
+ }
+ return attribTableSize;
+}
+
+static void fillAttributeTable(const uint32 *attribBuffer, uint32 numfaces, const uint32 *indices, DXAttributeRange *attribTable) {
+ uint32 attribTableSize = 0;
+ uint32 lastAttribute = attribBuffer[0];
+ uint32 minVertex, maxVertex, i, j;
+
+ attribTable[0]._attribId = lastAttribute;
+ attribTable[0]._faceStart = 0;
+ minVertex = (uint32)-1;
+ maxVertex = 0;
+ for (i = 0; i < numfaces; i++) {
+ if (attribBuffer[i] != lastAttribute) {
+ lastAttribute = attribBuffer[i];
+ attribTable[attribTableSize]._faceCount = i - attribTable[attribTableSize]._faceStart;
+ attribTable[attribTableSize]._vertexStart = minVertex;
+ attribTable[attribTableSize]._vertexCount = maxVertex - minVertex + 1;
+ attribTableSize++;
+ attribTable[attribTableSize]._attribId = attribBuffer[i];
+ attribTable[attribTableSize]._faceStart = i;
+ minVertex = (uint32)-1;
+ maxVertex = 0;
+ }
+ for (j = 0; j < 3; j++) {
+ uint32 vertex_index = indices[i * 3 + j];
+ if (vertex_index < minVertex)
+ minVertex = vertex_index;
+ if (vertex_index > maxVertex)
+ maxVertex = vertex_index;
+ }
+ }
+ attribTable[attribTableSize]._faceCount = i - attribTable[attribTableSize]._faceStart;
+ attribTable[attribTableSize]._vertexStart = minVertex;
+ attribTable[attribTableSize]._vertexCount = maxVertex - minVertex + 1;
+ attribTableSize++;
+}
+
+bool DXSkinInfo::create(uint32 vertexCount, uint32 boneCount) {
+ _numVertices = vertexCount;
+ _numBones = boneCount;
+ _fvf = 0;
+
+ _bones = new DXBone[boneCount];
+ if (!_bones) {
+ return false;
+ }
+ memset(_bones, 0, boneCount * sizeof(DXBone));
+ return true;
+}
+
+void DXSkinInfo::destroy() {
+ delete[] _bones;
+ _bones = nullptr;
+}
+
+bool DXSkinInfo::updateSkinnedMesh(const DXMatrix *boneTransforms, void *srcVertices, void *dstVertices) {
+ uint32 size = DXGetFVFVertexSize(_fvf);
+ uint32 i, j;
+
+ for (i = 0; i < _numVertices; i++) {
+ DXVector3 *position = (DXVector3 *)((byte *)dstVertices + size * i);
+ position->_x = 0.0f;
+ position->_y = 0.0f;
+ position->_z = 0.0f;
+ }
+
+ for (i = 0; i < _numBones; i++) {
+ DXMatrix boneInverse, matrix;
+
+ DXMatrixInverse(&boneInverse, NULL, &_bones[i]._transform);
+ DXMatrixMultiply(&matrix, &boneTransforms[i], &boneInverse);
+ DXMatrixMultiply(&matrix, &matrix, &_bones[i]._transform);
+
+ for (j = 0; j < _bones[i]._numInfluences; j++) {
+ DXVector3 position;
+ DXVector3 *position_src = (DXVector3 *)((byte *)srcVertices + size * _bones[i]._vertices[j]);
+ DXVector3 *position_dest = (DXVector3 *)((byte *)dstVertices + size * _bones[i]._vertices[j]);
+ float weight = _bones[i]._weights[j];
+
+ DXVec3TransformCoord(&position, position_src, &matrix);
+ position_dest->_x += weight * position._x;
+ position_dest->_y += weight * position._y;
+ position_dest->_z += weight * position._z;
+ }
+ }
+
+ if (_fvf & DXFVF_NORMAL) {
+ for (i = 0; i < _numVertices; i++) {
+ DXVector3 *normal = (DXVector3 *)((byte *)dstVertices + size * i + sizeof(DXVector3));
+ normal->_x = 0.0f;
+ normal->_y = 0.0f;
+ normal->_z = 0.0f;
+ }
+
+ for (i = 0; i < _numBones; i++) {
+ DXMatrix boneInverse, matrix;
+
+ DXMatrixInverse(&boneInverse, nullptr, &_bones[i]._transform);
+ DXMatrixMultiply(&matrix, &_bones[i]._transform, &boneTransforms[i]);
+
+ for (j = 0; j < _bones[i]._numInfluences; j++) {
+ DXVector3 normal;
+ DXVector3 *normalSrc = (DXVector3 *)((byte *)srcVertices + size * _bones[i]._vertices[j] + sizeof(DXVector3));
+ DXVector3 *normalDest = (DXVector3 *)((byte *)dstVertices + size * _bones[i]._vertices[j] + sizeof(DXVector3));
+ float weight = _bones[i]._weights[j];
+
+ DXVec3TransformNormal(&normal, normalSrc, &boneInverse);
+ DXVec3TransformNormal(&normal, &normal, &matrix);
+ normalDest->_x += weight * normal._x;
+ normalDest->_y += weight * normal._y;
+ normalDest->_z += weight * normal._z;
+ }
+ }
+
+ for (i = 0; i < _numVertices; i++) {
+ DXVector3 *normalDest = (DXVector3 *)((byte *)dstVertices + (i * size) + sizeof(DXVector3));
+ if ((normalDest->_x != 0.0f) && (normalDest->_y != 0.0f) && (normalDest->_z != 0.0f)) {
+ DXVec3Normalize(normalDest, normalDest);
+ }
+ }
+ }
+
+ return true;
+}
+
+bool DXSkinInfo::setBoneName(uint32 boneIdx, const char *name) {
+ if (boneIdx >= _numBones || !name)
+ return false;
+
+ uint32 size = strlen(name) + 1;
+ char *newName = new char[size];
+ if (!newName)
+ return false;
+ memcpy(newName, name, size);
+ delete[] _bones[boneIdx]._name;
+ _bones[boneIdx]._name = newName;
+
+ return true;
+}
+
+bool DXSkinInfo::setBoneInfluence(uint32 boneIdx, uint32 numInfluences, const uint32 *vertices, const float *weights) {
+ DXBone *bone;
+ uint32 *newVertices = NULL;
+ float *newWeights = NULL;
+
+ if (boneIdx >= _numBones || !vertices || !weights) {
+ return false;
+ }
+
+ if (numInfluences) {
+ newVertices = new uint32[numInfluences];
+ if (!newVertices)
+ return false;
+ newWeights = new float[numInfluences];
+ if (!newWeights) {
+ delete[] newVertices;
+ return false;
+ }
+ memcpy(newVertices, vertices, numInfluences * sizeof(*vertices));
+ memcpy(newWeights, weights, numInfluences * sizeof(*weights));
+ }
+ bone = &_bones[boneIdx];
+ bone->_numInfluences = numInfluences;
+ delete[] bone->_vertices;
+ delete[] bone->_weights;
+ bone->_vertices = newVertices;
+ bone->_weights = newWeights;
+
+ return true;
+}
+
+DXBone *DXSkinInfo::getBone(uint32 boneIdx) {
+ return &_bones[boneIdx];
+}
+
+bool DXSkinInfo::setBoneOffsetMatrix(uint32 boneIdx, const float *boneTransform) {
+ if (boneIdx >= _numBones || !boneTransform)
+ return false;
+
+ for (int m = 0; m < 16; m++) {
+ _bones[boneIdx]._transform._m4x4[m] = boneTransform[m];
+ }
+ return true;
+}
+
+static bool parseVertexDuplicationIndices(XFileData &fileData, struct MeshData */*meshData*/) {
+ auto vertexDuplObj = fileData.getXVertexDuplicationIndicesObject();
+ if (!vertexDuplObj) {
+ return false;
+ }
+
+ // skipping this data
+ return true;
+}
+
+static bool parseFVFData(XFileData &fileData, struct MeshData */*meshData*/) {
+ auto vfvDataObj = fileData.getXFVFDataObject();
+ if (!vfvDataObj) {
+ return false;
+ }
+
+ // FVFData suppose contains proper layout for declared FVF
+ // instead they are not complete and duplicated to already loaded
+ // so skipping this data
+ return true;
+}
+
+static bool parseDeclData(XFileData &fileData, struct MeshData *meshData) {
+ uint32 i, vertexSize = 0;
+ uint32 normalOffset = -1;
+ uint32 textureOffset = -1;
+ //uint32 tangentOffset = -1;
+ //uint32 binormalOffset = -1;
+
+ auto declObj = fileData.getXDeclDataObject();
+ if (!declObj) {
+ return false;
+ }
+
+ for (i = 0; i < declObj->_numElements; ++i) {
+ switch (declObj->_elements[i]._usage) {
+ case DXDECLUSAGE_NORMAL:
+ assert(!(meshData->_fvf & DXFVF_NORMAL));
+ normalOffset = vertexSize;
+ break;
+ case DXDECLUSAGE_TEXCOORD:
+ assert(!(meshData->_fvf & DXFVF_TEX1));
+ textureOffset = vertexSize;
+ break;
+ case DXDECLUSAGE_TANGENT:
+ //tangentOffset = vertexSize;
+ break;
+ case DXDECLUSAGE_BINORMAL:
+ //binormalOffset = vertexSize;
+ break;
+ default:
+ error("parseDeclData() Error: not handled DeclUsage: %d", declObj->_elements[i]._usage);
+ }
+ switch (declObj->_elements[i]._type) {
+ case DXDECLTYPE_FLOAT2:
+ vertexSize += 2;
+ break;
+ case DXDECLTYPE_FLOAT3:
+ vertexSize += 3;
+ break;
+ default:
+ error("parseDeclData() Error: not handled DeclType: %d", declObj->_elements[i]._type);
+ }
+ }
+
+ if (vertexSize * meshData->_numVertices != declObj->_numData) {
+ return false;
+ }
+
+ if (normalOffset != (uint32)-1) {
+ if (!meshData->_indices)
+ return false;
+ delete[] meshData->_normals;
+ uint32 numFaceIndices = meshData->_numPolyFaces * 2 + meshData->_numTriFaces;
+ meshData->_numNormals = meshData->_numVertices;
+ meshData->_normals = new DXVector3[meshData->_numNormals];
+ meshData->_normalIndices = new uint32[numFaceIndices];
+ if (!meshData->_normals || !meshData->_normalIndices) {
+ return false;
+ }
+ memcpy(meshData->_normalIndices, meshData->_indices, numFaceIndices * sizeof(uint32));
+ meshData->_fvf |= DXFVF_NORMAL;
+ }
+
+ if (textureOffset != (uint32)-1) {
+ delete[] meshData->_texCoords;
+ meshData->_texCoords = new DXVector2[meshData->_numVertices];
+ if (!meshData->_texCoords) {
+ return false;
+ }
+ meshData->_fvf |= DXFVF_TEX1;
+ }
+
+ for (i = 0; i < meshData->_numVertices; ++i) {
+ if (meshData->_fvf & DXFVF_NORMAL) {
+ float *vertexNormalData = reinterpret_cast<float *>(declObj->_data + vertexSize * i + normalOffset);
+ meshData->_normals[i]._x = vertexNormalData[0];
+ meshData->_normals[i]._y = vertexNormalData[1];
+ meshData->_normals[i]._z = vertexNormalData[2];
+ DXVec3Normalize(&meshData->_normals[i], &meshData->_normals[i]);
+ }
+
+ if (meshData->_fvf & DXFVF_TEX1) {
+ float *vertexTextureCoordsData = reinterpret_cast<float *>(declObj->_data + vertexSize * i + textureOffset);
+ meshData->_texCoords[i]._x = vertexTextureCoordsData[0];
+ meshData->_texCoords[i]._y = vertexTextureCoordsData[1];
+ }
+
+ if (textureOffset != (uint32)-1) {
+ //float *vertexTangentData = reinterpret_cast<float *>(declObj->_data + vertexSize * i + tangentOffset);
+ }
+
+ if (textureOffset != (uint32)-1) {
+ //float *vertexBinormalData = reinterpret_cast<float *>(declObj->_data + vertexSize * i + binormalOffset);
+ }
+ }
+
+ return true;
+}
+
+static bool parseSkinWeightsInfo(XFileData &fileData, struct MeshData *meshData) {
+ uint32 influenceCount;
+ const char *name;
+ uint32 index = meshData->_skinWeightsInfoCount;
+
+ if (!meshData->_skinInfo) {
+ return false;
+ }
+
+ auto skinWeightsObj = fileData.getXSkinWeightsObject();
+ if (!skinWeightsObj) {
+ return false;
+ }
+
+ name = skinWeightsObj->_transformNodeName;
+ influenceCount = skinWeightsObj->_numWeights;
+
+ if (meshData->_skinInfo->setBoneName(index, name)) {
+ if (meshData->_skinInfo->setBoneInfluence(index, influenceCount, skinWeightsObj->_vertexIndices, skinWeightsObj->_weights)) {
+ if (meshData->_skinInfo->setBoneOffsetMatrix(index, skinWeightsObj->_matrixOffset)) {
+ ++meshData->_skinWeightsInfoCount;
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+static bool parseSkinMeshHeader(XFileData &fileData, struct MeshData *meshData) {
+ if (meshData->_skinInfo) {
+ return false;
+ }
+
+ auto skinMeshHeaderObj = fileData.getXSkinMeshHeaderObject();
+ if (!skinMeshHeaderObj) {
+ return false;
+ }
+
+ meshData->_boneCount = skinMeshHeaderObj->_nBones;
+ return createSkinInfo(meshData->_numVertices, meshData->_boneCount, &meshData->_skinInfo);
+}
+
+static bool parseTextureFilename(XFileData &fileData, char *filenameOut) {
+ auto textureNameObj = fileData.getXTextureFilenameObject();
+ if (!textureNameObj) {
+ return false;
+ }
+
+ Common::strlcpy(filenameOut, textureNameObj->_filename, XMAX_NAME_LEN);
+
+ return true;
+}
+
+static bool parseMaterial(XFileData &fileData, DXMaterial *material) {
+ XFileData child;
+ XClassType type;
+ uint nbChildren;
+ uint32 i;
+
+ auto materialObj = fileData.getXMaterialObject();
+ if (!materialObj) {
+ return false;
+ }
+
+ material->_diffuse.color._r = materialObj->_colorR;
+ material->_diffuse.color._g = materialObj->_colorG;
+ material->_diffuse.color._b = materialObj->_colorB;
+ material->_diffuse.color._a = materialObj->_colorA;
+ material->_power = materialObj->_power;
+ material->_specular.color._r = materialObj->_specularR;
+ material->_specular.color._g = materialObj->_specularG;
+ material->_specular.color._b = materialObj->_specularB;
+ material->_specular.color._a = 1.0f;
+ material->_emissive.color._r = materialObj->_emissiveR;
+ material->_emissive.color._g = materialObj->_emissiveG;
+ material->_emissive.color._b = materialObj->_emissiveB;
+ material->_emissive.color._a = 1.0f;
+ material->_ambient.color._r = 0.0f;
+ material->_ambient.color._g = 0.0f;
+ material->_ambient.color._b = 0.0f;
+ material->_ambient.color._a = 1.0f;
+ material->_textureFilename[0] = '\0';
+
+ if (!fileData.getChildren(nbChildren)) {
+ return false;
+ }
+
+ for (i = 0; i < nbChildren; i++) {
+ if (!fileData.getChild(i, child)) {
+ return false;
+ }
+ if (!child.getType(type)) {
+ return false;
+ }
+
+ if (type == XClassType::kXClassTextureFilename) {
+ if (!parseTextureFilename(child, material->_textureFilename)) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+static void destroyMaterials(struct MeshData *meshData) {
+ delete[] meshData->_materials;
+ meshData->_materials = nullptr;
+ delete[] meshData->_materialIndices;
+ meshData->_materialIndices = nullptr;
+ meshData->_numMaterials = 0;
+}
+
+static bool parseMaterialList(XFileData &fileData, struct MeshData *meshData) {
+ XFileData child;
+ XClassType type;
+ uint nbChildren;
+ uint32 materialCount, i;
+
+ destroyMaterials(meshData);
+
+ auto materialListObj = fileData.getXMeshMaterialListObject();
+ if (!materialListObj) {
+ return false;
+ }
+
+ materialCount = materialListObj->_nMaterials;
+
+ if (materialListObj->_numFaceIndexes != meshData->_numPolyFaces) {
+ return false;
+ }
+ for (i = 0; i < meshData->_numPolyFaces; ++i) {
+ if (materialListObj->_faceIndexes[i] >= materialCount) {
+ return false;
+ }
+ }
+
+ meshData->_materials = new DXMaterial[materialCount];
+ meshData->_materialIndices = new uint32[meshData->_numPolyFaces];
+ if (!meshData->_materials || !meshData->_materialIndices) {
+ return false;
+ }
+ for (i = 0; i < meshData->_numPolyFaces; ++i) {
+ meshData->_materialIndices[i] = materialListObj->_faceIndexes[i];
+ }
+
+ if (!fileData.getChildren(nbChildren)) {
+ return false;
+ }
+
+ for (i = 0; i < nbChildren; i++) {
+ if (!fileData.getChild(i, child)) {
+ return false;
+ }
+ if (!child.getType(type)) {
+ return false;
+ }
+
+ if (type == XClassType::kXClassMaterial) {
+ if (meshData->_numMaterials >= materialCount) {
+ return false;
+ }
+ if (!parseMaterial(child, &meshData->_materials[meshData->_numMaterials++])) {
+ return false;
+ }
+ }
+ // missing referenced material
+ if (type == XClassType::kXClassUnknown) {
+ materialCount--;
+ }
+ }
+ if (materialCount != meshData->_numMaterials) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool parseTextureCoords(XFileData &fileData, struct MeshData *meshData) {
+ uint32 i;
+
+ delete[] meshData->_texCoords;
+ meshData->_texCoords = nullptr;
+
+ auto textureCordsObj = fileData.getXMeshTextureCoordsObject();
+ if (!textureCordsObj) {
+ return false;
+ }
+
+ if (textureCordsObj->_numTextureCoords != meshData->_numVertices) {
+ return false;
+ }
+
+ meshData->_texCoords = new DXVector2[meshData->_numVertices];
+ if (!meshData->_texCoords) {
+ return false;
+ }
+ for (i = 0; i < meshData->_numVertices; i++) {
+ meshData->_texCoords[i]._x = textureCordsObj->_textureCoords[i]._u;
+ meshData->_texCoords[i]._y = textureCordsObj->_textureCoords[i]._v;
+ }
+
+ meshData->_fvf |= DXFVF_TEX1;
+
+ return true;
+}
+
+static bool parseVertexColors(XFileData &fileData, struct MeshData *meshData) {
+ uint32 i;
+
+ delete[] meshData->_vertexColors;
+ meshData->_vertexColors = nullptr;
+
+ auto colorsObj = fileData.getXMeshVertexColorsObject();
+ if (!colorsObj) {
+ return false;
+ }
+ uint32 colorCount = colorsObj->_numVertexColors;
+
+ meshData->_vertexColors = new DXColorValue[meshData->_numVertices];
+ if (!meshData->_vertexColors) {
+ return false;
+ }
+
+ for (i = 0; i < meshData->_numVertices; i++) {
+ meshData->_vertexColors[i].color._r = 1.0f;
+ meshData->_vertexColors[i].color._g = 1.0f;
+ meshData->_vertexColors[i].color._b = 1.0f;
+ meshData->_vertexColors[i].color._a = 0.0f;
+ }
+
+ for (i = 0; i < colorCount; ++i) {
+ DXColorValue color;
+ uint32 index = colorsObj->_vertexColors[i]._index;
+ if (index >= meshData->_numVertices) {
+ return false;
+ }
+ color.color._r = colorsObj->_vertexColors[i]._indexColorR;
+ color.color._g = colorsObj->_vertexColors[i]._indexColorG;
+ color.color._b = colorsObj->_vertexColors[i]._indexColorB;
+ color.color._a = colorsObj->_vertexColors[i]._indexColorA;
+ meshData->_vertexColors[index].color._r = MIN(1.0f, MAX(0.0f, color.color._r));
+ meshData->_vertexColors[index].color._g = MIN(1.0f, MAX(0.0f, color.color._g));
+ meshData->_vertexColors[index].color._b = MIN(1.0f, MAX(0.0f, color.color._b));
+ meshData->_vertexColors[index].color._a = MIN(1.0f, MAX(0.0f, color.color._a));
+ }
+
+ meshData->_fvf |= DXFVF_DIFFUSE;
+
+ return true;
+}
+
+static bool parseNormals(XFileData &fileData, struct MeshData *meshData) {
+ uint32 numFaceIndices = meshData->_numPolyFaces * 2 + meshData->_numTriFaces;
+ uint32 i, j;
+
+ auto normalsObj = fileData.getXMeshNormalsObject();
+ if (!normalsObj) {
+ return false;
+ }
+
+ delete[] meshData->_normals;
+ meshData->_normals = nullptr;
+
+ meshData->_fvf |= DXFVF_NORMAL;
+ meshData->_numNormals = normalsObj->_numNormals;
+ meshData->_normals = new DXVector3[meshData->_numNormals];
+ meshData->_normalIndices = new uint32[numFaceIndices];
+ if (!meshData->_normals || !meshData->_normalIndices) {
+ return false;
+ }
+
+ memcpy(meshData->_normals, normalsObj->_normals, meshData->_numNormals * sizeof(DXVector3));
+ for (i = 0; i < meshData->_numNormals; i++) {
+ DXVec3Normalize(&meshData->_normals[i], &meshData->_normals[i]);
+ }
+
+ if (normalsObj->_numFaceNormals != meshData->_numPolyFaces) {
+ return false;
+ }
+
+ uint32 index = 0;
+ for (i = 0; i < meshData->_numPolyFaces; i++) {
+ uint32 count = normalsObj->_faceNormals[i]._numFaceVertexIndices;
+ if (count != meshData->_numTriPerFace[i] + 2) {
+ return false;
+ }
+
+ for (j = 0; j < count; j++) {
+ uint32 normalIndex = normalsObj->_faceNormals[i]._faceVertexIndices[j];
+ if (normalIndex >= meshData->_numNormals) {
+ return false;
+ }
+ meshData->_normalIndices[index++] = normalIndex;
+ }
+ }
+
+ return true;
+}
+
+static bool parseMesh(XFileData *fileData, struct MeshData *meshData) {
+ XFileData child;
+ XClassType type;
+ uint32 childCount;
+ uint32 i, j;
+ bool result = true;
+
+ meshData->_skinWeightsInfoCount = 0;
+
+ XMeshObject *meshObj = fileData->getXMeshObject();
+ if (!meshObj) {
+ return false;
+ }
+
+ meshData->_numVertices = meshObj->_numVertices;
+ meshData->_numPolyFaces = meshObj->_numFaces;
+ meshData->_numTriFaces = 0;
+ for (i = 0; i < meshData->_numPolyFaces; i++) {
+ meshData->_numTriFaces += meshObj->_faces[i]._numFaceVertexIndices - 2;
+ }
+
+ meshData->_fvf = DXFVF_XYZ;
+
+ meshData->_vertices = new DXVector3[meshData->_numVertices];
+ meshData->_numTriPerFace = new uint32[meshData->_numPolyFaces];
+ meshData->_indices = new uint32[meshData->_numTriFaces + meshData->_numPolyFaces * 2];
+ if (!meshData->_vertices || !meshData->_numTriPerFace || !meshData->_indices) {
+ return false;
+ }
+
+ memcpy(meshData->_vertices, meshObj->_vertices, meshData->_numVertices * sizeof(DXVector3));
+
+ uint32 index = 0;
+ for (i = 0; i < meshData->_numPolyFaces; i++) {
+ uint32 count = meshObj->_faces[i]._numFaceVertexIndices;
+ meshData->_numTriPerFace[i] = count - 2;
+ for (j = 0; j < count; j++) {
+ meshData->_indices[index++] = meshObj->_faces[i]._faceVertexIndices[j];
+ }
+ }
+
+ if (!fileData->getChildren(childCount))
+ return false;
+
+ for (i = 0; i < childCount; i++) {
+ if (!fileData->getChild(i, child))
+ return false;
+ if (!child.getType(type))
+ return false;
+ switch (type) {
+ case XClassType::kXClassMeshNormals:
+ result = parseNormals(child, meshData);
+ break;
+ case XClassType::kXClassMeshVertexColors:
+ result = parseVertexColors(child, meshData);
+ break;
+ case XClassType::kXClassMeshTextureCoords:
+ result = parseTextureCoords(child, meshData);
+ break;
+ case XClassType::kXClassMeshMaterialList:
+ result = parseMaterialList(child, meshData);
+ break;
+ case XClassType::kXClassSkinMeshHeader:
+ result = parseSkinMeshHeader(child, meshData);
+ break;
+ case XClassType::kXClassSkinWeights:
+ result = parseSkinWeightsInfo(child, meshData);
+ break;
+ case XClassType::kXClassDeclData:
+ result = parseDeclData(child, meshData);
+ break;
+ case XClassType::kXClassFVFData:
+ result = parseFVFData(child, meshData);
+ break;
+ case XClassType::kXClassVertexDuplicationIndices:
+ result = parseVertexDuplicationIndices(child, meshData);
+ break;
+ default:
+ break;
+ }
+ if (!result)
+ return false;
+ }
+
+ if (meshData->_skinInfo && (meshData->_skinWeightsInfoCount != meshData->_boneCount)) {
+ return false;
+ }
+
+ if (!meshData->_skinInfo) {
+ /*result = createSkinInfo(meshData->_numVertices, meshData->_boneCount, &meshData->_skinInfo);
+ if (!result)
+ return false;*/
+ }
+
+ return true;
+}
+
+static void cleanupMeshData(MeshData *meshData, bool releaseSkin = true) {
+ delete[] meshData->_vertices;
+ delete[] meshData->_numTriPerFace;
+ delete[] meshData->_indices;
+ delete[] meshData->_normals;
+ delete[] meshData->_normalIndices;
+ delete[] meshData->_vertexNormals;
+ destroyMaterials(meshData);
+ delete[] meshData->_texCoords;
+ delete[] meshData->_vertexColors;
+ if (releaseSkin)
+ delete meshData->_skinInfo;
+}
+
+bool DXLoadSkinMesh(XFileData *fileData, DXBuffer &adjacencyOut, DXBuffer &materialsOut, uint32 &numMaterialsOut, DXSkinInfo **skinInfoOut, DXMesh **meshOut) {
+ MeshData meshData{};
+ DXMesh *mesh;
+ uint32 i;
+
+ bool result = parseMesh(fileData, &meshData);
+ if (!result) {
+ cleanupMeshData(&meshData, true);
+ return false;
+ }
+ if (meshData._numVertices == 0) {
+ createMesh(meshData._numTriFaces, meshData._numVertices, meshData._fvf, &mesh);
+ *meshOut = mesh;
+ adjacencyOut = DXBuffer(meshData._numTriFaces * 3 * sizeof(uint32));
+ numMaterialsOut = meshData._numMaterials;
+ materialsOut = DXBuffer(meshData._numMaterials * sizeof(DXMaterial));
+ *skinInfoOut = meshData._skinInfo;
+ cleanupMeshData(&meshData, false);
+ return true;
+ }
+
+ uint32 totalVertices = meshData._numVertices;
+ if (meshData._fvf & DXFVF_NORMAL) {
+ meshData._vertexNormals = new DXVector3[meshData._numVertices];
+ memset(meshData._vertexNormals, 0, meshData._numVertices * sizeof(DXVector3));
+ uint32 numFaceIndices = meshData._numPolyFaces * 2 + meshData._numTriFaces;
+ for (i = 0; i < numFaceIndices; i++) {
+ uint32 vertexIndex = meshData._indices[i];
+ uint32 normalIndex = meshData._normalIndices[i];
+ assert(vertexIndex < meshData._numVertices);
+ assert(normalIndex < meshData._numNormals);
+ meshData._vertexNormals[vertexIndex]._x = meshData._normals[normalIndex]._x;
+ meshData._vertexNormals[vertexIndex]._y = meshData._normals[normalIndex]._y;
+ meshData._vertexNormals[vertexIndex]._z = meshData._normals[normalIndex]._z;
+ }
+ }
+
+ result = createMesh(meshData._numTriFaces, totalVertices, meshData._fvf, &mesh);
+ if (!result) {
+ cleanupMeshData(&meshData);
+ delete mesh;
+ return false;
+ }
+
+ float *vertices = (float *)mesh->getVertexBuffer().ptr();
+ float *outPtr = vertices;
+ for (i = 0; i < meshData._numVertices; i++) {
+ if (meshData._fvf & DXFVF_XYZ) {
+ *outPtr++ = meshData._vertices[i]._x;
+ *outPtr++ = meshData._vertices[i]._y;
+ *outPtr++ = meshData._vertices[i]._z;
+ }
+ if (meshData._fvf & DXFVF_NORMAL) {
+ *outPtr++ = meshData._vertexNormals[i]._x;
+ *outPtr++ = meshData._vertexNormals[i]._y;
+ *outPtr++ = meshData._vertexNormals[i]._z;
+ }
+ if (meshData._fvf & DXFVF_DIFFUSE) {
+ *outPtr++ = meshData._vertexColors[i].color._r;
+ *outPtr++ = meshData._vertexColors[i].color._g;
+ *outPtr++ = meshData._vertexColors[i].color._b;
+ *outPtr++ = meshData._vertexColors[i].color._a;
+ }
+ if (meshData._fvf & (DXFVF_TEX1)) {
+ *outPtr++ = meshData._texCoords[i]._x;
+ *outPtr++ = meshData._texCoords[i]._y;
+ }
+ }
+
+
+ uint32 *indices = (uint32 *)mesh->getIndexBuffer().ptr();
+ uint32 *indexInPtr = meshData._indices;
+ for (i = 0; i < meshData._numPolyFaces; i++) {
+ uint32 count = meshData._numTriPerFace[i];
+ uint32 firstIndex = *indexInPtr++;
+ // 1 -> 1
+ // 2 -> 2
+ // 3 -> 3
+ // 1 -> 4
+ // 3 -> 5
+ // 4 -> 6
+ while (count--) {
+ *indices++ = firstIndex;
+ *indices++ = *indexInPtr;
+ indexInPtr++;
+ *indices++ = *indexInPtr;
+ }
+ indexInPtr++;
+ }
+
+ if (meshData._materialIndices) {
+ uint32 index = 0;
+ uint32 *attribBuffer = (uint32 *)mesh->getAtribBuffer().ptr();
+ for (i = 0; i < meshData._numPolyFaces; i++) {
+ uint32 count = meshData._numTriPerFace[i];
+ while (count--)
+ attribBuffer[index++] = meshData._materialIndices[i];
+ }
+
+ uint32 attribTableSize = countAttributes(attribBuffer, meshData._numTriFaces);
+ auto attribTable = new DXAttributeRange[attribTableSize];
+ if (!attribTable) {
+ cleanupMeshData(&meshData);
+ delete mesh;
+ return false;
+ }
+ auto rangeTable = mesh->getAttributeTable();
+ rangeTable->_size = attribTableSize;
+ rangeTable->_ptr = attribTable;
+
+ indices = (uint32 *)mesh->getIndexBuffer().ptr();
+ fillAttributeTable(attribBuffer, meshData._numTriFaces, indices, attribTable);
+ }
+
+ uint32 bufferSize = meshData._numMaterials * sizeof(DXMaterial);
+ DXBuffer materials = DXBuffer(bufferSize);
+ if (!materials.ptr()) {
+ cleanupMeshData(&meshData);
+ delete mesh;
+ return false;
+ }
+ memcpy(materials.ptr(), meshData._materials, meshData._numMaterials * sizeof(DXMaterial));
+
+ if (meshData._numTriFaces== 0) {
+ materials.free();
+ cleanupMeshData(&meshData);
+ delete mesh;
+ return false;
+ }
+ DXBuffer adjacency = DXBuffer(meshData._numTriFaces * 3 * sizeof(uint32));
+ if (!adjacency.ptr()) {
+ materials.free();
+ cleanupMeshData(&meshData);
+ delete mesh;
+ return false;
+ }
+ if (!mesh->generateAdjacency((uint32 *)adjacency.ptr())) {
+ materials.free();
+ adjacency.free();
+ cleanupMeshData(&meshData);
+ delete mesh;
+ return false;
+ }
+
+ *meshOut = mesh;
+ adjacencyOut = adjacency;
+ numMaterialsOut = meshData._numMaterials;
+ materialsOut = materials;
+ *skinInfoOut = meshData._skinInfo;
+
+ cleanupMeshData(&meshData, false);
+
+ return result;
+}
+
+} // namespace Wintermute
diff --git a/engines/wintermute/base/gfx/xskinmesh.h b/engines/wintermute/base/gfx/xskinmesh.h
new file mode 100644
index 00000000000..dfe37d251c7
--- /dev/null
+++ b/engines/wintermute/base/gfx/xskinmesh.h
@@ -0,0 +1,165 @@
+/* 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/>.
+ *
+ */
+
+/*
+ * Based on skin and mesh code from Wine sources.
+ * Copyright (C) 2005 Henri Verbeet
+ * Copyright (C) 2006 Ivan Gyurdiev
+ * Copyright (C) 2009 David Adam
+ * Copyright (C) 2010 Tony Wasserka
+ * Copyright (C) 2011 Dylan Smith
+ * Copyright (C) 2011 Michael Mc Donnell
+ * Copyright (C) 2013 Christian Costa
+ */
+
+#ifndef WINTERMUTE_XSKINMESH_H
+#define WINTERMUTE_XSKINMESH_H
+
+#include "engines/wintermute/base/gfx/xbuffer.h"
+#include "engines/wintermute/base/gfx/xfile_loader.h"
+#include "engines/wintermute/base/gfx/xmath.h"
+
+namespace Wintermute {
+
+#define DXFVF_XYZ 0x0002
+#define DXFVF_NORMAL 0x0010
+#define DXFVF_DIFFUSE 0x0040
+#define DXFVF_TEX1 0x0100
+
+typedef enum {
+ DXDECLUSAGE_NORMAL = 3,
+ DXDECLUSAGE_TEXCOORD = 5,
+ DXDECLUSAGE_TANGENT = 6,
+ DXDECLUSAGE_BINORMAL = 7,
+} DXDECLUSAGE;
+
+typedef enum {
+ DXDECLTYPE_FLOAT2 = 1,
+ DXDECLTYPE_FLOAT3 = 2,
+} DXDECLTYPE;
+
+#if defined(SCUMMVM_USE_PRAGMA_PACK)
+#pragma pack(4)
+#endif
+
+struct DXAttributeRange {
+ uint32 _attribId;
+ uint32 _faceStart;
+ uint32 _faceCount;
+ uint32 _vertexStart;
+ uint32 _vertexCount;
+};
+
+struct DXAttributeRangeTable {
+ uint32 _size;
+ DXAttributeRange *_ptr;
+};
+
+typedef union {
+ struct {
+ float _r;
+ float _g;
+ float _b;
+ float _a;
+ } color;
+ float _data[4];
+} DXColorValue;
+
+typedef struct {
+ DXColorValue _diffuse;
+ DXColorValue _ambient;
+ DXColorValue _specular;
+ DXColorValue _emissive;
+ float _power;
+ char _textureFilename[XMAX_NAME_LEN];
+} DXMaterial;
+
+struct DXBone {
+ char *_name;
+ DXMatrix _transform;
+ uint32 _numInfluences;
+ uint32 *_vertices;
+ float *_weights;
+};
+
+#if defined(SCUMMVM_USE_PRAGMA_PACK)
+#pragma pack()
+#endif
+
+class DXSkinInfo {
+ uint32 _fvf;
+ uint32 _numVertices{};
+ uint32 _numBones{};
+ DXBone *_bones{};
+
+public:
+ ~DXSkinInfo() { destroy(); }
+ bool create(uint32 vertexCount, uint32 boneCount);
+ void destroy();
+ uint32 getNumBones() { return _numBones; }
+ bool setBoneName(uint32 boneIdx, const char *name);
+ char *getBoneName(uint32 boneIdx) { return _bones[boneIdx]._name; }
+ bool setBoneInfluence(uint32 boneIdx, uint32 numInfluences, const uint32 *vertices, const float *weights);
+ DXBone *getBone(uint32 boneIdx);
+ bool setBoneOffsetMatrix(uint32 boneIdx, const float *boneTransform);
+ DXMatrix *getBoneOffsetMatrix(uint32 boneIdx) { return &_bones[boneIdx]._transform; }
+ bool updateSkinnedMesh(const DXMatrix *boneTransforms, void *srcVertices, void *dstVertices);
+};
+
+class DXMesh {
+ uint32 _numFaces;
+ uint32 _numVertices;
+ uint32 _fvf;
+ uint32 _vertexSize;
+ DXBuffer _vertexBuffer;
+ DXBuffer _indexBuffer;
+ DXBuffer _attribBuffer;
+ DXAttributeRangeTable _attribTable;
+
+ struct DXVertexMetadata {
+ float _key;
+ uint32 _vertexIndex;
+ uint32 _firstSharedIndex;
+ };
+
+ static int compareVertexKeys(const void *a, const void *b);
+
+public:
+ ~DXMesh() { destroy(); }
+ bool create(uint32 numFaces, uint32 numVertices, uint32 fvf);
+ void destroy();
+ bool cloneMesh(DXMesh **cloneMeshOut);
+ uint32 getNumFaces() { return _numFaces; }
+ uint32 getNumVertices() { return _numVertices; }
+ uint32 getFVF() { return _fvf; }
+ DXBuffer getVertexBuffer() { return _vertexBuffer; }
+ DXBuffer getIndexBuffer() { return _indexBuffer; }
+ DXBuffer getAtribBuffer() { return _attribBuffer; }
+ DXAttributeRangeTable *getAttributeTable() { return &_attribTable; }
+ bool generateAdjacency(uint32 *adjacency);
+};
+
+bool DXLoadSkinMesh(XFileData *fileData, DXBuffer &adjacencyOut, DXBuffer &materialsOut, uint32 &numMaterialsOut, DXSkinInfo **skinInfoOut, DXMesh **meshOut);
+uint32 DXGetFVFVertexSize(uint32 fvf);
+
+} // namespace Wintermute
+
+#endif
diff --git a/engines/wintermute/base/gfx/xskinmesh_loader.cpp b/engines/wintermute/base/gfx/xskinmesh_loader.cpp
index bbd8dfde5a6..ab78622445b 100644
--- a/engines/wintermute/base/gfx/xskinmesh_loader.cpp
+++ b/engines/wintermute/base/gfx/xskinmesh_loader.cpp
@@ -25,6 +25,7 @@
#include "engines/wintermute/base/gfx/xframe_node.h"
#include "engines/wintermute/base/gfx/xfile_loader.h"
#include "engines/wintermute/base/gfx/xskinmesh_loader.h"
+#include "engines/wintermute/base/gfx/xskinmesh.h"
#include "engines/wintermute/base/gfx/xmodel.h"
#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/math/math_util.h"
@@ -34,9 +35,11 @@ namespace Wintermute {
// define constant to make it available to the linker
const uint32 XSkinMeshLoader::kNullIndex;
-XSkinMeshLoader::XSkinMeshLoader(XMesh *mesh, XMeshObject *meshObject) {
+XSkinMeshLoader::XSkinMeshLoader(XMesh *mesh, XMeshObject *meshObject, DXMesh *dxmesh, DXSkinInfo *skinInfo) {
_mesh = mesh;
_meshObject = meshObject;
+ _dxmesh = dxmesh;
+ _skinInfo = skinInfo;
_vertexCount = meshObject->_numVertices;
// vertex format for .X meshes will be position + normals + textures
@@ -54,435 +57,95 @@ XSkinMeshLoader::~XSkinMeshLoader() {
}
void XSkinMeshLoader::loadMesh(const Common::String &filename, XFileData *xobj, Common::Array<MaterialReference> &materialReferences) {
- parsePositionCoords(_meshObject);
+ auto fvf = _dxmesh->getFVF();
+ uint32 vertexSize = DXGetFVFVertexSize(fvf) / sizeof(float);
+ float *vertexBuffer = (float *)_dxmesh->getVertexBuffer().ptr();
+ uint32 offset = 0, normalOffset, /*diffuseOffset, */textureOffset;
- uint numFaces = _meshObject->_numFaces;
-
- Common::Array<int> indexCountPerFace;
-
- parseFaces(_meshObject, numFaces, indexCountPerFace);
-
- uint numChildren = 0;
- xobj->getChildren(numChildren);
-
- for (uint32 i = 0; i < numChildren; i++) {
- XFileData xchildData;
- XClassType objectType;
- if (xobj->getChild(i, xchildData)) {
- if (xchildData.getType(objectType)) {
- if (objectType == kXClassMeshTextureCoords) {
- parseTextureCoords(&xchildData);
- } else if (objectType == kXClassMeshNormals) {
- parseNormalCoords(&xchildData);
- } else if (objectType == kXClassMeshMaterialList) {
- parseMaterials(&xchildData, _mesh->_gameRef, numFaces, filename, materialReferences, indexCountPerFace);
- } else if (objectType == kXClassMaterial) {
- Material *mat = new Material(_mesh->_gameRef);
- mat->loadFromX(&xchildData, filename);
- _mesh->_materials.add(mat);
-
- // one material = one index range
- _mesh->_numAttrs = 1;
- _indexRanges.push_back(0);
- _indexRanges.push_back(_indexData.size());
- } else if (objectType == kXClassSkinMeshHeader) {
- int boneCount = xchildData.getXSkinMeshHeaderObject()->_nBones;
- _mesh->_skinnedMesh = boneCount > 0;
- } else if (objectType == kXClassSkinWeights) {
- _mesh->_skinnedMesh = true;
- parseSkinWeights(&xchildData);
- } else if (objectType == kXClassDeclData) {
- parseVertexDeclaration(&xchildData);
- }
- }
- }
+ if (fvf & DXFVF_XYZ) {
+ offset += sizeof(DXVector3) / sizeof(float);
+ }
+ if (fvf & DXFVF_NORMAL) {
+ normalOffset = offset;
+ offset += sizeof(DXVector3) / sizeof(float);
+ }
+ if (fvf & DXFVF_DIFFUSE) {
+ //diffuseOffset = offset;
+ offset += sizeof(DXColorValue) / sizeof(float);
+ }
+ if (fvf & DXFVF_TEX1) {
+ textureOffset = offset;
+ offset += sizeof(DXVector2) / sizeof(float);
}
- generateAdjacency(_mesh->_adjacency);
-}
-
-bool XSkinMeshLoader::parsePositionCoords(XMeshObject *mesh) {
for (uint i = 0; i < _vertexCount; ++i) {
- _vertexPositionData[i * 3 + 0] = mesh->_vertices[i]._x;
- _vertexPositionData[i * 3 + 1] = mesh->_vertices[i]._y;
- _vertexPositionData[i * 3 + 2] = mesh->_vertices[i]._z;
+ _vertexPositionData[i * 3 + 0] = vertexBuffer[i * vertexSize + 0];
+ _vertexPositionData[i * 3 + 1] = vertexBuffer[i * vertexSize + 1];
+ _vertexPositionData[i * 3 + 2] = vertexBuffer[i * vertexSize + 2];
for (int j = 0; j < 3; ++j) {
_vertexData[i * kVertexComponentCount + kPositionOffset + j] = _vertexPositionData[i * 3 + j];
}
-
+ // mirror z coordinate to change to OpenGL coordinate system
_vertexPositionData[i * 3 + 2] *= -1.0f;
_vertexData[i * kVertexComponentCount + kPositionOffset + 2] *= -1.0f;
+
+ if (fvf & DXFVF_NORMAL) {
+ _vertexNormalData[i * 3 + 0] = vertexBuffer[i * vertexSize + normalOffset + 0];
+ _vertexNormalData[i * 3 + 1] = vertexBuffer[i * vertexSize + normalOffset + 1];
+ _vertexNormalData[i * 3 + 2] = vertexBuffer[i * vertexSize + normalOffset + 2];
+ for (int j = 0; j < 3; ++j) {
+ _vertexData[i * kVertexComponentCount + kNormalOffset + j] = _vertexNormalData[i * 3 + j];
+ }
+ // mirror z coordinate to change to OpenGL coordinate system
+ _vertexNormalData[i * 3 + 2] *= -1.0f;
+ _vertexData[i * kVertexComponentCount + kNormalOffset + 2] *= -1.0f;
+ }
+
+ if (fvf & DXFVF_DIFFUSE) {
+ // nothing
+ }
+
+ if (fvf & DXFVF_TEX1) {
+ _vertexData[i * kVertexComponentCount + kTextureCoordOffset + 0] = vertexBuffer[i * vertexSize + textureOffset + 0];
+ _vertexData[i * kVertexComponentCount + kTextureCoordOffset + 1] = vertexBuffer[i * vertexSize + textureOffset + 1];
+ }
}
- return true;
-}
-bool XSkinMeshLoader::parseFaces(XMeshObject *mesh, int faceCount, Common::Array<int> &indexCountPerFace) {
- for (int i = 0; i < faceCount; ++i) {
- XMeshFace *face = &mesh->_faces[i];
+ uint numFaces = _meshObject->_numFaces;
+
+ Common::Array<int> indexCountPerFace;
+
+ uint32 *indexPtr = (uint32 *)_dxmesh->getIndexBuffer().ptr();
+
+ for (uint i = 0; i < numFaces; ++i) {
+ XMeshFace *face = &_meshObject->_faces[i];
int indexCount = face->_numFaceVertexIndices;
+ uint16 index1, index2, index3, index4, index5, index6;
if (indexCount == 3) {
- uint16 index1 = face->_faceVertexIndices[0];
- uint16 index2 = face->_faceVertexIndices[1];
- uint16 index3 = face->_faceVertexIndices[2];
-
+ index1 = *indexPtr++;
+ index2 = *indexPtr++;
+ index3 = *indexPtr++;
_indexData.push_back(index3);
_indexData.push_back(index2);
_indexData.push_back(index1);
-
indexCountPerFace.push_back(3);
- } else if (indexCount == 4) {
- uint16 index1 = face->_faceVertexIndices[0];
- uint16 index2 = face->_faceVertexIndices[1];
- uint16 index3 = face->_faceVertexIndices[2];
- uint16 index4 = face->_faceVertexIndices[3];
-
+ } else {
+ index1 = *indexPtr++;
+ index2 = *indexPtr++;
+ index3 = *indexPtr++;
+ index4 = *indexPtr++;
+ index5 = *indexPtr++;
+ index6 = *indexPtr++;
_indexData.push_back(index3);
_indexData.push_back(index2);
_indexData.push_back(index1);
-
+ _indexData.push_back(index6);
+ _indexData.push_back(index5);
_indexData.push_back(index4);
- _indexData.push_back(index3);
- _indexData.push_back(index1);
-
indexCountPerFace.push_back(6);
- } else {
- warning("XMeshLoader::parseFaces faces with more than four vertices are not supported");
- return false;
- }
- }
-
- return true;
-}
-
-bool XSkinMeshLoader::parseTextureCoords(XFileData *xobj) {
- XMeshTextureCoordsObject *texCoords = xobj->getXMeshTextureCoordsObject();
- if (!texCoords)
- return false;
- // should be the same as _vertexCount
- int textureCoordCount = texCoords->_numTextureCoords;
-
- for (int i = 0; i < textureCoordCount; ++i) {
- _vertexData[i * kVertexComponentCount + kTextureCoordOffset + 0] = texCoords->_textureCoords[i]._u;
- _vertexData[i * kVertexComponentCount + kTextureCoordOffset + 1] = texCoords->_textureCoords[i]._v;
- }
-
- return true;
-}
-
-bool XSkinMeshLoader::parseNormalCoords(XFileData *xobj) {
- XMeshNormalsObject *normals = xobj->getXMeshNormalsObject();
- if (!normals)
- return false;
- // should be the same as _vertex count
- uint vertexNormalCount = normals->_numNormals;
- //assert(vertexNormalCount == _vertexCount);
-
- Common::Array<float> vertexNormalData;
- vertexNormalData.resize(3 * vertexNormalCount);
-
- for (uint i = 0; i < vertexNormalCount; ++i) {
- vertexNormalData[i * 3 + 0] = normals->_normals[i]._x;
- vertexNormalData[i * 3 + 1] = normals->_normals[i]._y;
- // mirror z coordinate to change to OpenGL coordinate system
- vertexNormalData[i * 3 + 2] = -normals->_normals[i]._z;
- }
-
- uint faceNormalCount = normals->_numFaceNormals;
- Common::Array<int> faceNormals;
-
- for (uint i = 0; i < faceNormalCount; ++i) {
- XMeshFace *normalFace = &normals->_faceNormals[i];
- int indexCount = normalFace->_numFaceVertexIndices;
-
- if (indexCount == 3) {
- uint16 index1 = normalFace->_faceVertexIndices[0];
- uint16 index2 = normalFace->_faceVertexIndices[1];
- uint16 index3 = normalFace->_faceVertexIndices[2];
-
- faceNormals.push_back(index3);
- faceNormals.push_back(index2);
- faceNormals.push_back(index1);
- } else if (indexCount == 4) {
- uint16 index1 = normalFace->_faceVertexIndices[0];
- uint16 index2 = normalFace->_faceVertexIndices[1];
- uint16 index3 = normalFace->_faceVertexIndices[2];
- uint16 index4 = normalFace->_faceVertexIndices[3];
-
- faceNormals.push_back(index3);
- faceNormals.push_back(index2);
- faceNormals.push_back(index1);
-
- faceNormals.push_back(index4);
- faceNormals.push_back(index3);
- faceNormals.push_back(index1);
- } else {
- warning("XMeshLoader::parseNormalCoords faces with more than four vertices are not supported");
- return false;
}
}
-
- assert(_indexData.size() == faceNormals.size());
-
- for (uint i = 0; i < faceNormals.size(); ++i) {
- uint16 vertexIndex = _indexData[i];
- int normalIndex = faceNormals[i];
-
- for (int j = 0; j < 3; ++j) {
- _vertexData[vertexIndex * kVertexComponentCount + kNormalOffset + j] = vertexNormalData[3 * normalIndex + j];
- _vertexNormalData[3 * vertexIndex + j] = vertexNormalData[3 * normalIndex + j];
- }
- }
-
- return true;
-}
-
-bool XSkinMeshLoader::parseMaterials(XFileData *xobj, BaseGame *inGame,
- int faceCount, const Common::String &filename,
- Common::Array<MaterialReference> &materialReferences,
- const Common::Array<int> &indexCountPerFace) {
- XMeshMaterialListObject *materialList = xobj->getXMeshMaterialListObject();
- if (!materialList)
- return false;
-
- // there can be unused materials inside a .X file
- // so this piece of information is probably useless
- // should be the same as faceCount
- int faceMaterialCount = materialList->_numFaceIndexes;
- assert(faceMaterialCount == faceCount);
-
- _indexRanges.push_back(0);
- int currentMaterialIndex = materialList->_faceIndexes[0];
- _materialIndices.push_back(currentMaterialIndex);
-
- int currentIndex = indexCountPerFace[0];
-
- for (int i = 1; i < faceMaterialCount; ++i) {
- int currentMaterialIndexTmp = materialList->_faceIndexes[i];
-
- if (currentMaterialIndex != currentMaterialIndexTmp) {
- currentMaterialIndex = currentMaterialIndexTmp;
- _indexRanges.push_back(currentIndex);
- _materialIndices.push_back(currentMaterialIndex);
- }
-
- currentIndex += indexCountPerFace[i];
- }
-
- _indexRanges.push_back(currentIndex);
- _mesh->_numAttrs = _indexRanges.size() - 1;
-
- uint numChildren = 0;
- xobj->getChildren(numChildren);
-
- for (uint32 i = 0; i < numChildren; i++) {
- XFileData xchildData;
- XClassType objectType;
- bool res = xobj->getChild(i, xchildData);
- if (res) {
- res = xchildData.getType(objectType);
- if (res) {
- if (xchildData.isReference()) {
- Common::String materialReference;
- xchildData.getName(materialReference);
- for (uint32 j = 0; j < materialReferences.size(); j++) {
- if (materialReferences[j]._name == materialReference) {
- _mesh->_materials.add(materialReferences[j]._material);
- break;
- }
- }
- } else if (objectType == kXClassMaterial) {
- Material *mat = new Material(inGame);
- mat->loadFromX(&xchildData, filename);
- _mesh->_materials.add(mat);
- MaterialReference materialReference;
- materialReference._material = mat;
- materialReferences.push_back(materialReference);
- }
- }
- }
- }
-
- return true;
-}
-
-bool XSkinMeshLoader::parseSkinWeights(XFileData *xobj) {
- XSkinWeightsObject *skinWeights = xobj->getXSkinWeightsObject();
- if (!skinWeights)
- return false;
-
- _skinWeightsList.resize(_skinWeightsList.size() + 1);
- SkinWeights &currSkinWeights = _skinWeightsList.back();
-
- currSkinWeights._boneName = skinWeights->_transformNodeName;
-
- int weightCount = skinWeights->_numWeights;
- currSkinWeights._vertexIndices.resize(weightCount);
- currSkinWeights._vertexWeights.resize(weightCount);
-
- for (int i = 0; i < weightCount; ++i) {
- currSkinWeights._vertexIndices[i] = skinWeights->_vertexIndices[i];
- }
-
- for (int i = 0; i < weightCount; ++i) {
- currSkinWeights._vertexWeights[i] = skinWeights->_weights[i];
- }
-
- for (int r = 0; r < 4; ++r) {
- for (int c = 0; c < 4; ++c) {
- currSkinWeights._offsetMatrix(c, r) = skinWeights->_matrixOffset[r * 4 + c];
- }
- }
-
- // mirror at orign
- currSkinWeights._offsetMatrix(2, 3) *= -1.0f;
-
- // mirror base vectors
- currSkinWeights._offsetMatrix(2, 0) *= -1.0f;
- currSkinWeights._offsetMatrix(2, 1) *= -1.0f;
-
- // change handedness
- currSkinWeights._offsetMatrix(0, 2) *= -1.0f;
- currSkinWeights._offsetMatrix(1, 2) *= -1.0f;
-
- return true;
-}
-
-bool XSkinMeshLoader::parseVertexDeclaration(XFileData *xobj) {
- XDeclDataObject *declData = xobj->getXDeclDataObject();
- if (!declData)
- return false;
-
- int vertexElementCount = declData->_numElements;
-
- // size of a vertex measured in four byte blocks
- int vertexSize = 0;
- int normalOffset = -1;
- int textureOffset = -1;
-
- for (int i = 0; i < vertexElementCount; ++i) {
- int type = declData->_elements[i]._type;
- int method = declData->_elements[i]._method;
- int usage = declData->_elements[i]._usage;
- int usageIndex = declData->_elements[i]._usageIndex;
-
- debug(2, "Vertex Element: Type: %i, Method: %i, Usage: %i, Usage index: %i", type, method, usage, usageIndex);
-
- // we only care about normal vectors and texture coords
- switch (usage) {
- case 3:
- normalOffset = vertexSize;
- break;
- case 5:
- textureOffset = vertexSize;
- break;
- }
-
- // This is a first guess, based on
- // https://docs.microsoft.com/en-us/windows/win32/direct3d9/vertexelement
- switch (type) {
- case 0:
- vertexSize += 1;
- warning("D3DDECLTYPE_FLOAT1 encountered in .X model");
- break;
- case 1:
- vertexSize += 2;
- break;
- case 2:
- vertexSize += 3;
- break;
- case 3:
- vertexSize += 4;
- warning("D3DDECLTYPE_FLOAT4 encountered in .X model");
- break;
- case 4:
- vertexSize += 1;
- warning("D3DDECLTYPE_D3DCOLOR encountered in .X model");
- break;
- case 5:
- vertexSize += 1;
- warning("D3DDECLTYPE_UBYTE4 encountered in .X model");
- break;
- case 6:
- vertexSize += 2;
- warning("D3DDECLTYPE_SHORT2 encountered in .X model");
- break;
- case 7:
- vertexSize += 4;
- warning("D3DDECLTYPE_SHORT4 encountered in .X model");
- break;
- case 8:
- vertexSize += 1;
- warning("D3DDECLTYPE_UBYTE4N encountered in .X model");
- break;
- case 9:
- vertexSize += 2;
- warning("D3DDECLTYPE_SHORT2N encountered in .X model");
- break;
- case 10:
- vertexSize += 4;
- warning("D3DDECLTYPE_SHORT4N encountered in .X model");
- break;
- case 11:
- vertexSize += 2;
- warning("D3DDECLTYPE_USHORT2N encountered in .X model");
- break;
- case 12:
- vertexSize += 4;
- warning("D3DDECLTYPE_USHORT4N encountered in .X model");
- break;
- case 13:
- vertexSize += 3;
- warning("D3DDECLTYPE_UDEC3 encountered in .X model");
- break;
- case 14:
- vertexSize += 3;
- warning("D3DDECLTYPE_DEC3N encountered in .X model");
- break;
- case 15:
- vertexSize += 2;
- warning("D3DDECLTYPE_FLOAT16_2 encountered in .X model");
- break;
- case 16:
- vertexSize += 4;
- warning("D3DDECLTYPE_FLOAT16_4 encountered in .X model");
- break;
- default:
- warning("Unknown type in vertex declaration encountered");
- break;
- }
- }
-
- int dataSize = declData->_numData;
- Common::Array<uint32> data;
- data.reserve(dataSize);
-
- for (int i = 0; i < dataSize; ++i) {
- data.push_back(declData->_data[i]);
- }
-
- assert(dataSize % vertexSize == 0);
- assert(dataSize / vertexSize == static_cast<int>(_vertexCount));
-
- for (uint i = 0; i < _vertexCount; ++i) {
- if (normalOffset != -1) {
- float *vertexNormalData = reinterpret_cast<float *>(data.data() + vertexSize * i + normalOffset);
-
- for (int j = 0; j < 3; ++j) {
- _vertexNormalData[3 * i + j] = vertexNormalData[j];
- _vertexData[kVertexComponentCount * i + kNormalOffset + j] = vertexNormalData[j];
- }
- }
-
- if (textureOffset != -1) {
- float *vertexTextureCoordsData = reinterpret_cast<float *>(data.data() + vertexSize * i + textureOffset);
-
- _vertexData[kVertexComponentCount * i + kTextureCoordOffset + 0] = vertexTextureCoordsData[0];
- _vertexData[kVertexComponentCount * i + kTextureCoordOffset + 1] = vertexTextureCoordsData[1];
- }
- }
-
- return true;
}
//////////////////////////////////////////////////////////////////////////
diff --git a/engines/wintermute/base/gfx/xskinmesh_loader.h b/engines/wintermute/base/gfx/xskinmesh_loader.h
index c797764ec1e..cc9530e9713 100644
--- a/engines/wintermute/base/gfx/xskinmesh_loader.h
+++ b/engines/wintermute/base/gfx/xskinmesh_loader.h
@@ -36,6 +36,8 @@ class ShadowVolume;
class SkinMeshHelper;
class VideoTheoraPlayer;
struct XMeshObject;
+class DXMesh;
+class DXSkinInfo;
struct SkinWeights {
Common::String _boneName;
@@ -51,7 +53,7 @@ class XSkinMeshLoader {
friend class SkinMeshHelper;
public:
- XSkinMeshLoader(XMesh *mesh, XMeshObject *meshObject);
+ XSkinMeshLoader(XMesh *mesh, XMeshObject *meshObject, DXMesh *dxmesh, DXSkinInfo *skinInfo);
virtual ~XSkinMeshLoader();
void loadMesh(const Common::String &filename, XFileData *xobj, Common::Array<MaterialReference> &materialReferences);
@@ -68,15 +70,10 @@ protected:
bool adjacentEdge(uint16 index1, uint16 index2, uint16 index3, uint16 index4);
public:
- bool parsePositionCoords(XMeshObject *mesh);
- bool parseFaces(XMeshObject *mesh, int faceCount, Common::Array<int> &indexCountPerFace);
- bool parseTextureCoords(XFileData *xobj);
- bool parseNormalCoords(XFileData *xobj);
- bool parseMaterials(XFileData *xobj, BaseGame *inGame, int faceCount, const Common::String &filename,
- Common::Array<MaterialReference> &materialReferences, const Common::Array<int> &indexCountPerFace);
- bool parseSkinWeights(XFileData *xobj);
- bool parseVertexDeclaration(XFileData *xobj);
+ BaseArray<int> _indexRanges;
+ BaseArray<int> _materialIndices;
+
protected:
float *_vertexData;
@@ -84,15 +81,14 @@ protected:
float *_vertexNormalData;
uint32 _vertexCount;
Common::Array<uint16> _indexData;
-
+
BaseArray<Math::Matrix4 *> _boneMatrices;
BaseArray<SkinWeights> _skinWeightsList;
-
- BaseArray<int> _indexRanges;
- BaseArray<int> _materialIndices;
XMesh *_mesh;
XMeshObject *_meshObject;
+ DXMesh *_dxmesh;
+ DXSkinInfo *_skinInfo;
};
} // namespace Wintermute
diff --git a/engines/wintermute/module.mk b/engines/wintermute/module.mk
index 903fbe0a31d..fa1bc028f56 100644
--- a/engines/wintermute/module.mk
+++ b/engines/wintermute/module.mk
@@ -174,8 +174,10 @@ MODULE_OBJS += \
base/gfx/xfile_loader.o \
base/gfx/xframe_node.o \
base/gfx/xmaterial.o \
+ base/gfx/xmath.o \
base/gfx/xmesh.o \
base/gfx/xmodel.o \
+ base/gfx/xskinmesh.o \
base/gfx/xskinmesh_loader.o \
base/gfx/opengl/base_surface_opengl3d.o \
base/gfx/opengl/base_render_opengl3d.o \
More information about the Scummvm-git-logs
mailing list