mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-07-14 16:14:38 +00:00
update assimp to 5.2.3 Bugfix-Release
This commit is contained in:
parent
3f796d2a06
commit
f297476092
1150 changed files with 165834 additions and 112019 deletions
973
Engine/lib/assimp/code/AssetLib/Ogre/OgreBinarySerializer.cpp
Normal file
973
Engine/lib/assimp/code/AssetLib/Ogre/OgreBinarySerializer.cpp
Normal file
|
|
@ -0,0 +1,973 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "OgreBinarySerializer.h"
|
||||
#include "OgreParsingUtils.h"
|
||||
#include "OgreXmlSerializer.h"
|
||||
|
||||
#include <assimp/TinyFormatter.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
|
||||
|
||||
// Define as 1 to get verbose logging.
|
||||
#define OGRE_BINARY_SERIALIZER_DEBUG 0
|
||||
|
||||
namespace Assimp {
|
||||
namespace Ogre {
|
||||
|
||||
static constexpr auto MESH_VERSION_1_8 = "[MeshSerializer_v1.8]";
|
||||
static constexpr auto SKELETON_VERSION_1_8 = "[Serializer_v1.80]";
|
||||
static constexpr auto SKELETON_VERSION_1_1 = "[Serializer_v1.10]";
|
||||
|
||||
const unsigned short HEADER_CHUNK_ID = 0x1000;
|
||||
|
||||
const long MSTREAM_OVERHEAD_SIZE = sizeof(uint16_t) + sizeof(uint32_t);
|
||||
const long MSTREAM_BONE_SIZE_WITHOUT_SCALE = MSTREAM_OVERHEAD_SIZE + sizeof(unsigned short) + (sizeof(float) * 7);
|
||||
const long MSTREAM_KEYFRAME_SIZE_WITHOUT_SCALE = MSTREAM_OVERHEAD_SIZE + (sizeof(float) * 8);
|
||||
|
||||
template <>
|
||||
inline bool OgreBinarySerializer::Read<bool>() {
|
||||
return (m_reader->GetU1() > 0);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline char OgreBinarySerializer::Read<char>() {
|
||||
return static_cast<char>(m_reader->GetU1());
|
||||
}
|
||||
|
||||
template <>
|
||||
inline uint8_t OgreBinarySerializer::Read<uint8_t>() {
|
||||
return m_reader->GetU1();
|
||||
}
|
||||
|
||||
template <>
|
||||
inline uint16_t OgreBinarySerializer::Read<uint16_t>() {
|
||||
return m_reader->GetU2();
|
||||
}
|
||||
|
||||
template <>
|
||||
inline uint32_t OgreBinarySerializer::Read<uint32_t>() {
|
||||
return m_reader->GetU4();
|
||||
}
|
||||
|
||||
template <>
|
||||
inline float OgreBinarySerializer::Read<float>() {
|
||||
return m_reader->GetF4();
|
||||
}
|
||||
|
||||
void OgreBinarySerializer::ReadBytes(char *dest, size_t numBytes) {
|
||||
ReadBytes(static_cast<void *>(dest), numBytes);
|
||||
}
|
||||
|
||||
void OgreBinarySerializer::ReadBytes(uint8_t *dest, size_t numBytes) {
|
||||
ReadBytes(static_cast<void *>(dest), numBytes);
|
||||
}
|
||||
|
||||
void OgreBinarySerializer::ReadBytes(void *dest, size_t numBytes) {
|
||||
m_reader->CopyAndAdvance(dest, numBytes);
|
||||
}
|
||||
|
||||
uint8_t *OgreBinarySerializer::ReadBytes(size_t numBytes) {
|
||||
uint8_t *bytes = new uint8_t[numBytes];
|
||||
ReadBytes(bytes, numBytes);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
void OgreBinarySerializer::ReadVector(aiVector3D &vec) {
|
||||
m_reader->CopyAndAdvance(&vec.x, sizeof(float) * 3);
|
||||
}
|
||||
|
||||
void OgreBinarySerializer::ReadQuaternion(aiQuaternion &quat) {
|
||||
float temp[4];
|
||||
m_reader->CopyAndAdvance(temp, sizeof(float) * 4);
|
||||
quat.x = temp[0];
|
||||
quat.y = temp[1];
|
||||
quat.z = temp[2];
|
||||
quat.w = temp[3];
|
||||
}
|
||||
|
||||
bool OgreBinarySerializer::AtEnd() const {
|
||||
return (m_reader->GetRemainingSize() == 0);
|
||||
}
|
||||
|
||||
std::string OgreBinarySerializer::ReadString(size_t len) {
|
||||
std::string str;
|
||||
str.resize(len);
|
||||
ReadBytes(&str[0], len);
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string OgreBinarySerializer::ReadLine() {
|
||||
std::string str;
|
||||
while (!AtEnd()) {
|
||||
char c = Read<char>();
|
||||
if (c == '\n')
|
||||
break;
|
||||
str += c;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
uint16_t OgreBinarySerializer::ReadHeader(bool readLen) {
|
||||
uint16_t id = Read<uint16_t>();
|
||||
if (readLen)
|
||||
m_currentLen = Read<uint32_t>();
|
||||
|
||||
#if (OGRE_BINARY_SERIALIZER_DEBUG == 1)
|
||||
if (id != HEADER_CHUNK_ID) {
|
||||
ASSIMP_LOG_DEBUG((assetMode == AM_Mesh ? MeshHeaderToString(static_cast<MeshChunkId>(id)) : SkeletonHeaderToString(static_cast<SkeletonChunkId>(id))));
|
||||
}
|
||||
#endif
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
void OgreBinarySerializer::RollbackHeader() {
|
||||
m_reader->IncPtr(-MSTREAM_OVERHEAD_SIZE);
|
||||
}
|
||||
|
||||
void OgreBinarySerializer::SkipBytes(size_t numBytes) {
|
||||
#if (OGRE_BINARY_SERIALIZER_DEBUG == 1)
|
||||
ASSIMP_LOG_VERBOSE_DEBUG("Skipping ", numBytes, " bytes");
|
||||
#endif
|
||||
|
||||
m_reader->IncPtr(numBytes);
|
||||
}
|
||||
|
||||
// Mesh
|
||||
|
||||
Mesh *OgreBinarySerializer::ImportMesh(MemoryStreamReader *stream) {
|
||||
OgreBinarySerializer serializer(stream, OgreBinarySerializer::AM_Mesh);
|
||||
|
||||
uint16_t id = serializer.ReadHeader(false);
|
||||
if (id != HEADER_CHUNK_ID) {
|
||||
throw DeadlyImportError("Invalid Ogre Mesh file header.");
|
||||
}
|
||||
|
||||
/// @todo Check what we can actually support.
|
||||
std::string version = serializer.ReadLine();
|
||||
if (version != MESH_VERSION_1_8) {
|
||||
throw DeadlyImportError("Mesh version ", version, " not supported by this importer. Run OgreMeshUpgrader tool on the file and try again.",
|
||||
" Supported versions: ", MESH_VERSION_1_8);
|
||||
}
|
||||
|
||||
Mesh *mesh = new Mesh();
|
||||
while (!serializer.AtEnd()) {
|
||||
id = serializer.ReadHeader();
|
||||
switch (id) {
|
||||
case M_MESH: {
|
||||
serializer.ReadMesh(mesh);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return mesh;
|
||||
}
|
||||
|
||||
void OgreBinarySerializer::ReadMesh(Mesh *mesh) {
|
||||
mesh->hasSkeletalAnimations = Read<bool>();
|
||||
|
||||
ASSIMP_LOG_VERBOSE_DEBUG("Reading Mesh");
|
||||
ASSIMP_LOG_VERBOSE_DEBUG(" - Skeletal animations: ", mesh->hasSkeletalAnimations ? "true" : "false");
|
||||
|
||||
if (!AtEnd()) {
|
||||
uint16_t id = ReadHeader();
|
||||
while (!AtEnd() &&
|
||||
(id == M_GEOMETRY ||
|
||||
id == M_SUBMESH ||
|
||||
id == M_MESH_SKELETON_LINK ||
|
||||
id == M_MESH_BONE_ASSIGNMENT ||
|
||||
id == M_MESH_LOD ||
|
||||
id == M_MESH_BOUNDS ||
|
||||
id == M_SUBMESH_NAME_TABLE ||
|
||||
id == M_EDGE_LISTS ||
|
||||
id == M_POSES ||
|
||||
id == M_ANIMATIONS ||
|
||||
id == M_TABLE_EXTREMES)) {
|
||||
switch (id) {
|
||||
case M_GEOMETRY: {
|
||||
mesh->sharedVertexData = new VertexData();
|
||||
ReadGeometry(mesh->sharedVertexData);
|
||||
break;
|
||||
}
|
||||
case M_SUBMESH: {
|
||||
ReadSubMesh(mesh);
|
||||
break;
|
||||
}
|
||||
case M_MESH_SKELETON_LINK: {
|
||||
ReadMeshSkeletonLink(mesh);
|
||||
break;
|
||||
}
|
||||
case M_MESH_BONE_ASSIGNMENT: {
|
||||
ReadBoneAssignment(mesh->sharedVertexData);
|
||||
break;
|
||||
}
|
||||
case M_MESH_LOD: {
|
||||
ReadMeshLodInfo(mesh);
|
||||
break;
|
||||
}
|
||||
case M_MESH_BOUNDS: {
|
||||
ReadMeshBounds(mesh);
|
||||
break;
|
||||
}
|
||||
case M_SUBMESH_NAME_TABLE: {
|
||||
ReadSubMeshNames(mesh);
|
||||
break;
|
||||
}
|
||||
case M_EDGE_LISTS: {
|
||||
ReadEdgeList(mesh);
|
||||
break;
|
||||
}
|
||||
case M_POSES: {
|
||||
ReadPoses(mesh);
|
||||
break;
|
||||
}
|
||||
case M_ANIMATIONS: {
|
||||
ReadAnimations(mesh);
|
||||
break;
|
||||
}
|
||||
case M_TABLE_EXTREMES: {
|
||||
ReadMeshExtremes(mesh);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!AtEnd())
|
||||
id = ReadHeader();
|
||||
}
|
||||
if (!AtEnd())
|
||||
RollbackHeader();
|
||||
}
|
||||
|
||||
NormalizeBoneWeights(mesh->sharedVertexData);
|
||||
}
|
||||
|
||||
void OgreBinarySerializer::ReadMeshLodInfo(Mesh *mesh) {
|
||||
// Assimp does not acknowledge LOD levels as far as I can see it. This info is just skipped.
|
||||
// @todo Put this stuff to scene/mesh custom properties. If manual mesh the app can use the information.
|
||||
ReadLine(); // strategy name
|
||||
uint16_t numLods = Read<uint16_t>();
|
||||
bool manual = Read<bool>();
|
||||
|
||||
/// @note Main mesh is considered as LOD 0, start from index 1.
|
||||
for (size_t i = 1; i < numLods; ++i) {
|
||||
uint16_t id = ReadHeader();
|
||||
if (id != M_MESH_LOD_USAGE) {
|
||||
throw DeadlyImportError("M_MESH_LOD does not contain a M_MESH_LOD_USAGE for each LOD level");
|
||||
}
|
||||
|
||||
m_reader->IncPtr(sizeof(float)); // user value
|
||||
|
||||
if (manual) {
|
||||
id = ReadHeader();
|
||||
if (id != M_MESH_LOD_MANUAL) {
|
||||
throw DeadlyImportError("Manual M_MESH_LOD_USAGE does not contain M_MESH_LOD_MANUAL");
|
||||
}
|
||||
|
||||
ReadLine(); // manual mesh name (ref to another mesh)
|
||||
} else {
|
||||
for (size_t si = 0, silen = mesh->NumSubMeshes(); si < silen; ++si) {
|
||||
id = ReadHeader();
|
||||
if (id != M_MESH_LOD_GENERATED) {
|
||||
throw DeadlyImportError("Generated M_MESH_LOD_USAGE does not contain M_MESH_LOD_GENERATED");
|
||||
}
|
||||
|
||||
uint32_t indexCount = Read<uint32_t>();
|
||||
bool is32bit = Read<bool>();
|
||||
|
||||
if (indexCount > 0) {
|
||||
uint32_t len = indexCount * (is32bit ? sizeof(uint32_t) : sizeof(uint16_t));
|
||||
m_reader->IncPtr(len);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OgreBinarySerializer::ReadMeshSkeletonLink(Mesh *mesh) {
|
||||
mesh->skeletonRef = ReadLine();
|
||||
}
|
||||
|
||||
void OgreBinarySerializer::ReadMeshBounds(Mesh * /*mesh*/) {
|
||||
// Skip bounds, not compatible with Assimp.
|
||||
// 2x float vec3 + 1x float sphere radius
|
||||
SkipBytes(sizeof(float) * 7);
|
||||
}
|
||||
|
||||
void OgreBinarySerializer::ReadMeshExtremes(Mesh * /*mesh*/) {
|
||||
// Skip extremes, not compatible with Assimp.
|
||||
size_t numBytes = m_currentLen - MSTREAM_OVERHEAD_SIZE;
|
||||
SkipBytes(numBytes);
|
||||
}
|
||||
|
||||
void OgreBinarySerializer::ReadBoneAssignment(VertexData *dest) {
|
||||
if (!dest) {
|
||||
throw DeadlyImportError("Cannot read bone assignments, vertex data is null.");
|
||||
}
|
||||
|
||||
VertexBoneAssignment ba;
|
||||
ba.vertexIndex = Read<uint32_t>();
|
||||
ba.boneIndex = Read<uint16_t>();
|
||||
ba.weight = Read<float>();
|
||||
|
||||
dest->boneAssignments.push_back(ba);
|
||||
}
|
||||
|
||||
void OgreBinarySerializer::ReadSubMesh(Mesh *mesh) {
|
||||
uint16_t id = 0;
|
||||
|
||||
SubMesh *submesh = new SubMesh();
|
||||
submesh->materialRef = ReadLine();
|
||||
submesh->usesSharedVertexData = Read<bool>();
|
||||
|
||||
submesh->indexData->count = Read<uint32_t>();
|
||||
submesh->indexData->faceCount = static_cast<uint32_t>(submesh->indexData->count / 3);
|
||||
submesh->indexData->is32bit = Read<bool>();
|
||||
|
||||
ASSIMP_LOG_VERBOSE_DEBUG("Reading SubMesh ", mesh->subMeshes.size());
|
||||
ASSIMP_LOG_VERBOSE_DEBUG(" - Material: '", submesh->materialRef, "'");
|
||||
ASSIMP_LOG_VERBOSE_DEBUG(" - Uses shared geometry: ", submesh->usesSharedVertexData ? "true" : "false");
|
||||
|
||||
// Index buffer
|
||||
if (submesh->indexData->count > 0) {
|
||||
uint32_t numBytes = submesh->indexData->count * (submesh->indexData->is32bit ? sizeof(uint32_t) : sizeof(uint16_t));
|
||||
uint8_t *indexBuffer = ReadBytes(numBytes);
|
||||
submesh->indexData->buffer = MemoryStreamPtr(new Assimp::MemoryIOStream(indexBuffer, numBytes, true));
|
||||
|
||||
ASSIMP_LOG_VERBOSE_DEBUG(" - ", submesh->indexData->faceCount,
|
||||
" faces from ", submesh->indexData->count, (submesh->indexData->is32bit ? " 32bit" : " 16bit"),
|
||||
" indexes of ", numBytes, " bytes");
|
||||
}
|
||||
|
||||
// Vertex buffer if not referencing the shared geometry
|
||||
if (!submesh->usesSharedVertexData) {
|
||||
id = ReadHeader();
|
||||
if (id != M_GEOMETRY) {
|
||||
throw DeadlyImportError("M_SUBMESH does not contain M_GEOMETRY, but shader geometry is set to false");
|
||||
}
|
||||
|
||||
submesh->vertexData = new VertexData();
|
||||
ReadGeometry(submesh->vertexData);
|
||||
}
|
||||
|
||||
// Bone assignment, submesh operation and texture aliases
|
||||
if (!AtEnd()) {
|
||||
id = ReadHeader();
|
||||
while (!AtEnd() &&
|
||||
(id == M_SUBMESH_OPERATION ||
|
||||
id == M_SUBMESH_BONE_ASSIGNMENT ||
|
||||
id == M_SUBMESH_TEXTURE_ALIAS)) {
|
||||
switch (id) {
|
||||
case M_SUBMESH_OPERATION: {
|
||||
ReadSubMeshOperation(submesh);
|
||||
break;
|
||||
}
|
||||
case M_SUBMESH_BONE_ASSIGNMENT: {
|
||||
ReadBoneAssignment(submesh->vertexData);
|
||||
break;
|
||||
}
|
||||
case M_SUBMESH_TEXTURE_ALIAS: {
|
||||
ReadSubMeshTextureAlias(submesh);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!AtEnd())
|
||||
id = ReadHeader();
|
||||
}
|
||||
if (!AtEnd())
|
||||
RollbackHeader();
|
||||
}
|
||||
|
||||
NormalizeBoneWeights(submesh->vertexData);
|
||||
|
||||
submesh->index = static_cast<unsigned int>(mesh->subMeshes.size());
|
||||
mesh->subMeshes.push_back(submesh);
|
||||
}
|
||||
|
||||
void OgreBinarySerializer::NormalizeBoneWeights(VertexData *vertexData) const {
|
||||
if (!vertexData || vertexData->boneAssignments.empty())
|
||||
return;
|
||||
|
||||
std::set<uint32_t> influencedVertices;
|
||||
for (VertexBoneAssignmentList::const_iterator baIter = vertexData->boneAssignments.begin(), baEnd = vertexData->boneAssignments.end(); baIter != baEnd; ++baIter) {
|
||||
influencedVertices.insert(baIter->vertexIndex);
|
||||
}
|
||||
|
||||
/** Normalize bone weights.
|
||||
Some exporters won't care if the sum of all bone weights
|
||||
for a single vertex equals 1 or not, so validate here. */
|
||||
const float epsilon = 0.05f;
|
||||
for (const uint32_t vertexIndex : influencedVertices) {
|
||||
float sum = 0.0f;
|
||||
for (VertexBoneAssignmentList::const_iterator baIter = vertexData->boneAssignments.begin(), baEnd = vertexData->boneAssignments.end(); baIter != baEnd; ++baIter) {
|
||||
if (baIter->vertexIndex == vertexIndex)
|
||||
sum += baIter->weight;
|
||||
}
|
||||
if ((sum < (1.0f - epsilon)) || (sum > (1.0f + epsilon))) {
|
||||
for (auto &boneAssign : vertexData->boneAssignments) {
|
||||
if (boneAssign.vertexIndex == vertexIndex)
|
||||
boneAssign.weight /= sum;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OgreBinarySerializer::ReadSubMeshOperation(SubMesh *submesh) {
|
||||
submesh->operationType = static_cast<SubMesh::OperationType>(Read<uint16_t>());
|
||||
}
|
||||
|
||||
void OgreBinarySerializer::ReadSubMeshTextureAlias(SubMesh *submesh) {
|
||||
submesh->textureAliasName = ReadLine();
|
||||
submesh->textureAliasRef = ReadLine();
|
||||
}
|
||||
|
||||
void OgreBinarySerializer::ReadSubMeshNames(Mesh *mesh) {
|
||||
uint16_t id = 0;
|
||||
|
||||
if (!AtEnd()) {
|
||||
id = ReadHeader();
|
||||
while (!AtEnd() && id == M_SUBMESH_NAME_TABLE_ELEMENT) {
|
||||
uint16_t submeshIndex = Read<uint16_t>();
|
||||
SubMesh *submesh = mesh->GetSubMesh(submeshIndex);
|
||||
if (!submesh) {
|
||||
throw DeadlyImportError("Ogre Mesh does not include submesh ", submeshIndex, " referenced in M_SUBMESH_NAME_TABLE_ELEMENT. Invalid mesh file.");
|
||||
}
|
||||
|
||||
submesh->name = ReadLine();
|
||||
ASSIMP_LOG_VERBOSE_DEBUG(" - SubMesh ", submesh->index, " name '", submesh->name, "'");
|
||||
|
||||
if (!AtEnd())
|
||||
id = ReadHeader();
|
||||
}
|
||||
if (!AtEnd())
|
||||
RollbackHeader();
|
||||
}
|
||||
}
|
||||
|
||||
void OgreBinarySerializer::ReadGeometry(VertexData *dest) {
|
||||
dest->count = Read<uint32_t>();
|
||||
|
||||
ASSIMP_LOG_VERBOSE_DEBUG(" - Reading geometry of ", dest->count, " vertices");
|
||||
|
||||
if (!AtEnd()) {
|
||||
uint16_t id = ReadHeader();
|
||||
while (!AtEnd() &&
|
||||
(id == M_GEOMETRY_VERTEX_DECLARATION ||
|
||||
id == M_GEOMETRY_VERTEX_BUFFER)) {
|
||||
switch (id) {
|
||||
case M_GEOMETRY_VERTEX_DECLARATION: {
|
||||
ReadGeometryVertexDeclaration(dest);
|
||||
break;
|
||||
}
|
||||
case M_GEOMETRY_VERTEX_BUFFER: {
|
||||
ReadGeometryVertexBuffer(dest);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!AtEnd())
|
||||
id = ReadHeader();
|
||||
}
|
||||
if (!AtEnd())
|
||||
RollbackHeader();
|
||||
}
|
||||
}
|
||||
|
||||
void OgreBinarySerializer::ReadGeometryVertexDeclaration(VertexData *dest) {
|
||||
if (!AtEnd()) {
|
||||
uint16_t id = ReadHeader();
|
||||
while (!AtEnd() && id == M_GEOMETRY_VERTEX_ELEMENT) {
|
||||
ReadGeometryVertexElement(dest);
|
||||
|
||||
if (!AtEnd())
|
||||
id = ReadHeader();
|
||||
}
|
||||
if (!AtEnd())
|
||||
RollbackHeader();
|
||||
}
|
||||
}
|
||||
|
||||
void OgreBinarySerializer::ReadGeometryVertexElement(VertexData *dest) {
|
||||
VertexElement element;
|
||||
element.source = Read<uint16_t>();
|
||||
element.type = static_cast<VertexElement::Type>(Read<uint16_t>());
|
||||
element.semantic = static_cast<VertexElement::Semantic>(Read<uint16_t>());
|
||||
element.offset = Read<uint16_t>();
|
||||
element.index = Read<uint16_t>();
|
||||
|
||||
ASSIMP_LOG_VERBOSE_DEBUG(" - Vertex element ", element.SemanticToString(), " of type ",
|
||||
element.TypeToString(), " index=", element.index, " source=", element.source);
|
||||
|
||||
dest->vertexElements.push_back(element);
|
||||
}
|
||||
|
||||
void OgreBinarySerializer::ReadGeometryVertexBuffer(VertexData *dest) {
|
||||
uint16_t bindIndex = Read<uint16_t>();
|
||||
uint16_t vertexSize = Read<uint16_t>();
|
||||
|
||||
uint16_t id = ReadHeader();
|
||||
if (id != M_GEOMETRY_VERTEX_BUFFER_DATA)
|
||||
throw DeadlyImportError("M_GEOMETRY_VERTEX_BUFFER_DATA not found in M_GEOMETRY_VERTEX_BUFFER");
|
||||
|
||||
if (dest->VertexSize(bindIndex) != vertexSize)
|
||||
throw DeadlyImportError("Vertex buffer size does not agree with vertex declaration in M_GEOMETRY_VERTEX_BUFFER");
|
||||
|
||||
size_t numBytes = dest->count * vertexSize;
|
||||
uint8_t *vertexBuffer = ReadBytes(numBytes);
|
||||
dest->vertexBindings[bindIndex] = MemoryStreamPtr(new Assimp::MemoryIOStream(vertexBuffer, numBytes, true));
|
||||
|
||||
ASSIMP_LOG_VERBOSE_DEBUG(" - Read vertex buffer for source ", bindIndex, " of ", numBytes, " bytes");
|
||||
}
|
||||
|
||||
void OgreBinarySerializer::ReadEdgeList(Mesh * /*mesh*/) {
|
||||
// Assimp does not acknowledge LOD levels as far as I can see it. This info is just skipped.
|
||||
|
||||
if (!AtEnd()) {
|
||||
uint16_t id = ReadHeader();
|
||||
while (!AtEnd() && id == M_EDGE_LIST_LOD) {
|
||||
m_reader->IncPtr(sizeof(uint16_t)); // lod index
|
||||
bool manual = Read<bool>();
|
||||
|
||||
if (!manual) {
|
||||
m_reader->IncPtr(sizeof(uint8_t));
|
||||
uint32_t numTriangles = Read<uint32_t>();
|
||||
uint32_t numEdgeGroups = Read<uint32_t>();
|
||||
|
||||
size_t skipBytes = (sizeof(uint32_t) * 8 + sizeof(float) * 4) * numTriangles;
|
||||
m_reader->IncPtr(skipBytes);
|
||||
|
||||
for (size_t i = 0; i < numEdgeGroups; ++i) {
|
||||
uint16_t curId = ReadHeader();
|
||||
if (curId != M_EDGE_GROUP)
|
||||
throw DeadlyImportError("M_EDGE_GROUP not found in M_EDGE_LIST_LOD");
|
||||
|
||||
m_reader->IncPtr(sizeof(uint32_t) * 3);
|
||||
uint32_t numEdges = Read<uint32_t>();
|
||||
for (size_t j = 0; j < numEdges; ++j) {
|
||||
m_reader->IncPtr(sizeof(uint32_t) * 6 + sizeof(uint8_t));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!AtEnd())
|
||||
id = ReadHeader();
|
||||
}
|
||||
if (!AtEnd())
|
||||
RollbackHeader();
|
||||
}
|
||||
}
|
||||
|
||||
void OgreBinarySerializer::ReadPoses(Mesh *mesh) {
|
||||
if (!AtEnd()) {
|
||||
uint16_t id = ReadHeader();
|
||||
while (!AtEnd() && id == M_POSE) {
|
||||
Pose *pose = new Pose();
|
||||
pose->name = ReadLine();
|
||||
pose->target = Read<uint16_t>();
|
||||
pose->hasNormals = Read<bool>();
|
||||
|
||||
ReadPoseVertices(pose);
|
||||
|
||||
mesh->poses.push_back(pose);
|
||||
|
||||
if (!AtEnd())
|
||||
id = ReadHeader();
|
||||
}
|
||||
if (!AtEnd())
|
||||
RollbackHeader();
|
||||
}
|
||||
}
|
||||
|
||||
void OgreBinarySerializer::ReadPoseVertices(Pose *pose) {
|
||||
if (!AtEnd()) {
|
||||
uint16_t id = ReadHeader();
|
||||
while (!AtEnd() && id == M_POSE_VERTEX) {
|
||||
Pose::Vertex v;
|
||||
v.index = Read<uint32_t>();
|
||||
ReadVector(v.offset);
|
||||
if (pose->hasNormals)
|
||||
ReadVector(v.normal);
|
||||
|
||||
pose->vertices[v.index] = v;
|
||||
|
||||
if (!AtEnd())
|
||||
id = ReadHeader();
|
||||
}
|
||||
if (!AtEnd())
|
||||
RollbackHeader();
|
||||
}
|
||||
}
|
||||
|
||||
void OgreBinarySerializer::ReadAnimations(Mesh *mesh) {
|
||||
if (!AtEnd()) {
|
||||
uint16_t id = ReadHeader();
|
||||
while (!AtEnd() && id == M_ANIMATION) {
|
||||
Animation *anim = new Animation(mesh);
|
||||
anim->name = ReadLine();
|
||||
anim->length = Read<float>();
|
||||
|
||||
ReadAnimation(anim);
|
||||
|
||||
mesh->animations.push_back(anim);
|
||||
|
||||
if (!AtEnd())
|
||||
id = ReadHeader();
|
||||
}
|
||||
if (!AtEnd())
|
||||
RollbackHeader();
|
||||
}
|
||||
}
|
||||
|
||||
void OgreBinarySerializer::ReadAnimation(Animation *anim) {
|
||||
if (!AtEnd()) {
|
||||
uint16_t id = ReadHeader();
|
||||
if (id == M_ANIMATION_BASEINFO) {
|
||||
anim->baseName = ReadLine();
|
||||
anim->baseTime = Read<float>();
|
||||
|
||||
// Advance to first track
|
||||
id = ReadHeader();
|
||||
}
|
||||
|
||||
while (!AtEnd() && id == M_ANIMATION_TRACK) {
|
||||
VertexAnimationTrack track;
|
||||
track.type = static_cast<VertexAnimationTrack::Type>(Read<uint16_t>());
|
||||
track.target = Read<uint16_t>();
|
||||
|
||||
ReadAnimationKeyFrames(anim, &track);
|
||||
|
||||
anim->tracks.push_back(track);
|
||||
|
||||
if (!AtEnd())
|
||||
id = ReadHeader();
|
||||
}
|
||||
if (!AtEnd())
|
||||
RollbackHeader();
|
||||
}
|
||||
}
|
||||
|
||||
void OgreBinarySerializer::ReadAnimationKeyFrames(Animation *anim, VertexAnimationTrack *track) {
|
||||
if (!AtEnd()) {
|
||||
uint16_t id = ReadHeader();
|
||||
while (!AtEnd() &&
|
||||
(id == M_ANIMATION_MORPH_KEYFRAME ||
|
||||
id == M_ANIMATION_POSE_KEYFRAME)) {
|
||||
if (id == M_ANIMATION_MORPH_KEYFRAME) {
|
||||
MorphKeyFrame kf;
|
||||
kf.timePos = Read<float>();
|
||||
bool hasNormals = Read<bool>();
|
||||
|
||||
size_t vertexCount = anim->AssociatedVertexData(track)->count;
|
||||
size_t vertexSize = sizeof(float) * (hasNormals ? 6 : 3);
|
||||
size_t numBytes = vertexCount * vertexSize;
|
||||
|
||||
uint8_t *morphBuffer = ReadBytes(numBytes);
|
||||
kf.buffer = MemoryStreamPtr(new Assimp::MemoryIOStream(morphBuffer, numBytes, true));
|
||||
|
||||
track->morphKeyFrames.push_back(kf);
|
||||
} else if (id == M_ANIMATION_POSE_KEYFRAME) {
|
||||
PoseKeyFrame kf;
|
||||
kf.timePos = Read<float>();
|
||||
|
||||
if (!AtEnd()) {
|
||||
id = ReadHeader();
|
||||
while (!AtEnd() && id == M_ANIMATION_POSE_REF) {
|
||||
PoseRef pr;
|
||||
pr.index = Read<uint16_t>();
|
||||
pr.influence = Read<float>();
|
||||
kf.references.push_back(pr);
|
||||
|
||||
if (!AtEnd())
|
||||
id = ReadHeader();
|
||||
}
|
||||
if (!AtEnd())
|
||||
RollbackHeader();
|
||||
}
|
||||
|
||||
track->poseKeyFrames.push_back(kf);
|
||||
}
|
||||
|
||||
if (!AtEnd())
|
||||
id = ReadHeader();
|
||||
}
|
||||
if (!AtEnd())
|
||||
RollbackHeader();
|
||||
}
|
||||
}
|
||||
|
||||
// Skeleton
|
||||
|
||||
bool OgreBinarySerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, Mesh *mesh) {
|
||||
if (!mesh || mesh->skeletonRef.empty())
|
||||
return false;
|
||||
|
||||
// Highly unusual to see in read world cases but support
|
||||
// binary mesh referencing a XML skeleton file.
|
||||
if (EndsWith(mesh->skeletonRef, ".skeleton.xml", false)) {
|
||||
OgreXmlSerializer::ImportSkeleton(pIOHandler, mesh);
|
||||
return false;
|
||||
}
|
||||
|
||||
MemoryStreamReaderPtr reader = OpenReader(pIOHandler, mesh->skeletonRef);
|
||||
if (!reader)
|
||||
return false;
|
||||
|
||||
Skeleton *skeleton = new Skeleton();
|
||||
OgreBinarySerializer serializer(reader.get(), OgreBinarySerializer::AM_Skeleton);
|
||||
serializer.ReadSkeleton(skeleton);
|
||||
mesh->skeleton = skeleton;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OgreBinarySerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, MeshXml *mesh) {
|
||||
if (!mesh || mesh->skeletonRef.empty())
|
||||
return false;
|
||||
|
||||
MemoryStreamReaderPtr reader = OpenReader(pIOHandler, mesh->skeletonRef);
|
||||
if (!reader.get())
|
||||
return false;
|
||||
|
||||
Skeleton *skeleton = new Skeleton();
|
||||
OgreBinarySerializer serializer(reader.get(), OgreBinarySerializer::AM_Skeleton);
|
||||
serializer.ReadSkeleton(skeleton);
|
||||
mesh->skeleton = skeleton;
|
||||
return true;
|
||||
}
|
||||
|
||||
MemoryStreamReaderPtr OgreBinarySerializer::OpenReader(Assimp::IOSystem *pIOHandler, const std::string &filename) {
|
||||
if (!EndsWith(filename, ".skeleton", false)) {
|
||||
ASSIMP_LOG_ERROR("Imported Mesh is referencing to unsupported '", filename, "' skeleton file.");
|
||||
return MemoryStreamReaderPtr();
|
||||
}
|
||||
|
||||
if (!pIOHandler->Exists(filename)) {
|
||||
ASSIMP_LOG_ERROR("Failed to find skeleton file '", filename, "' that is referenced by imported Mesh.");
|
||||
return MemoryStreamReaderPtr();
|
||||
}
|
||||
|
||||
IOStream *f = pIOHandler->Open(filename, "rb");
|
||||
if (!f) {
|
||||
throw DeadlyImportError("Failed to open skeleton file ", filename);
|
||||
}
|
||||
|
||||
return MemoryStreamReaderPtr(new MemoryStreamReader(f));
|
||||
}
|
||||
|
||||
void OgreBinarySerializer::ReadSkeleton(Skeleton *skeleton) {
|
||||
uint16_t id = ReadHeader(false);
|
||||
if (id != HEADER_CHUNK_ID) {
|
||||
throw DeadlyImportError("Invalid Ogre Skeleton file header.");
|
||||
}
|
||||
|
||||
// This deserialization supports both versions of the skeleton spec
|
||||
std::string version = ReadLine();
|
||||
if (version != SKELETON_VERSION_1_8 && version != SKELETON_VERSION_1_1) {
|
||||
throw DeadlyImportError("Skeleton version ", version, " not supported by this importer.",
|
||||
" Supported versions: ", SKELETON_VERSION_1_8, " and ", SKELETON_VERSION_1_1);
|
||||
}
|
||||
|
||||
ASSIMP_LOG_VERBOSE_DEBUG("Reading Skeleton");
|
||||
|
||||
bool firstBone = true;
|
||||
bool firstAnim = true;
|
||||
|
||||
while (!AtEnd()) {
|
||||
id = ReadHeader();
|
||||
switch (id) {
|
||||
case SKELETON_BLENDMODE: {
|
||||
skeleton->blendMode = static_cast<Skeleton::BlendMode>(Read<uint16_t>());
|
||||
break;
|
||||
}
|
||||
case SKELETON_BONE: {
|
||||
if (firstBone) {
|
||||
ASSIMP_LOG_VERBOSE_DEBUG(" - Bones");
|
||||
firstBone = false;
|
||||
}
|
||||
|
||||
ReadBone(skeleton);
|
||||
break;
|
||||
}
|
||||
case SKELETON_BONE_PARENT: {
|
||||
ReadBoneParent(skeleton);
|
||||
break;
|
||||
}
|
||||
case SKELETON_ANIMATION: {
|
||||
if (firstAnim) {
|
||||
ASSIMP_LOG_VERBOSE_DEBUG(" - Animations");
|
||||
firstAnim = false;
|
||||
}
|
||||
|
||||
ReadSkeletonAnimation(skeleton);
|
||||
break;
|
||||
}
|
||||
case SKELETON_ANIMATION_LINK: {
|
||||
ReadSkeletonAnimationLink(skeleton);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate bone matrices for root bones. Recursively calculates their children.
|
||||
for (size_t i = 0, len = skeleton->bones.size(); i < len; ++i) {
|
||||
Bone *bone = skeleton->bones[i];
|
||||
if (!bone->IsParented())
|
||||
bone->CalculateWorldMatrixAndDefaultPose(skeleton);
|
||||
}
|
||||
}
|
||||
|
||||
void OgreBinarySerializer::ReadBone(Skeleton *skeleton) {
|
||||
Bone *bone = new Bone();
|
||||
bone->name = ReadLine();
|
||||
bone->id = Read<uint16_t>();
|
||||
|
||||
// Pos and rot
|
||||
ReadVector(bone->position);
|
||||
ReadQuaternion(bone->rotation);
|
||||
|
||||
// Scale (optional)
|
||||
if (m_currentLen > MSTREAM_BONE_SIZE_WITHOUT_SCALE)
|
||||
ReadVector(bone->scale);
|
||||
|
||||
// Bone indexes need to start from 0 and be contiguous
|
||||
if (bone->id != skeleton->bones.size()) {
|
||||
throw DeadlyImportError("Ogre Skeleton bone indexes not contiguous. Error at bone index ", bone->id);
|
||||
}
|
||||
|
||||
ASSIMP_LOG_VERBOSE_DEBUG(" ", bone->id, " ", bone->name);
|
||||
|
||||
skeleton->bones.push_back(bone);
|
||||
}
|
||||
|
||||
void OgreBinarySerializer::ReadBoneParent(Skeleton *skeleton) {
|
||||
uint16_t childId = Read<uint16_t>();
|
||||
uint16_t parentId = Read<uint16_t>();
|
||||
|
||||
Bone *child = skeleton->BoneById(childId);
|
||||
Bone *parent = skeleton->BoneById(parentId);
|
||||
|
||||
if (child && parent)
|
||||
parent->AddChild(child);
|
||||
else
|
||||
throw DeadlyImportError("Failed to find bones for parenting: Child id ", childId, " for parent id ", parentId);
|
||||
}
|
||||
|
||||
void OgreBinarySerializer::ReadSkeletonAnimation(Skeleton *skeleton) {
|
||||
Animation *anim = new Animation(skeleton);
|
||||
anim->name = ReadLine();
|
||||
anim->length = Read<float>();
|
||||
|
||||
if (!AtEnd()) {
|
||||
uint16_t id = ReadHeader();
|
||||
if (id == SKELETON_ANIMATION_BASEINFO) {
|
||||
anim->baseName = ReadLine();
|
||||
anim->baseTime = Read<float>();
|
||||
|
||||
// Advance to first track
|
||||
id = ReadHeader();
|
||||
}
|
||||
|
||||
while (!AtEnd() && id == SKELETON_ANIMATION_TRACK) {
|
||||
ReadSkeletonAnimationTrack(skeleton, anim);
|
||||
|
||||
if (!AtEnd())
|
||||
id = ReadHeader();
|
||||
}
|
||||
if (!AtEnd())
|
||||
RollbackHeader();
|
||||
}
|
||||
|
||||
skeleton->animations.push_back(anim);
|
||||
|
||||
ASSIMP_LOG_VERBOSE_DEBUG(" ", anim->name, " (", anim->length, " sec, ", anim->tracks.size(), " tracks)");
|
||||
}
|
||||
|
||||
void OgreBinarySerializer::ReadSkeletonAnimationTrack(Skeleton * /*skeleton*/, Animation *dest) {
|
||||
uint16_t boneId = Read<uint16_t>();
|
||||
Bone *bone = dest->parentSkeleton->BoneById(boneId);
|
||||
if (!bone) {
|
||||
throw DeadlyImportError("Cannot read animation track, target bone ", boneId, " not in target Skeleton");
|
||||
}
|
||||
|
||||
VertexAnimationTrack track;
|
||||
track.type = VertexAnimationTrack::VAT_TRANSFORM;
|
||||
track.boneName = bone->name;
|
||||
|
||||
uint16_t id = ReadHeader();
|
||||
while (!AtEnd() && id == SKELETON_ANIMATION_TRACK_KEYFRAME) {
|
||||
ReadSkeletonAnimationKeyFrame(&track);
|
||||
|
||||
if (!AtEnd())
|
||||
id = ReadHeader();
|
||||
}
|
||||
if (!AtEnd())
|
||||
RollbackHeader();
|
||||
|
||||
dest->tracks.push_back(track);
|
||||
}
|
||||
|
||||
void OgreBinarySerializer::ReadSkeletonAnimationKeyFrame(VertexAnimationTrack *dest) {
|
||||
TransformKeyFrame keyframe;
|
||||
keyframe.timePos = Read<float>();
|
||||
|
||||
// Rot and pos
|
||||
ReadQuaternion(keyframe.rotation);
|
||||
ReadVector(keyframe.position);
|
||||
|
||||
// Scale (optional)
|
||||
if (m_currentLen > MSTREAM_KEYFRAME_SIZE_WITHOUT_SCALE)
|
||||
ReadVector(keyframe.scale);
|
||||
|
||||
dest->transformKeyFrames.push_back(keyframe);
|
||||
}
|
||||
|
||||
void OgreBinarySerializer::ReadSkeletonAnimationLink(Skeleton * /*skeleton*/) {
|
||||
// Skip bounds, not compatible with Assimp.
|
||||
ReadLine(); // skeleton name
|
||||
SkipBytes(sizeof(float) * 3); // scale
|
||||
}
|
||||
|
||||
} // namespace Ogre
|
||||
} // namespace Assimp
|
||||
|
||||
#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER
|
||||
415
Engine/lib/assimp/code/AssetLib/Ogre/OgreBinarySerializer.h
Normal file
415
Engine/lib/assimp/code/AssetLib/Ogre/OgreBinarySerializer.h
Normal file
|
|
@ -0,0 +1,415 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef AI_OGREBINARYSERIALIZER_H_INC
|
||||
#define AI_OGREBINARYSERIALIZER_H_INC
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
|
||||
|
||||
#include "OgreStructs.h"
|
||||
#include <assimp/StreamReader.h>
|
||||
|
||||
namespace Assimp {
|
||||
namespace Ogre {
|
||||
|
||||
typedef Assimp::StreamReaderLE MemoryStreamReader;
|
||||
typedef std::shared_ptr<MemoryStreamReader> MemoryStreamReaderPtr;
|
||||
|
||||
class OgreBinarySerializer {
|
||||
public:
|
||||
/// Imports mesh and returns the result.
|
||||
/** @note Fatal unrecoverable errors will throw a DeadlyImportError. */
|
||||
static Mesh *ImportMesh(MemoryStreamReader *reader);
|
||||
|
||||
/// Imports skeleton to @c mesh into Mesh::skeleton.
|
||||
/** If mesh does not have a skeleton reference or the skeleton file
|
||||
cannot be found it is not a fatal DeadlyImportError.
|
||||
@return If skeleton import was successful. */
|
||||
static bool ImportSkeleton(Assimp::IOSystem *pIOHandler, Mesh *mesh);
|
||||
static bool ImportSkeleton(Assimp::IOSystem *pIOHandler, MeshXml *mesh);
|
||||
|
||||
private:
|
||||
enum AssetMode {
|
||||
AM_Mesh,
|
||||
AM_Skeleton
|
||||
};
|
||||
|
||||
OgreBinarySerializer(MemoryStreamReader *reader, AssetMode mode) :
|
||||
m_currentLen(0),
|
||||
m_reader(reader),
|
||||
assetMode(mode) {
|
||||
}
|
||||
|
||||
static MemoryStreamReaderPtr OpenReader(Assimp::IOSystem *pIOHandler, const std::string &filename);
|
||||
|
||||
// Header
|
||||
|
||||
uint16_t ReadHeader(bool readLen = true);
|
||||
void RollbackHeader();
|
||||
|
||||
// Mesh
|
||||
|
||||
void ReadMesh(Mesh *mesh);
|
||||
void ReadMeshLodInfo(Mesh *mesh);
|
||||
void ReadMeshSkeletonLink(Mesh *mesh);
|
||||
void ReadMeshBounds(Mesh *mesh);
|
||||
void ReadMeshExtremes(Mesh *mesh);
|
||||
|
||||
void ReadSubMesh(Mesh *mesh);
|
||||
void ReadSubMeshNames(Mesh *mesh);
|
||||
void ReadSubMeshOperation(SubMesh *submesh);
|
||||
void ReadSubMeshTextureAlias(SubMesh *submesh);
|
||||
|
||||
void ReadBoneAssignment(VertexData *dest);
|
||||
|
||||
void ReadGeometry(VertexData *dest);
|
||||
void ReadGeometryVertexDeclaration(VertexData *dest);
|
||||
void ReadGeometryVertexElement(VertexData *dest);
|
||||
void ReadGeometryVertexBuffer(VertexData *dest);
|
||||
|
||||
void ReadEdgeList(Mesh *mesh);
|
||||
void ReadPoses(Mesh *mesh);
|
||||
void ReadPoseVertices(Pose *pose);
|
||||
|
||||
void ReadAnimations(Mesh *mesh);
|
||||
void ReadAnimation(Animation *anim);
|
||||
void ReadAnimationKeyFrames(Animation *anim, VertexAnimationTrack *track);
|
||||
|
||||
void NormalizeBoneWeights(VertexData *vertexData) const;
|
||||
|
||||
// Skeleton
|
||||
|
||||
void ReadSkeleton(Skeleton *skeleton);
|
||||
|
||||
void ReadBone(Skeleton *skeleton);
|
||||
void ReadBoneParent(Skeleton *skeleton);
|
||||
|
||||
void ReadSkeletonAnimation(Skeleton *skeleton);
|
||||
void ReadSkeletonAnimationTrack(Skeleton *skeleton, Animation *dest);
|
||||
void ReadSkeletonAnimationKeyFrame(VertexAnimationTrack *dest);
|
||||
void ReadSkeletonAnimationLink(Skeleton *skeleton);
|
||||
|
||||
// Reader utils
|
||||
bool AtEnd() const;
|
||||
|
||||
template <typename T>
|
||||
inline T Read();
|
||||
|
||||
void ReadBytes(char *dest, size_t numBytes);
|
||||
void ReadBytes(uint8_t *dest, size_t numBytes);
|
||||
void ReadBytes(void *dest, size_t numBytes);
|
||||
uint8_t *ReadBytes(size_t numBytes);
|
||||
|
||||
void ReadVector(aiVector3D &vec);
|
||||
void ReadQuaternion(aiQuaternion &quat);
|
||||
|
||||
std::string ReadString(size_t len);
|
||||
std::string ReadLine();
|
||||
|
||||
void SkipBytes(size_t numBytes);
|
||||
|
||||
uint32_t m_currentLen;
|
||||
MemoryStreamReader *m_reader;
|
||||
|
||||
AssetMode assetMode;
|
||||
};
|
||||
|
||||
enum MeshChunkId {
|
||||
M_HEADER = 0x1000,
|
||||
// char* version : Version number check
|
||||
M_MESH = 0x3000,
|
||||
// bool skeletallyAnimated // important flag which affects h/w buffer policies
|
||||
// Optional M_GEOMETRY chunk
|
||||
M_SUBMESH = 0x4000,
|
||||
// char* materialName
|
||||
// bool useSharedVertices
|
||||
// unsigned int indexCount
|
||||
// bool indexes32Bit
|
||||
// unsigned int* faceVertexIndices (indexCount)
|
||||
// OR
|
||||
// unsigned short* faceVertexIndices (indexCount)
|
||||
// M_GEOMETRY chunk (Optional: present only if useSharedVertices = false)
|
||||
M_SUBMESH_OPERATION = 0x4010, // optional, trilist assumed if missing
|
||||
// unsigned short operationType
|
||||
M_SUBMESH_BONE_ASSIGNMENT = 0x4100,
|
||||
// Optional bone weights (repeating section)
|
||||
// unsigned int vertexIndex;
|
||||
// unsigned short boneIndex;
|
||||
// float weight;
|
||||
// Optional chunk that matches a texture name to an alias
|
||||
// a texture alias is sent to the submesh material to use this texture name
|
||||
// instead of the one in the texture unit with a matching alias name
|
||||
M_SUBMESH_TEXTURE_ALIAS = 0x4200, // Repeating section
|
||||
// char* aliasName;
|
||||
// char* textureName;
|
||||
|
||||
M_GEOMETRY = 0x5000, // NB this chunk is embedded within M_MESH and M_SUBMESH
|
||||
// unsigned int vertexCount
|
||||
M_GEOMETRY_VERTEX_DECLARATION = 0x5100,
|
||||
M_GEOMETRY_VERTEX_ELEMENT = 0x5110, // Repeating section
|
||||
// unsigned short source; // buffer bind source
|
||||
// unsigned short type; // VertexElementType
|
||||
// unsigned short semantic; // VertexElementSemantic
|
||||
// unsigned short offset; // start offset in buffer in bytes
|
||||
// unsigned short index; // index of the semantic (for colours and texture coords)
|
||||
M_GEOMETRY_VERTEX_BUFFER = 0x5200, // Repeating section
|
||||
// unsigned short bindIndex; // Index to bind this buffer to
|
||||
// unsigned short vertexSize; // Per-vertex size, must agree with declaration at this index
|
||||
M_GEOMETRY_VERTEX_BUFFER_DATA = 0x5210,
|
||||
// raw buffer data
|
||||
M_MESH_SKELETON_LINK = 0x6000,
|
||||
// Optional link to skeleton
|
||||
// char* skeletonName : name of .skeleton to use
|
||||
M_MESH_BONE_ASSIGNMENT = 0x7000,
|
||||
// Optional bone weights (repeating section)
|
||||
// unsigned int vertexIndex;
|
||||
// unsigned short boneIndex;
|
||||
// float weight;
|
||||
M_MESH_LOD = 0x8000,
|
||||
// Optional LOD information
|
||||
// string strategyName;
|
||||
// unsigned short numLevels;
|
||||
// bool manual; (true for manual alternate meshes, false for generated)
|
||||
M_MESH_LOD_USAGE = 0x8100,
|
||||
// Repeating section, ordered in increasing depth
|
||||
// NB LOD 0 (full detail from 0 depth) is omitted
|
||||
// LOD value - this is a distance, a pixel count etc, based on strategy
|
||||
// float lodValue;
|
||||
M_MESH_LOD_MANUAL = 0x8110,
|
||||
// Required if M_MESH_LOD section manual = true
|
||||
// String manualMeshName;
|
||||
M_MESH_LOD_GENERATED = 0x8120,
|
||||
// Required if M_MESH_LOD section manual = false
|
||||
// Repeating section (1 per submesh)
|
||||
// unsigned int indexCount;
|
||||
// bool indexes32Bit
|
||||
// unsigned short* faceIndexes; (indexCount)
|
||||
// OR
|
||||
// unsigned int* faceIndexes; (indexCount)
|
||||
M_MESH_BOUNDS = 0x9000,
|
||||
// float minx, miny, minz
|
||||
// float maxx, maxy, maxz
|
||||
// float radius
|
||||
|
||||
// Added By DrEvil
|
||||
// optional chunk that contains a table of submesh indexes and the names of
|
||||
// the sub-meshes.
|
||||
M_SUBMESH_NAME_TABLE = 0xA000,
|
||||
// Subchunks of the name table. Each chunk contains an index & string
|
||||
M_SUBMESH_NAME_TABLE_ELEMENT = 0xA100,
|
||||
// short index
|
||||
// char* name
|
||||
// Optional chunk which stores precomputed edge data
|
||||
M_EDGE_LISTS = 0xB000,
|
||||
// Each LOD has a separate edge list
|
||||
M_EDGE_LIST_LOD = 0xB100,
|
||||
// unsigned short lodIndex
|
||||
// bool isManual // If manual, no edge data here, loaded from manual mesh
|
||||
// bool isClosed
|
||||
// unsigned long numTriangles
|
||||
// unsigned long numEdgeGroups
|
||||
// Triangle* triangleList
|
||||
// unsigned long indexSet
|
||||
// unsigned long vertexSet
|
||||
// unsigned long vertIndex[3]
|
||||
// unsigned long sharedVertIndex[3]
|
||||
// float normal[4]
|
||||
|
||||
M_EDGE_GROUP = 0xB110,
|
||||
// unsigned long vertexSet
|
||||
// unsigned long triStart
|
||||
// unsigned long triCount
|
||||
// unsigned long numEdges
|
||||
// Edge* edgeList
|
||||
// unsigned long triIndex[2]
|
||||
// unsigned long vertIndex[2]
|
||||
// unsigned long sharedVertIndex[2]
|
||||
// bool degenerate
|
||||
// Optional poses section, referred to by pose keyframes
|
||||
M_POSES = 0xC000,
|
||||
M_POSE = 0xC100,
|
||||
// char* name (may be blank)
|
||||
// unsigned short target // 0 for shared geometry,
|
||||
// 1+ for submesh index + 1
|
||||
// bool includesNormals [1.8+]
|
||||
M_POSE_VERTEX = 0xC111,
|
||||
// unsigned long vertexIndex
|
||||
// float xoffset, yoffset, zoffset
|
||||
// float xnormal, ynormal, znormal (optional, 1.8+)
|
||||
// Optional vertex animation chunk
|
||||
M_ANIMATIONS = 0xD000,
|
||||
M_ANIMATION = 0xD100,
|
||||
// char* name
|
||||
// float length
|
||||
M_ANIMATION_BASEINFO = 0xD105,
|
||||
// [Optional] base keyframe information (pose animation only)
|
||||
// char* baseAnimationName (blank for self)
|
||||
// float baseKeyFrameTime
|
||||
M_ANIMATION_TRACK = 0xD110,
|
||||
// unsigned short type // 1 == morph, 2 == pose
|
||||
// unsigned short target // 0 for shared geometry,
|
||||
// 1+ for submesh index + 1
|
||||
M_ANIMATION_MORPH_KEYFRAME = 0xD111,
|
||||
// float time
|
||||
// bool includesNormals [1.8+]
|
||||
// float x,y,z // repeat by number of vertices in original geometry
|
||||
M_ANIMATION_POSE_KEYFRAME = 0xD112,
|
||||
// float time
|
||||
M_ANIMATION_POSE_REF = 0xD113, // repeat for number of referenced poses
|
||||
// unsigned short poseIndex
|
||||
// float influence
|
||||
// Optional submesh extreme vertex list chink
|
||||
M_TABLE_EXTREMES = 0xE000
|
||||
// unsigned short submesh_index;
|
||||
// float extremes [n_extremes][3];
|
||||
};
|
||||
|
||||
/*
|
||||
static std::string MeshHeaderToString(MeshChunkId id)
|
||||
{
|
||||
switch(id)
|
||||
{
|
||||
case M_HEADER: return "HEADER";
|
||||
case M_MESH: return "MESH";
|
||||
case M_SUBMESH: return "SUBMESH";
|
||||
case M_SUBMESH_OPERATION: return "SUBMESH_OPERATION";
|
||||
case M_SUBMESH_BONE_ASSIGNMENT: return "SUBMESH_BONE_ASSIGNMENT";
|
||||
case M_SUBMESH_TEXTURE_ALIAS: return "SUBMESH_TEXTURE_ALIAS";
|
||||
case M_GEOMETRY: return "GEOMETRY";
|
||||
case M_GEOMETRY_VERTEX_DECLARATION: return "GEOMETRY_VERTEX_DECLARATION";
|
||||
case M_GEOMETRY_VERTEX_ELEMENT: return "GEOMETRY_VERTEX_ELEMENT";
|
||||
case M_GEOMETRY_VERTEX_BUFFER: return "GEOMETRY_VERTEX_BUFFER";
|
||||
case M_GEOMETRY_VERTEX_BUFFER_DATA: return "GEOMETRY_VERTEX_BUFFER_DATA";
|
||||
case M_MESH_SKELETON_LINK: return "MESH_SKELETON_LINK";
|
||||
case M_MESH_BONE_ASSIGNMENT: return "MESH_BONE_ASSIGNMENT";
|
||||
case M_MESH_LOD: return "MESH_LOD";
|
||||
case M_MESH_LOD_USAGE: return "MESH_LOD_USAGE";
|
||||
case M_MESH_LOD_MANUAL: return "MESH_LOD_MANUAL";
|
||||
case M_MESH_LOD_GENERATED: return "MESH_LOD_GENERATED";
|
||||
case M_MESH_BOUNDS: return "MESH_BOUNDS";
|
||||
case M_SUBMESH_NAME_TABLE: return "SUBMESH_NAME_TABLE";
|
||||
case M_SUBMESH_NAME_TABLE_ELEMENT: return "SUBMESH_NAME_TABLE_ELEMENT";
|
||||
case M_EDGE_LISTS: return "EDGE_LISTS";
|
||||
case M_EDGE_LIST_LOD: return "EDGE_LIST_LOD";
|
||||
case M_EDGE_GROUP: return "EDGE_GROUP";
|
||||
case M_POSES: return "POSES";
|
||||
case M_POSE: return "POSE";
|
||||
case M_POSE_VERTEX: return "POSE_VERTEX";
|
||||
case M_ANIMATIONS: return "ANIMATIONS";
|
||||
case M_ANIMATION: return "ANIMATION";
|
||||
case M_ANIMATION_BASEINFO: return "ANIMATION_BASEINFO";
|
||||
case M_ANIMATION_TRACK: return "ANIMATION_TRACK";
|
||||
case M_ANIMATION_MORPH_KEYFRAME: return "ANIMATION_MORPH_KEYFRAME";
|
||||
case M_ANIMATION_POSE_KEYFRAME: return "ANIMATION_POSE_KEYFRAME";
|
||||
case M_ANIMATION_POSE_REF: return "ANIMATION_POSE_REF";
|
||||
case M_TABLE_EXTREMES: return "TABLE_EXTREMES";
|
||||
}
|
||||
return "Unknown_MeshChunkId";
|
||||
}
|
||||
*/
|
||||
|
||||
enum SkeletonChunkId {
|
||||
SKELETON_HEADER = 0x1000,
|
||||
// char* version : Version number check
|
||||
SKELETON_BLENDMODE = 0x1010, // optional
|
||||
// unsigned short blendmode : SkeletonAnimationBlendMode
|
||||
SKELETON_BONE = 0x2000,
|
||||
// Repeating section defining each bone in the system.
|
||||
// Bones are assigned indexes automatically based on their order of declaration
|
||||
// starting with 0.
|
||||
// char* name : name of the bone
|
||||
// unsigned short handle : handle of the bone, should be contiguous & start at 0
|
||||
// Vector3 position : position of this bone relative to parent
|
||||
// Quaternion orientation : orientation of this bone relative to parent
|
||||
// Vector3 scale : scale of this bone relative to parent
|
||||
SKELETON_BONE_PARENT = 0x3000,
|
||||
// Record of the parent of a single bone, used to build the node tree
|
||||
// Repeating section, listed in Bone Index order, one per Bone
|
||||
// unsigned short handle : child bone
|
||||
// unsigned short parentHandle : parent bone
|
||||
SKELETON_ANIMATION = 0x4000,
|
||||
// A single animation for this skeleton
|
||||
// char* name : Name of the animation
|
||||
// float length : Length of the animation in seconds
|
||||
SKELETON_ANIMATION_BASEINFO = 0x4010,
|
||||
// [Optional] base keyframe information
|
||||
// char* baseAnimationName (blank for self)
|
||||
// float baseKeyFrameTime
|
||||
SKELETON_ANIMATION_TRACK = 0x4100,
|
||||
// A single animation track (relates to a single bone)
|
||||
// Repeating section (within SKELETON_ANIMATION)
|
||||
// unsigned short boneIndex : Index of bone to apply to
|
||||
SKELETON_ANIMATION_TRACK_KEYFRAME = 0x4110,
|
||||
// A single keyframe within the track
|
||||
// Repeating section
|
||||
// float time : The time position (seconds)
|
||||
// Quaternion rotate : Rotation to apply at this keyframe
|
||||
// Vector3 translate : Translation to apply at this keyframe
|
||||
// Vector3 scale : Scale to apply at this keyframe
|
||||
SKELETON_ANIMATION_LINK = 0x5000
|
||||
// Link to another skeleton, to re-use its animations
|
||||
// char* skeletonName : name of skeleton to get animations from
|
||||
// float scale : scale to apply to trans/scale keys
|
||||
};
|
||||
|
||||
/*
|
||||
static std::string SkeletonHeaderToString(SkeletonChunkId id)
|
||||
{
|
||||
switch(id)
|
||||
{
|
||||
case SKELETON_HEADER: return "HEADER";
|
||||
case SKELETON_BLENDMODE: return "BLENDMODE";
|
||||
case SKELETON_BONE: return "BONE";
|
||||
case SKELETON_BONE_PARENT: return "BONE_PARENT";
|
||||
case SKELETON_ANIMATION: return "ANIMATION";
|
||||
case SKELETON_ANIMATION_BASEINFO: return "ANIMATION_BASEINFO";
|
||||
case SKELETON_ANIMATION_TRACK: return "ANIMATION_TRACK";
|
||||
case SKELETON_ANIMATION_TRACK_KEYFRAME: return "ANIMATION_TRACK_KEYFRAME";
|
||||
case SKELETON_ANIMATION_LINK: return "ANIMATION_LINK";
|
||||
}
|
||||
return "Unknown_SkeletonChunkId";
|
||||
}
|
||||
*/
|
||||
} // namespace Ogre
|
||||
} // namespace Assimp
|
||||
|
||||
#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER
|
||||
#endif // AI_OGREBINARYSERIALIZER_H_INC
|
||||
135
Engine/lib/assimp/code/AssetLib/Ogre/OgreImporter.cpp
Normal file
135
Engine/lib/assimp/code/AssetLib/Ogre/OgreImporter.cpp
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
|
||||
|
||||
#include "OgreImporter.h"
|
||||
#include "OgreBinarySerializer.h"
|
||||
#include "OgreXmlSerializer.h"
|
||||
#include <assimp/importerdesc.h>
|
||||
#include <assimp/Importer.hpp>
|
||||
#include <memory>
|
||||
|
||||
static const aiImporterDesc desc = {
|
||||
"Ogre3D Mesh Importer",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportBinaryFlavour,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
"mesh mesh.xml"
|
||||
};
|
||||
|
||||
namespace Assimp {
|
||||
namespace Ogre {
|
||||
|
||||
const aiImporterDesc *OgreImporter::GetInfo() const {
|
||||
return &desc;
|
||||
}
|
||||
|
||||
void OgreImporter::SetupProperties(const Importer *pImp) {
|
||||
m_userDefinedMaterialLibFile = pImp->GetPropertyString(AI_CONFIG_IMPORT_OGRE_MATERIAL_FILE, "Scene.material");
|
||||
m_detectTextureTypeFromFilename = pImp->GetPropertyBool(AI_CONFIG_IMPORT_OGRE_TEXTURETYPE_FROM_FILENAME, false);
|
||||
}
|
||||
|
||||
bool OgreImporter::CanRead(const std::string &pFile, Assimp::IOSystem *pIOHandler, bool /*checkSig*/) const {
|
||||
if (EndsWith(pFile, ".mesh.xml", false)) {
|
||||
static const char *tokens[] = { "<mesh>" };
|
||||
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
|
||||
}
|
||||
|
||||
/// @todo Read and validate first header chunk?
|
||||
return EndsWith(pFile, ".mesh", false);
|
||||
}
|
||||
|
||||
void OgreImporter::InternReadFile(const std::string &pFile, aiScene *pScene, Assimp::IOSystem *pIOHandler) {
|
||||
// Open source file
|
||||
IOStream *f = pIOHandler->Open(pFile, "rb");
|
||||
if (!f) {
|
||||
throw DeadlyImportError("Failed to open file ", pFile);
|
||||
}
|
||||
|
||||
// Binary .mesh import
|
||||
if (EndsWith(pFile, ".mesh", false)) {
|
||||
/// @note MemoryStreamReader takes ownership of f.
|
||||
MemoryStreamReader reader(f);
|
||||
|
||||
// Import mesh
|
||||
std::unique_ptr<Mesh> mesh(OgreBinarySerializer::ImportMesh(&reader));
|
||||
|
||||
// Import skeleton
|
||||
OgreBinarySerializer::ImportSkeleton(pIOHandler, mesh.get());
|
||||
|
||||
// Import mesh referenced materials
|
||||
ReadMaterials(pFile, pIOHandler, pScene, mesh.get());
|
||||
|
||||
// Convert to Assimp
|
||||
mesh->ConvertToAssimpScene(pScene);
|
||||
return;
|
||||
}
|
||||
// XML .mesh.xml import
|
||||
/// @note XmlReader does not take ownership of f, hence the scoped ptr.
|
||||
std::unique_ptr<IOStream> scopedFile(f);
|
||||
XmlParser xmlParser;
|
||||
|
||||
//std::unique_ptr<CIrrXML_IOStreamReader> xmlStream(new CIrrXML_IOStreamReader(scopedFile.get()));
|
||||
//std::unique_ptr<XmlReader> reader(irr::io::createIrrXMLReader(xmlStream.get()));
|
||||
xmlParser.parse(scopedFile.get());
|
||||
// Import mesh
|
||||
std::unique_ptr<MeshXml> mesh(OgreXmlSerializer::ImportMesh(&xmlParser));
|
||||
|
||||
// Import skeleton
|
||||
OgreXmlSerializer::ImportSkeleton(pIOHandler, mesh.get());
|
||||
|
||||
// Import mesh referenced materials
|
||||
ReadMaterials(pFile, pIOHandler, pScene, mesh.get());
|
||||
|
||||
// Convert to Assimp
|
||||
mesh->ConvertToAssimpScene(pScene);
|
||||
}
|
||||
|
||||
} // namespace Ogre
|
||||
} // namespace Assimp
|
||||
|
||||
#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER
|
||||
98
Engine/lib/assimp/code/AssetLib/Ogre/OgreImporter.h
Normal file
98
Engine/lib/assimp/code/AssetLib/Ogre/OgreImporter.h
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
#pragma once
|
||||
#ifndef AI_OGREIMPORTER_H_INC
|
||||
#define AI_OGREIMPORTER_H_INC
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
|
||||
|
||||
#include <assimp/BaseImporter.h>
|
||||
#include <assimp/material.h>
|
||||
|
||||
#include "OgreParsingUtils.h"
|
||||
#include "OgreStructs.h"
|
||||
|
||||
namespace Assimp {
|
||||
namespace Ogre {
|
||||
|
||||
/** Importer for Ogre mesh, skeleton and material formats.
|
||||
@todo Support vertex colors.
|
||||
@todo Support poses/animations from the mesh file.
|
||||
Currently only skeleton file animations are supported. */
|
||||
class OgreImporter : public BaseImporter {
|
||||
public:
|
||||
/// BaseImporter override.
|
||||
virtual bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const override;
|
||||
|
||||
protected:
|
||||
/// BaseImporter override.
|
||||
virtual void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) override;
|
||||
|
||||
/// BaseImporter override.
|
||||
virtual const aiImporterDesc *GetInfo() const override;
|
||||
|
||||
/// BaseImporter override.
|
||||
virtual void SetupProperties(const Importer *pImp) override;
|
||||
|
||||
private:
|
||||
/// Read materials referenced by the @c mesh to @c pScene.
|
||||
void ReadMaterials(const std::string &pFile, Assimp::IOSystem *pIOHandler, aiScene *pScene, Mesh *mesh);
|
||||
void ReadMaterials(const std::string &pFile, Assimp::IOSystem *pIOHandler, aiScene *pScene, MeshXml *mesh);
|
||||
void AssignMaterials(aiScene *pScene, std::vector<aiMaterial *> &materials);
|
||||
|
||||
/// Reads material
|
||||
aiMaterial *ReadMaterial(const std::string &pFile, Assimp::IOSystem *pIOHandler, const std::string &MaterialName);
|
||||
|
||||
// These functions parse blocks from a material file from @c ss. Starting parsing from "{" and ending it to "}".
|
||||
bool ReadTechnique(const std::string &techniqueName, std::stringstream &ss, aiMaterial *material);
|
||||
bool ReadPass(const std::string &passName, std::stringstream &ss, aiMaterial *material);
|
||||
bool ReadTextureUnit(const std::string &textureUnitName, std::stringstream &ss, aiMaterial *material);
|
||||
|
||||
private:
|
||||
std::string m_userDefinedMaterialLibFile;
|
||||
bool m_detectTextureTypeFromFilename;
|
||||
std::map<aiTextureType, unsigned int> m_textures;
|
||||
};
|
||||
} // namespace Ogre
|
||||
} // namespace Assimp
|
||||
|
||||
#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER
|
||||
#endif // AI_OGREIMPORTER_H_INC
|
||||
500
Engine/lib/assimp/code/AssetLib/Ogre/OgreMaterial.cpp
Normal file
500
Engine/lib/assimp/code/AssetLib/Ogre/OgreMaterial.cpp
Normal file
|
|
@ -0,0 +1,500 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
|
||||
|
||||
#include "OgreImporter.h"
|
||||
#include <assimp/StringUtils.h>
|
||||
#include <assimp/TinyFormatter.h>
|
||||
#include <assimp/fast_atof.h>
|
||||
#include <assimp/material.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Assimp {
|
||||
namespace Ogre {
|
||||
|
||||
static const string partComment = "//";
|
||||
static const string partBlockStart = "{";
|
||||
static const string partBlockEnd = "}";
|
||||
|
||||
void OgreImporter::ReadMaterials(const std::string &pFile, Assimp::IOSystem *pIOHandler, aiScene *pScene, Mesh *mesh) {
|
||||
std::vector<aiMaterial *> materials;
|
||||
|
||||
// Create materials that can be found and parsed via the IOSystem.
|
||||
for (size_t i = 0, len = mesh->NumSubMeshes(); i < len; ++i) {
|
||||
SubMesh *submesh = mesh->GetSubMesh(i);
|
||||
if (submesh && !submesh->materialRef.empty()) {
|
||||
aiMaterial *material = ReadMaterial(pFile, pIOHandler, submesh->materialRef);
|
||||
if (material) {
|
||||
submesh->materialIndex = static_cast<int>(materials.size());
|
||||
materials.push_back(material);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AssignMaterials(pScene, materials);
|
||||
}
|
||||
|
||||
void OgreImporter::ReadMaterials(const std::string &pFile, Assimp::IOSystem *pIOHandler, aiScene *pScene, MeshXml *mesh) {
|
||||
std::vector<aiMaterial *> materials;
|
||||
|
||||
// Create materials that can be found and parsed via the IOSystem.
|
||||
for (size_t i = 0, len = mesh->NumSubMeshes(); i < len; ++i) {
|
||||
SubMeshXml *submesh = mesh->GetSubMesh(static_cast<uint16_t>(i));
|
||||
if (submesh && !submesh->materialRef.empty()) {
|
||||
aiMaterial *material = ReadMaterial(pFile, pIOHandler, submesh->materialRef);
|
||||
if (material) {
|
||||
submesh->materialIndex = static_cast<int>(materials.size());
|
||||
materials.push_back(material);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AssignMaterials(pScene, materials);
|
||||
}
|
||||
|
||||
void OgreImporter::AssignMaterials(aiScene *pScene, std::vector<aiMaterial *> &materials) {
|
||||
pScene->mNumMaterials = static_cast<unsigned int>(materials.size());
|
||||
if (pScene->mNumMaterials > 0) {
|
||||
pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials];
|
||||
for (size_t i = 0; i < pScene->mNumMaterials; ++i) {
|
||||
pScene->mMaterials[i] = materials[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
aiMaterial *OgreImporter::ReadMaterial(const std::string &pFile, Assimp::IOSystem *pIOHandler, const std::string &materialName) {
|
||||
if (materialName.empty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Full reference and examples of Ogre Material Script
|
||||
// can be found from http://www.ogre3d.org/docs/manual/manual_14.html
|
||||
|
||||
/*and here is another one:
|
||||
|
||||
import * from abstract_base_passes_depth.material
|
||||
import * from abstract_base.material
|
||||
import * from mat_shadow_caster.material
|
||||
import * from mat_character_singlepass.material
|
||||
|
||||
material hero/hair/caster : mat_shadow_caster_skin_areject
|
||||
{
|
||||
set $diffuse_map "hero_hair_alpha_c.dds"
|
||||
}
|
||||
|
||||
material hero/hair_alpha : mat_char_cns_singlepass_areject_4weights
|
||||
{
|
||||
set $diffuse_map "hero_hair_alpha_c.dds"
|
||||
set $specular_map "hero_hair_alpha_s.dds"
|
||||
set $normal_map "hero_hair_alpha_n.dds"
|
||||
set $light_map "black_lightmap.dds"
|
||||
|
||||
set $shadow_caster_material "hero/hair/caster"
|
||||
}
|
||||
*/
|
||||
|
||||
stringstream ss;
|
||||
|
||||
// Scope for scopre_ptr auto release
|
||||
{
|
||||
/* There are three .material options in priority order:
|
||||
1) File with the material name (materialName)
|
||||
2) File with the mesh files base name (pFile)
|
||||
3) Optional user defined material library file (m_userDefinedMaterialLibFile) */
|
||||
std::vector<string> potentialFiles;
|
||||
potentialFiles.push_back(materialName + ".material");
|
||||
potentialFiles.push_back(pFile.substr(0, pFile.rfind(".mesh")) + ".material");
|
||||
if (!m_userDefinedMaterialLibFile.empty())
|
||||
potentialFiles.push_back(m_userDefinedMaterialLibFile);
|
||||
|
||||
IOStream *materialFile = 0;
|
||||
for (size_t i = 0; i < potentialFiles.size(); ++i) {
|
||||
materialFile = pIOHandler->Open(potentialFiles[i]);
|
||||
if (materialFile) {
|
||||
break;
|
||||
}
|
||||
ASSIMP_LOG_VERBOSE_DEBUG("Source file for material '", materialName, "' ", potentialFiles[i], " does not exist");
|
||||
}
|
||||
if (!materialFile) {
|
||||
ASSIMP_LOG_ERROR("Failed to find source file for material '", materialName, "'");
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::unique_ptr<IOStream> stream(materialFile);
|
||||
if (stream->FileSize() == 0) {
|
||||
ASSIMP_LOG_WARN("Source file for material '", materialName, "' is empty (size is 0 bytes)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Read bytes
|
||||
vector<char> data(stream->FileSize());
|
||||
stream->Read(&data[0], stream->FileSize(), 1);
|
||||
|
||||
// Convert to UTF-8 and terminate the string for ss
|
||||
BaseImporter::ConvertToUTF8(data);
|
||||
data.push_back('\0');
|
||||
|
||||
ss << &data[0];
|
||||
}
|
||||
|
||||
ASSIMP_LOG_VERBOSE_DEBUG("Reading material '", materialName, "'");
|
||||
|
||||
aiMaterial *material = new aiMaterial();
|
||||
m_textures.clear();
|
||||
|
||||
aiString matName(materialName);
|
||||
material->AddProperty(&matName, AI_MATKEY_NAME);
|
||||
|
||||
// The stringstream will push words from a line until newline.
|
||||
// It will also trim whitespace from line start and between words.
|
||||
string linePart;
|
||||
ss >> linePart;
|
||||
|
||||
const string partMaterial = "material";
|
||||
const string partTechnique = "technique";
|
||||
|
||||
while (!ss.eof()) {
|
||||
// Skip commented lines
|
||||
if (linePart == partComment) {
|
||||
NextAfterNewLine(ss, linePart);
|
||||
continue;
|
||||
}
|
||||
if (linePart != partMaterial) {
|
||||
ss >> linePart;
|
||||
continue;
|
||||
}
|
||||
|
||||
ss >> linePart;
|
||||
if (linePart != materialName) {
|
||||
ss >> linePart;
|
||||
continue;
|
||||
}
|
||||
|
||||
NextAfterNewLine(ss, linePart);
|
||||
if (linePart != partBlockStart) {
|
||||
ASSIMP_LOG_ERROR("Invalid material: block start missing near index ", ss.tellg());
|
||||
return material;
|
||||
}
|
||||
|
||||
ASSIMP_LOG_VERBOSE_DEBUG("material '", materialName, "'");
|
||||
|
||||
while (linePart != partBlockEnd) {
|
||||
// Proceed to the first technique
|
||||
ss >> linePart;
|
||||
|
||||
if (linePart == partTechnique) {
|
||||
std::string techniqueName = SkipLine(ss);
|
||||
ReadTechnique(ai_trim(techniqueName), ss, material);
|
||||
}
|
||||
|
||||
// Read information from a custom material
|
||||
/** @todo This "set $x y" does not seem to be a official Ogre material system feature.
|
||||
Materials can inherit other materials and override texture units by using the (unique)
|
||||
parent texture unit name in your cloned material.
|
||||
This is not yet supported and below code is probably some hack from the original
|
||||
author of this Ogre importer. Should be removed? */
|
||||
if (linePart == "set") {
|
||||
ss >> linePart;
|
||||
if (linePart == "$specular") //todo load this values:
|
||||
{
|
||||
} else if (linePart == "$diffuse") {
|
||||
} else if (linePart == "$ambient") {
|
||||
} else if (linePart == "$colormap") {
|
||||
ss >> linePart;
|
||||
aiString cm(linePart);
|
||||
material->AddProperty(&cm, AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE, 0));
|
||||
} else if (linePart == "$normalmap") {
|
||||
ss >> linePart;
|
||||
aiString nm(linePart);
|
||||
material->AddProperty(&nm, AI_MATKEY_TEXTURE(aiTextureType_NORMALS, 0));
|
||||
} else if (linePart == "$shininess_strength") {
|
||||
ss >> linePart;
|
||||
float Shininess = fast_atof(linePart.c_str());
|
||||
material->AddProperty(&Shininess, 1, AI_MATKEY_SHININESS_STRENGTH);
|
||||
} else if (linePart == "$shininess_exponent") {
|
||||
ss >> linePart;
|
||||
float Shininess = fast_atof(linePart.c_str());
|
||||
material->AddProperty(&Shininess, 1, AI_MATKEY_SHININESS);
|
||||
}
|
||||
//Properties from Venetica:
|
||||
else if (linePart == "$diffuse_map") {
|
||||
ss >> linePart;
|
||||
if (linePart[0] == '"') // "file" -> file
|
||||
linePart = linePart.substr(1, linePart.size() - 2);
|
||||
aiString ts(linePart);
|
||||
material->AddProperty(&ts, AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE, 0));
|
||||
} else if (linePart == "$specular_map") {
|
||||
ss >> linePart;
|
||||
if (linePart[0] == '"') // "file" -> file
|
||||
linePart = linePart.substr(1, linePart.size() - 2);
|
||||
aiString ts(linePart);
|
||||
material->AddProperty(&ts, AI_MATKEY_TEXTURE(aiTextureType_SHININESS, 0));
|
||||
} else if (linePart == "$normal_map") {
|
||||
ss >> linePart;
|
||||
if (linePart[0] == '"') // "file" -> file
|
||||
linePart = linePart.substr(1, linePart.size() - 2);
|
||||
aiString ts(linePart);
|
||||
material->AddProperty(&ts, AI_MATKEY_TEXTURE(aiTextureType_NORMALS, 0));
|
||||
} else if (linePart == "$light_map") {
|
||||
ss >> linePart;
|
||||
if (linePart[0] == '"') {
|
||||
linePart = linePart.substr(1, linePart.size() - 2);
|
||||
}
|
||||
aiString ts(linePart);
|
||||
material->AddProperty(&ts, AI_MATKEY_TEXTURE(aiTextureType_LIGHTMAP, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
ss >> linePart;
|
||||
}
|
||||
|
||||
return material;
|
||||
}
|
||||
|
||||
bool OgreImporter::ReadTechnique(const std::string &techniqueName, stringstream &ss, aiMaterial *material) {
|
||||
string linePart;
|
||||
ss >> linePart;
|
||||
|
||||
if (linePart != partBlockStart) {
|
||||
ASSIMP_LOG_ERROR("Invalid material: Technique block start missing near index ", ss.tellg());
|
||||
return false;
|
||||
}
|
||||
|
||||
ASSIMP_LOG_VERBOSE_DEBUG(" technique '", techniqueName, "'");
|
||||
|
||||
const string partPass = "pass";
|
||||
|
||||
while (linePart != partBlockEnd) {
|
||||
ss >> linePart;
|
||||
|
||||
// Skip commented lines
|
||||
if (linePart == partComment) {
|
||||
SkipLine(ss);
|
||||
continue;
|
||||
}
|
||||
|
||||
/// @todo Techniques have other attributes than just passes.
|
||||
if (linePart == partPass) {
|
||||
string passName = SkipLine(ss);
|
||||
ReadPass(ai_trim(passName), ss, material);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OgreImporter::ReadPass(const std::string &passName, stringstream &ss, aiMaterial *material) {
|
||||
string linePart;
|
||||
ss >> linePart;
|
||||
|
||||
if (linePart != partBlockStart) {
|
||||
ASSIMP_LOG_ERROR("Invalid material: Pass block start missing near index ", ss.tellg());
|
||||
return false;
|
||||
}
|
||||
|
||||
ASSIMP_LOG_VERBOSE_DEBUG(" pass '", passName, "'");
|
||||
|
||||
const string partAmbient = "ambient";
|
||||
const string partDiffuse = "diffuse";
|
||||
const string partSpecular = "specular";
|
||||
const string partEmissive = "emissive";
|
||||
const string partTextureUnit = "texture_unit";
|
||||
|
||||
while (linePart != partBlockEnd) {
|
||||
ss >> linePart;
|
||||
|
||||
// Skip commented lines
|
||||
if (linePart == partComment) {
|
||||
SkipLine(ss);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Colors
|
||||
/// @todo Support alpha via aiColor4D.
|
||||
if (linePart == partAmbient || linePart == partDiffuse || linePart == partSpecular || linePart == partEmissive) {
|
||||
float r, g, b;
|
||||
ss >> r >> g >> b;
|
||||
const aiColor3D color(r, g, b);
|
||||
|
||||
ASSIMP_LOG_VERBOSE_DEBUG(" ", linePart, " ", r, " ", g, " ", b);
|
||||
|
||||
if (linePart == partAmbient) {
|
||||
material->AddProperty(&color, 1, AI_MATKEY_COLOR_AMBIENT);
|
||||
} else if (linePart == partDiffuse) {
|
||||
material->AddProperty(&color, 1, AI_MATKEY_COLOR_DIFFUSE);
|
||||
} else if (linePart == partSpecular) {
|
||||
material->AddProperty(&color, 1, AI_MATKEY_COLOR_SPECULAR);
|
||||
} else if (linePart == partEmissive) {
|
||||
material->AddProperty(&color, 1, AI_MATKEY_COLOR_EMISSIVE);
|
||||
}
|
||||
} else if (linePart == partTextureUnit) {
|
||||
string textureUnitName = SkipLine(ss);
|
||||
ReadTextureUnit(ai_trim(textureUnitName), ss, material);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OgreImporter::ReadTextureUnit(const std::string &textureUnitName, stringstream &ss, aiMaterial *material) {
|
||||
string linePart;
|
||||
ss >> linePart;
|
||||
|
||||
if (linePart != partBlockStart) {
|
||||
ASSIMP_LOG_ERROR("Invalid material: Texture unit block start missing near index ", ss.tellg());
|
||||
return false;
|
||||
}
|
||||
|
||||
ASSIMP_LOG_VERBOSE_DEBUG(" texture_unit '", textureUnitName, "'");
|
||||
|
||||
const string partTexture = "texture";
|
||||
const string partTextCoordSet = "tex_coord_set";
|
||||
const string partColorOp = "colour_op";
|
||||
|
||||
aiTextureType textureType = aiTextureType_NONE;
|
||||
std::string textureRef;
|
||||
int uvCoord = 0;
|
||||
|
||||
while (linePart != partBlockEnd) {
|
||||
ss >> linePart;
|
||||
|
||||
// Skip commented lines
|
||||
if (linePart == partComment) {
|
||||
SkipLine(ss);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (linePart == partTexture) {
|
||||
ss >> linePart;
|
||||
textureRef = linePart;
|
||||
|
||||
// User defined Assimp config property to detect texture type from filename.
|
||||
if (m_detectTextureTypeFromFilename) {
|
||||
size_t posSuffix = textureRef.find_last_of('.');
|
||||
size_t posUnderscore = textureRef.find_last_of('_');
|
||||
|
||||
if (posSuffix != string::npos && posUnderscore != string::npos && posSuffix > posUnderscore) {
|
||||
string identifier = ai_tolower(textureRef.substr(posUnderscore, posSuffix - posUnderscore));
|
||||
ASSIMP_LOG_VERBOSE_DEBUG("Detecting texture type from filename postfix '", identifier, "'");
|
||||
|
||||
if (identifier == "_n" || identifier == "_nrm" || identifier == "_nrml" || identifier == "_normal" || identifier == "_normals" || identifier == "_normalmap") {
|
||||
textureType = aiTextureType_NORMALS;
|
||||
} else if (identifier == "_s" || identifier == "_spec" || identifier == "_specular" || identifier == "_specularmap") {
|
||||
textureType = aiTextureType_SPECULAR;
|
||||
} else if (identifier == "_l" || identifier == "_light" || identifier == "_lightmap" || identifier == "_occ" || identifier == "_occlusion") {
|
||||
textureType = aiTextureType_LIGHTMAP;
|
||||
} else if (identifier == "_disp" || identifier == "_displacement") {
|
||||
textureType = aiTextureType_DISPLACEMENT;
|
||||
} else {
|
||||
textureType = aiTextureType_DIFFUSE;
|
||||
}
|
||||
} else {
|
||||
textureType = aiTextureType_DIFFUSE;
|
||||
}
|
||||
}
|
||||
// Detect from texture unit name. This cannot be too broad as
|
||||
// authors might give names like "LightSaber" or "NormalNinja".
|
||||
else {
|
||||
string unitNameLower = ai_tolower(textureUnitName);
|
||||
if (unitNameLower.find("normalmap") != string::npos) {
|
||||
textureType = aiTextureType_NORMALS;
|
||||
} else if (unitNameLower.find("specularmap") != string::npos) {
|
||||
textureType = aiTextureType_SPECULAR;
|
||||
} else if (unitNameLower.find("lightmap") != string::npos) {
|
||||
textureType = aiTextureType_LIGHTMAP;
|
||||
} else if (unitNameLower.find("displacementmap") != string::npos) {
|
||||
textureType = aiTextureType_DISPLACEMENT;
|
||||
} else {
|
||||
textureType = aiTextureType_DIFFUSE;
|
||||
}
|
||||
}
|
||||
} else if (linePart == partTextCoordSet) {
|
||||
ss >> uvCoord;
|
||||
}
|
||||
/// @todo Implement
|
||||
else if (linePart == partColorOp) {
|
||||
/*
|
||||
ss >> linePart;
|
||||
if("replace"==linePart)//I don't think, assimp has something for this...
|
||||
{
|
||||
}
|
||||
else if("modulate"==linePart)
|
||||
{
|
||||
//TODO: set value
|
||||
//material->AddProperty(aiTextureOp_Multiply)
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
if (textureRef.empty()) {
|
||||
ASSIMP_LOG_WARN("Texture reference is empty, ignoring texture_unit.");
|
||||
return false;
|
||||
}
|
||||
if (textureType == aiTextureType_NONE) {
|
||||
ASSIMP_LOG_WARN("Failed to detect texture type for '", textureRef, "', ignoring texture_unit.");
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int textureTypeIndex = m_textures[textureType];
|
||||
m_textures[textureType]++;
|
||||
|
||||
ASSIMP_LOG_VERBOSE_DEBUG(" texture '", textureRef, "' type ", textureType,
|
||||
" index ", textureTypeIndex, " UV ", uvCoord);
|
||||
|
||||
aiString assimpTextureRef(textureRef);
|
||||
material->AddProperty(&assimpTextureRef, AI_MATKEY_TEXTURE(textureType, textureTypeIndex));
|
||||
material->AddProperty(&uvCoord, 1, AI_MATKEY_UVWSRC(textureType, textureTypeIndex));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Ogre
|
||||
} // namespace Assimp
|
||||
|
||||
#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER
|
||||
95
Engine/lib/assimp/code/AssetLib/Ogre/OgreParsingUtils.h
Normal file
95
Engine/lib/assimp/code/AssetLib/Ogre/OgreParsingUtils.h
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef AI_OGREPARSINGUTILS_H_INC
|
||||
#define AI_OGREPARSINGUTILS_H_INC
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
|
||||
|
||||
#include <assimp/ParsingUtils.h>
|
||||
#include <cstdint>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <functional>
|
||||
#include <sstream>
|
||||
|
||||
namespace Assimp {
|
||||
namespace Ogre {
|
||||
|
||||
|
||||
/// Returns if @c s ends with @c suffix. If @c caseSensitive is false, both strings will be lower cased before matching.
|
||||
static inline bool EndsWith(const std::string &s, const std::string &suffix, bool caseSensitive = true) {
|
||||
if (s.empty() || suffix.empty()) {
|
||||
return false;
|
||||
} else if (s.length() < suffix.length()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!caseSensitive) {
|
||||
return EndsWith(ai_tolower(s), ai_tolower(suffix), true);
|
||||
}
|
||||
|
||||
size_t len = suffix.length();
|
||||
std::string sSuffix = s.substr(s.length() - len, len);
|
||||
|
||||
return (ASSIMP_stricmp(sSuffix, suffix) == 0);
|
||||
}
|
||||
|
||||
// Skips a line from current @ss position until a newline. Returns the skipped part.
|
||||
static inline std::string SkipLine(std::stringstream &ss) {
|
||||
std::string skipped;
|
||||
getline(ss, skipped);
|
||||
return skipped;
|
||||
}
|
||||
|
||||
// Skips a line and reads next element from @c ss to @c nextElement.
|
||||
/** @return Skipped line content until newline. */
|
||||
static inline std::string NextAfterNewLine(std::stringstream &ss, std::string &nextElement) {
|
||||
std::string skipped = SkipLine(ss);
|
||||
ss >> nextElement;
|
||||
return skipped;
|
||||
}
|
||||
|
||||
} // namespace Ogre
|
||||
} // namespace Assimp
|
||||
|
||||
#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER
|
||||
#endif // AI_OGREPARSINGUTILS_H_INC
|
||||
1076
Engine/lib/assimp/code/AssetLib/Ogre/OgreStructs.cpp
Normal file
1076
Engine/lib/assimp/code/AssetLib/Ogre/OgreStructs.cpp
Normal file
File diff suppressed because it is too large
Load diff
696
Engine/lib/assimp/code/AssetLib/Ogre/OgreStructs.h
Normal file
696
Engine/lib/assimp/code/AssetLib/Ogre/OgreStructs.h
Normal file
|
|
@ -0,0 +1,696 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef AI_OGRESTRUCTS_H_INC
|
||||
#define AI_OGRESTRUCTS_H_INC
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
|
||||
|
||||
#include <assimp/MemoryIOWrapper.h>
|
||||
#include <memory>
|
||||
#include <assimp/mesh.h>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
||||
struct aiNodeAnim;
|
||||
struct aiAnimation;
|
||||
struct aiNode;
|
||||
struct aiMaterial;
|
||||
struct aiScene;
|
||||
|
||||
/** @note Parts of this implementation, for example enums, deserialization constants and logic
|
||||
has been copied directly with minor modifications from the MIT licensed Ogre3D code base.
|
||||
See more from https://bitbucket.org/sinbad/ogre. */
|
||||
|
||||
namespace Assimp
|
||||
{
|
||||
namespace Ogre
|
||||
{
|
||||
|
||||
// Forward decl
|
||||
class Mesh;
|
||||
class MeshXml;
|
||||
class SubMesh;
|
||||
class SubMeshXml;
|
||||
class Skeleton;
|
||||
|
||||
#define OGRE_SAFE_DELETE(p) delete p; p=0;
|
||||
|
||||
// Typedefs
|
||||
typedef Assimp::MemoryIOStream MemoryStream;
|
||||
typedef std::shared_ptr<MemoryStream> MemoryStreamPtr;
|
||||
typedef std::map<uint16_t, MemoryStreamPtr> VertexBufferBindings;
|
||||
|
||||
// Ogre Vertex Element
|
||||
class VertexElement
|
||||
{
|
||||
public:
|
||||
/// Vertex element semantics, used to identify the meaning of vertex buffer contents
|
||||
enum Semantic {
|
||||
/// Position, 3 reals per vertex
|
||||
VES_POSITION = 1,
|
||||
/// Blending weights
|
||||
VES_BLEND_WEIGHTS = 2,
|
||||
/// Blending indices
|
||||
VES_BLEND_INDICES = 3,
|
||||
/// Normal, 3 reals per vertex
|
||||
VES_NORMAL = 4,
|
||||
/// Diffuse colours
|
||||
VES_DIFFUSE = 5,
|
||||
/// Specular colours
|
||||
VES_SPECULAR = 6,
|
||||
/// Texture coordinates
|
||||
VES_TEXTURE_COORDINATES = 7,
|
||||
/// Binormal (Y axis if normal is Z)
|
||||
VES_BINORMAL = 8,
|
||||
/// Tangent (X axis if normal is Z)
|
||||
VES_TANGENT = 9,
|
||||
/// The number of VertexElementSemantic elements (note - the first value VES_POSITION is 1)
|
||||
VES_COUNT = 9
|
||||
};
|
||||
|
||||
/// Vertex element type, used to identify the base types of the vertex contents
|
||||
enum Type
|
||||
{
|
||||
VET_FLOAT1 = 0,
|
||||
VET_FLOAT2 = 1,
|
||||
VET_FLOAT3 = 2,
|
||||
VET_FLOAT4 = 3,
|
||||
/// alias to more specific colour type - use the current rendersystem's colour packing
|
||||
VET_COLOUR = 4,
|
||||
VET_SHORT1 = 5,
|
||||
VET_SHORT2 = 6,
|
||||
VET_SHORT3 = 7,
|
||||
VET_SHORT4 = 8,
|
||||
VET_UBYTE4 = 9,
|
||||
/// D3D style compact colour
|
||||
VET_COLOUR_ARGB = 10,
|
||||
/// GL style compact colour
|
||||
VET_COLOUR_ABGR = 11,
|
||||
VET_DOUBLE1 = 12,
|
||||
VET_DOUBLE2 = 13,
|
||||
VET_DOUBLE3 = 14,
|
||||
VET_DOUBLE4 = 15,
|
||||
VET_USHORT1 = 16,
|
||||
VET_USHORT2 = 17,
|
||||
VET_USHORT3 = 18,
|
||||
VET_USHORT4 = 19,
|
||||
VET_INT1 = 20,
|
||||
VET_INT2 = 21,
|
||||
VET_INT3 = 22,
|
||||
VET_INT4 = 23,
|
||||
VET_UINT1 = 24,
|
||||
VET_UINT2 = 25,
|
||||
VET_UINT3 = 26,
|
||||
VET_UINT4 = 27
|
||||
};
|
||||
|
||||
VertexElement();
|
||||
|
||||
/// Size of the vertex element in bytes.
|
||||
size_t Size() const;
|
||||
|
||||
/// Count of components in this element, eg. VET_FLOAT3 return 3.
|
||||
size_t ComponentCount() const;
|
||||
|
||||
/// Type as string.
|
||||
std::string TypeToString();
|
||||
|
||||
/// Semantic as string.
|
||||
std::string SemanticToString();
|
||||
|
||||
static size_t TypeSize(Type type);
|
||||
static size_t ComponentCount(Type type);
|
||||
static std::string TypeToString(Type type);
|
||||
static std::string SemanticToString(Semantic semantic);
|
||||
|
||||
uint16_t index;
|
||||
uint16_t source;
|
||||
uint16_t offset;
|
||||
Type type;
|
||||
Semantic semantic;
|
||||
};
|
||||
typedef std::vector<VertexElement> VertexElementList;
|
||||
|
||||
/// Ogre Vertex Bone Assignment
|
||||
struct VertexBoneAssignment
|
||||
{
|
||||
uint32_t vertexIndex;
|
||||
uint16_t boneIndex;
|
||||
float weight;
|
||||
};
|
||||
typedef std::vector<VertexBoneAssignment> VertexBoneAssignmentList;
|
||||
typedef std::map<uint32_t, VertexBoneAssignmentList > VertexBoneAssignmentsMap;
|
||||
typedef std::map<uint16_t, std::vector<aiVertexWeight> > AssimpVertexBoneWeightList;
|
||||
|
||||
// Ogre Vertex Data interface, inherited by the binary and XML implementations.
|
||||
class IVertexData
|
||||
{
|
||||
public:
|
||||
IVertexData();
|
||||
|
||||
/// Returns if bone assignments are available.
|
||||
bool HasBoneAssignments() const;
|
||||
|
||||
/// Add vertex mapping from old to new index.
|
||||
void AddVertexMapping(uint32_t oldIndex, uint32_t newIndex);
|
||||
|
||||
/// Returns re-mapped bone assignments.
|
||||
/** @note Uses mappings added via AddVertexMapping. */
|
||||
AssimpVertexBoneWeightList AssimpBoneWeights(size_t vertices);
|
||||
|
||||
/// Returns a set of bone indexes that are referenced by bone assignments (weights).
|
||||
std::set<uint16_t> ReferencedBonesByWeights() const;
|
||||
|
||||
/// Vertex count.
|
||||
uint32_t count;
|
||||
|
||||
/// Bone assignments.
|
||||
VertexBoneAssignmentList boneAssignments;
|
||||
|
||||
private:
|
||||
void BoneAssignmentsForVertex(uint32_t currentIndex, uint32_t newIndex, VertexBoneAssignmentList &dest) const;
|
||||
|
||||
std::map<uint32_t, std::vector<uint32_t> > vertexIndexMapping;
|
||||
VertexBoneAssignmentsMap boneAssignmentsMap;
|
||||
};
|
||||
|
||||
// Ogre Vertex Data
|
||||
class VertexData : public IVertexData
|
||||
{
|
||||
public:
|
||||
VertexData();
|
||||
~VertexData();
|
||||
|
||||
/// Releases all memory that this data structure owns.
|
||||
void Reset();
|
||||
|
||||
/// Get vertex size for @c source.
|
||||
uint32_t VertexSize(uint16_t source) const;
|
||||
|
||||
/// Get vertex buffer for @c source.
|
||||
MemoryStream *VertexBuffer(uint16_t source);
|
||||
|
||||
/// Get vertex element for @c semantic for @c index.
|
||||
VertexElement *GetVertexElement(VertexElement::Semantic semantic, uint16_t index = 0);
|
||||
|
||||
/// Vertex elements.
|
||||
VertexElementList vertexElements;
|
||||
|
||||
/// Vertex buffers mapped to bind index.
|
||||
VertexBufferBindings vertexBindings;
|
||||
};
|
||||
|
||||
// Ogre Index Data
|
||||
class IndexData
|
||||
{
|
||||
public:
|
||||
IndexData();
|
||||
~IndexData();
|
||||
|
||||
/// Releases all memory that this data structure owns.
|
||||
void Reset();
|
||||
|
||||
/// Index size in bytes.
|
||||
size_t IndexSize() const;
|
||||
|
||||
/// Face size in bytes.
|
||||
size_t FaceSize() const;
|
||||
|
||||
/// Index count.
|
||||
uint32_t count;
|
||||
|
||||
/// Face count.
|
||||
uint32_t faceCount;
|
||||
|
||||
/// If has 32-bit indexes.
|
||||
bool is32bit;
|
||||
|
||||
/// Index buffer.
|
||||
MemoryStreamPtr buffer;
|
||||
};
|
||||
|
||||
/// Ogre Pose
|
||||
class Pose
|
||||
{
|
||||
public:
|
||||
struct Vertex
|
||||
{
|
||||
uint32_t index;
|
||||
aiVector3D offset;
|
||||
aiVector3D normal;
|
||||
};
|
||||
typedef std::map<uint32_t, Vertex> PoseVertexMap;
|
||||
|
||||
Pose() : target(0), hasNormals(false) {}
|
||||
|
||||
/// Name.
|
||||
std::string name;
|
||||
|
||||
/// Target.
|
||||
uint16_t target;
|
||||
|
||||
/// Does vertices map have normals.
|
||||
bool hasNormals;
|
||||
|
||||
/// Vertex offset and normals.
|
||||
PoseVertexMap vertices;
|
||||
};
|
||||
typedef std::vector<Pose*> PoseList;
|
||||
|
||||
/// Ogre Pose Key Frame Ref
|
||||
struct PoseRef
|
||||
{
|
||||
uint16_t index;
|
||||
float influence;
|
||||
};
|
||||
typedef std::vector<PoseRef> PoseRefList;
|
||||
|
||||
/// Ogre Pose Key Frame
|
||||
struct PoseKeyFrame
|
||||
{
|
||||
/// Time position in the animation.
|
||||
float timePos;
|
||||
|
||||
PoseRefList references;
|
||||
};
|
||||
typedef std::vector<PoseKeyFrame> PoseKeyFrameList;
|
||||
|
||||
/// Ogre Morph Key Frame
|
||||
struct MorphKeyFrame
|
||||
{
|
||||
/// Time position in the animation.
|
||||
float timePos;
|
||||
|
||||
MemoryStreamPtr buffer;
|
||||
};
|
||||
typedef std::vector<MorphKeyFrame> MorphKeyFrameList;
|
||||
|
||||
/// Ogre animation key frame
|
||||
struct TransformKeyFrame
|
||||
{
|
||||
TransformKeyFrame();
|
||||
|
||||
aiMatrix4x4 Transform();
|
||||
|
||||
float timePos;
|
||||
|
||||
aiQuaternion rotation;
|
||||
aiVector3D position;
|
||||
aiVector3D scale;
|
||||
};
|
||||
typedef std::vector<TransformKeyFrame> TransformKeyFrameList;
|
||||
|
||||
/// Ogre Animation Track
|
||||
struct VertexAnimationTrack
|
||||
{
|
||||
enum Type
|
||||
{
|
||||
/// No animation
|
||||
VAT_NONE = 0,
|
||||
/// Morph animation is made up of many interpolated snapshot keyframes
|
||||
VAT_MORPH = 1,
|
||||
/// Pose animation is made up of a single delta pose keyframe
|
||||
VAT_POSE = 2,
|
||||
/// Keyframe that has its on pos, rot and scale for a time position
|
||||
VAT_TRANSFORM = 3
|
||||
};
|
||||
|
||||
VertexAnimationTrack();
|
||||
|
||||
/// Convert to Assimp node animation.
|
||||
aiNodeAnim *ConvertToAssimpAnimationNode(Skeleton *skeleton);
|
||||
|
||||
// Animation type.
|
||||
Type type;
|
||||
|
||||
/// Vertex data target.
|
||||
/** 0 == shared geometry
|
||||
>0 == submesh index + 1 */
|
||||
uint16_t target;
|
||||
|
||||
/// Only valid for VAT_TRANSFORM.
|
||||
std::string boneName;
|
||||
|
||||
/// Only one of these will contain key frames, depending on the type enum.
|
||||
PoseKeyFrameList poseKeyFrames;
|
||||
MorphKeyFrameList morphKeyFrames;
|
||||
TransformKeyFrameList transformKeyFrames;
|
||||
};
|
||||
typedef std::vector<VertexAnimationTrack> VertexAnimationTrackList;
|
||||
|
||||
/// Ogre Animation
|
||||
class Animation
|
||||
{
|
||||
public:
|
||||
explicit Animation(Skeleton *parent);
|
||||
explicit Animation(Mesh *parent);
|
||||
|
||||
/// Returns the associated vertex data for a track in this animation.
|
||||
/** @note Only valid to call when parent Mesh is set. */
|
||||
VertexData *AssociatedVertexData(VertexAnimationTrack *track) const;
|
||||
|
||||
/// Convert to Assimp animation.
|
||||
aiAnimation *ConvertToAssimpAnimation();
|
||||
|
||||
/// Parent mesh.
|
||||
/** @note Set only when animation is read from a mesh. */
|
||||
Mesh *parentMesh;
|
||||
|
||||
/// Parent skeleton.
|
||||
/** @note Set only when animation is read from a skeleton. */
|
||||
Skeleton *parentSkeleton;
|
||||
|
||||
/// Animation name.
|
||||
std::string name;
|
||||
|
||||
/// Base animation name.
|
||||
std::string baseName;
|
||||
|
||||
/// Length in seconds.
|
||||
float length;
|
||||
|
||||
/// Base animation key time.
|
||||
float baseTime;
|
||||
|
||||
/// Animation tracks.
|
||||
VertexAnimationTrackList tracks;
|
||||
};
|
||||
typedef std::vector<Animation*> AnimationList;
|
||||
|
||||
/// Ogre Bone
|
||||
class Bone
|
||||
{
|
||||
public:
|
||||
Bone();
|
||||
|
||||
/// Returns if this bone is parented.
|
||||
bool IsParented() const;
|
||||
|
||||
/// Parent index as uint16_t. Internally int32_t as -1 means unparented.
|
||||
uint16_t ParentId() const;
|
||||
|
||||
/// Add child bone.
|
||||
void AddChild(Bone *bone);
|
||||
|
||||
/// Calculates the world matrix for bone and its children.
|
||||
void CalculateWorldMatrixAndDefaultPose(Skeleton *skeleton);
|
||||
|
||||
/// Convert to Assimp node (animation nodes).
|
||||
aiNode *ConvertToAssimpNode(Skeleton *parent, aiNode *parentNode = 0);
|
||||
|
||||
/// Convert to Assimp bone (mesh bones).
|
||||
aiBone *ConvertToAssimpBone(Skeleton *parent, const std::vector<aiVertexWeight> &boneWeights);
|
||||
|
||||
uint16_t id;
|
||||
std::string name;
|
||||
|
||||
Bone *parent;
|
||||
int32_t parentId;
|
||||
std::vector<uint16_t> children;
|
||||
|
||||
aiVector3D position;
|
||||
aiQuaternion rotation;
|
||||
aiVector3D scale;
|
||||
|
||||
aiMatrix4x4 worldMatrix;
|
||||
aiMatrix4x4 defaultPose;
|
||||
};
|
||||
typedef std::vector<Bone*> BoneList;
|
||||
|
||||
/// Ogre Skeleton
|
||||
class Skeleton
|
||||
{
|
||||
public:
|
||||
enum BlendMode
|
||||
{
|
||||
/// Animations are applied by calculating a weighted average of all animations
|
||||
ANIMBLEND_AVERAGE = 0,
|
||||
/// Animations are applied by calculating a weighted cumulative total
|
||||
ANIMBLEND_CUMULATIVE = 1
|
||||
};
|
||||
|
||||
Skeleton();
|
||||
~Skeleton();
|
||||
|
||||
/// Releases all memory that this data structure owns.
|
||||
void Reset();
|
||||
|
||||
/// Returns unparented root bones.
|
||||
BoneList RootBones() const;
|
||||
|
||||
/// Returns number of unparented root bones.
|
||||
size_t NumRootBones() const;
|
||||
|
||||
/// Get bone by name.
|
||||
Bone *BoneByName(const std::string &name) const;
|
||||
|
||||
/// Get bone by id.
|
||||
Bone *BoneById(uint16_t id) const;
|
||||
|
||||
BoneList bones;
|
||||
AnimationList animations;
|
||||
|
||||
/// @todo Take blend mode into account, but where?
|
||||
BlendMode blendMode;
|
||||
};
|
||||
|
||||
/// Ogre Sub Mesh interface, inherited by the binary and XML implementations.
|
||||
class ISubMesh
|
||||
{
|
||||
public:
|
||||
/// @note Full list of Ogre types, not all of them are supported and exposed to Assimp.
|
||||
enum OperationType
|
||||
{
|
||||
/// A list of points, 1 vertex per point
|
||||
OT_POINT_LIST = 1,
|
||||
/// A list of lines, 2 vertices per line
|
||||
OT_LINE_LIST = 2,
|
||||
/// A strip of connected lines, 1 vertex per line plus 1 start vertex
|
||||
OT_LINE_STRIP = 3,
|
||||
/// A list of triangles, 3 vertices per triangle
|
||||
OT_TRIANGLE_LIST = 4,
|
||||
/// A strip of triangles, 3 vertices for the first triangle, and 1 per triangle after that
|
||||
OT_TRIANGLE_STRIP = 5,
|
||||
/// A fan of triangles, 3 vertices for the first triangle, and 1 per triangle after that
|
||||
OT_TRIANGLE_FAN = 6
|
||||
};
|
||||
|
||||
ISubMesh();
|
||||
|
||||
/// SubMesh index.
|
||||
unsigned int index;
|
||||
|
||||
/// SubMesh name.
|
||||
std::string name;
|
||||
|
||||
/// Material used by this submesh.
|
||||
std::string materialRef;
|
||||
|
||||
/// Texture alias information.
|
||||
std::string textureAliasName;
|
||||
std::string textureAliasRef;
|
||||
|
||||
/// Assimp scene material index used by this submesh.
|
||||
/** -1 if no material or material could not be imported. */
|
||||
int materialIndex;
|
||||
|
||||
/// If submesh uses shared geometry from parent mesh.
|
||||
bool usesSharedVertexData;
|
||||
|
||||
/// Operation type.
|
||||
OperationType operationType;
|
||||
};
|
||||
|
||||
/// Ogre SubMesh
|
||||
class SubMesh : public ISubMesh
|
||||
{
|
||||
public:
|
||||
SubMesh();
|
||||
~SubMesh();
|
||||
|
||||
/// Releases all memory that this data structure owns.
|
||||
/** @note Vertex and index data contains shared ptrs
|
||||
that are freed automatically. In practice the ref count
|
||||
should be 0 after this reset. */
|
||||
void Reset();
|
||||
|
||||
/// Convert to Assimp mesh.
|
||||
aiMesh *ConvertToAssimpMesh(Mesh *parent);
|
||||
|
||||
/// Vertex data.
|
||||
VertexData *vertexData;
|
||||
|
||||
/// Index data.
|
||||
IndexData *indexData;
|
||||
};
|
||||
typedef std::vector<SubMesh*> SubMeshList;
|
||||
|
||||
/// Ogre Mesh
|
||||
class Mesh
|
||||
{
|
||||
public:
|
||||
/// Constructor.
|
||||
Mesh();
|
||||
|
||||
/// Destructor.
|
||||
~Mesh();
|
||||
|
||||
/// Releases all memory that this data structure owns.
|
||||
void Reset();
|
||||
|
||||
/// Returns number of subMeshes.
|
||||
size_t NumSubMeshes() const;
|
||||
|
||||
/// Returns submesh for @c index.
|
||||
SubMesh *GetSubMesh( size_t index) const;
|
||||
|
||||
/// Convert mesh to Assimp scene.
|
||||
void ConvertToAssimpScene(aiScene* dest);
|
||||
|
||||
/// Mesh has skeletal animations.
|
||||
bool hasSkeletalAnimations;
|
||||
|
||||
/// Skeleton reference.
|
||||
std::string skeletonRef;
|
||||
|
||||
/// Skeleton.
|
||||
Skeleton *skeleton;
|
||||
|
||||
/// Vertex data
|
||||
VertexData *sharedVertexData;
|
||||
|
||||
/// Sub meshes.
|
||||
SubMeshList subMeshes;
|
||||
|
||||
/// Animations
|
||||
AnimationList animations;
|
||||
|
||||
/// Poses
|
||||
PoseList poses;
|
||||
};
|
||||
|
||||
/// Ogre XML Vertex Data
|
||||
class VertexDataXml : public IVertexData
|
||||
{
|
||||
public:
|
||||
VertexDataXml();
|
||||
|
||||
bool HasPositions() const;
|
||||
bool HasNormals() const;
|
||||
bool HasTangents() const;
|
||||
bool HasUvs() const;
|
||||
size_t NumUvs() const;
|
||||
|
||||
std::vector<aiVector3D> positions;
|
||||
std::vector<aiVector3D> normals;
|
||||
std::vector<aiVector3D> tangents;
|
||||
std::vector<std::vector<aiVector3D> > uvs;
|
||||
};
|
||||
|
||||
/// Ogre XML Index Data
|
||||
class IndexDataXml
|
||||
{
|
||||
public:
|
||||
IndexDataXml() : faceCount(0) {}
|
||||
|
||||
/// Face count.
|
||||
uint32_t faceCount;
|
||||
|
||||
std::vector<aiFace> faces;
|
||||
};
|
||||
|
||||
/// Ogre XML SubMesh
|
||||
class SubMeshXml : public ISubMesh
|
||||
{
|
||||
public:
|
||||
SubMeshXml();
|
||||
~SubMeshXml();
|
||||
|
||||
/// Releases all memory that this data structure owns.
|
||||
void Reset();
|
||||
|
||||
aiMesh *ConvertToAssimpMesh(MeshXml *parent);
|
||||
|
||||
IndexDataXml *indexData;
|
||||
VertexDataXml *vertexData;
|
||||
};
|
||||
typedef std::vector<SubMeshXml*> SubMeshXmlList;
|
||||
|
||||
/// Ogre XML Mesh
|
||||
class MeshXml
|
||||
{
|
||||
public:
|
||||
MeshXml();
|
||||
~MeshXml();
|
||||
|
||||
/// Releases all memory that this data structure owns.
|
||||
void Reset();
|
||||
|
||||
/// Returns number of subMeshes.
|
||||
size_t NumSubMeshes() const;
|
||||
|
||||
/// Returns submesh for @c index.
|
||||
SubMeshXml *GetSubMesh(uint16_t index) const;
|
||||
|
||||
/// Convert mesh to Assimp scene.
|
||||
void ConvertToAssimpScene(aiScene* dest);
|
||||
|
||||
/// Skeleton reference.
|
||||
std::string skeletonRef;
|
||||
|
||||
/// Skeleton.
|
||||
Skeleton *skeleton;
|
||||
|
||||
/// Vertex data
|
||||
VertexDataXml *sharedVertexData;
|
||||
|
||||
/// Sub meshes.
|
||||
SubMeshXmlList subMeshes;
|
||||
};
|
||||
|
||||
} // Ogre
|
||||
} // Assimp
|
||||
|
||||
#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER
|
||||
#endif // AI_OGRESTRUCTS_H_INC
|
||||
755
Engine/lib/assimp/code/AssetLib/Ogre/OgreXmlSerializer.cpp
Normal file
755
Engine/lib/assimp/code/AssetLib/Ogre/OgreXmlSerializer.cpp
Normal file
|
|
@ -0,0 +1,755 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "OgreXmlSerializer.h"
|
||||
#include "OgreBinarySerializer.h"
|
||||
#include "OgreParsingUtils.h"
|
||||
|
||||
#include <assimp/TinyFormatter.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
|
||||
|
||||
// Define as 1 to get verbose logging.
|
||||
#define OGRE_XML_SERIALIZER_DEBUG 0
|
||||
|
||||
namespace Assimp {
|
||||
namespace Ogre {
|
||||
|
||||
//AI_WONT_RETURN void ThrowAttibuteError(const XmlParser *reader, const std::string &name, const std::string &error = "") AI_WONT_RETURN_SUFFIX;
|
||||
|
||||
AI_WONT_RETURN void ThrowAttibuteError(const std::string &nodeName, const std::string &name, const std::string &error) {
|
||||
if (!error.empty()) {
|
||||
throw DeadlyImportError(error, " in node '", nodeName, "' and attribute '", name, "'");
|
||||
} else {
|
||||
throw DeadlyImportError("Attribute '", name, "' does not exist in node '", nodeName, "'");
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
int32_t OgreXmlSerializer::ReadAttribute<int32_t>(XmlNode &xmlNode, const char *name) const {
|
||||
if (!XmlParser::hasAttribute(xmlNode, name)) {
|
||||
ThrowAttibuteError(xmlNode.name(), name, "Not found");
|
||||
}
|
||||
pugi::xml_attribute attr = xmlNode.attribute(name);
|
||||
return static_cast<int32_t>(attr.as_int());
|
||||
}
|
||||
|
||||
template <>
|
||||
uint32_t OgreXmlSerializer::ReadAttribute<uint32_t>(XmlNode &xmlNode, const char *name) const {
|
||||
if (!XmlParser::hasAttribute(xmlNode, name)) {
|
||||
ThrowAttibuteError(xmlNode.name(), name, "Not found");
|
||||
}
|
||||
|
||||
// @note This is hackish. But we are never expecting unsigned values that go outside the
|
||||
// int32_t range. Just monitor for negative numbers and kill the import.
|
||||
int32_t temp = ReadAttribute<int32_t>(xmlNode, name);
|
||||
if (temp < 0) {
|
||||
ThrowAttibuteError(xmlNode.name(), name, "Found a negative number value where expecting a uint32_t value");
|
||||
}
|
||||
|
||||
return static_cast<uint32_t>(temp);
|
||||
}
|
||||
|
||||
template <>
|
||||
uint16_t OgreXmlSerializer::ReadAttribute<uint16_t>(XmlNode &xmlNode, const char *name) const {
|
||||
if (!XmlParser::hasAttribute(xmlNode, name)) {
|
||||
ThrowAttibuteError(xmlNode.name(), name, "Not found");
|
||||
}
|
||||
|
||||
return static_cast<uint16_t>(xmlNode.attribute(name).as_int());
|
||||
}
|
||||
|
||||
template <>
|
||||
float OgreXmlSerializer::ReadAttribute<float>(XmlNode &xmlNode, const char *name) const {
|
||||
if (!XmlParser::hasAttribute(xmlNode, name)) {
|
||||
ThrowAttibuteError(xmlNode.name(), name, "Not found");
|
||||
}
|
||||
|
||||
return xmlNode.attribute(name).as_float();
|
||||
}
|
||||
|
||||
template <>
|
||||
std::string OgreXmlSerializer::ReadAttribute<std::string>(XmlNode &xmlNode, const char *name) const {
|
||||
if (!XmlParser::hasAttribute(xmlNode, name)) {
|
||||
ThrowAttibuteError(xmlNode.name(), name, "Not found");
|
||||
}
|
||||
|
||||
return xmlNode.attribute(name).as_string();
|
||||
}
|
||||
|
||||
template <>
|
||||
bool OgreXmlSerializer::ReadAttribute<bool>(XmlNode &xmlNode, const char *name) const {
|
||||
std::string value = ai_tolower(ReadAttribute<std::string>(xmlNode, name));
|
||||
if (ASSIMP_stricmp(value, "true") == 0) {
|
||||
return true;
|
||||
} else if (ASSIMP_stricmp(value, "false") == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ThrowAttibuteError(xmlNode.name(), name, "Boolean value is expected to be 'true' or 'false', encountered '" + value + "'");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Mesh XML constants
|
||||
|
||||
// <mesh>
|
||||
static const char *nnMesh = "mesh";
|
||||
static const char *nnSharedGeometry = "sharedgeometry";
|
||||
static const char *nnSubMeshes = "submeshes";
|
||||
static const char *nnSubMesh = "submesh";
|
||||
//static const char *nnSubMeshNames = "submeshnames";
|
||||
static const char *nnSkeletonLink = "skeletonlink";
|
||||
//static const char *nnLOD = "levelofdetail";
|
||||
//static const char *nnExtremes = "extremes";
|
||||
//static const char *nnPoses = "poses";
|
||||
static const char *nnAnimations = "animations";
|
||||
|
||||
// <submesh>
|
||||
static const char *nnFaces = "faces";
|
||||
static const char *nnFace = "face";
|
||||
static const char *nnGeometry = "geometry";
|
||||
//static const char *nnTextures = "textures";
|
||||
|
||||
// <mesh/submesh>
|
||||
static const char *nnBoneAssignments = "boneassignments";
|
||||
|
||||
// <sharedgeometry/geometry>
|
||||
static const char *nnVertexBuffer = "vertexbuffer";
|
||||
|
||||
// <vertexbuffer>
|
||||
//static const char *nnVertex = "vertex";
|
||||
static const char *nnPosition = "position";
|
||||
static const char *nnNormal = "normal";
|
||||
static const char *nnTangent = "tangent";
|
||||
//static const char *nnBinormal = "binormal";
|
||||
static const char *nnTexCoord = "texcoord";
|
||||
//static const char *nnColorDiffuse = "colour_diffuse";
|
||||
//static const char *nnColorSpecular = "colour_specular";
|
||||
|
||||
// <boneassignments>
|
||||
static const char *nnVertexBoneAssignment = "vertexboneassignment";
|
||||
|
||||
// Skeleton XML constants
|
||||
|
||||
// <skeleton>
|
||||
static const char *nnSkeleton = "skeleton";
|
||||
static const char *nnBones = "bones";
|
||||
static const char *nnBoneHierarchy = "bonehierarchy";
|
||||
//static const char *nnAnimationLinks = "animationlinks";
|
||||
|
||||
// <bones>
|
||||
static const char *nnBone = "bone";
|
||||
static const char *nnRotation = "rotation";
|
||||
static const char *nnAxis = "axis";
|
||||
static const char *nnScale = "scale";
|
||||
|
||||
// <bonehierarchy>
|
||||
static const char *nnBoneParent = "boneparent";
|
||||
|
||||
// <animations>
|
||||
static const char *nnAnimation = "animation";
|
||||
static const char *nnTracks = "tracks";
|
||||
|
||||
// <tracks>
|
||||
static const char *nnTrack = "track";
|
||||
static const char *nnKeyFrames = "keyframes";
|
||||
static const char *nnKeyFrame = "keyframe";
|
||||
static const char *nnTranslate = "translate";
|
||||
static const char *nnRotate = "rotate";
|
||||
|
||||
// Common XML constants
|
||||
static const char *anX = "x";
|
||||
static const char *anY = "y";
|
||||
static const char *anZ = "z";
|
||||
|
||||
// Mesh
|
||||
|
||||
OgreXmlSerializer::OgreXmlSerializer(XmlParser *parser) :
|
||||
mParser(parser) {
|
||||
// empty
|
||||
}
|
||||
|
||||
MeshXml *OgreXmlSerializer::ImportMesh(XmlParser *parser) {
|
||||
if (nullptr == parser) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
OgreXmlSerializer serializer(parser);
|
||||
|
||||
MeshXml *mesh = new MeshXml();
|
||||
serializer.ReadMesh(mesh);
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
void OgreXmlSerializer::ReadMesh(MeshXml *mesh) {
|
||||
XmlNode root = mParser->getRootNode();
|
||||
if (nullptr == root) {
|
||||
throw DeadlyImportError("Root node is <" + std::string(root.name()) + "> expecting <mesh>");
|
||||
}
|
||||
|
||||
XmlNode startNode = root.child(nnMesh);
|
||||
if (startNode.empty()) {
|
||||
throw DeadlyImportError("Root node is <" + std::string(root.name()) + "> expecting <mesh>");
|
||||
}
|
||||
for (XmlNode currentNode : startNode.children()) {
|
||||
const std::string currentName = currentNode.name();
|
||||
if (currentName == nnSharedGeometry) {
|
||||
mesh->sharedVertexData = new VertexDataXml();
|
||||
ReadGeometry(currentNode, mesh->sharedVertexData);
|
||||
} else if (currentName == nnSubMeshes) {
|
||||
for (XmlNode &subMeshesNode : currentNode.children()) {
|
||||
const std::string ¤tSMName = subMeshesNode.name();
|
||||
if (currentSMName == nnSubMesh) {
|
||||
ReadSubMesh(subMeshesNode, mesh);
|
||||
}
|
||||
}
|
||||
} else if (currentName == nnBoneAssignments) {
|
||||
ReadBoneAssignments(currentNode, mesh->sharedVertexData);
|
||||
} else if (currentName == nnSkeletonLink) {
|
||||
}
|
||||
}
|
||||
|
||||
ASSIMP_LOG_VERBOSE_DEBUG("Reading Mesh");
|
||||
}
|
||||
|
||||
void OgreXmlSerializer::ReadGeometry(XmlNode &node, VertexDataXml *dest) {
|
||||
dest->count = ReadAttribute<uint32_t>(node, "vertexcount");
|
||||
ASSIMP_LOG_VERBOSE_DEBUG(" - Reading geometry of ", dest->count, " vertices");
|
||||
|
||||
for (XmlNode currentNode : node.children()) {
|
||||
const std::string ¤tName = currentNode.name();
|
||||
if (currentName == nnVertexBuffer) {
|
||||
ReadGeometryVertexBuffer(currentNode, dest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OgreXmlSerializer::ReadGeometryVertexBuffer(XmlNode &node, VertexDataXml *dest) {
|
||||
bool positions = (XmlParser::hasAttribute(node, "positions") && ReadAttribute<bool>(node, "positions"));
|
||||
bool normals = (XmlParser::hasAttribute(node, "normals") && ReadAttribute<bool>(node, "normals"));
|
||||
bool tangents = (XmlParser::hasAttribute(node, "tangents") && ReadAttribute<bool>(node, "tangents"));
|
||||
uint32_t uvs = (XmlParser::hasAttribute(node, "texture_coords") ? ReadAttribute<uint32_t>(node, "texture_coords") : 0);
|
||||
|
||||
// Not having positions is a error only if a previous vertex buffer did not have them.
|
||||
if (!positions && !dest->HasPositions()) {
|
||||
throw DeadlyImportError("Vertex buffer does not contain positions!");
|
||||
}
|
||||
|
||||
if (positions) {
|
||||
ASSIMP_LOG_VERBOSE_DEBUG(" - Contains positions");
|
||||
dest->positions.reserve(dest->count);
|
||||
}
|
||||
if (normals) {
|
||||
ASSIMP_LOG_VERBOSE_DEBUG(" - Contains normals");
|
||||
dest->normals.reserve(dest->count);
|
||||
}
|
||||
if (tangents) {
|
||||
ASSIMP_LOG_VERBOSE_DEBUG(" - Contains tangents");
|
||||
dest->tangents.reserve(dest->count);
|
||||
}
|
||||
if (uvs > 0) {
|
||||
ASSIMP_LOG_VERBOSE_DEBUG(" - Contains ", uvs, " texture coords");
|
||||
dest->uvs.resize(uvs);
|
||||
for (size_t i = 0, len = dest->uvs.size(); i < len; ++i) {
|
||||
dest->uvs[i].reserve(dest->count);
|
||||
}
|
||||
}
|
||||
|
||||
for (XmlNode currentNode : node.children("vertex")) {
|
||||
for (XmlNode vertexNode : currentNode.children()) {
|
||||
const std::string ¤tName = vertexNode.name();
|
||||
if (positions && currentName == nnPosition) {
|
||||
aiVector3D pos;
|
||||
pos.x = ReadAttribute<float>(vertexNode, anX);
|
||||
pos.y = ReadAttribute<float>(vertexNode, anY);
|
||||
pos.z = ReadAttribute<float>(vertexNode, anZ);
|
||||
dest->positions.push_back(pos);
|
||||
} else if (normals && currentName == nnNormal) {
|
||||
aiVector3D normal;
|
||||
normal.x = ReadAttribute<float>(vertexNode, anX);
|
||||
normal.y = ReadAttribute<float>(vertexNode, anY);
|
||||
normal.z = ReadAttribute<float>(vertexNode, anZ);
|
||||
dest->normals.push_back(normal);
|
||||
} else if (tangents && currentName == nnTangent) {
|
||||
aiVector3D tangent;
|
||||
tangent.x = ReadAttribute<float>(vertexNode, anX);
|
||||
tangent.y = ReadAttribute<float>(vertexNode, anY);
|
||||
tangent.z = ReadAttribute<float>(vertexNode, anZ);
|
||||
dest->tangents.push_back(tangent);
|
||||
} else if (uvs > 0 && currentName == nnTexCoord) {
|
||||
for (auto &curUvs : dest->uvs) {
|
||||
aiVector3D uv;
|
||||
uv.x = ReadAttribute<float>(vertexNode, "u");
|
||||
uv.y = (ReadAttribute<float>(vertexNode, "v") * -1) + 1; // Flip UV from Ogre to Assimp form
|
||||
curUvs.push_back(uv);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sanity checks
|
||||
if (dest->positions.size() != dest->count) {
|
||||
throw DeadlyImportError("Read only ", dest->positions.size(), " positions when should have read ", dest->count);
|
||||
}
|
||||
if (normals && dest->normals.size() != dest->count) {
|
||||
throw DeadlyImportError("Read only ", dest->normals.size(), " normals when should have read ", dest->count);
|
||||
}
|
||||
if (tangents && dest->tangents.size() != dest->count) {
|
||||
throw DeadlyImportError("Read only ", dest->tangents.size(), " tangents when should have read ", dest->count);
|
||||
}
|
||||
for (unsigned int i = 0; i < dest->uvs.size(); ++i) {
|
||||
if (dest->uvs[i].size() != dest->count) {
|
||||
throw DeadlyImportError("Read only ", dest->uvs[i].size(),
|
||||
" uvs for uv index ", i, " when should have read ", dest->count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OgreXmlSerializer::ReadSubMesh(XmlNode &node, MeshXml *mesh) {
|
||||
static const char *anMaterial = "material";
|
||||
static const char *anUseSharedVertices = "usesharedvertices";
|
||||
static const char *anCount = "count";
|
||||
static const char *anV1 = "v1";
|
||||
static const char *anV2 = "v2";
|
||||
static const char *anV3 = "v3";
|
||||
static const char *anV4 = "v4";
|
||||
|
||||
SubMeshXml *submesh = new SubMeshXml();
|
||||
|
||||
if (XmlParser::hasAttribute(node, anMaterial)) {
|
||||
submesh->materialRef = ReadAttribute<std::string>(node, anMaterial);
|
||||
}
|
||||
if (XmlParser::hasAttribute(node, anUseSharedVertices)) {
|
||||
submesh->usesSharedVertexData = ReadAttribute<bool>(node, anUseSharedVertices);
|
||||
}
|
||||
|
||||
ASSIMP_LOG_VERBOSE_DEBUG("Reading SubMesh ", mesh->subMeshes.size());
|
||||
ASSIMP_LOG_VERBOSE_DEBUG(" - Material: '", submesh->materialRef, "'");
|
||||
ASSIMP_LOG_VERBOSE_DEBUG(" - Uses shared geometry: ", (submesh->usesSharedVertexData ? "true" : "false"));
|
||||
|
||||
// TODO: maybe we have always just 1 faces and 1 geometry and always in this order. this loop will only work correct, when the order
|
||||
// of faces and geometry changed, and not if we have more than one of one
|
||||
/// @todo Fix above comment with better read logic below
|
||||
|
||||
bool quadWarned = false;
|
||||
|
||||
for (XmlNode ¤tNode : node.children()) {
|
||||
const std::string ¤tName = currentNode.name();
|
||||
if (currentName == nnFaces) {
|
||||
submesh->indexData->faceCount = ReadAttribute<uint32_t>(currentNode, anCount);
|
||||
submesh->indexData->faces.reserve(submesh->indexData->faceCount);
|
||||
for (XmlNode currentChildNode : currentNode.children()) {
|
||||
const std::string ¤tChildName = currentChildNode.name();
|
||||
if (currentChildName == nnFace) {
|
||||
aiFace face;
|
||||
face.mNumIndices = 3;
|
||||
face.mIndices = new unsigned int[3];
|
||||
face.mIndices[0] = ReadAttribute<uint32_t>(currentChildNode, anV1);
|
||||
face.mIndices[1] = ReadAttribute<uint32_t>(currentChildNode, anV2);
|
||||
face.mIndices[2] = ReadAttribute<uint32_t>(currentChildNode, anV3);
|
||||
/// @todo Support quads if Ogre even supports them in XML (I'm not sure but I doubt it)
|
||||
if (!quadWarned && XmlParser::hasAttribute(currentChildNode, anV4)) {
|
||||
ASSIMP_LOG_WARN("Submesh <face> has quads with <v4>, only triangles are supported at the moment!");
|
||||
quadWarned = true;
|
||||
}
|
||||
submesh->indexData->faces.push_back(face);
|
||||
}
|
||||
}
|
||||
if (submesh->indexData->faces.size() == submesh->indexData->faceCount) {
|
||||
ASSIMP_LOG_VERBOSE_DEBUG(" - Faces ", submesh->indexData->faceCount);
|
||||
} else {
|
||||
throw DeadlyImportError("Read only ", submesh->indexData->faces.size(), " faces when should have read ", submesh->indexData->faceCount);
|
||||
}
|
||||
} else if (currentName == nnGeometry) {
|
||||
if (submesh->usesSharedVertexData) {
|
||||
throw DeadlyImportError("Found <geometry> in <submesh> when use shared geometry is true. Invalid mesh file.");
|
||||
}
|
||||
|
||||
submesh->vertexData = new VertexDataXml();
|
||||
ReadGeometry(currentNode, submesh->vertexData);
|
||||
} else if (currentName == nnBoneAssignments) {
|
||||
ReadBoneAssignments(currentNode, submesh->vertexData);
|
||||
}
|
||||
}
|
||||
|
||||
submesh->index = static_cast<unsigned int>(mesh->subMeshes.size());
|
||||
mesh->subMeshes.push_back(submesh);
|
||||
}
|
||||
|
||||
void OgreXmlSerializer::ReadBoneAssignments(XmlNode &node, VertexDataXml *dest) {
|
||||
if (!dest) {
|
||||
throw DeadlyImportError("Cannot read bone assignments, vertex data is null.");
|
||||
}
|
||||
|
||||
static const char *anVertexIndex = "vertexindex";
|
||||
static const char *anBoneIndex = "boneindex";
|
||||
static const char *anWeight = "weight";
|
||||
|
||||
std::set<uint32_t> influencedVertices;
|
||||
for (XmlNode ¤tNode : node.children()) {
|
||||
const std::string ¤tName = currentNode.name();
|
||||
if (currentName == nnVertexBoneAssignment) {
|
||||
VertexBoneAssignment ba;
|
||||
ba.vertexIndex = ReadAttribute<uint32_t>(currentNode, anVertexIndex);
|
||||
ba.boneIndex = ReadAttribute<uint16_t>(currentNode, anBoneIndex);
|
||||
ba.weight = ReadAttribute<float>(currentNode, anWeight);
|
||||
|
||||
dest->boneAssignments.push_back(ba);
|
||||
influencedVertices.insert(ba.vertexIndex);
|
||||
}
|
||||
}
|
||||
|
||||
/** Normalize bone weights.
|
||||
Some exporters won't care if the sum of all bone weights
|
||||
for a single vertex equals 1 or not, so validate here. */
|
||||
const float epsilon = 0.05f;
|
||||
for (const uint32_t vertexIndex : influencedVertices) {
|
||||
float sum = 0.0f;
|
||||
for (VertexBoneAssignmentList::const_iterator baIter = dest->boneAssignments.begin(), baEnd = dest->boneAssignments.end(); baIter != baEnd; ++baIter) {
|
||||
if (baIter->vertexIndex == vertexIndex)
|
||||
sum += baIter->weight;
|
||||
}
|
||||
if ((sum < (1.0f - epsilon)) || (sum > (1.0f + epsilon))) {
|
||||
for (auto &boneAssign : dest->boneAssignments) {
|
||||
if (boneAssign.vertexIndex == vertexIndex)
|
||||
boneAssign.weight /= sum;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ASSIMP_LOG_VERBOSE_DEBUG(" - ", dest->boneAssignments.size(), " bone assignments");
|
||||
}
|
||||
|
||||
// Skeleton
|
||||
|
||||
bool OgreXmlSerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, MeshXml *mesh) {
|
||||
if (!mesh || mesh->skeletonRef.empty())
|
||||
return false;
|
||||
|
||||
// Highly unusual to see in read world cases but support
|
||||
// XML mesh referencing a binary skeleton file.
|
||||
if (EndsWith(mesh->skeletonRef, ".skeleton", false)) {
|
||||
if (OgreBinarySerializer::ImportSkeleton(pIOHandler, mesh))
|
||||
return true;
|
||||
|
||||
/** Last fallback if .skeleton failed to be read. Try reading from
|
||||
.skeleton.xml even if the XML file referenced a binary skeleton.
|
||||
@note This logic was in the previous version and I don't want to break
|
||||
old code that might depends on it. */
|
||||
mesh->skeletonRef = mesh->skeletonRef + ".xml";
|
||||
}
|
||||
|
||||
XmlParserPtr xmlParser = OpenXmlParser(pIOHandler, mesh->skeletonRef);
|
||||
if (!xmlParser.get())
|
||||
return false;
|
||||
|
||||
Skeleton *skeleton = new Skeleton();
|
||||
OgreXmlSerializer serializer(xmlParser.get());
|
||||
XmlNode root = xmlParser->getRootNode();
|
||||
serializer.ReadSkeleton(root, skeleton);
|
||||
mesh->skeleton = skeleton;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OgreXmlSerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, Mesh *mesh) {
|
||||
if (!mesh || mesh->skeletonRef.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
XmlParserPtr xmlParser = OpenXmlParser(pIOHandler, mesh->skeletonRef);
|
||||
if (!xmlParser.get()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Skeleton *skeleton = new Skeleton();
|
||||
OgreXmlSerializer serializer(xmlParser.get());
|
||||
XmlNode root = xmlParser->getRootNode();
|
||||
|
||||
serializer.ReadSkeleton(root, skeleton);
|
||||
mesh->skeleton = skeleton;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
XmlParserPtr OgreXmlSerializer::OpenXmlParser(Assimp::IOSystem *pIOHandler, const std::string &filename) {
|
||||
if (!EndsWith(filename, ".skeleton.xml", false)) {
|
||||
ASSIMP_LOG_ERROR("Imported Mesh is referencing to unsupported '", filename, "' skeleton file.");
|
||||
return XmlParserPtr();
|
||||
}
|
||||
|
||||
if (!pIOHandler->Exists(filename)) {
|
||||
ASSIMP_LOG_ERROR("Failed to find skeleton file '", filename, "' that is referenced by imported Mesh.");
|
||||
return XmlParserPtr();
|
||||
}
|
||||
|
||||
std::unique_ptr<IOStream> file(pIOHandler->Open(filename));
|
||||
if (!file.get()) {
|
||||
throw DeadlyImportError("Failed to open skeleton file ", filename);
|
||||
}
|
||||
|
||||
XmlParserPtr xmlParser = std::make_shared<XmlParser>();
|
||||
if (!xmlParser->parse(file.get())) {
|
||||
throw DeadlyImportError("Failed to create XML reader for skeleton file " + filename);
|
||||
}
|
||||
return xmlParser;
|
||||
}
|
||||
|
||||
void OgreXmlSerializer::ReadSkeleton(XmlNode &node, Skeleton *skeleton) {
|
||||
if (node.name() != nnSkeleton) {
|
||||
throw DeadlyImportError("Root node is <" + std::string(node.name()) + "> expecting <skeleton>");
|
||||
}
|
||||
|
||||
ASSIMP_LOG_VERBOSE_DEBUG("Reading Skeleton");
|
||||
|
||||
// Optional blend mode from root node
|
||||
if (XmlParser::hasAttribute(node, "blendmode")) {
|
||||
skeleton->blendMode = (ai_tolower(ReadAttribute<std::string>(node, "blendmode")) == "cumulative" ? Skeleton::ANIMBLEND_CUMULATIVE : Skeleton::ANIMBLEND_AVERAGE);
|
||||
}
|
||||
|
||||
for (XmlNode ¤tNode : node.children()) {
|
||||
const std::string currentName = currentNode.name();
|
||||
if (currentName == nnBones) {
|
||||
ReadBones(currentNode, skeleton);
|
||||
} else if (currentName == nnBoneHierarchy) {
|
||||
ReadBoneHierarchy(currentNode, skeleton);
|
||||
} else if (currentName == nnAnimations) {
|
||||
ReadAnimations(currentNode, skeleton);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OgreXmlSerializer::ReadAnimations(XmlNode &node, Skeleton *skeleton) {
|
||||
if (skeleton->bones.empty()) {
|
||||
throw DeadlyImportError("Cannot read <animations> for a Skeleton without bones");
|
||||
}
|
||||
|
||||
ASSIMP_LOG_VERBOSE_DEBUG(" - Animations");
|
||||
|
||||
for (XmlNode ¤tNode : node.children()) {
|
||||
const std::string currentName = currentNode.name();
|
||||
if (currentName == nnAnimation) {
|
||||
Animation *anim = new Animation(skeleton);
|
||||
anim->name = ReadAttribute<std::string>(currentNode, "name");
|
||||
anim->length = ReadAttribute<float>(currentNode, "length");
|
||||
for (XmlNode ¤tChildNode : currentNode.children()) {
|
||||
const std::string currentChildName = currentNode.name();
|
||||
if (currentChildName == nnTracks) {
|
||||
ReadAnimationTracks(currentChildNode, anim);
|
||||
skeleton->animations.push_back(anim);
|
||||
} else {
|
||||
throw DeadlyImportError("No <tracks> found in <animation> ", anim->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OgreXmlSerializer::ReadAnimationTracks(XmlNode &node, Animation *dest) {
|
||||
for (XmlNode ¤tNode : node.children()) {
|
||||
const std::string currentName = currentNode.name();
|
||||
if (currentName == nnTrack) {
|
||||
VertexAnimationTrack track;
|
||||
track.type = VertexAnimationTrack::VAT_TRANSFORM;
|
||||
track.boneName = ReadAttribute<std::string>(currentNode, "bone");
|
||||
for (XmlNode ¤tChildNode : currentNode.children()) {
|
||||
const std::string currentChildName = currentNode.name();
|
||||
if (currentChildName == nnKeyFrames) {
|
||||
ReadAnimationKeyFrames(currentChildNode, dest, &track);
|
||||
dest->tracks.push_back(track);
|
||||
} else {
|
||||
throw DeadlyImportError("No <keyframes> found in <track> ", dest->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OgreXmlSerializer::ReadAnimationKeyFrames(XmlNode &node, Animation *anim, VertexAnimationTrack *dest) {
|
||||
const aiVector3D zeroVec(0.f, 0.f, 0.f);
|
||||
for (XmlNode ¤tNode : node.children()) {
|
||||
TransformKeyFrame keyframe;
|
||||
const std::string currentName = currentNode.name();
|
||||
if (currentName == nnKeyFrame) {
|
||||
keyframe.timePos = ReadAttribute<float>(currentNode, "time");
|
||||
for (XmlNode ¤tChildNode : currentNode.children()) {
|
||||
const std::string currentChildName = currentNode.name();
|
||||
if (currentChildName == nnTranslate) {
|
||||
keyframe.position.x = ReadAttribute<float>(currentChildNode, anX);
|
||||
keyframe.position.y = ReadAttribute<float>(currentChildNode, anY);
|
||||
keyframe.position.z = ReadAttribute<float>(currentChildNode, anZ);
|
||||
} else if (currentChildName == nnRotate) {
|
||||
float angle = ReadAttribute<float>(currentChildNode, "angle");
|
||||
for (XmlNode ¤tChildChildNode : currentNode.children()) {
|
||||
const std::string currentChildChildName = currentNode.name();
|
||||
if (currentChildChildName == nnAxis) {
|
||||
aiVector3D axis;
|
||||
axis.x = ReadAttribute<float>(currentChildChildNode, anX);
|
||||
axis.y = ReadAttribute<float>(currentChildChildNode, anY);
|
||||
axis.z = ReadAttribute<float>(currentChildChildNode, anZ);
|
||||
if (axis.Equal(zeroVec)) {
|
||||
axis.x = 1.0f;
|
||||
if (angle != 0) {
|
||||
ASSIMP_LOG_WARN("Found invalid a key frame with a zero rotation axis in animation: ", anim->name);
|
||||
}
|
||||
}
|
||||
keyframe.rotation = aiQuaternion(axis, angle);
|
||||
}
|
||||
}
|
||||
} else if (currentChildName == nnScale) {
|
||||
keyframe.scale.x = ReadAttribute<float>(currentChildNode, anX);
|
||||
keyframe.scale.y = ReadAttribute<float>(currentChildNode, anY);
|
||||
keyframe.scale.z = ReadAttribute<float>(currentChildNode, anZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
dest->transformKeyFrames.push_back(keyframe);
|
||||
}
|
||||
}
|
||||
|
||||
void OgreXmlSerializer::ReadBoneHierarchy(XmlNode &node, Skeleton *skeleton) {
|
||||
if (skeleton->bones.empty()) {
|
||||
throw DeadlyImportError("Cannot read <bonehierarchy> for a Skeleton without bones");
|
||||
}
|
||||
|
||||
for (XmlNode ¤tNode : node.children()) {
|
||||
const std::string currentName = currentNode.name();
|
||||
if (currentName == nnBoneParent) {
|
||||
const std::string name = ReadAttribute<std::string>(currentNode, "bone");
|
||||
const std::string parentName = ReadAttribute<std::string>(currentNode, "parent");
|
||||
|
||||
Bone *bone = skeleton->BoneByName(name);
|
||||
Bone *parent = skeleton->BoneByName(parentName);
|
||||
|
||||
if (bone && parent) {
|
||||
parent->AddChild(bone);
|
||||
} else {
|
||||
throw DeadlyImportError("Failed to find bones for parenting: Child ", name, " for parent ", parentName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate bone matrices for root bones. Recursively calculates their children.
|
||||
for (size_t i = 0, len = skeleton->bones.size(); i < len; ++i) {
|
||||
Bone *bone = skeleton->bones[i];
|
||||
if (!bone->IsParented())
|
||||
bone->CalculateWorldMatrixAndDefaultPose(skeleton);
|
||||
}
|
||||
}
|
||||
|
||||
static bool BoneCompare(Bone *a, Bone *b) {
|
||||
ai_assert(nullptr != a);
|
||||
ai_assert(nullptr != b);
|
||||
|
||||
return (a->id < b->id);
|
||||
}
|
||||
|
||||
void OgreXmlSerializer::ReadBones(XmlNode &node, Skeleton *skeleton) {
|
||||
ASSIMP_LOG_VERBOSE_DEBUG(" - Bones");
|
||||
|
||||
for (XmlNode ¤tNode : node.children()) {
|
||||
const std::string currentName = currentNode.name();
|
||||
if (currentName == nnBone) {
|
||||
Bone *bone = new Bone();
|
||||
bone->id = ReadAttribute<uint16_t>(currentNode, "id");
|
||||
bone->name = ReadAttribute<std::string>(currentNode, "name");
|
||||
for (XmlNode ¤tChildNode : currentNode.children()) {
|
||||
const std::string currentChildName = currentNode.name();
|
||||
if (currentChildName == nnRotation) {
|
||||
bone->position.x = ReadAttribute<float>(currentChildNode, anX);
|
||||
bone->position.y = ReadAttribute<float>(currentChildNode, anY);
|
||||
bone->position.z = ReadAttribute<float>(currentChildNode, anZ);
|
||||
} else if (currentChildName == nnScale) {
|
||||
float angle = ReadAttribute<float>(currentChildNode, "angle");
|
||||
for (XmlNode currentChildChildNode : currentChildNode.children()) {
|
||||
const std::string ¤tChildChildName = currentChildChildNode.name();
|
||||
if (currentChildChildName == nnAxis) {
|
||||
aiVector3D axis;
|
||||
axis.x = ReadAttribute<float>(currentChildChildNode, anX);
|
||||
axis.y = ReadAttribute<float>(currentChildChildNode, anY);
|
||||
axis.z = ReadAttribute<float>(currentChildChildNode, anZ);
|
||||
|
||||
bone->rotation = aiQuaternion(axis, angle);
|
||||
} else {
|
||||
throw DeadlyImportError("No axis specified for bone rotation in bone ", bone->id);
|
||||
}
|
||||
}
|
||||
} else if (currentChildName == nnScale) {
|
||||
if (XmlParser::hasAttribute(currentChildNode, "factor")) {
|
||||
float factor = ReadAttribute<float>(currentChildNode, "factor");
|
||||
bone->scale.Set(factor, factor, factor);
|
||||
} else {
|
||||
if (XmlParser::hasAttribute(currentChildNode, anX))
|
||||
bone->scale.x = ReadAttribute<float>(currentChildNode, anX);
|
||||
if (XmlParser::hasAttribute(currentChildNode, anY))
|
||||
bone->scale.y = ReadAttribute<float>(currentChildNode, anY);
|
||||
if (XmlParser::hasAttribute(currentChildNode, anZ))
|
||||
bone->scale.z = ReadAttribute<float>(currentChildNode, anZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
skeleton->bones.push_back(bone);
|
||||
}
|
||||
}
|
||||
|
||||
// Order bones by Id
|
||||
std::sort(skeleton->bones.begin(), skeleton->bones.end(), BoneCompare);
|
||||
|
||||
// Validate that bone indexes are not skipped.
|
||||
/** @note Left this from original authors code, but not sure if this is strictly necessary
|
||||
as per the Ogre skeleton spec. It might be more that other (later) code in this imported does not break. */
|
||||
for (size_t i = 0, len = skeleton->bones.size(); i < len; ++i) {
|
||||
Bone *b = skeleton->bones[i];
|
||||
ASSIMP_LOG_VERBOSE_DEBUG(" ", b->id, " ", b->name);
|
||||
|
||||
if (b->id != static_cast<uint16_t>(i)) {
|
||||
throw DeadlyImportError("Bone ids are not in sequence starting from 0. Missing index ", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Ogre
|
||||
} // namespace Assimp
|
||||
|
||||
#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER
|
||||
102
Engine/lib/assimp/code/AssetLib/Ogre/OgreXmlSerializer.h
Normal file
102
Engine/lib/assimp/code/AssetLib/Ogre/OgreXmlSerializer.h
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef AI_OGREXMLSERIALIZER_H_INC
|
||||
#define AI_OGREXMLSERIALIZER_H_INC
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
|
||||
|
||||
#include "OgreStructs.h"
|
||||
#include <assimp/XmlParser.h>
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
namespace Ogre {
|
||||
|
||||
using XmlParserPtr = std::shared_ptr<::Assimp::XmlParser> ;
|
||||
|
||||
class OgreXmlSerializer {
|
||||
public:
|
||||
/// Imports mesh and returns the result.
|
||||
/// @note Fatal unrecoverable errors will throw a DeadlyImportError.
|
||||
static MeshXml *ImportMesh(XmlParser *parser);
|
||||
|
||||
/// Imports skeleton to @c mesh.
|
||||
/// If mesh does not have a skeleton reference or the skeleton file
|
||||
/// cannot be found it is not a fatal DeadlyImportError.
|
||||
/// @return If skeleton import was successful.
|
||||
static bool ImportSkeleton(IOSystem *pIOHandler, MeshXml *mesh);
|
||||
static bool ImportSkeleton(IOSystem *pIOHandler, Mesh *mesh);
|
||||
|
||||
private:
|
||||
explicit OgreXmlSerializer(XmlParser *xmlParser);
|
||||
|
||||
static XmlParserPtr OpenXmlParser(Assimp::IOSystem *pIOHandler, const std::string &filename);
|
||||
|
||||
// Mesh
|
||||
void ReadMesh(MeshXml *mesh);
|
||||
void ReadSubMesh(XmlNode &node, MeshXml *mesh);
|
||||
void ReadGeometry(XmlNode &node, VertexDataXml *dest);
|
||||
void ReadGeometryVertexBuffer(XmlNode &node, VertexDataXml *dest);
|
||||
void ReadBoneAssignments(XmlNode &node, VertexDataXml *dest);
|
||||
|
||||
// Skeleton
|
||||
void ReadSkeleton(XmlNode &node, Skeleton *skeleton);
|
||||
void ReadBones(XmlNode &node, Skeleton *skeleton);
|
||||
void ReadBoneHierarchy(XmlNode &node, Skeleton *skeleton);
|
||||
void ReadAnimations(XmlNode &node, Skeleton *skeleton);
|
||||
void ReadAnimationTracks(XmlNode &node, Animation *dest);
|
||||
void ReadAnimationKeyFrames(XmlNode &node, Animation *anim, VertexAnimationTrack *dest);
|
||||
|
||||
template <typename T>
|
||||
T ReadAttribute(XmlNode &xmlNode, const char *name) const;
|
||||
|
||||
private:
|
||||
XmlParser *mParser;
|
||||
};
|
||||
|
||||
|
||||
} // namespace Ogre
|
||||
} // namespace Assimp
|
||||
|
||||
#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER
|
||||
#endif // AI_OGREXMLSERIALIZER_H_INC
|
||||
Loading…
Add table
Add a link
Reference in a new issue