From e6c197fa871ae38c0d64ec7621a12003f02edbf4 Mon Sep 17 00:00:00 2001 From: cutealien Date: Thu, 23 Apr 2015 18:11:52 +0000 Subject: [PATCH] Add b3d mesh-writer. - Interface getMeshType moved from IAnimatedMesh up to IMesh. - Static b3d mesh-writer written by Hendu, support for animated meshes added by JLouisB, testing and bugfixes by CuteAlien. git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@5095 dfc29bdd-3216-0410-991c-e03cc46cb475 --- changes.txt | 2 + examples/BuildAllExamples.workspace | 4 +- include/EMeshWriterEnums.h | 5 +- include/IAnimatedMesh.h | 42 -- include/IMesh.h | 59 ++ include/IMeshWriter.h | 2 +- include/IrrCompileConfig.h | 5 + source/Irrlicht/CB3DMeshFileLoader.h | 51 +- source/Irrlicht/CB3DMeshWriter.cpp | 649 +++++++++++++++++++ source/Irrlicht/CB3DMeshWriter.h | 53 ++ source/Irrlicht/CSceneManager.cpp | 11 + source/Irrlicht/Irrlicht-gcc.cbp | 3 + source/Irrlicht/Irrlicht10.0.vcxproj | 3 + source/Irrlicht/Irrlicht10.0.vcxproj.filters | 9 + source/Irrlicht/Irrlicht11.0.vcxproj | 3 + source/Irrlicht/Irrlicht11.0.vcxproj.filters | 9 + source/Irrlicht/Irrlicht12.0.vcxproj | 3 + source/Irrlicht/Irrlicht12.0.vcxproj.filters | 9 + source/Irrlicht/Irrlicht9.0.vcproj | 8 + source/Irrlicht/Makefile | 2 +- source/Irrlicht/SB3DStructs.h | 71 ++ 21 files changed, 906 insertions(+), 97 deletions(-) create mode 100644 source/Irrlicht/CB3DMeshWriter.cpp create mode 100644 source/Irrlicht/CB3DMeshWriter.h create mode 100644 source/Irrlicht/SB3DStructs.h diff --git a/changes.txt b/changes.txt index dbf29036..ba2c641c 100644 --- a/changes.txt +++ b/changes.txt @@ -1,6 +1,8 @@ -------------------------- Changes in 1.9 (not yet released) +- Interface getMeshType moved from IAnimatedMesh up to IMesh. +- Add b3d mesh-writer. Static writer written by Hendu, support for animated meshes added by JLouisB, testing and bugfixes by CuteAlien. - Node-collision functions of SceneCollisionManager like getSceneNodeFromScreenCoordinatesBB will now ignore collisions against empty boundingboxes. - Cameras return again an empty boundingbox (at 0,0,0) instead of returning the frustum boundingbox (was changed in very old Irrlicht version). You can access the frustum boundingbox through the frustum itself. diff --git a/examples/BuildAllExamples.workspace b/examples/BuildAllExamples.workspace index 7ddbb5b4..5b070708 100644 --- a/examples/BuildAllExamples.workspace +++ b/examples/BuildAllExamples.workspace @@ -5,7 +5,7 @@ - + @@ -27,7 +27,7 @@ - + diff --git a/include/EMeshWriterEnums.h b/include/EMeshWriterEnums.h index fb2cfa4b..11f2e299 100644 --- a/include/EMeshWriterEnums.h +++ b/include/EMeshWriterEnums.h @@ -31,7 +31,10 @@ namespace scene EMWT_OBJ = MAKE_IRR_ID('o','b','j',0), //! PLY mesh writer for .ply files - EMWT_PLY = MAKE_IRR_ID('p','l','y',0) + EMWT_PLY = MAKE_IRR_ID('p','l','y',0), + + //! B3D mesh writer, for static .b3d files + EMWT_B3D = MAKE_IRR_ID('b', '3', 'd', 0) }; diff --git a/include/IAnimatedMesh.h b/include/IAnimatedMesh.h index 3e08528d..d883bbf5 100644 --- a/include/IAnimatedMesh.h +++ b/include/IAnimatedMesh.h @@ -12,48 +12,6 @@ namespace irr { namespace scene { - //! Possible types of (animated) meshes. - enum E_ANIMATED_MESH_TYPE - { - //! Unknown animated mesh type. - EAMT_UNKNOWN = 0, - - //! Quake 2 MD2 model file - EAMT_MD2, - - //! Quake 3 MD3 model file - EAMT_MD3, - - //! Maya .obj static model - EAMT_OBJ, - - //! Quake 3 .bsp static Map - EAMT_BSP, - - //! 3D Studio .3ds file - EAMT_3DS, - - //! My3D Mesh, the file format by Zhuck Dimitry - EAMT_MY3D, - - //! Pulsar LMTools .lmts file. This Irrlicht loader was written by Jonas Petersen - EAMT_LMTS, - - //! Cartography Shop .csm file. This loader was created by Saurav Mohapatra. - EAMT_CSM, - - //! .oct file for Paul Nette's FSRad or from Murphy McCauley's Blender .oct exporter. - /** The oct file format contains 3D geometry and lightmaps and - can be loaded directly by Irrlicht */ - EAMT_OCT, - - //! Halflife MDL model file - EAMT_MDL_HALFLIFE, - - //! generic skinned mesh - EAMT_SKINNED - }; - //! Interface for an animated mesh. /** There are already simple implementations of this interface available so you don't have to implement this interface on your own if you need to: diff --git a/include/IMesh.h b/include/IMesh.h index 8e0bcc2d..1650e595 100644 --- a/include/IMesh.h +++ b/include/IMesh.h @@ -13,6 +13,54 @@ namespace irr { namespace scene { + //! Possible types of meshes. + // Note: Was previously only used in IAnimatedMesh so it still has the "animated" in the name. + // But can now be used for all mesh-types as we need those casts as well. + enum E_ANIMATED_MESH_TYPE + { + //! Unknown animated mesh type. + EAMT_UNKNOWN = 0, + + //! Quake 2 MD2 model file + EAMT_MD2, + + //! Quake 3 MD3 model file + EAMT_MD3, + + //! Maya .obj static model + EAMT_OBJ, + + //! Quake 3 .bsp static Map + EAMT_BSP, + + //! 3D Studio .3ds file + EAMT_3DS, + + //! My3D Mesh, the file format by Zhuck Dimitry + EAMT_MY3D, + + //! Pulsar LMTools .lmts file. This Irrlicht loader was written by Jonas Petersen + EAMT_LMTS, + + //! Cartography Shop .csm file. This loader was created by Saurav Mohapatra. + EAMT_CSM, + + //! .oct file for Paul Nette's FSRad or from Murphy McCauley's Blender .oct exporter. + /** The oct file format contains 3D geometry and lightmaps and + can be loaded directly by Irrlicht */ + EAMT_OCT, + + //! Halflife MDL model file + EAMT_MDL_HALFLIFE, + + //! generic skinned mesh + EAMT_SKINNED, + + //! generig non-animated mesh + EAMT_STATIC + }; + + class IMeshBuffer; //! Class which holds the geometry of an object. @@ -66,6 +114,17 @@ namespace scene indices have changed. Otherwise, changes won't be updated on the GPU in the next render cycle. */ virtual void setDirty(E_BUFFER_TYPE buffer=EBT_VERTEX_AND_INDEX) = 0; + + //! Returns the type of the meshes. + /** This is useful for making a safe downcast. For example, + if getMeshType() returns EAMT_MD2 it's safe to cast the + IMesh to IAnimatedMeshMD2. + Note: It's no longer just about animated meshes, that name has just historical reasons. + \returns Type of the mesh */ + virtual E_ANIMATED_MESH_TYPE getMeshType() const + { + return EAMT_STATIC; + } }; } // end namespace scene diff --git a/include/IMeshWriter.h b/include/IMeshWriter.h index 555a7988..f7c1820a 100644 --- a/include/IMeshWriter.h +++ b/include/IMeshWriter.h @@ -43,7 +43,7 @@ namespace scene s32 flags=EMWF_NONE) = 0; // Writes an animated mesh - // for future use, no writer is able to write animated meshes currently + // for future use, only b3d writer is able to write animated meshes currently and that was implemented using the writeMesh above. /* \return Returns true if sucessful */ //virtual bool writeAnimatedMesh(io::IWriteFile* file, // scene::IAnimatedMesh* mesh, diff --git a/include/IrrCompileConfig.h b/include/IrrCompileConfig.h index 966371ac..b6485e15 100644 --- a/include/IrrCompileConfig.h +++ b/include/IrrCompileConfig.h @@ -482,6 +482,11 @@ B3D, MS3D or X meshes */ #ifdef NO_IRR_COMPILE_WITH_PLY_WRITER_ #undef _IRR_COMPILE_WITH_PLY_WRITER_ #endif +//! Define _IRR_COMPILE_WITH_B3D_WRITER_ if you want to write .b3d files +#define _IRR_COMPILE_WITH_B3D_WRITER_ +#ifdef NO_IRR_COMPILE_WITH_B3D_WRITER_ +#undef _IRR_COMPILE_WITH_B3D_WRITER_ +#endif //! Define _IRR_COMPILE_WITH_BMP_LOADER_ if you want to load .bmp files //! Disabling this loader will also disable the built-in font diff --git a/source/Irrlicht/CB3DMeshFileLoader.h b/source/Irrlicht/CB3DMeshFileLoader.h index dba44d79..ea78e532 100644 --- a/source/Irrlicht/CB3DMeshFileLoader.h +++ b/source/Irrlicht/CB3DMeshFileLoader.h @@ -14,6 +14,7 @@ #include "IMeshLoader.h" #include "ISceneManager.h" #include "CSkinnedMesh.h" +#include "SB3DStructs.h" #include "IReadFile.h" namespace irr @@ -42,56 +43,6 @@ public: private: - struct SB3dChunkHeader - { - c8 name[4]; - s32 size; - }; - - struct SB3dChunk - { - SB3dChunk(const SB3dChunkHeader& header, long sp) - : length(header.size+8), startposition(sp) - { - name[0]=header.name[0]; - name[1]=header.name[1]; - name[2]=header.name[2]; - name[3]=header.name[3]; - } - - c8 name[4]; - s32 length; - long startposition; - }; - - struct SB3dTexture - { - core::stringc TextureName; - s32 Flags; - s32 Blend; - f32 Xpos; - f32 Ypos; - f32 Xscale; - f32 Yscale; - f32 Angle; - }; - - struct SB3dMaterial - { - SB3dMaterial() : red(1.0f), green(1.0f), - blue(1.0f), alpha(1.0f), shininess(0.0f), blend(1), - fx(0) - { - for (u32 i=0; iwrite("BB3D", 4); + file->write(&Size, sizeof(u32)); // Updated later once known. + + int version = 1; + write(file, &version, sizeof(int)); + + // + + const u32 numBeshBuffers = mesh->getMeshBufferCount(); + array texs; + map tex2id; // TODO: texture pointer as key not sufficient as same texture can have several id's + u32 texsizes = 0; + for (u32 i = 0; i < numBeshBuffers; i++) + { + const IMeshBuffer * const mb = mesh->getMeshBuffer(i); + const SMaterial &mat = mb->getMaterial(); + + for (u32 j = 0; j < MATERIAL_MAX_TEXTURES; j++) + { + if (mat.getTexture(j)) + { + SB3dTexture t; + t.TextureName = core::stringc(mat.getTexture(j)->getName().getPath()); + + // TODO: need some description of Blitz3D texture-flags to figure this out. But Blend should likely depend on material-type. + t.Flags = j == 2 ? 65536 : 1; + t.Blend = 2; + + // TODO: evaluate texture matrix + t.Xpos = 0; + t.Ypos = 0; + t.Xscale = 1; + t.Yscale = 1; + t.Angle = 0; + + texs.push_back(t); + texsizes += 7*4 + t.TextureName.size() + 1; + tex2id[mat.getTexture(j)] = texs.size() - 1; + } + } + } + + write(file, "TEXS", 4); + write(file, &texsizes, 4); + + u32 numTexture = texs.size(); + for (u32 i = 0; i < numTexture; i++) + { + write(file, texs[i].TextureName.c_str(), texs[i].TextureName.size() + 1); + write(file, &texs[i].Flags, 7*4); + } + + // + + const u32 brushsize = (7 * 4 + 1) * numBeshBuffers + numBeshBuffers * 4 * MATERIAL_MAX_TEXTURES + 4; + write(file, "BRUS", 4); + write(file, &brushsize, 4); + u32 brushcheck = Size; + const u32 usedtex = MATERIAL_MAX_TEXTURES; + write(file, &usedtex, 4); + + for (u32 i = 0; i < numBeshBuffers; i++) + { + const IMeshBuffer * const mb = mesh->getMeshBuffer(i); + const SMaterial &mat = mb->getMaterial(); + + write(file, "", 1); + + float f = 1; + write(file, &f, 4); + write(file, &f, 4); + write(file, &f, 4); + write(file, &f, 4); + + f = 0; + write(file, &f, 4); + + u32 tmp = 1; + write(file, &tmp, 4); + tmp = 0; + write(file, &tmp, 4); + + for (u32 j = 0; j < MATERIAL_MAX_TEXTURES; j++) + { + if (mat.getTexture(j)) + { + const u32 id = tex2id[mat.getTexture(j)]; + write(file, &id, 4); + } + else + { + const int id = -1; + write(file, &id, 4); + } + } + } + + // Check brushsize + brushcheck = Size - brushcheck; + if (brushcheck != brushsize) + { + printf("Failed in brush size calculation, size %u advanced %u\n", + brushsize, brushcheck); + } + + write(file, "NODE", 4); + + // Calculate node size + u32 nodesize = 41 + 8 + 4 + 8; + u32 bonesSize = 0; + + if(ISkinnedMesh *skinnedMesh = getSkinned(mesh)) + { + if (!skinnedMesh->isStatic()) + { + bonesSize += 20; + } + + const core::array rootJoints = getRootJoints(skinnedMesh); + for (u32 i = 0; i < rootJoints.size(); i++) + { + bonesSize += getJointChunkSize(skinnedMesh, rootJoints[i]); + } + nodesize += bonesSize; + + // ------------------- + + } + + // VERT data + nodesize += 12; + + const u32 texcoords = getUVlayerCount(mesh); + for (u32 i = 0; i < numBeshBuffers; i++) + { + nodesize += 8 + 4; + const IMeshBuffer * const mb = mesh->getMeshBuffer(i); + + nodesize += mb->getVertexCount() * 10 * 4; + + nodesize += mb->getVertexCount() * texcoords * 2 * 4; + nodesize += mb->getIndexCount() * 4; + } + write(file, &nodesize, 4); + u32 nodecheck = Size; + + // Node + write(file, "", 1); + float f = 0; + write(file, &f, 4); + write(file, &f, 4); + write(file, &f, 4); + + f = 1; + write(file, &f, 4); + write(file, &f, 4); + write(file, &f, 4); + + write(file, &f, 4); + f = 0; + write(file, &f, 4); + write(file, &f, 4); + write(file, &f, 4); + + // Mesh + write(file, "MESH", 4); + const u32 meshsize = nodesize - 41 - 8 - bonesSize; + write(file, &meshsize, 4); + s32 brushID = -1; + write(file, &brushID, 4); + + + + // Verts + write(file, "VRTS", 4); + u32 vertsize = 12; + + for (u32 i = 0; i < numBeshBuffers; i++) + { + const IMeshBuffer * const mb = mesh->getMeshBuffer(i); + + vertsize += mb->getVertexCount() * 10 * 4 + + mb->getVertexCount() * texcoords * 2 * 4; + } + write(file, &vertsize, 4); + u32 vertcheck = Size; + + int flagsB3D = 3; + write(file, &flagsB3D, 4); + + write(file, &texcoords, 4); + flagsB3D = 2; + write(file, &flagsB3D, 4); + + for (u32 i = 0; i < numBeshBuffers; i++) + { + const IMeshBuffer * const mb = mesh->getMeshBuffer(i); + irr::u32 numVertices = mb->getVertexCount(); + for (u32 j = 0; j < numVertices; j++) + { + const vector3df &pos = mb->getPosition(j); + write(file, &pos.X, 4); + write(file, &pos.Y, 4); + write(file, &pos.Z, 4); + + const vector3df &n = mb->getNormal(j); + write(file, &n.X, 4); + write(file, &n.Y, 4); + write(file, &n.Z, 4); + + const u32 zero = 0; + switch (mb->getVertexType()) + { + case EVT_STANDARD: + { + S3DVertex *v = (S3DVertex *) mb->getVertices(); + const SColorf col(v[j].Color); + write(file, &col.r, 4); + write(file, &col.g, 4); + write(file, &col.b, 4); + write(file, &col.a, 4); + + write(file, &v[j].TCoords.X, 4); + write(file, &v[j].TCoords.Y, 4); + if (texcoords == 2) + { + write(file, &zero, 4); + write(file, &zero, 4); + } + } + break; + case EVT_2TCOORDS: + { + S3DVertex2TCoords *v = (S3DVertex2TCoords *) mb->getVertices(); + const SColorf col(v[j].Color); + write(file, &col.r, 4); + write(file, &col.g, 4); + write(file, &col.b, 4); + write(file, &col.a, 4); + + write(file, &v[j].TCoords.X, 4); + write(file, &v[j].TCoords.Y, 4); + write(file, &v[j].TCoords2.X, 4); + write(file, &v[j].TCoords2.Y, 4); + } + break; + case EVT_TANGENTS: + { + S3DVertexTangents *v = (S3DVertexTangents *) mb->getVertices(); + const SColorf col(v[j].Color); + write(file, &col.r, 4); + write(file, &col.g, 4); + write(file, &col.b, 4); + write(file, &col.a, 4); + + write(file, &v[j].TCoords.X, 4); + write(file, &v[j].TCoords.Y, 4); + if (texcoords == 2) + { + write(file, &zero, 4); + write(file, &zero, 4); + } + } + break; + } + } + } + // Check vertsize + vertcheck = Size - vertcheck; + if (vertcheck != vertsize) + { + printf("Failed in vertex size calculation, size %u advanced %u\n", + vertsize, vertcheck); + } + + u32 currentMeshBufferIndex = 0; + // Tris + for (u32 i = 0; i < numBeshBuffers; i++) + { + const IMeshBuffer * const mb = mesh->getMeshBuffer(i); + write(file, "TRIS", 4); + const u32 trisize = 4 + mb->getIndexCount() * 4; + write(file, &trisize, 4); + + u32 tricheck = Size; + + write(file, &i, 4); + + u32 numIndices = mb->getIndexCount(); + const u16 * const idx = (u16 *) mb->getIndices(); + for (u32 j = 0; j < numIndices; j += 3) + { + u32 tmp = idx[j] + currentMeshBufferIndex; + write(file, &tmp, sizeof(u32)); + + tmp = idx[j + 1] + currentMeshBufferIndex; + write(file, &tmp, sizeof(u32)); + + tmp = idx[j + 2] + currentMeshBufferIndex; + write(file, &tmp, sizeof(u32)); + } + + // Check that tris calculation was ok + tricheck = Size - tricheck; + if (tricheck != trisize) + { + printf("Failed in tris size calculation, size %u advanced %u\n", + trisize, tricheck); + } + + currentMeshBufferIndex += mb->getVertexCount(); + } + + if(ISkinnedMesh *skinnedMesh = getSkinned(mesh)) + { + // Write animation data + if (!skinnedMesh->isStatic()) + { + write(file, "ANIM", 4); + + const u32 animsize = 12; + write(file, &animsize, 4); + + const u32 flags = 0; + const u32 frames = skinnedMesh->getFrameCount(); + const f32 fps = skinnedMesh->getAnimationSpeed(); + + write(file, &flags, 4); + write(file, &frames, 4); + write(file, &fps, 4); + } + + // Write joints + core::array rootJoints = getRootJoints(skinnedMesh); + + for (u32 i = 0; i < rootJoints.size(); i++) + { + writeJointChunk(file, skinnedMesh, rootJoints[i]); + } + } + + // Check that node calculation was ok + nodecheck = Size - nodecheck; + if (nodecheck != nodesize) + { + printf("Failed in node size calculation, size %u advanced %u\n", + nodesize, nodecheck); + } + file->seek(4); + file->write(&Size, 4); + + return true; +} + + + +void CB3DMeshWriter::writeJointChunk(io::IWriteFile* file, ISkinnedMesh* mesh , ISkinnedMesh::SJoint* joint) +{ + // Node + write(file, "NODE", 4); + + // Calculate node size + u32 nodesize = getJointChunkSize(mesh, joint); + nodesize -= 8; // The declaration + size of THIS chunk shouldn't be added to the size + + write(file, &nodesize, 4); + + + core::stringc name = joint->Name; + write(file, name.c_str(), name.size()); + write(file, "", 1); + + core::vector3df pos = joint->Animatedposition; + // Position + write(file, &pos.X, 4); + write(file, &pos.Y, 4); + write(file, &pos.Z, 4); + + // Scale + core::vector3df scale = joint->Animatedscale; + if (scale == core::vector3df(0, 0, 0)) + scale = core::vector3df(1, 1, 1); + + write(file, &scale.X, 4); + write(file, &scale.Y, 4); + write(file, &scale.Z, 4); + + // Rotation + core::quaternion quat = joint->Animatedrotation; + write(file, &quat.W, 4); + write(file, &quat.X, 4); + write(file, &quat.Y, 4); + write(file, &quat.Z, 4); + + // Bone + write(file, "BONE", 4); + u32 bonesize = 8 * joint->Weights.size(); + write(file, &bonesize, 4); + + // Skinning ------------------ + for (u32 i = 0; i < joint->Weights.size(); i++) + { + const u32 vertexID = joint->Weights[i].vertex_id; + const u32 bufferID = joint->Weights[i].buffer_id; + const f32 weight = joint->Weights[i].strength; + + u32 b3dVertexID = vertexID; + for (u32 j = 0; j < bufferID; j++) + { + b3dVertexID += mesh->getMeshBuffer(j)->getVertexCount(); + } + + write(file, &b3dVertexID, 4); + write(file, &weight, 4); + } + // --------------------------- + + // Animation keys + if (joint->PositionKeys.size()) + { + write(file, "KEYS", 4); + u32 keysSize = 4 * joint->PositionKeys.size() * 4; // X, Y and Z pos + frame + keysSize += 4; // Flag to define the type of the key + write(file, &keysSize, 4); + + u32 flag = 1; // 1 = flag for position keys + write(file, &flag, 4); + + for (u32 i = 0; i < joint->PositionKeys.size(); i++) + { + const s32 frame = static_cast(joint->PositionKeys[i].frame); + const core::vector3df pos = joint->PositionKeys[i].position; + + write (file, &frame, 4); + + write (file, &pos.X, 4); + write (file, &pos.Y, 4); + write (file, &pos.Z, 4); + + } + } + if (joint->RotationKeys.size()) + { + write(file, "KEYS", 4); + u32 keysSize = 4 * joint->RotationKeys.size() * 5; // W, X, Y and Z rot + frame + keysSize += 4; // Flag + write(file, &keysSize, 4); + + u32 flag = 4; + write(file, &flag, 4); + + for (u32 i = 0; i < joint->RotationKeys.size(); i++) + { + const s32 frame = static_cast(joint->RotationKeys[i].frame); + const core::quaternion rot = joint->RotationKeys[i].rotation; + + write (file, &frame, 4); + + write (file, &rot.W, 4); + write (file, &rot.X, 4); + write (file, &rot.Y, 4); + write (file, &rot.Z, 4); + } + } + if (joint->ScaleKeys.size()) + { + write(file, "KEYS", 4); + u32 keysSize = 4 * joint->ScaleKeys.size() * 4; // X, Y and Z scale + frame + keysSize += 4; // Flag + write(file, &keysSize, 4); + + u32 flag = 2; + write(file, &flag, 4); + + for (u32 i = 0; i < joint->ScaleKeys.size(); i++) + { + const s32 frame = static_cast(joint->ScaleKeys[i].frame); + const core::vector3df scale = joint->ScaleKeys[i].scale; + + write (file, &frame, 4); + + write (file, &scale.X, 4); + write (file, &scale.Y, 4); + write (file, &scale.Z, 4); + } + } + + for (u32 i = 0; i < joint->Children.size(); i++) + { + writeJointChunk(file, mesh, joint->Children[i]); + } +} + + +ISkinnedMesh* CB3DMeshWriter::getSkinned (IMesh *mesh) +{ + if (mesh->getMeshType() == EAMT_SKINNED) + { + return static_cast(mesh); + } + return 0; +} + +u32 CB3DMeshWriter::getJointChunkSize(const ISkinnedMesh* mesh, ISkinnedMesh::SJoint* joint) +{ + u32 chunkSize = 8 + 40; // Chunk declaration + chunk data + chunkSize += joint->Name.size() + 1; // the NULL character at the end of the string + + u32 boneSize = joint->Weights.size() * 8; // vertex_id + weight = 8 bits per weight block + boneSize += 8; // declaration + size of he BONE chunk + + u32 keysSize = 0; + if (joint->PositionKeys.size() != 0) + { + keysSize += 8; // KEYS + chunk size + keysSize += 4; // flags + + keysSize += (joint->PositionKeys.size() * 16); + } + if (joint->RotationKeys.size() != 0) + { + keysSize += 8; // KEYS + chunk size + keysSize += 4; // flags + + keysSize += (joint->RotationKeys.size() * 20); + } + if (joint->ScaleKeys.size() != 0) + { + keysSize += 8; // KEYS + chunk size + keysSize += 4; // flags + + keysSize += (joint->ScaleKeys.size() * 16); + } + + chunkSize += boneSize; + chunkSize += keysSize; + + for (u32 i = 0; i < joint->Children.size(); ++i) + { + chunkSize += (getJointChunkSize(mesh, joint->Children[i])); + } + return chunkSize; +} + +core::array CB3DMeshWriter::getRootJoints(const ISkinnedMesh* mesh) +{ + core::array roots; + + core::array allJoints = mesh->getAllJoints(); + for (u32 i = 0; i < allJoints.size(); i++) + { + bool isRoot = true; + ISkinnedMesh::SJoint* testedJoint = allJoints[i]; + for (u32 j = 0; j < allJoints.size(); j++) + { + ISkinnedMesh::SJoint* testedJoint2 = allJoints[j]; + for (u32 k = 0; k < testedJoint2->Children.size(); k++) + { + if (testedJoint == testedJoint2->Children[k]) + isRoot = false; + } + } + if (isRoot) + roots.push_back(testedJoint); + } + + return roots; +} + +u32 CB3DMeshWriter::getUVlayerCount(IMesh* mesh) +{ + const u32 numBeshBuffers = mesh->getMeshBufferCount(); + for (u32 i = 0; i < numBeshBuffers; i++) + { + const IMeshBuffer * const mb = mesh->getMeshBuffer(i); + + if (mb->getVertexType() == EVT_2TCOORDS) + { + return 2; + } + } + return 1; +} + +void CB3DMeshWriter::write(io::IWriteFile* file, const void *ptr, const u32 bytes) +{ + file->write(ptr, bytes); + Size += bytes; +} + +} // end namespace +} // end namespace + +#endif // _IRR_COMPILE_WITH_B3D_WRITER_ + diff --git a/source/Irrlicht/CB3DMeshWriter.h b/source/Irrlicht/CB3DMeshWriter.h new file mode 100644 index 00000000..d4653afd --- /dev/null +++ b/source/Irrlicht/CB3DMeshWriter.h @@ -0,0 +1,53 @@ +// Copyright (C) 2014 Lauri Kasanen +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +// Modified version with rigging/skinning support + +#ifndef __IRR_B3D_MESH_WRITER_H_INCLUDED__ +#define __IRR_B3D_MESH_WRITER_H_INCLUDED__ + +#include "IMeshWriter.h" +#include "IFileSystem.h" +#include "SB3DStructs.h" +#include "ISkinnedMesh.h" + + + +namespace irr +{ +namespace scene +{ + +//! class to write B3D mesh files +class CB3DMeshWriter : public IMeshWriter +{ +public: + + CB3DMeshWriter(io::IFileSystem *fs); + + //! Returns the type of the mesh writer + virtual EMESH_WRITER_TYPE getType() const; + + //! writes a mesh + virtual bool writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32 flags=EMWF_NONE); + +private: + io::IFileSystem *FileSystem; + u32 Size; + + void writeJointChunk(io::IWriteFile* file, ISkinnedMesh* mesh , ISkinnedMesh::SJoint* joint); + u32 getJointChunkSize(const ISkinnedMesh* mesh, ISkinnedMesh::SJoint* joint); + core::array getRootJoints(const ISkinnedMesh* mesh); + + u32 getUVlayerCount(IMesh *mesh); + ISkinnedMesh* getSkinned (IMesh *mesh); + + void write(io::IWriteFile* file, const void *ptr, const u32 bytes); + +}; + +} // end namespace +} // end namespace + +#endif diff --git a/source/Irrlicht/CSceneManager.cpp b/source/Irrlicht/CSceneManager.cpp index 08a61797..62e5e38b 100644 --- a/source/Irrlicht/CSceneManager.cpp +++ b/source/Irrlicht/CSceneManager.cpp @@ -134,6 +134,10 @@ #include "CPLYMeshWriter.h" #endif +#ifdef _IRR_COMPILE_WITH_B3D_WRITER_ +#include "CB3DMeshWriter.h" +#endif + #include "CCubeSceneNode.h" #include "CSphereSceneNode.h" #include "CAnimatedMeshSceneNode.h" @@ -2545,6 +2549,13 @@ IMeshWriter* CSceneManager::createMeshWriter(EMESH_WRITER_TYPE type) #else return 0; #endif + + case EMWT_B3D: +#ifdef _IRR_COMPILE_WITH_B3D_WRITER_ + return new CB3DMeshWriter(FileSystem); +#else + return 0; +#endif } return 0; diff --git a/source/Irrlicht/Irrlicht-gcc.cbp b/source/Irrlicht/Irrlicht-gcc.cbp index e89ee4bb..80318220 100644 --- a/source/Irrlicht/Irrlicht-gcc.cbp +++ b/source/Irrlicht/Irrlicht-gcc.cbp @@ -614,6 +614,8 @@ + + @@ -1013,6 +1015,7 @@ + diff --git a/source/Irrlicht/Irrlicht10.0.vcxproj b/source/Irrlicht/Irrlicht10.0.vcxproj index fbcf39f5..e8c10738 100644 --- a/source/Irrlicht/Irrlicht10.0.vcxproj +++ b/source/Irrlicht/Irrlicht10.0.vcxproj @@ -994,6 +994,7 @@ + @@ -1103,6 +1104,7 @@ + @@ -1240,6 +1242,7 @@ + diff --git a/source/Irrlicht/Irrlicht10.0.vcxproj.filters b/source/Irrlicht/Irrlicht10.0.vcxproj.filters index 259d94a5..4f528384 100644 --- a/source/Irrlicht/Irrlicht10.0.vcxproj.filters +++ b/source/Irrlicht/Irrlicht10.0.vcxproj.filters @@ -1309,6 +1309,12 @@ Irrlicht\video\OpenGL + + Irrlicht\scene\writers + + + Irrlicht\scene + @@ -2237,6 +2243,9 @@ Irrlicht\video\OpenGL + + Irrlicht\scene\writers + diff --git a/source/Irrlicht/Irrlicht11.0.vcxproj b/source/Irrlicht/Irrlicht11.0.vcxproj index cdd6762f..58875e38 100644 --- a/source/Irrlicht/Irrlicht11.0.vcxproj +++ b/source/Irrlicht/Irrlicht11.0.vcxproj @@ -1001,6 +1001,7 @@ + @@ -1109,6 +1110,7 @@ + @@ -1247,6 +1249,7 @@ + diff --git a/source/Irrlicht/Irrlicht11.0.vcxproj.filters b/source/Irrlicht/Irrlicht11.0.vcxproj.filters index 01d942e4..cbc33cb7 100644 --- a/source/Irrlicht/Irrlicht11.0.vcxproj.filters +++ b/source/Irrlicht/Irrlicht11.0.vcxproj.filters @@ -1308,6 +1308,12 @@ Irrlicht\video\OpenGL + + + Irrlicht\scene\writers + + + Irrlicht\scene @@ -2236,6 +2242,9 @@ Irrlicht\video\OpenGL + + + Irrlicht\scene\writers diff --git a/source/Irrlicht/Irrlicht12.0.vcxproj b/source/Irrlicht/Irrlicht12.0.vcxproj index 67b67772..e7d3b1f2 100644 --- a/source/Irrlicht/Irrlicht12.0.vcxproj +++ b/source/Irrlicht/Irrlicht12.0.vcxproj @@ -1001,6 +1001,7 @@ + @@ -1109,6 +1110,7 @@ + @@ -1247,6 +1249,7 @@ + diff --git a/source/Irrlicht/Irrlicht12.0.vcxproj.filters b/source/Irrlicht/Irrlicht12.0.vcxproj.filters index 01d942e4..cbc33cb7 100644 --- a/source/Irrlicht/Irrlicht12.0.vcxproj.filters +++ b/source/Irrlicht/Irrlicht12.0.vcxproj.filters @@ -1308,6 +1308,12 @@ Irrlicht\video\OpenGL + + + Irrlicht\scene\writers + + + Irrlicht\scene @@ -2236,6 +2242,9 @@ Irrlicht\video\OpenGL + + + Irrlicht\scene\writers diff --git a/source/Irrlicht/Irrlicht9.0.vcproj b/source/Irrlicht/Irrlicht9.0.vcproj index 2167802c..8382391f 100644 --- a/source/Irrlicht/Irrlicht9.0.vcproj +++ b/source/Irrlicht/Irrlicht9.0.vcproj @@ -2079,6 +2079,14 @@ RelativePath="CSTLMeshWriter.h" > + + + +