29 bool VertexDeclarationIsSane(
const unique_ptr_vector<Ogre::Mesh::ChunkGeometryVertexDeclElement> &decl,
const char *filename)
32 for(
auto& element: decl)
34 switch (element->semantic)
45 if (semanticSeen[element->semantic])
52 semanticSeen[element->semantic] =
true;
60 static_assert(N >= 4,
"");
61 dest[0] = dest[1] = dest[2] = 0; dest[3] = 1;
66 dest[3] = *
reinterpret_cast<const float*
>(source +
sizeof(float) * 3);
68 dest[2] = *
reinterpret_cast<const float*
>(source +
sizeof(float) * 2);
70 dest[1] = *
reinterpret_cast<const float*
>(source +
sizeof(float) * 1);
72 dest[0] = *
reinterpret_cast<const float*
>(source +
sizeof(float) * 0);
75 dest[3] = source[0] / 255.0f;
76 for (
int i = 0; i < 3; ++i)
77 dest[i] = source[3 - i] / 255.0f;
80 dest[3] = source[0] / 255.0f;
81 for (
int i = 0; i < 3; ++i)
82 dest[i] = source[i + 1] / 255.0f;
85 assert(!
"Unexpected enum value");
93 throw Ogre::Mesh::InvalidVertexDeclaration();
96 std::map<int, size_t> max_offset;
108 default: assert(!
"Unexpected enum value");
break;
110 max_offset[el->source] = std::max<size_t>(max_offset[el->source], el->offset + elsize);
114 std::map<int, const char *> cursors;
117 if (cursors.find(buf->index) != cursors.end())
118 throw Ogre::MultipleSingletonChunks(
"Multiple vertex buffers were bound to the same stream");
119 cursors[buf->index] =
static_cast<const char *
>(buf->data->data);
121 if (buf->vertexSize < max_offset[buf->index])
122 throw Ogre::InsufficientData(
"Vertices overlapping");
124 if (buf->GetSize() < (geo.
vertexCount - 1) * buf->vertexSize + max_offset[buf->index])
125 throw Ogre::InsufficientData(
"Vertex buffer too small");
126 max_offset.erase(buf->index);
129 if (!max_offset.empty())
130 throw Ogre::InsufficientData(
"A vertex element references an unbound stream");
133 std::vector<StdSubMesh::Vertex> vertices;
138 vertex.
nx = vertex.
ny = vertex.
nz = 0;
139 vertex.
x = vertex.
y = vertex.
z = 0;
140 vertex.
u = vertex.
v = 0;
141 bool read_tex =
false;
146 ReadNormalizedVertexData(values, cursors[element->source] + element->offset, element->type);
147 switch (element->semantic)
150 vertex.
x = values[0];
151 vertex.
y = values[1];
152 vertex.
z = values[2];
155 vertex.
nx = values[0];
156 vertex.
ny = values[1];
157 vertex.
nz = values[2];
161 vertex.
u = values[0];
162 vertex.
v = values[1];
173 for(
const std::unique_ptr<Ogre::Mesh::ChunkGeometryVertexBuffer> &buf: geo.
vertexBuffers)
174 cursors[buf->index] += buf->vertexSize;
183 assert(groupname !=
nullptr);
184 assert(filename !=
nullptr);
185 assert(skeleton !=
nullptr);
189 skeleton->PostInit();
196 AddSkeleton(filepath, skeleton);
205 if (!(command_with_definition == command))
210 const char* appendto =
"appendto";
211 const char* include =
"include";
214 if (command == appendto)
216 AppendtoSkeletons.insert(std::make_pair(filepath, definition));
218 else if (command == include)
220 IncludeSkeletons.insert(std::make_pair(filepath, definition));
228 std::vector<StdCopyStrBuf> delete_skeletons;
230 std::map<StdCopyStrBuf, std::shared_ptr<StdMeshSkeleton>>::iterator it;
231 for (it = Skeletons.begin(); it != Skeletons.end(); it++)
240 if (skeletongroup == group)
244 delete_skeletons.push_back(skeletonpath);
248 for (
const auto & delete_skeleton : delete_skeletons)
263 std::map<StdCopyStrBuf, std::shared_ptr<StdMeshSkeleton>>::iterator existing_skeleton = Skeletons.find(filepath);
264 if (existing_skeleton != Skeletons.end())
266 Skeletons.erase(existing_skeleton);
269 std::map<StdCopyStrBuf, StdCopyStrBuf>::iterator appendto_skeleton = AppendtoSkeletons.find(filepath);
270 if (appendto_skeleton != AppendtoSkeletons.end())
272 AppendtoSkeletons.erase(appendto_skeleton);
275 std::map<StdCopyStrBuf, StdCopyStrBuf>::iterator include_skeleton = IncludeSkeletons.find(filepath);
276 if (include_skeleton != IncludeSkeletons.end())
278 IncludeSkeletons.erase(include_skeleton);
282 void StdMeshSkeletonLoader::AddSkeleton(
const StdCopyStrBuf& filepath, std::shared_ptr<StdMeshSkeleton> skeleton)
284 std::pair<StdCopyStrBuf, std::shared_ptr<StdMeshSkeleton>> key_and_value = std::make_pair(filepath, skeleton);
285 std::pair<std::map<StdCopyStrBuf, std::shared_ptr<StdMeshSkeleton>>::iterator,
bool> insert = Skeletons.insert(key_and_value);
287 if (insert.second ==
false)
289 LogF(
"WARNING: Overloading skeleton %s", filepath.
getData());
291 Skeletons[filepath] = skeleton;
299 std::map<StdCopyStrBuf, std::shared_ptr<StdMeshSkeleton>>::const_iterator iter = Skeletons.find(filename);
300 if (iter == Skeletons.end())
return nullptr;
306 std::unique_ptr<Ogre::Skeleton::Chunk> chunk;
314 throw Ogre::Skeleton::InvalidVersion();
316 std::map<uint16_t, std::unique_ptr<StdMeshBone>> bones;
317 unique_ptr_vector<Ogre::Skeleton::ChunkAnimation> animations;
324 switch (chunk->GetType())
331 LogF(
"StdMeshLoader: CID_BlendMode not implemented.");
338 if (bones.find(cbone.
handle) != bones.end())
339 throw Ogre::Skeleton::IdNotUnique();
340 auto bone = std::make_unique<StdMeshBone>();
341 bone->Parent =
nullptr;
343 bone->Name = cbone.
name.c_str();
344 bone->Transformation.translate = cbone.
position;
346 bone->Transformation.scale = cbone.
scale;
348 bones.insert(std::make_pair(cbone.
handle, std::move(bone)));
355 throw Ogre::Skeleton::BoneNotFound();
365 assert(!
"Unexpected enum value");
368 if (stream.
AtEof())
break;
375 if (!
b.second->Parent)
377 master =
b.second.get();
378 Skeleton->AddMasterBone(master);
382 throw Ogre::Skeleton::MissingMasterBone();
385 for (
auto&
b: bones)
b.second.release();
389 std::map<uint16_t, size_t> handle_lookup;
390 for (
size_t i = 0; i < Skeleton->GetNumBones(); ++i)
392 handle_lookup[Skeleton->GetBone(i).ID] = i;
396 for(
auto &canim: animations)
399 anim.
Name = canim->name.c_str();
400 anim.
Length = canim->duration;
401 anim.Tracks.resize(Skeleton->GetNumBones());
402 anim.OriginSkeleton = &(*Skeleton);
404 for(
auto &catrack: canim->tracks)
406 const StdMeshBone &bone = Skeleton->GetBone(handle_lookup[catrack->bone]);
408 if (track !=
nullptr)
409 throw Ogre::Skeleton::MultipleBoneTracks();
411 for(
auto &catkf: catrack->keyframes)
438 std::unique_ptr<Ogre::Mesh::Chunk> root;
444 throw Ogre::Mesh::InvalidVersion();
449 throw Ogre::Mesh::InvalidVersion();
453 std::unique_ptr<StdMesh> mesh(
new StdMesh);
467 if (mesh->Skeleton ==
nullptr)
469 StdCopyStrBuf exception(
"The specified skeleton file was not found: ");
471 throw Ogre::InsufficientData(exception.
getData());
475 assert(mesh->Skeleton !=
nullptr);
478 std::map<uint16_t, size_t> bone_lookup;
479 for (
size_t i = 0; i < mesh->GetSkeleton().GetNumBones(); ++i)
481 bone_lookup[mesh->GetSkeleton().GetBone(i).ID] = i;
485 mesh->SubMeshes.reserve(cmesh.
submeshes.size());
486 for (
size_t i = 0; i < cmesh.
submeshes.size(); ++i)
493 throw Ogre::Mesh::InvalidMaterial();
495 throw Ogre::Mesh::NotImplemented(
"Submesh operations other than TriList aren't implemented yet");
497 for (
size_t face = 0; face < sm.Faces.size(); ++face)
499 sm.Faces[face].Vertices[0] = csm.
faceVertices[face * 3 + 0];
500 sm.Faces[face].Vertices[1] = csm.
faceVertices[face * 3 + 1];
501 sm.Faces[face].Vertices[2] = csm.
faceVertices[face * 3 + 2];
504 sm.Vertices = ReadSubmeshGeometry(geo, filename);
509 for(
const auto &ba : boneAssignments)
512 throw Ogre::Mesh::VertexNotFound();
513 if (bone_lookup.find(ba.bone) == bone_lookup.end())
514 throw Ogre::Skeleton::BoneNotFound();
515 size_t bone_index = bone_lookup[ba.bone];
520 throw Ogre::Mesh::NotImplemented(
"Vertex is influenced by too many bones");
553 for (
unsigned int i = 0; i < mesh->SubMeshes.size() + 1; ++i)
555 const std::vector<StdSubMesh::Vertex>* vertices =
nullptr;
556 if (i < mesh->SubMeshes.size())
557 vertices = &mesh->SubMeshes[i].Vertices;
559 vertices = &mesh->SharedVertices;
561 for (
const auto & vertex : *vertices)
563 const float d = std::sqrt(vertex.
x*vertex.
x
565 + vertex.
z*vertex.
z);
570 mesh->BoundingBox.x1 = mesh->BoundingBox.x2 = vertex.
x;
571 mesh->BoundingBox.y1 = mesh->BoundingBox.y2 = vertex.
y;
572 mesh->BoundingBox.z1 = mesh->BoundingBox.z2 = vertex.
z;
573 mesh->BoundingRadius = d;
578 mesh->BoundingBox.x1 = std::min(vertex.
x, mesh->BoundingBox.x1);
579 mesh->BoundingBox.x2 = std::max(vertex.
x, mesh->BoundingBox.x2);
580 mesh->BoundingBox.y1 = std::min(vertex.
y, mesh->BoundingBox.y1);
581 mesh->BoundingBox.y2 = std::max(vertex.
y, mesh->BoundingBox.y2);
582 mesh->BoundingBox.z1 = std::min(vertex.
z, mesh->BoundingBox.z1);
583 mesh->BoundingBox.z2 = std::max(vertex.
z, mesh->BoundingBox.z2);
584 mesh->BoundingRadius = std::max(mesh->BoundingRadius, d);
591 if(mesh->BoundingBox.x1 == mesh->BoundingBox.x2 || mesh->BoundingBox.y1 == mesh->BoundingBox.y2)
592 throw Ogre::Mesh::EmptyBoundingBox();
594 return mesh.release();
601 DoIncludeSkeletons();
604 void StdMeshSkeletonLoader::DoResetSkeletons()
606 std::map<StdCopyStrBuf, std::shared_ptr<StdMeshSkeleton>>::iterator it;
607 for (it = Skeletons.begin(); it != Skeletons.end(); it++)
609 std::shared_ptr<StdMeshSkeleton> skeleton = it->second;
612 std::map<StdCopyStrBuf, StdMeshAnimation>::const_iterator animations = skeleton->Animations.begin();
614 while (animations != skeleton->Animations.end())
616 if (animations->second.OriginSkeleton != &(*(skeleton)))
618 animations = skeleton->Animations.erase(animations);
628 void StdMeshSkeletonLoader::DoAppendSkeletons()
632 std::map<StdCopyStrBuf, StdCopyStrBuf>::iterator it;
633 for (it = AppendtoSkeletons.begin(); it != AppendtoSkeletons.end(); it++)
640 if (destination ==
nullptr)
644 LogF(
"WARNING: Appending skeleton '%s' failed", it->first.getData());
650 std::map<StdCopyStrBuf, StdMeshAnimation>::const_iterator animations;
653 for (animations = source->Animations.begin(); animations != source->Animations.end(); animations++)
655 if (destination->Animations.find(animations->first) != destination->Animations.end())
657 LogF(
"WARNING: Overloading animation '%s' is not allowed. This animation already exists in '%s'.", animations->first.getData(),
id.getData());
668 void StdMeshSkeletonLoader::DoIncludeSkeletons()
672 std::map<StdCopyStrBuf, StdCopyStrBuf>::iterator it;
673 for (it = IncludeSkeletons.begin(); it != IncludeSkeletons.end(); it++)
680 if (source ==
nullptr)
684 LogF(
"WARNING: Including skeleton '%s' failed", it->first.getData());
690 std::map<StdCopyStrBuf, StdMeshAnimation>::const_iterator animations;
693 for (animations = source->Animations.begin(); animations != source->Animations.end(); animations++)
695 if (destination->Animations.find(animations->first) != destination->Animations.end())
697 LogF(
"WARNING: Animation '%s' from %s is not included. A newer version of the animation exists in the destination file.", animations->first.getData(),
id.getData());
701 destination->InsertAnimation(*source, animations->second);
bool LogF(const char *strMessage,...)
char * GetExtension(char *szFilename)
bool GetParentPath(const char *szFilename, char *szBuffer)
const char * GetFilenameOnly(const char *strFilename)
StdMeshTransformation Transformation
static Type Peek(const DataStream *stream)
unique_ptr_vector< ChunkGeometryVertexDeclElement > vertexDeclaration
unique_ptr_vector< ChunkGeometryVertexBuffer > vertexBuffers
static std::unique_ptr< Chunk > Read(DataStream *stream)
std::unique_ptr< ChunkGeometry > geometry
std::vector< BoneAssignment > boneAssignments
unique_ptr_vector< ChunkSubmesh > submeshes
std::vector< size_t > faceVertices
std::unique_ptr< ChunkGeometry > geometry
enum Ogre::Mesh::ChunkSubmesh::SubmeshOperation SO_TriList
std::vector< BoneAssignment > boneAssignments
StdMeshQuaternion orientation
static std::unique_ptr< Chunk > Read(DataStream *stream)
StdMeshTransformation InverseTransformation
StdMeshTransformation Transformation
static StdMesh * LoadMeshBinary(const char *sourcefile, size_t size, const StdMeshMatManager &mat_mgr, StdMeshSkeletonLoader &loader, const char *filename=nullptr)
const StdMeshMaterial * GetMaterial(const char *material_name) const
void InsertAnimation(const StdMeshAnimation &animation)
virtual StdMeshSkeleton * GetSkeletonByDefinition(const char *definition) const =0
void LoadSkeletonBinary(const char *groupname, const char *filename, const char *sourcefile, size_t size)
static void MakeFullSkeletonPath(StdCopyStrBuf &out, const char *groupname, const char *filename)
void StoreSkeleton(const char *groupname, const char *filename, std::shared_ptr< StdMeshSkeleton > skeleton)
std::shared_ptr< StdMeshSkeleton > GetSkeletonByName(const StdStrBuf &name) const
void RemoveSkeletonsInGroup(const char *groupname)
void ResolveIncompleteSkeletons()
void RemoveSkeleton(const StdCopyStrBuf &filepath)
const char * getData() const
void Append(const char *pnData, size_t iChars)
size_t GetNumVertices() const
std::vector< std::unique_ptr< T > > unique_ptr_vector
StdSubMesh::Vertex TransformVertex(const StdSubMesh::Vertex &vertex)
StdMeshTransformation TransformTransformation(const StdMeshTransformation &trans)
uint16_t bone_index[MaxBoneWeightCount]
static const size_t MaxBoneWeightCount
float bone_weight[MaxBoneWeightCount]