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
master
cutealien 2015-04-23 18:11:52 +00:00
parent c6eec21cec
commit e6c197fa87
21 changed files with 906 additions and 97 deletions

View File

@ -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.

View File

@ -5,7 +5,7 @@
<Project filename="01.HelloWorld/HelloWorld.cbp" />
<Project filename="02.Quake3Map/Quake3Map.cbp" />
<Project filename="03.CustomSceneNode/CustomSceneNode.cbp" />
<Project filename="04.Movement/Movement.cbp" />
<Project filename="04.Movement/Movement.cbp" active="1" />
<Project filename="05.UserInterface/UserInterface.cbp" />
<Project filename="06.2DGraphics/2DGraphics.cbp" />
<Project filename="07.Collision/Collision.cbp" />
@ -27,7 +27,7 @@
<Project filename="24.CursorControl/CursorControl.cbp" />
<Project filename="25.XmlHandling/XmlHandling.cbp" />
<Project filename="26.OcclusionQuery/OcclusionQuery.cbp" />
<Project filename="30.Profiling/Profiling.cbp" active="1" />
<Project filename="30.Profiling/Profiling.cbp" />
<Project filename="Demo/demo.cbp" />
<Project filename="../tools/GUIEditor/GUIEditor_gcc.cbp" />
<Project filename="../tools/MeshConverter/MeshConverter.cbp" />

View File

@ -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)
};

View File

@ -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:

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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; i<video::MATERIAL_MAX_TEXTURES; ++i)
Textures[i]=0;
}
video::SMaterial Material;
f32 red, green, blue, alpha;
f32 shininess;
s32 blend,fx;
SB3dTexture *Textures[video::MATERIAL_MAX_TEXTURES];
};
bool load();
bool readChunkNODE(CSkinnedMesh::SJoint* InJoint);
bool readChunkMESH(CSkinnedMesh::SJoint* InJoint);

View File

@ -0,0 +1,649 @@
// 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
// TODO: replace printf's by logging messages
#include "IrrCompileConfig.h"
#define _IRR_COMPILE_WITH_B3D_WRITER_
#ifdef _IRR_COMPILE_WITH_B3D_WRITER_
#include "CB3DMeshWriter.h"
#include "os.h"
#include "ISkinnedMesh.h"
#include "IMeshBuffer.h"
#include "IWriteFile.h"
#include "ITexture.h"
#include "irrMap.h"
namespace irr
{
namespace scene
{
using namespace core;
using namespace video;
CB3DMeshWriter::CB3DMeshWriter(io::IFileSystem *fs): FileSystem(fs)
{
#ifdef _DEBUG
setDebugName("CB3DMeshWriter");
#endif
}
//! Returns the type of the mesh writer
EMESH_WRITER_TYPE CB3DMeshWriter::getType() const
{
return EMWT_B3D;
}
//! writes a mesh
bool CB3DMeshWriter::writeMesh(io::IWriteFile* file, IMesh* const mesh, s32 flags)
{
if (!file || !mesh)
return false;
#ifdef __BIG_ENDIAN__
os::Printer::log("B3D export does not support big-endian systems.", ELL_ERROR);
return false;
#endif
Size = 0;
file->write("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<SB3dTexture> texs;
map<ITexture *, u32> 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<ISkinnedMesh::SJoint*> 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<ISkinnedMesh::SJoint*> 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<s32>(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<s32>(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<s32>(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<ISkinnedMesh*>(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<ISkinnedMesh::SJoint*> CB3DMeshWriter::getRootJoints(const ISkinnedMesh* mesh)
{
core::array<ISkinnedMesh::SJoint*> roots;
core::array<ISkinnedMesh::SJoint*> 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_

View File

@ -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<ISkinnedMesh::SJoint*> 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

View File

@ -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;

View File

@ -614,6 +614,8 @@
<Unit filename="CAttributes.h" />
<Unit filename="CB3DMeshFileLoader.cpp" />
<Unit filename="CB3DMeshFileLoader.h" />
<Unit filename="CB3DMeshWriter.cpp" />
<Unit filename="CB3DMeshWriter.h" />
<Unit filename="CBSPMeshFileLoader.cpp" />
<Unit filename="CBSPMeshFileLoader.h" />
<Unit filename="CBillboardSceneNode.cpp" />
@ -1013,6 +1015,7 @@
<Unit filename="Octree.h" />
<Unit filename="S2DVertex.h" />
<Unit filename="S4DVertex.h" />
<Unit filename="SB3DStructs.h" />
<Unit filename="SoftwareDriver2_compile_config.h" />
<Unit filename="SoftwareDriver2_helper.h" />
<Unit filename="aesGladman\aes.h" />

View File

@ -994,6 +994,7 @@
<ClInclude Include="..\..\include\IGUIToolbar.h" />
<ClInclude Include="..\..\include\IGUITreeView.h" />
<ClInclude Include="..\..\include\IGUIWindow.h" />
<ClInclude Include="CB3DMeshWriter.h" />
<ClInclude Include="CD3D9RenderTarget.h" />
<ClInclude Include="CDefaultSceneNodeAnimatorFactory.h" />
<ClInclude Include="CDefaultSceneNodeFactory.h" />
@ -1103,6 +1104,7 @@
<ClInclude Include="COpenGLSLMaterialRenderer.h" />
<ClInclude Include="COpenGLTexture.h" />
<ClInclude Include="glext.h" />
<ClInclude Include="SB3DStructs.h" />
<ClInclude Include="wglext.h" />
<ClInclude Include="CColorConverter.h" />
<ClInclude Include="CFPSCounter.h" />
@ -1240,6 +1242,7 @@
<None Include="..\..\readme.txt" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="CB3DMeshWriter.cpp" />
<ClCompile Include="CD3D9RenderTarget.cpp" />
<ClCompile Include="CDefaultSceneNodeAnimatorFactory.cpp" />
<ClCompile Include="CDefaultSceneNodeFactory.cpp" />

View File

@ -1309,6 +1309,12 @@
<ClInclude Include="COpenGLRenderTarget.h">
<Filter>Irrlicht\video\OpenGL</Filter>
</ClInclude>
<ClInclude Include="CB3DMeshWriter.h">
<Filter>Irrlicht\scene\writers</Filter>
</ClInclude>
<ClInclude Include="SB3DStructs.h">
<Filter>Irrlicht\scene</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\..\changes.txt">
@ -2237,6 +2243,9 @@
<ClCompile Include="COpenGLRenderTarget.cpp">
<Filter>Irrlicht\video\OpenGL</Filter>
</ClCompile>
<ClCompile Include="CB3DMeshWriter.cpp">
<Filter>Irrlicht\scene\writers</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Irrlicht.rc" />

View File

@ -1001,6 +1001,7 @@
<ClInclude Include="..\..\include\IGUIToolbar.h" />
<ClInclude Include="..\..\include\IGUITreeView.h" />
<ClInclude Include="..\..\include\IGUIWindow.h" />
<ClInclude Include="CB3DMeshWriter.h" />
<ClInclude Include="CD3D9RenderTarget.h" />
<ClInclude Include="CDefaultSceneNodeAnimatorFactory.h" />
<ClInclude Include="CDefaultSceneNodeFactory.h" />
@ -1109,6 +1110,7 @@
<ClInclude Include="COpenGLSLMaterialRenderer.h" />
<ClInclude Include="COpenGLTexture.h" />
<ClInclude Include="glext.h" />
<ClInclude Include="SB3DStructs.h" />
<ClInclude Include="wglext.h" />
<ClInclude Include="CColorConverter.h" />
<ClInclude Include="CFPSCounter.h" />
@ -1247,6 +1249,7 @@
<None Include="..\..\readme.txt" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="CB3DMeshWriter.cpp" />
<ClCompile Include="CD3D9RenderTarget.cpp" />
<ClCompile Include="CDefaultSceneNodeAnimatorFactory.cpp" />
<ClCompile Include="CDefaultSceneNodeFactory.cpp" />

View File

@ -1308,6 +1308,12 @@
</ClInclude>
<ClInclude Include="COpenGLRenderTarget.h">
<Filter>Irrlicht\video\OpenGL</Filter>
</ClInclude>
<ClInclude Include="CB3DMeshWriter.h">
<Filter>Irrlicht\scene\writers</Filter>
</ClInclude>
<ClInclude Include="SB3DStructs.h">
<Filter>Irrlicht\scene</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
@ -2236,6 +2242,9 @@
</ClCompile>
<ClCompile Include="COpenGLRenderTarget.cpp">
<Filter>Irrlicht\video\OpenGL</Filter>
</ClCompile>
<ClCompile Include="CB3DMeshWriter.cpp">
<Filter>Irrlicht\scene\writers</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>

View File

@ -1001,6 +1001,7 @@
<ClInclude Include="..\..\include\IGUIToolbar.h" />
<ClInclude Include="..\..\include\IGUITreeView.h" />
<ClInclude Include="..\..\include\IGUIWindow.h" />
<ClInclude Include="CB3DMeshWriter.h" />
<ClInclude Include="CD3D9RenderTarget.h" />
<ClInclude Include="CDefaultSceneNodeAnimatorFactory.h" />
<ClInclude Include="CDefaultSceneNodeFactory.h" />
@ -1109,6 +1110,7 @@
<ClInclude Include="COpenGLSLMaterialRenderer.h" />
<ClInclude Include="COpenGLTexture.h" />
<ClInclude Include="glext.h" />
<ClInclude Include="SB3DStructs.h" />
<ClInclude Include="wglext.h" />
<ClInclude Include="CColorConverter.h" />
<ClInclude Include="CFPSCounter.h" />
@ -1247,6 +1249,7 @@
<None Include="..\..\readme.txt" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="CB3DMeshWriter.cpp" />
<ClCompile Include="CD3D9RenderTarget.cpp" />
<ClCompile Include="CDefaultSceneNodeAnimatorFactory.cpp" />
<ClCompile Include="CDefaultSceneNodeFactory.cpp" />

View File

@ -1308,6 +1308,12 @@
</ClInclude>
<ClInclude Include="COpenGLRenderTarget.h">
<Filter>Irrlicht\video\OpenGL</Filter>
</ClInclude>
<ClInclude Include="CB3DMeshWriter.h">
<Filter>Irrlicht\scene\writers</Filter>
</ClInclude>
<ClInclude Include="SB3DStructs.h">
<Filter>Irrlicht\scene</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
@ -2236,6 +2242,9 @@
</ClCompile>
<ClCompile Include="COpenGLRenderTarget.cpp">
<Filter>Irrlicht\video\OpenGL</Filter>
</ClCompile>
<ClCompile Include="CB3DMeshWriter.cpp">
<Filter>Irrlicht\scene\writers</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>

View File

@ -2079,6 +2079,14 @@
RelativePath="CSTLMeshWriter.h"
>
</File>
<File
RelativePath="CB3DMeshWriter.cpp"
>
</File>
<File
RelativePath="CB3DMeshWriter.h"
>
</File>
</Filter>
</Filter>
<Filter

View File

@ -30,7 +30,7 @@ VERSION_RELEASE = 0
#List of object files, separated based on engine architecture
IRRMESHLOADER = CBSPMeshFileLoader.o CMD2MeshFileLoader.o CMD3MeshFileLoader.o CMS3DMeshFileLoader.o CB3DMeshFileLoader.o C3DSMeshFileLoader.o COgreMeshFileLoader.o COBJMeshFileLoader.o CColladaFileLoader.o CCSMLoader.o CDMFLoader.o CLMTSMeshFileLoader.o CMY3DMeshFileLoader.o COCTLoader.o CXMeshFileLoader.o CIrrMeshFileLoader.o CSTLMeshFileLoader.o CLWOMeshFileLoader.o CPLYMeshFileLoader.o CSMFMeshFileLoader.o CMeshTextureLoader.o
IRRMESHWRITER = CColladaMeshWriter.o CIrrMeshWriter.o CSTLMeshWriter.o COBJMeshWriter.o CPLYMeshWriter.o
IRRMESHWRITER = CColladaMeshWriter.o CIrrMeshWriter.o CSTLMeshWriter.o COBJMeshWriter.o CPLYMeshWriter.o CB3DMeshWriter.o
IRRMESHOBJ = $(IRRMESHLOADER) $(IRRMESHWRITER) \
CSkinnedMesh.o CBoneSceneNode.o CMeshSceneNode.o \
CAnimatedMeshSceneNode.o CAnimatedMeshMD2.o CAnimatedMeshMD3.o \

View File

@ -0,0 +1,71 @@
// Copyright (C) 2006-2012 Luke Hoschke
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
// B3D Mesh loader
// File format designed by Mark Sibly for the Blitz3D engine and has been
// declared public domain
#include "IrrCompileConfig.h"
#ifndef SB3DSTRUCTS_H
#define SB3DSTRUCTS_H
#include "SMaterial.h"
namespace irr {
namespace scene {
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; i<video::MATERIAL_MAX_TEXTURES; ++i)
Textures[i]=0;
}
video::SMaterial Material;
f32 red, green, blue, alpha;
f32 shininess;
s32 blend,fx;
SB3dTexture *Textures[video::MATERIAL_MAX_TEXTURES];
};
} // end namespace scene
} // end namespace irr
#endif