1186 lines
33 KiB
C++
1186 lines
33 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* 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;
|
|
}
|
|
|
|
bool DXComputeBoundingBox(DXVector3 *pfirstposition, uint32 numvertices, uint32 dwstride, DXVector3 *pmin, DXVector3 *pmax) {
|
|
DXVector3 vec;
|
|
uint32 i;
|
|
|
|
if (!pfirstposition || !pmin || !pmax )
|
|
return false;
|
|
|
|
*pmin = *pfirstposition;
|
|
*pmax = *pmin;
|
|
|
|
for (i = 0; i < numvertices; i++) {
|
|
vec = *((DXVector3 *)((byte *)pfirstposition + dwstride * i));
|
|
|
|
if (vec._x < pmin->_x)
|
|
pmin->_x = vec._x;
|
|
if (vec._x > pmax->_x)
|
|
pmax->_x = vec._x;
|
|
|
|
if (vec._y < pmin->_y)
|
|
pmin->_y = vec._y;
|
|
if (vec._y > pmax->_y)
|
|
pmax->_y = vec._y;
|
|
|
|
if (vec._z < pmin->_z)
|
|
pmin->_z = vec._z;
|
|
if (vec._z > pmax->_z)
|
|
pmax->_z = vec._z;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
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 fvf, uint32 boneCount, DXSkinInfo **skinInfo) {
|
|
if (!skinInfo)
|
|
return false;
|
|
|
|
auto skin = new DXSkinInfo();
|
|
if (!skin)
|
|
return false;
|
|
|
|
if (!skin->create(vertexCount, fvf, 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 = (uint32)-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] = (uint32)-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 fvf, uint32 boneCount) {
|
|
_numVertices = vertexCount;
|
|
_numBones = boneCount;
|
|
_fvf = fvf;
|
|
|
|
_bones = new DXBone[boneCount];
|
|
if (!_bones) {
|
|
return false;
|
|
}
|
|
for (uint32 i = 0; i < boneCount; i++) {
|
|
_bones[i]._name = nullptr;
|
|
_bones[i]._numInfluences = 0;
|
|
_bones[i]._vertices = nullptr;
|
|
_bones[i]._weights = nullptr;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void DXSkinInfo::destroy() {
|
|
delete[] _bones;
|
|
_bones = nullptr;
|
|
}
|
|
|
|
bool DXSkinInfo::updateSkinnedMesh(const DXMatrix *boneTransforms, void *srcVertices, void *dstVertices) {
|
|
uint32 vertexSize = DXGetFVFVertexSize(_fvf);
|
|
uint32 normalOffset = sizeof(DXVector3);
|
|
uint32 i, j;
|
|
|
|
for (i = 0; i < _numVertices; i++) {
|
|
DXVector3 *position = (DXVector3 *)((byte *)dstVertices + vertexSize * i);
|
|
position->_x = 0.0f;
|
|
position->_y = 0.0f;
|
|
position->_z = 0.0f;
|
|
}
|
|
|
|
for (i = 0; i < _numBones; i++) {
|
|
DXMatrix boneMatrix = boneTransforms[i];
|
|
|
|
for (j = 0; j < _bones[i]._numInfluences; j++) {
|
|
DXVector3 position;
|
|
DXVector3 *positionSrc = (DXVector3 *)((byte *)srcVertices + vertexSize * _bones[i]._vertices[j]);
|
|
DXVector3 *positionDst = (DXVector3 *)((byte *)dstVertices + vertexSize * _bones[i]._vertices[j]);
|
|
float weight = _bones[i]._weights[j];
|
|
|
|
DXVec3TransformCoord(&position, positionSrc, &boneMatrix);
|
|
|
|
positionDst->_x += weight * position._x;
|
|
positionDst->_y += weight * position._y;
|
|
positionDst->_z += weight * position._z;
|
|
}
|
|
}
|
|
|
|
if (_fvf & DXFVF_NORMAL) {
|
|
for (i = 0; i < _numVertices; i++) {
|
|
DXVector3 *normal = (DXVector3 *)((byte *)dstVertices + vertexSize * i + normalOffset);
|
|
normal->_x = 0.0f;
|
|
normal->_y = 0.0f;
|
|
normal->_z = 0.0f;
|
|
}
|
|
|
|
for (i = 0; i < _numBones; i++) {
|
|
DXMatrix boneInverse = boneTransforms[i];
|
|
DXMatrixInverse(&boneInverse, NULL, &boneInverse);
|
|
DXMatrixTranspose(&boneInverse, &boneInverse);
|
|
|
|
for (j = 0; j < _bones[i]._numInfluences; j++) {
|
|
DXVector3 normal;
|
|
DXVector3 *normalSrc = (DXVector3 *)((byte *)srcVertices + vertexSize * _bones[i]._vertices[j] + normalOffset);
|
|
DXVector3 *normalDst = (DXVector3 *)((byte *)dstVertices + vertexSize * _bones[i]._vertices[j] + normalOffset);
|
|
float weight = _bones[i]._weights[j];
|
|
|
|
DXVec3TransformNormal(&normal, normalSrc, &boneInverse);
|
|
|
|
normalDst->_x += weight * normal._x;
|
|
normalDst->_y += weight * normal._y;
|
|
normalDst->_z += weight * normal._z;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < _numVertices; i++) {
|
|
DXVector3 *normalDest = (DXVector3 *)((byte *)dstVertices + (i * vertexSize) + normalOffset);
|
|
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 = (uint32)-1;
|
|
uint32 textureOffset = (uint32)-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:
|
|
normalOffset = vertexSize;
|
|
meshData->_fvf |= DXFVF_NORMAL;
|
|
break;
|
|
case DXDECLUSAGE_TEXCOORD:
|
|
textureOffset = vertexSize;
|
|
meshData->_fvf |= DXFVF_TEX1;
|
|
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 (meshData->_fvf & DXFVF_NORMAL) {
|
|
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));
|
|
}
|
|
|
|
if (meshData->_fvf & DXFVF_TEX1) {
|
|
delete[] meshData->_texCoords;
|
|
meshData->_texCoords = new DXVector2[meshData->_numVertices];
|
|
if (!meshData->_texCoords) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
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->_fvf, 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;
|
|
uint32 nbChildren, 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;
|
|
uint32 nbChildren, 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;
|
|
}
|
|
|
|
for (i = 0; i < meshData->_numNormals; i++) {
|
|
meshData->_normals[i]._x = normalsObj->_normals[i]._x;
|
|
meshData->_normals[i]._y = normalsObj->_normals[i]._y;
|
|
meshData->_normals[i]._z = normalsObj->_normals[i]._z;
|
|
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;
|
|
}
|
|
|
|
for (i = 0; i < meshData->_numVertices; i++) {
|
|
meshData->_vertices[i]._x = meshObj->_vertices[i]._x;
|
|
meshData->_vertices[i]._y = meshObj->_vertices[i]._y;
|
|
meshData->_vertices[i]._z = meshObj->_vertices[i]._z;
|
|
}
|
|
|
|
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->_fvf, 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 &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;
|
|
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];
|
|
for (i = 0; i < meshData._numVertices; i++) {
|
|
meshData._vertexNormals[i]._x = 0.0f;
|
|
meshData._vertexNormals[i]._y = 0.0f;
|
|
meshData._vertexNormals[i]._z = 0.0f;
|
|
}
|
|
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));
|
|
|
|
|
|
*meshOut = mesh;
|
|
numMaterialsOut = meshData._numMaterials;
|
|
materialsOut = materials;
|
|
*skinInfoOut = meshData._skinInfo;
|
|
|
|
cleanupMeshData(&meshData, false);
|
|
|
|
return result;
|
|
}
|
|
|
|
} // namespace Wintermute
|