mirror of
https://github.com/libretro/scummvm.git
synced 2025-02-10 12:55:24 +00:00
WME3D: Separate XMesh and skin mesh loader to much original code
This commit is contained in:
parent
fc20af02d9
commit
2b24709eaf
@ -26,6 +26,8 @@
|
||||
*/
|
||||
|
||||
#include "engines/wintermute/base/gfx/xmaterial.h"
|
||||
#include "engines/wintermute/base/gfx/xskinmesh_loader.h"
|
||||
#include "engines/wintermute/base/gfx/skin_mesh_helper.h"
|
||||
|
||||
#include "graphics/opengl/system_headers.h"
|
||||
|
||||
@ -46,12 +48,16 @@ XMeshOpenGL::~XMeshOpenGL() {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool XMeshOpenGL::render(XModel *model) {
|
||||
if (_vertexData == nullptr) {
|
||||
float *vertexData = _skinMesh->_mesh->_vertexData;
|
||||
auto indexData = _skinMesh->_mesh->_indexData;
|
||||
auto indexRanges = _skinMesh->_mesh->_indexRanges;
|
||||
auto materialIndices = _skinMesh->_mesh->_materialIndices;
|
||||
if (vertexData == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32 i = 0; i < _numAttrs; i++) {
|
||||
int materialIndex = _materialIndices[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);
|
||||
@ -73,12 +79,12 @@ bool XMeshOpenGL::render(XModel *model) {
|
||||
if (textureEnable)
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
|
||||
glVertexPointer(3, GL_FLOAT, kVertexComponentCount * sizeof(float), _vertexData + kPositionOffset);
|
||||
glNormalPointer(GL_FLOAT, kVertexComponentCount * sizeof(float), _vertexData + kNormalOffset);
|
||||
glVertexPointer(3, GL_FLOAT, XSkinMeshLoader::kVertexComponentCount * sizeof(float), vertexData + XSkinMeshLoader::kPositionOffset);
|
||||
glNormalPointer(GL_FLOAT, XSkinMeshLoader::kVertexComponentCount * sizeof(float), vertexData + XSkinMeshLoader::kNormalOffset);
|
||||
if (textureEnable)
|
||||
glTexCoordPointer(2, GL_FLOAT, kVertexComponentCount * sizeof(float), _vertexData + kTextureCoordOffset);
|
||||
glTexCoordPointer(2, GL_FLOAT, XSkinMeshLoader::kVertexComponentCount * sizeof(float), vertexData + XSkinMeshLoader::kTextureCoordOffset);
|
||||
|
||||
glDrawElements(GL_TRIANGLES, _indexRanges[i + 1] - _indexRanges[i], GL_UNSIGNED_SHORT, _indexData.data() + _indexRanges[i]);
|
||||
glDrawElements(GL_TRIANGLES, indexRanges[i + 1] - indexRanges[i], GL_UNSIGNED_SHORT, indexData.data() + indexRanges[i]);
|
||||
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
|
@ -26,6 +26,8 @@
|
||||
*/
|
||||
|
||||
#include "engines/wintermute/base/gfx/xmaterial.h"
|
||||
#include "engines/wintermute/base/gfx/xskinmesh_loader.h"
|
||||
#include "engines/wintermute/base/gfx/skin_mesh_helper.h"
|
||||
|
||||
#include "graphics/opengl/system_headers.h"
|
||||
|
||||
@ -50,12 +52,16 @@ XMeshOpenGLShader::~XMeshOpenGLShader() {
|
||||
}
|
||||
|
||||
bool XMeshOpenGLShader::loadFromXData(const Common::String &filename, XFileData *xobj, Common::Array<MaterialReference> &materialReferences) {
|
||||
auto indexData = _skinMesh->_mesh->_indexData;
|
||||
float *vertexData = _skinMesh->_mesh->_vertexData;
|
||||
uint32 vertexCount = _skinMesh->_mesh->_vertexCount;
|
||||
|
||||
if (XMesh::loadFromXData(filename, xobj, materialReferences)) {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, 4 * kVertexComponentCount * _vertexCount, _vertexData, GL_DYNAMIC_DRAW);
|
||||
glBufferData(GL_ARRAY_BUFFER, 4 * XSkinMeshLoader::kVertexComponentCount * vertexCount, vertexData, GL_DYNAMIC_DRAW);
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 2 * _indexData.size(), _indexData.data(), GL_STATIC_DRAW);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 2 * indexData.size(), indexData.data(), GL_STATIC_DRAW);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -65,20 +71,23 @@ bool XMeshOpenGLShader::loadFromXData(const Common::String &filename, XFileData
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool XMeshOpenGLShader::render(XModel *model) {
|
||||
if (_vertexData == nullptr) {
|
||||
float *vertexData = _skinMesh->_mesh->_vertexData;
|
||||
auto indexRanges = _skinMesh->_mesh->_indexRanges;
|
||||
auto materialIndices = _skinMesh->_mesh->_materialIndices;
|
||||
if (vertexData == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
|
||||
|
||||
_shader->enableVertexAttribute("position", _vertexBuffer, 3, GL_FLOAT, false, 4 * kVertexComponentCount, 4 * kPositionOffset);
|
||||
_shader->enableVertexAttribute("texcoord", _vertexBuffer, 2, GL_FLOAT, false, 4 * kVertexComponentCount, 4 * kTextureCoordOffset);
|
||||
_shader->enableVertexAttribute("normal", _vertexBuffer, 3, GL_FLOAT, false, 4 * kVertexComponentCount, 4 * kNormalOffset);
|
||||
_shader->enableVertexAttribute("position", _vertexBuffer, 3, GL_FLOAT, false, 4 * XSkinMeshLoader::kVertexComponentCount, 4 * XSkinMeshLoader::kPositionOffset);
|
||||
_shader->enableVertexAttribute("texcoord", _vertexBuffer, 2, GL_FLOAT, false, 4 * XSkinMeshLoader::kVertexComponentCount, 4 * XSkinMeshLoader::kTextureCoordOffset);
|
||||
_shader->enableVertexAttribute("normal", _vertexBuffer, 3, GL_FLOAT, false, 4 * XSkinMeshLoader::kVertexComponentCount, 4 * XSkinMeshLoader::kNormalOffset);
|
||||
|
||||
_shader->use(true);
|
||||
|
||||
for (uint32 i = 0; i < _numAttrs; i++) {
|
||||
int materialIndex = _materialIndices[i];
|
||||
int materialIndex = materialIndices[i];
|
||||
|
||||
if (_materials[materialIndex]->getSurface()) {
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
@ -93,8 +102,8 @@ bool XMeshOpenGLShader::render(XModel *model) {
|
||||
_shader->setUniform("diffuse", diffuse);
|
||||
_shader->setUniform("ambient", diffuse);
|
||||
|
||||
size_t offset = 2 * _indexRanges[i];
|
||||
glDrawElements(GL_TRIANGLES, _indexRanges[i + 1] - _indexRanges[i], GL_UNSIGNED_SHORT, (void *)offset);
|
||||
size_t offset = 2 * indexRanges[i];
|
||||
glDrawElements(GL_TRIANGLES, indexRanges[i + 1] - indexRanges[i], GL_UNSIGNED_SHORT, (void *)offset);
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
@ -107,16 +116,18 @@ bool XMeshOpenGLShader::render(XModel *model) {
|
||||
}
|
||||
|
||||
bool XMeshOpenGLShader::renderFlatShadowModel() {
|
||||
if (_vertexData == nullptr) {
|
||||
float *vertexData = _skinMesh->_mesh->_vertexData;
|
||||
auto indexRanges = _skinMesh->_mesh->_indexRanges;
|
||||
if (vertexData == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
|
||||
|
||||
_flatShadowShader->enableVertexAttribute("position", _vertexBuffer, 3, GL_FLOAT, false, 4 * kVertexComponentCount, 4 * kPositionOffset);
|
||||
_flatShadowShader->enableVertexAttribute("position", _vertexBuffer, 3, GL_FLOAT, false, 4 * XSkinMeshLoader::kVertexComponentCount, 4 * XSkinMeshLoader::kPositionOffset);
|
||||
_flatShadowShader->use(true);
|
||||
|
||||
glDrawElements(GL_TRIANGLES, _indexRanges.back(), GL_UNSIGNED_SHORT, 0);
|
||||
glDrawElements(GL_TRIANGLES, indexRanges.back(), GL_UNSIGNED_SHORT, 0);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
@ -127,8 +138,11 @@ bool XMeshOpenGLShader::renderFlatShadowModel() {
|
||||
bool XMeshOpenGLShader::update(FrameNode *parentFrame) {
|
||||
XMesh::update(parentFrame);
|
||||
|
||||
float *vertexData = _skinMesh->_mesh->_vertexData;
|
||||
uint32 vertexCount = _skinMesh->_mesh->_vertexCount;
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, 0, 4 * kVertexComponentCount * _vertexCount, _vertexData);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, 0, 4 * XSkinMeshLoader::kVertexComponentCount * vertexCount, vertexData);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
84
engines/wintermute/base/gfx/skin_mesh_helper.cpp
Normal file
84
engines/wintermute/base/gfx/skin_mesh_helper.cpp
Normal file
@ -0,0 +1,84 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is based on WME.
|
||||
* http://dead-code.org/redir.php?target=wme
|
||||
* Copyright (c) 2003-2013 Jan Nedoma and contributors
|
||||
*/
|
||||
|
||||
#include "engines/wintermute/dcgf.h"
|
||||
#include "engines/wintermute/base/gfx/skin_mesh_helper.h"
|
||||
#include "engines/wintermute/base/gfx/xskinmesh_loader.h"
|
||||
|
||||
namespace Wintermute {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
SkinMeshHelper::SkinMeshHelper(XSkinMeshLoader *mesh) {
|
||||
_mesh = mesh;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
SkinMeshHelper::~SkinMeshHelper() {
|
||||
delete _mesh;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
uint SkinMeshHelper::getNumFaces() {
|
||||
return 0;//_mesh->getNumFaces();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
uint SkinMeshHelper::getNumBones() {
|
||||
return 0;//_mesh->getNumBones();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool SkinMeshHelper::getOriginalMesh(XSkinMeshLoader **mesh) {
|
||||
return true;//_mesh->cloneMeshFVF(_mesh->getOptions(), _mesh->getFVF(), mesh);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool SkinMeshHelper::generateSkinnedMesh(uint32 options, float minWeight, uint32 *adjacencyOut, XSkinMeshLoader **mesh) {
|
||||
bool res = getOriginalMesh(mesh);
|
||||
/* if (res) {
|
||||
(*mesh)->generateAdjacency(adjacencyOut);
|
||||
}*/
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool SkinMeshHelper::updateSkinnedMesh(const Math::Matrix4 *boneTransforms, XSkinMeshLoader *mesh) {
|
||||
return true;//_mesh->updateSkinnedMesh(boneTransforms);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
const char *SkinMeshHelper::getBoneName(uint boneIndex) {
|
||||
return "";//_mesh->getBoneName(boneIndex);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
Math::Matrix4 SkinMeshHelper::getBoneOffsetMatrix(uint boneIndex) {
|
||||
return Math::Matrix4();//_mesh->getBoneOffsetMatrix(boneIndex);
|
||||
}
|
||||
|
||||
} // namespace Wintermute
|
64
engines/wintermute/base/gfx/skin_mesh_helper.h
Normal file
64
engines/wintermute/base/gfx/skin_mesh_helper.h
Normal file
@ -0,0 +1,64 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is based on WME.
|
||||
* http://dead-code.org/redir.php?target=wme
|
||||
* Copyright (c) 2003-2013 Jan Nedoma and contributors
|
||||
*/
|
||||
|
||||
#ifndef WINTERMUTE_SKIN_MESH_HELPER_H
|
||||
#define WINTERMUTE_SKIN_MESH_HELPER_H
|
||||
|
||||
#include "math/matrix4.h"
|
||||
#include "math/vector3d.h"
|
||||
|
||||
namespace Wintermute {
|
||||
|
||||
class XSkinMeshLoader;
|
||||
class XMesh;
|
||||
class XMeshOpenGL;
|
||||
class XMeshOpenGLShader;
|
||||
|
||||
class SkinMeshHelper {
|
||||
friend class XMesh;
|
||||
friend class XMeshOpenGL;
|
||||
friend class XMeshOpenGLShader;
|
||||
|
||||
public:
|
||||
SkinMeshHelper(XSkinMeshLoader *mesh);
|
||||
virtual ~SkinMeshHelper();
|
||||
|
||||
uint getNumFaces();
|
||||
uint getNumBones();
|
||||
bool getOriginalMesh(XSkinMeshLoader **mesh);
|
||||
bool generateSkinnedMesh(uint32 options, float minWeight, uint32 *adjacencyOut, XSkinMeshLoader **mesh);
|
||||
bool updateSkinnedMesh(const Math::Matrix4 *boneTransforms, XSkinMeshLoader *mesh);
|
||||
const char *getBoneName(uint boneIndex);
|
||||
Math::Matrix4 getBoneOffsetMatrix(uint boneIndex);
|
||||
|
||||
private:
|
||||
XSkinMeshLoader *_mesh;
|
||||
};
|
||||
|
||||
} // namespace Wintermute
|
||||
|
||||
#endif
|
@ -28,6 +28,8 @@
|
||||
#include "engines/wintermute/base/gfx/3dshadow_volume.h"
|
||||
#include "engines/wintermute/base/gfx/xmaterial.h"
|
||||
#include "engines/wintermute/base/gfx/xmesh.h"
|
||||
#include "engines/wintermute/base/gfx/xskinmesh_loader.h"
|
||||
#include "engines/wintermute/base/gfx/skin_mesh_helper.h"
|
||||
#include "engines/wintermute/base/gfx/xframe_node.h"
|
||||
#include "engines/wintermute/base/gfx/xfile_loader.h"
|
||||
#include "engines/wintermute/base/gfx/xmodel.h"
|
||||
@ -36,27 +38,18 @@
|
||||
|
||||
namespace Wintermute {
|
||||
|
||||
// define constant to make it available to the linker
|
||||
const uint32 XMesh::kNullIndex;
|
||||
|
||||
XMesh::XMesh(Wintermute::BaseGame *inGame) : BaseNamedObject(inGame) {
|
||||
_numAttrs = 0;
|
||||
|
||||
_skinMesh = nullptr;
|
||||
_skinnedMesh = false;
|
||||
|
||||
_BBoxStart = Math::Vector3d(0.0f, 0.0f, 0.0f);
|
||||
_BBoxEnd = Math::Vector3d(0.0f, 0.0f, 0.0f);
|
||||
|
||||
_vertexData = nullptr;
|
||||
_vertexPositionData = nullptr;
|
||||
_vertexNormalData = nullptr;
|
||||
_vertexCount = 0;
|
||||
}
|
||||
|
||||
XMesh::~XMesh() {
|
||||
delete[] _vertexData;
|
||||
delete[] _vertexPositionData;
|
||||
delete[] _vertexNormalData;
|
||||
|
||||
delete _skinMesh;
|
||||
_materials.clear();
|
||||
}
|
||||
|
||||
@ -68,28 +61,31 @@ bool XMesh::loadFromXData(const Common::String &filename, XFileData *xobj, Commo
|
||||
return false;
|
||||
}
|
||||
|
||||
XMeshObject *mesh = xobj->getXMeshObject();
|
||||
if (!mesh) {
|
||||
XMeshObject *meshObject = xobj->getXMeshObject();
|
||||
if (!meshObject) {
|
||||
BaseEngine::LOG(0, "Error loading skin mesh");
|
||||
return false;
|
||||
}
|
||||
|
||||
_vertexCount = mesh->_numVertices;
|
||||
XSkinMeshLoader *mesh = new XSkinMeshLoader(this);
|
||||
_skinMesh = new SkinMeshHelper(mesh);
|
||||
|
||||
mesh->_vertexCount = meshObject->_numVertices;
|
||||
|
||||
// vertex format for .X meshes will be position + normals + textures
|
||||
_vertexData = new float[kVertexComponentCount * _vertexCount]();
|
||||
_vertexPositionData = new float[3 * _vertexCount]();
|
||||
mesh->_vertexData = new float[XSkinMeshLoader::kVertexComponentCount * mesh->_vertexCount]();
|
||||
mesh->_vertexPositionData = new float[3 * mesh->_vertexCount]();
|
||||
// we already know how big this is supposed to be
|
||||
// TODO: might have to generate normals if file does not contain any
|
||||
_vertexNormalData = new float[3 * _vertexCount]();
|
||||
mesh->_vertexNormalData = new float[3 * mesh->_vertexCount]();
|
||||
|
||||
parsePositionCoords(mesh);
|
||||
mesh->parsePositionCoords(meshObject);
|
||||
|
||||
int faceCount = mesh->_numFaces;
|
||||
int faceCount = meshObject->_numFaces;
|
||||
|
||||
Common::Array<int> indexCountPerFace;
|
||||
|
||||
parseFaces(mesh, faceCount, indexCountPerFace);
|
||||
mesh->parseFaces(meshObject, faceCount, indexCountPerFace);
|
||||
|
||||
uint numChildren = 0;
|
||||
xobj->getChildren(numChildren);
|
||||
@ -100,11 +96,11 @@ bool XMesh::loadFromXData(const Common::String &filename, XFileData *xobj, Commo
|
||||
if (xobj->getChild(i, xchildData)) {
|
||||
if (xchildData.getType(objectType)) {
|
||||
if (objectType == kXClassMeshTextureCoords) {
|
||||
parseTextureCoords(&xchildData);
|
||||
mesh->parseTextureCoords(&xchildData);
|
||||
} else if (objectType == kXClassMeshNormals) {
|
||||
parseNormalCoords(&xchildData);
|
||||
mesh->parseNormalCoords(&xchildData);
|
||||
} else if (objectType == kXClassMeshMaterialList) {
|
||||
parseMaterials(&xchildData, faceCount, filename, materialReferences, indexCountPerFace);
|
||||
mesh->parseMaterials(&xchildData, _gameRef, faceCount, filename, materialReferences, indexCountPerFace);
|
||||
} else if (objectType == kXClassMaterial) {
|
||||
Material *mat = new Material(_gameRef);
|
||||
mat->loadFromX(&xchildData, filename);
|
||||
@ -112,77 +108,33 @@ bool XMesh::loadFromXData(const Common::String &filename, XFileData *xobj, Commo
|
||||
|
||||
// one material = one index range
|
||||
_numAttrs = 1;
|
||||
_indexRanges.push_back(0);
|
||||
_indexRanges.push_back(_indexData.size());
|
||||
mesh->_indexRanges.push_back(0);
|
||||
mesh->_indexRanges.push_back(mesh->_indexData.size());
|
||||
} else if (objectType == kXClassSkinMeshHeader) {
|
||||
int boneCount = xchildData.getXSkinMeshHeaderObject()->_nBones;
|
||||
_skinnedMesh = boneCount > 0;
|
||||
} else if (objectType == kXClassSkinWeights) {
|
||||
_skinnedMesh = true;
|
||||
parseSkinWeights(&xchildData);
|
||||
mesh->parseSkinWeights(&xchildData);
|
||||
} else if (objectType == kXClassDeclData) {
|
||||
parseVertexDeclaration(&xchildData);
|
||||
mesh->parseVertexDeclaration(&xchildData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
generateAdjacency();
|
||||
mesh->generateAdjacency(_adjacency);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool XMesh::generateAdjacency() {
|
||||
_adjacency = Common::Array<uint32>(_indexData.size(), kNullIndex);
|
||||
|
||||
for (uint32 i = 0; i < _indexData.size() / 3; ++i) {
|
||||
for (uint32 j = i + 1; j < _indexData.size() / 3; ++j) {
|
||||
for (int edge1 = 0; edge1 < 3; ++edge1) {
|
||||
uint16 index1 = _indexData[i * 3 + edge1];
|
||||
uint16 index2 = _indexData[i * 3 + (edge1 + 1) % 3];
|
||||
|
||||
for (int edge2 = 0; edge2 < 3; ++edge2) {
|
||||
uint16 index3 = _indexData[j * 3 + edge2];
|
||||
uint16 index4 = _indexData[j * 3 + (edge2 + 1) % 3];
|
||||
|
||||
if (_adjacency[i * 3 + edge1] == kNullIndex && _adjacency[j * 3 + edge2] == kNullIndex && adjacentEdge(index1, index2, index3, index4)) {
|
||||
_adjacency[i * 3 + edge1] = j;
|
||||
_adjacency[j * 3 + edge2] = i;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool XMesh::adjacentEdge(uint16 index1, uint16 index2, uint16 index3, uint16 index4) {
|
||||
Math::Vector3d vertex1(_vertexPositionData + 3 * index1);
|
||||
Math::Vector3d vertex2(_vertexPositionData + 3 * index2);
|
||||
Math::Vector3d vertex3(_vertexPositionData + 3 * index3);
|
||||
Math::Vector3d vertex4(_vertexPositionData + 3 * index4);
|
||||
|
||||
// wme uses a function from the D3DX library, which takes in an epsilon for floating point comparison
|
||||
// wme passes in zero, so we just do a direct comparison
|
||||
if (vertex1 == vertex3 && vertex2 == vertex4) {
|
||||
return true;
|
||||
} else if (vertex1 == vertex4 && vertex2 == vertex3) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool XMesh::findBones(FrameNode *rootFrame) {
|
||||
// normal meshes don't have bones
|
||||
if (!_skinnedMesh) {
|
||||
return true;
|
||||
}
|
||||
auto skinWeightsList = _skinMesh->_mesh->_skinWeightsList;
|
||||
|
||||
_boneMatrices.resize(skinWeightsList.size());
|
||||
|
||||
@ -201,10 +153,16 @@ bool XMesh::findBones(FrameNode *rootFrame) {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool XMesh::update(FrameNode *parentFrame) {
|
||||
if (_vertexData == nullptr) {
|
||||
float *vertexData = _skinMesh->_mesh->_vertexData;
|
||||
if (vertexData == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
float *vertexPositionData = _skinMesh->_mesh->_vertexPositionData;
|
||||
float *vertexNormalData = _skinMesh->_mesh->_vertexNormalData;
|
||||
uint32 vertexCount = _skinMesh->_mesh->_vertexCount;
|
||||
auto skinWeightsList = _skinMesh->_mesh->_skinWeightsList;
|
||||
|
||||
// update skinned mesh
|
||||
if (_skinnedMesh) {
|
||||
BaseArray<Math::Matrix4> finalBoneMatrices;
|
||||
@ -217,9 +175,9 @@ bool XMesh::update(FrameNode *parentFrame) {
|
||||
// the new vertex coordinates are the weighted sum of the product
|
||||
// of the combined bone transformation matrices and the static pose coordinates
|
||||
// to be able too add the weighted summands together, we reset everything to zero first
|
||||
for (uint32 i = 0; i < _vertexCount; ++i) {
|
||||
for (uint32 i = 0; i < vertexCount; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
_vertexData[i * kVertexComponentCount + kPositionOffset + j] = 0.0f;
|
||||
vertexData[i * XSkinMeshLoader::kVertexComponentCount + XSkinMeshLoader::kPositionOffset + j] = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
@ -231,12 +189,12 @@ bool XMesh::update(FrameNode *parentFrame) {
|
||||
for (uint i = 0; i < skinWeightsList[boneIndex]._vertexIndices.size(); ++i) {
|
||||
uint32 vertexIndex = skinWeightsList[boneIndex]._vertexIndices[i];
|
||||
Math::Vector3d pos;
|
||||
pos.setData(_vertexPositionData + vertexIndex * 3);
|
||||
pos.setData(vertexPositionData + vertexIndex * 3);
|
||||
finalBoneMatrices[boneIndex].transform(&pos, true);
|
||||
pos *= skinWeightsList[boneIndex]._vertexWeights[i];
|
||||
|
||||
for (uint j = 0; j < 3; ++j) {
|
||||
_vertexData[vertexIndex * kVertexComponentCount + kPositionOffset + j] += pos.getData()[j];
|
||||
vertexData[vertexIndex * XSkinMeshLoader::kVertexComponentCount + XSkinMeshLoader::kPositionOffset + j] += pos.getData()[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -248,9 +206,9 @@ bool XMesh::update(FrameNode *parentFrame) {
|
||||
}
|
||||
|
||||
// reset so we can form the weighted sums
|
||||
for (uint32 i = 0; i < _vertexCount; ++i) {
|
||||
for (uint32 i = 0; i < vertexCount; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
_vertexData[i * kVertexComponentCount + kNormalOffset + j] = 0.0f;
|
||||
vertexData[i * XSkinMeshLoader::kVertexComponentCount + XSkinMeshLoader::kNormalOffset + j] = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
@ -258,24 +216,24 @@ bool XMesh::update(FrameNode *parentFrame) {
|
||||
for (uint i = 0; i < skinWeightsList[boneIndex]._vertexIndices.size(); ++i) {
|
||||
uint32 vertexIndex = skinWeightsList[boneIndex]._vertexIndices[i];
|
||||
Math::Vector3d pos;
|
||||
pos.setData(_vertexNormalData + vertexIndex * 3);
|
||||
pos.setData(vertexNormalData + vertexIndex * 3);
|
||||
finalBoneMatrices[boneIndex].transform(&pos, true);
|
||||
pos *= skinWeightsList[boneIndex]._vertexWeights[i];
|
||||
|
||||
for (uint j = 0; j < 3; ++j) {
|
||||
_vertexData[vertexIndex * kVertexComponentCount + kNormalOffset + j] += pos.getData()[j];
|
||||
vertexData[vertexIndex * XSkinMeshLoader::kVertexComponentCount + XSkinMeshLoader::kNormalOffset + j] += pos.getData()[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//updateNormals();
|
||||
} else { // update static
|
||||
for (uint32 i = 0; i < _vertexCount; ++i) {
|
||||
Math::Vector3d pos(_vertexPositionData + 3 * i);
|
||||
for (uint32 i = 0; i < vertexCount; ++i) {
|
||||
Math::Vector3d pos(vertexPositionData + 3 * i);
|
||||
parentFrame->getCombinedMatrix()->transform(&pos, true);
|
||||
|
||||
for (uint j = 0; j < 3; ++j) {
|
||||
_vertexData[i * kVertexComponentCount + kPositionOffset + j] = pos.getData()[j];
|
||||
vertexData[i * XSkinMeshLoader::kVertexComponentCount + XSkinMeshLoader::kPositionOffset + j] = pos.getData()[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -287,7 +245,8 @@ bool XMesh::update(FrameNode *parentFrame) {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool XMesh::updateShadowVol(ShadowVolume *shadow, Math::Matrix4 &modelMat, const Math::Vector3d &light, float extrusionDepth) {
|
||||
if (_vertexData == nullptr) {
|
||||
float *vertexData = _skinMesh->_mesh->_vertexData;
|
||||
if (vertexData == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -298,17 +257,18 @@ bool XMesh::updateShadowVol(ShadowVolume *shadow, Math::Matrix4 &modelMat, const
|
||||
|
||||
uint32 numEdges = 0;
|
||||
|
||||
Common::Array<bool> isFront(_indexData.size() / 3, false);
|
||||
auto indexData = _skinMesh->_mesh->_indexData;
|
||||
Common::Array<bool> isFront(indexData.size() / 3, false);
|
||||
|
||||
// First pass : for each face, record if it is front or back facing the light
|
||||
for (uint32 i = 0; i < _indexData.size() / 3; i++) {
|
||||
uint16 index0 = _indexData[3 * i + 0];
|
||||
uint16 index1 = _indexData[3 * i + 1];
|
||||
uint16 index2 = _indexData[3 * i + 2];
|
||||
for (uint32 i = 0; i < indexData.size() / 3; i++) {
|
||||
uint16 index0 = indexData[3 * i + 0];
|
||||
uint16 index1 = indexData[3 * i + 1];
|
||||
uint16 index2 = indexData[3 * i + 2];
|
||||
|
||||
Math::Vector3d v0(_vertexData + index0 * kVertexComponentCount + kPositionOffset);
|
||||
Math::Vector3d v1(_vertexData + index1 * kVertexComponentCount + kPositionOffset);
|
||||
Math::Vector3d v2(_vertexData + index2 * kVertexComponentCount + kPositionOffset);
|
||||
Math::Vector3d v0(vertexData + index0 * XSkinMeshLoader::kVertexComponentCount + XSkinMeshLoader::kPositionOffset);
|
||||
Math::Vector3d v1(vertexData + index1 * XSkinMeshLoader::kVertexComponentCount + XSkinMeshLoader::kPositionOffset);
|
||||
Math::Vector3d v2(vertexData + index2 * XSkinMeshLoader::kVertexComponentCount + XSkinMeshLoader::kPositionOffset);
|
||||
|
||||
// Transform vertices or transform light?
|
||||
Math::Vector3d vNormal = Math::Vector3d::crossProduct(v2 - v1, v1 - v0);
|
||||
@ -321,32 +281,32 @@ bool XMesh::updateShadowVol(ShadowVolume *shadow, Math::Matrix4 &modelMat, const
|
||||
}
|
||||
|
||||
// Allocate a temporary edge list
|
||||
Common::Array<uint16> edges(_indexData.size() * 2, 0);
|
||||
Common::Array<uint16> edges(indexData.size() * 2, 0);
|
||||
|
||||
// First pass : for each face, record if it is front or back facing the light
|
||||
for (uint32 i = 0; i < _indexData.size() / 3; i++) {
|
||||
for (uint32 i = 0; i < indexData.size() / 3; i++) {
|
||||
if (isFront[i]) {
|
||||
uint16 wFace0 = _indexData[3 * i + 0];
|
||||
uint16 wFace1 = _indexData[3 * i + 1];
|
||||
uint16 wFace2 = _indexData[3 * i + 2];
|
||||
uint16 wFace0 = indexData[3 * i + 0];
|
||||
uint16 wFace1 = indexData[3 * i + 1];
|
||||
uint16 wFace2 = indexData[3 * i + 2];
|
||||
|
||||
uint32 adjacent0 = _adjacency[3 * i + 0];
|
||||
uint32 adjacent1 = _adjacency[3 * i + 1];
|
||||
uint32 adjacent2 = _adjacency[3 * i + 2];
|
||||
|
||||
if (adjacent0 == kNullIndex || isFront[adjacent0] == false) {
|
||||
if (adjacent0 == XSkinMeshLoader::kNullIndex || isFront[adjacent0] == false) {
|
||||
// add edge v0-v1
|
||||
edges[2 * numEdges + 0] = wFace0;
|
||||
edges[2 * numEdges + 1] = wFace1;
|
||||
numEdges++;
|
||||
}
|
||||
if (adjacent1 == kNullIndex || isFront[adjacent1] == false) {
|
||||
if (adjacent1 == XSkinMeshLoader::kNullIndex || isFront[adjacent1] == false) {
|
||||
// add edge v1-v2
|
||||
edges[2 * numEdges + 0] = wFace1;
|
||||
edges[2 * numEdges + 1] = wFace2;
|
||||
numEdges++;
|
||||
}
|
||||
if (adjacent2 == kNullIndex || isFront[adjacent2] == false) {
|
||||
if (adjacent2 == XSkinMeshLoader::kNullIndex || isFront[adjacent2] == false) {
|
||||
// add edge v2-v0
|
||||
edges[2 * numEdges + 0] = wFace2;
|
||||
edges[2 * numEdges + 1] = wFace0;
|
||||
@ -356,8 +316,8 @@ bool XMesh::updateShadowVol(ShadowVolume *shadow, Math::Matrix4 &modelMat, const
|
||||
}
|
||||
|
||||
for (uint32 i = 0; i < numEdges; i++) {
|
||||
Math::Vector3d v1(_vertexData + edges[2 * i + 0] * kVertexComponentCount + kPositionOffset);
|
||||
Math::Vector3d v2(_vertexData + edges[2 * i + 1] * kVertexComponentCount + kPositionOffset);
|
||||
Math::Vector3d v1(vertexData + edges[2 * i + 0] * XSkinMeshLoader::kVertexComponentCount + XSkinMeshLoader::kPositionOffset);
|
||||
Math::Vector3d v2(vertexData + edges[2 * i + 1] * XSkinMeshLoader::kVertexComponentCount + XSkinMeshLoader::kPositionOffset);
|
||||
Math::Vector3d v3 = v1 - invLight * extrusionDepth;
|
||||
Math::Vector3d v4 = v2 - invLight * extrusionDepth;
|
||||
|
||||
@ -375,23 +335,25 @@ bool XMesh::updateShadowVol(ShadowVolume *shadow, Math::Matrix4 &modelMat, const
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool XMesh::pickPoly(Math::Vector3d *pickRayOrig, Math::Vector3d *pickRayDir) {
|
||||
if (_vertexData == nullptr) {
|
||||
float *vertexData = _skinMesh->_mesh->_vertexData;
|
||||
if (vertexData == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool res = false;
|
||||
|
||||
for (uint16 i = 0; i < _indexData.size(); i += 3) {
|
||||
uint16 index1 = _indexData[i + 0];
|
||||
uint16 index2 = _indexData[i + 1];
|
||||
uint16 index3 = _indexData[i + 2];
|
||||
auto indexData = _skinMesh->_mesh->_indexData;
|
||||
for (uint16 i = 0; i < indexData.size(); i += 3) {
|
||||
uint16 index1 = indexData[i + 0];
|
||||
uint16 index2 = indexData[i + 1];
|
||||
uint16 index3 = indexData[i + 2];
|
||||
|
||||
Math::Vector3d v0;
|
||||
v0.setData(&_vertexData[index1 * kVertexComponentCount + kPositionOffset]);
|
||||
v0.setData(&vertexData[index1 * XSkinMeshLoader::kVertexComponentCount + XSkinMeshLoader::kPositionOffset]);
|
||||
Math::Vector3d v1;
|
||||
v1.setData(&_vertexData[index2 * kVertexComponentCount + kPositionOffset]);
|
||||
v1.setData(&vertexData[index2 * XSkinMeshLoader::kVertexComponentCount + XSkinMeshLoader::kPositionOffset]);
|
||||
Math::Vector3d v2;
|
||||
v2.setData(&_vertexData[index3 * kVertexComponentCount + kPositionOffset]);
|
||||
v2.setData(&vertexData[index3 * XSkinMeshLoader::kVertexComponentCount + XSkinMeshLoader::kPositionOffset]);
|
||||
|
||||
if (isnan(v0.x()))
|
||||
continue;
|
||||
@ -444,405 +406,25 @@ bool XMesh::restoreDeviceObjects() {
|
||||
}
|
||||
|
||||
if (_skinnedMesh) {
|
||||
return generateAdjacency();
|
||||
return _skinMesh->_mesh->generateAdjacency(_adjacency);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool XMesh::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;
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
_vertexData[i * kVertexComponentCount + kPositionOffset + j] = _vertexPositionData[i * 3 + j];
|
||||
}
|
||||
|
||||
_vertexPositionData[i * 3 + 2] *= -1.0f;
|
||||
_vertexData[i * kVertexComponentCount + kPositionOffset + 2] *= -1.0f;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool XMesh::parseFaces(XMeshObject *mesh, int faceCount, Common::Array<int> &indexCountPerFace) {
|
||||
for (int i = 0; i < faceCount; ++i) {
|
||||
XMeshFace *face = &mesh->_faces[i];
|
||||
int indexCount = face->_numFaceVertexIndices;
|
||||
if (indexCount == 3) {
|
||||
uint16 index1 = face->_faceVertexIndices[0];
|
||||
uint16 index2 = face->_faceVertexIndices[1];
|
||||
uint16 index3 = face->_faceVertexIndices[2];
|
||||
|
||||
_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];
|
||||
|
||||
_indexData.push_back(index3);
|
||||
_indexData.push_back(index2);
|
||||
_indexData.push_back(index1);
|
||||
|
||||
_indexData.push_back(index4);
|
||||
_indexData.push_back(index3);
|
||||
_indexData.push_back(index1);
|
||||
|
||||
indexCountPerFace.push_back(6);
|
||||
} else {
|
||||
warning("XMeshOpenGL::loadFromX faces with more than four vertices are not supported");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool XMesh::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 XMesh::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("XMeshOpenGL::loadFromX 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 XMesh::parseMaterials(XFileData *xobj, 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);
|
||||
_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) {
|
||||
_materials.add(materialReferences[j]._material);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (objectType == kXClassMaterial) {
|
||||
Material *mat = new Material(_gameRef);
|
||||
mat->loadFromX(&xchildData, filename);
|
||||
_materials.add(mat);
|
||||
MaterialReference materialReference;
|
||||
materialReference._material = mat;
|
||||
materialReferences.push_back(materialReference);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool XMesh::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 XMesh::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("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;
|
||||
}
|
||||
|
||||
void XMesh::updateBoundingBox() {
|
||||
if (_vertexData == nullptr || _vertexCount == 0) {
|
||||
float *vertexData = _skinMesh->_mesh->_vertexData;
|
||||
uint32 vertexCount = _skinMesh->_mesh->_vertexCount;
|
||||
if (vertexData == nullptr || vertexCount == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
_BBoxStart.setData(&_vertexData[0 + kPositionOffset]);
|
||||
_BBoxEnd.setData(&_vertexData[0 + kPositionOffset]);
|
||||
|
||||
for (uint16 i = 1; i < _vertexCount; ++i) {
|
||||
_BBoxStart.setData(&vertexData[0 + XSkinMeshLoader::kPositionOffset]);
|
||||
_BBoxEnd.setData(&vertexData[0 + XSkinMeshLoader::kPositionOffset]);
|
||||
|
||||
for (uint16 i = 1; i < vertexCount; ++i) {
|
||||
Math::Vector3d v;
|
||||
v.setData(&_vertexData[i * kVertexComponentCount + kPositionOffset]);
|
||||
v.setData(&vertexData[i * XSkinMeshLoader::kVertexComponentCount + XSkinMeshLoader::kPositionOffset]);
|
||||
|
||||
_BBoxStart.x() = MIN(_BBoxStart.x(), v.x());
|
||||
_BBoxStart.y() = MIN(_BBoxStart.y(), v.y());
|
||||
|
@ -40,19 +40,13 @@ namespace Wintermute {
|
||||
class BaseSprite;
|
||||
class FrameNode;
|
||||
class Material;
|
||||
class XModel;
|
||||
class ShadowVolume;
|
||||
class VideoTheoraPlayer;
|
||||
class SkinMeshHelper;
|
||||
struct XMeshObject;
|
||||
|
||||
struct SkinWeights {
|
||||
Common::String _boneName;
|
||||
Math::Matrix4 _offsetMatrix;
|
||||
BaseArray<uint32> _vertexIndices;
|
||||
BaseArray<float> _vertexWeights;
|
||||
};
|
||||
|
||||
class XMesh : public BaseNamedObject {
|
||||
friend class XSkinMeshLoader;
|
||||
public:
|
||||
XMesh(BaseGame *inGame);
|
||||
virtual ~XMesh();
|
||||
@ -76,47 +70,23 @@ public:
|
||||
bool restoreDeviceObjects();
|
||||
|
||||
protected:
|
||||
static const int kVertexComponentCount = 8;
|
||||
static const int kPositionOffset = 5;
|
||||
static const int kTextureCoordOffset = 0;
|
||||
static const int kNormalOffset = 2;
|
||||
|
||||
// anything which does not fit into 16 bits would we fine
|
||||
static const uint32 kNullIndex = 0xFFFFFFFF;
|
||||
|
||||
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, int faceCount, const Common::String &filename, Common::Array<MaterialReference> &materialReferences, const Common::Array<int> &indexCountPerFace);
|
||||
bool parseSkinWeights(XFileData *xobj);
|
||||
bool parseVertexDeclaration(XFileData *xobj);
|
||||
|
||||
void updateBoundingBox();
|
||||
|
||||
bool generateAdjacency();
|
||||
bool adjacentEdge(uint16 index1, uint16 index2, uint16 index3, uint16 index4);
|
||||
|
||||
float *_vertexData;
|
||||
float *_vertexPositionData;
|
||||
float *_vertexNormalData;
|
||||
uint32 _vertexCount;
|
||||
Common::Array<uint16> _indexData;
|
||||
|
||||
BaseArray<Math::Matrix4 *> _boneMatrices;
|
||||
BaseArray<SkinWeights> skinWeightsList;
|
||||
|
||||
Common::Array<uint32> _adjacency;
|
||||
|
||||
BaseArray<Material *> _materials;
|
||||
BaseArray<int> _indexRanges;
|
||||
BaseArray<int> _materialIndices;
|
||||
uint32 _numAttrs;
|
||||
|
||||
// Wintermute3D used the ID3DXSKININFO interface
|
||||
// we will only store, whether this mesh is skinned at all
|
||||
// and factor out the necessary computations into some functions
|
||||
bool _skinnedMesh;
|
||||
|
||||
SkinMeshHelper *_skinMesh;
|
||||
|
||||
BaseArray<Math::Matrix4 *> _boneMatrices;
|
||||
|
||||
Common::Array<uint32> _adjacency;
|
||||
|
||||
BaseArray<Material *> _materials;
|
||||
};
|
||||
|
||||
} // namespace Wintermute
|
||||
|
480
engines/wintermute/base/gfx/xskinmesh_loader.cpp
Normal file
480
engines/wintermute/base/gfx/xskinmesh_loader.cpp
Normal file
@ -0,0 +1,480 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "engines/wintermute/base/gfx/3dshadow_volume.h"
|
||||
#include "engines/wintermute/base/gfx/xmaterial.h"
|
||||
#include "engines/wintermute/base/gfx/xskinmesh_loader.h"
|
||||
#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/xmodel.h"
|
||||
#include "engines/wintermute/base/base_engine.h"
|
||||
#include "engines/wintermute/math/math_util.h"
|
||||
|
||||
namespace Wintermute {
|
||||
|
||||
// define constant to make it available to the linker
|
||||
const uint32 XSkinMeshLoader::kNullIndex;
|
||||
|
||||
XSkinMeshLoader::XSkinMeshLoader(XMesh *mesh) {
|
||||
_mesh = mesh;
|
||||
|
||||
_vertexData = nullptr;
|
||||
_vertexPositionData = nullptr;
|
||||
_vertexNormalData = nullptr;
|
||||
_vertexCount = 0;
|
||||
}
|
||||
|
||||
XSkinMeshLoader::~XSkinMeshLoader() {
|
||||
delete[] _vertexData;
|
||||
delete[] _vertexPositionData;
|
||||
delete[] _vertexNormalData;
|
||||
}
|
||||
|
||||
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;
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
_vertexData[i * kVertexComponentCount + kPositionOffset + j] = _vertexPositionData[i * 3 + j];
|
||||
}
|
||||
|
||||
_vertexPositionData[i * 3 + 2] *= -1.0f;
|
||||
_vertexData[i * kVertexComponentCount + kPositionOffset + 2] *= -1.0f;
|
||||
}
|
||||
|
||||
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];
|
||||
int indexCount = face->_numFaceVertexIndices;
|
||||
if (indexCount == 3) {
|
||||
uint16 index1 = face->_faceVertexIndices[0];
|
||||
uint16 index2 = face->_faceVertexIndices[1];
|
||||
uint16 index3 = face->_faceVertexIndices[2];
|
||||
|
||||
_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];
|
||||
|
||||
_indexData.push_back(index3);
|
||||
_indexData.push_back(index2);
|
||||
_indexData.push_back(index1);
|
||||
|
||||
_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;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool XSkinMeshLoader::generateAdjacency(Common::Array<uint32> &adjacency) {
|
||||
adjacency = Common::Array<uint32>(_indexData.size(), XSkinMeshLoader::kNullIndex);
|
||||
|
||||
for (uint32 i = 0; i < _indexData.size() / 3; ++i) {
|
||||
for (uint32 j = i + 1; j < _indexData.size() / 3; ++j) {
|
||||
for (int edge1 = 0; edge1 < 3; ++edge1) {
|
||||
uint16 index1 = _indexData[i * 3 + edge1];
|
||||
uint16 index2 = _indexData[i * 3 + (edge1 + 1) % 3];
|
||||
|
||||
for (int edge2 = 0; edge2 < 3; ++edge2) {
|
||||
uint16 index3 = _indexData[j * 3 + edge2];
|
||||
uint16 index4 = _indexData[j * 3 + (edge2 + 1) % 3];
|
||||
|
||||
if (adjacency[i * 3 + edge1] == XSkinMeshLoader::kNullIndex && adjacency[j * 3 + edge2] == XSkinMeshLoader::kNullIndex && adjacentEdge(index1, index2, index3, index4)) {
|
||||
adjacency[i * 3 + edge1] = j;
|
||||
adjacency[j * 3 + edge2] = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool XSkinMeshLoader::adjacentEdge(uint16 index1, uint16 index2, uint16 index3, uint16 index4) {
|
||||
Math::Vector3d vertex1(_vertexPositionData + 3 * index1);
|
||||
Math::Vector3d vertex2(_vertexPositionData + 3 * index2);
|
||||
Math::Vector3d vertex3(_vertexPositionData + 3 * index3);
|
||||
Math::Vector3d vertex4(_vertexPositionData + 3 * index4);
|
||||
|
||||
// wme uses a function from the D3DX library, which takes in an epsilon for floating point comparison
|
||||
// wme passes in zero, so we just do a direct comparison
|
||||
if (vertex1 == vertex3 && vertex2 == vertex4) {
|
||||
return true;
|
||||
} else if (vertex1 == vertex4 && vertex2 == vertex3) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace Wintermute
|
96
engines/wintermute/base/gfx/xskinmesh_loader.h
Normal file
96
engines/wintermute/base/gfx/xskinmesh_loader.h
Normal file
@ -0,0 +1,96 @@
|
||||
/* 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_XSKINMESH_LOADER_H
|
||||
#define WINTERMUTE_XSKINMESH_LOADER_H
|
||||
|
||||
#include "engines/wintermute/base/gfx/xmodel.h"
|
||||
|
||||
#include "math/matrix4.h"
|
||||
#include "math/vector3d.h"
|
||||
|
||||
namespace Wintermute {
|
||||
|
||||
class Material;
|
||||
class XModel;
|
||||
class XMesh;
|
||||
class ShadowVolume;
|
||||
class VideoTheoraPlayer;
|
||||
struct XMeshObject;
|
||||
|
||||
struct SkinWeights {
|
||||
Common::String _boneName;
|
||||
Math::Matrix4 _offsetMatrix;
|
||||
BaseArray<uint32> _vertexIndices;
|
||||
BaseArray<float> _vertexWeights;
|
||||
};
|
||||
|
||||
class XSkinMeshLoader {
|
||||
friend class XMesh;
|
||||
friend class XMeshOpenGL;
|
||||
friend class XMeshOpenGLShader;
|
||||
|
||||
public:
|
||||
XSkinMeshLoader(XMesh *mesh);
|
||||
virtual ~XSkinMeshLoader();
|
||||
|
||||
protected:
|
||||
static const int kVertexComponentCount = 8;
|
||||
static const int kPositionOffset = 5;
|
||||
static const int kTextureCoordOffset = 0;
|
||||
static const int kNormalOffset = 2;
|
||||
|
||||
// anything which does not fit into 16 bits would we fine
|
||||
static const uint32 kNullIndex = 0xFFFFFFFF;
|
||||
|
||||
bool generateAdjacency(Common::Array<uint32> &adjacency);
|
||||
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);
|
||||
|
||||
protected:
|
||||
|
||||
float *_vertexData;
|
||||
float *_vertexPositionData;
|
||||
float *_vertexNormalData;
|
||||
uint32 _vertexCount;
|
||||
Common::Array<uint16> _indexData;
|
||||
|
||||
BaseArray<Math::Matrix4 *> _boneMatrices;
|
||||
BaseArray<SkinWeights> _skinWeightsList;
|
||||
|
||||
BaseArray<int> _indexRanges;
|
||||
BaseArray<int> _materialIndices;
|
||||
|
||||
XMesh *_mesh;
|
||||
};
|
||||
|
||||
} // namespace Wintermute
|
||||
|
||||
#endif
|
@ -165,6 +165,7 @@ MODULE_OBJS += \
|
||||
base/gfx/3dmesh.o \
|
||||
base/gfx/3dshadow_volume.o \
|
||||
base/gfx/base_renderer3d.o \
|
||||
base/gfx/skin_mesh_helper.o \
|
||||
base/gfx/xactive_animation.o \
|
||||
base/gfx/xanimation.o \
|
||||
base/gfx/xanimation_channel.o \
|
||||
@ -175,6 +176,7 @@ MODULE_OBJS += \
|
||||
base/gfx/xmaterial.o \
|
||||
base/gfx/xmesh.o \
|
||||
base/gfx/xmodel.o \
|
||||
base/gfx/xskinmesh_loader.o \
|
||||
base/gfx/opengl/base_surface_opengl3d.o \
|
||||
base/gfx/opengl/base_render_opengl3d.o \
|
||||
base/gfx/opengl/base_render_opengl3d_shader.o \
|
||||
|
Loading…
x
Reference in New Issue
Block a user