diff --git a/.gitignore b/.gitignore
index 646e446ff..4b02d3928 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,4 +21,7 @@ scripts/glext.h
*visualstudio/
# vscode cmake plugin
-build/*
\ No newline at end of file
+build/*
+CTestTestfile.cmake
+source/Irrlicht/CTestTestfile.cmake
+test/CTestTestfile.cmake
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 000000000..f872a55a8
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,5 @@
+{
+ "files.associations": {
+ "filesystem": "cpp"
+ }
+}
\ No newline at end of file
diff --git a/include/EMeshWriterEnums.h b/include/EMeshWriterEnums.h
deleted file mode 100644
index f3e2649f6..000000000
--- a/include/EMeshWriterEnums.h
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright (C) 2002-2012 Nikolaus Gebhardt
-// This file is part of the "Irrlicht Engine".
-// For conditions of distribution and use, see copyright notice in irrlicht.h
-
-#ifndef __E_MESH_WRITER_ENUMS_H_INCLUDED__
-#define __E_MESH_WRITER_ENUMS_H_INCLUDED__
-
-#include "irrTypes.h"
-
-namespace irr
-{
-namespace scene
-{
-
- //! An enumeration for all supported types of built-in mesh writers
- /** A scene mesh writers is represented by a four character code
- such as 'irrm' or 'coll' instead of simple numbers, to avoid
- name clashes with external mesh writers.*/
- enum EMESH_WRITER_TYPE
- {
- //! Irrlicht native mesh writer, for static .irrmesh files.
- EMWT_IRR_MESH = MAKE_IRR_ID('i','r','r','m'),
-
- //! COLLADA mesh writer for .dae and .xml files
- EMWT_COLLADA = MAKE_IRR_ID('c','o','l','l'),
-
- //! STL mesh writer for .stl files
- EMWT_STL = MAKE_IRR_ID('s','t','l',0),
-
- //! OBJ mesh writer for .obj files
- EMWT_OBJ = MAKE_IRR_ID('o','b','j',0),
-
- //! PLY mesh writer for .ply files
- 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)
- };
-
-
- //! flags configuring mesh writing
- enum E_MESH_WRITER_FLAGS
- {
- //! no writer flags
- EMWF_NONE = 0,
-
- //! write lightmap textures out if possible
- //! Currently not used by any Irrlicht mesh-writer
- // (Note: User meshwriters can still use it)
- EMWF_WRITE_LIGHTMAPS = 0x1,
-
- //! write in a way that consumes less disk space
- // (Note: Mainly there for user meshwriters)
- EMWF_WRITE_COMPRESSED = 0x2,
-
- //! write in binary format rather than text
- EMWF_WRITE_BINARY = 0x4
- };
-
-} // end namespace scene
-} // end namespace irr
-
-
-#endif // __E_MESH_WRITER_ENUMS_H_INCLUDED__
-
diff --git a/include/IAnimatedMesh.h b/include/IAnimatedMesh.h
index 228a4c15d..49432bd07 100644
--- a/include/IAnimatedMesh.h
+++ b/include/IAnimatedMesh.h
@@ -45,7 +45,7 @@ namespace scene
frame number is getFrameCount() - 1;
\param detailLevel: Level of detail. 0 is the lowest, 255 the
highest level of detail. Most meshes will ignore the detail level.
- \param startFrameLoop: Because some animated meshes (.MD2) are
+ \param startFrameLoop: Because some animated meshes (.MD2 [which no longer exists in irrlicht]) are
blended between 2 static frames, and maybe animated in a loop,
the startFrameLoop and the endFrameLoop have to be defined, to
prevent the animation to be blended between frames which are
@@ -57,9 +57,7 @@ namespace scene
//! Returns the type of the animated mesh.
/** In most cases it is not necessary to use this method.
- This is useful for making a safe downcast. For example,
- if getMeshType() returns EAMT_MD2 it's safe to cast the
- IAnimatedMesh to IAnimatedMeshMD2.
+ This is useful for making a safe downcast.
\returns Type of the mesh. */
E_ANIMATED_MESH_TYPE getMeshType() const override
{
diff --git a/include/IMesh.h b/include/IMesh.h
index b00f22f23..da26566db 100644
--- a/include/IMesh.h
+++ b/include/IMesh.h
@@ -21,37 +21,8 @@ namespace scene
//! 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,
+ //! Graphics Language Transmission Format 2.0 (.gltf) mesh
+ EAMT_GLTF2,
//! generic skinned mesh
EAMT_SKINNED,
@@ -111,9 +82,7 @@ namespace scene
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.
+ /** This is useful for making a safe downcast.
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
diff --git a/include/IMeshWriter.h b/include/IMeshWriter.h
deleted file mode 100644
index 8e98d965a..000000000
--- a/include/IMeshWriter.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright (C) 2002-2012 Nikolaus Gebhardt
-// This file is part of the "Irrlicht Engine".
-// For conditions of distribution and use, see copyright notice in irrlicht.h
-
-#pragma once
-#include "IReferenceCounted.h"
-#include "EMeshWriterEnums.h"
-
-namespace irr
-{
-namespace io
-{
- class IWriteFile;
-} // end namespace io
-
-namespace scene
-{
- class IMesh;
-
- //! Interface for writing meshes
- class IMeshWriter : public virtual IReferenceCounted
- {
- public:
-
- //! Destructor
- virtual ~IMeshWriter() {}
-
- //! Get the type of the mesh writer
- /** For own implementations, use MAKE_IRR_ID as shown in the
- EMESH_WRITER_TYPE enumeration to return your own unique mesh
- type id.
- \return Type of the mesh writer. */
- virtual EMESH_WRITER_TYPE getType() const = 0;
-
- //! Write a static mesh.
- /** \param file File handle to write the mesh to.
- \param mesh Pointer to mesh to be written.
- \param flags Optional flags to set properties of the writer.
- \return True if successful */
- virtual bool writeMesh(io::IWriteFile* file, scene::IMesh* mesh,
- s32 flags=EMWF_NONE) = 0;
-
- // Writes an animated mesh
- // 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 successful */
- //virtual bool writeAnimatedMesh(io::IWriteFile* file,
- // scene::IAnimatedMesh* mesh,
- // s32 flags=EMWF_NONE) = 0;
- };
-
-
-} // end namespace
-} // end namespace
-
-
diff --git a/include/ISceneManager.h b/include/ISceneManager.h
index 50869e383..798757c6d 100644
--- a/include/ISceneManager.h
+++ b/include/ISceneManager.h
@@ -13,7 +13,6 @@
#include "dimension2d.h"
#include "SColor.h"
#include "ESceneNodeTypes.h"
-#include "EMeshWriterEnums.h"
#include "SceneParameters.h"
#include "ISkinnedMesh.h"
@@ -109,7 +108,6 @@ namespace scene
class IMeshLoader;
class IMeshManipulator;
class IMeshSceneNode;
- class IMeshWriter;
class ISceneNode;
class ISceneNodeFactory;
@@ -139,182 +137,12 @@ namespace scene
*
Format |
* Description |
*
- *
- * 3D Studio (.3ds) |
- * Loader for 3D-Studio files which lots of 3D packages
- * are able to export. Only static meshes are currently
- * supported by this importer. |
- *
- *
- * 3D World Studio (.smf) |
- * Loader for Leadwerks SMF mesh files, a simple mesh format
- * containing static geometry for games. The proprietary .STF texture format
- * is not supported yet. This loader was originally written by Joseph Ellis. |
- *
- *
- * Bliz Basic B3D (.b3d) |
- * Loader for blitz basic files, developed by Mark
- * Sibly. This is the ideal animated mesh format for game
- * characters as it is both rigidly defined and widely
- * supported by modeling and animation software.
- * As this format supports skeletal animations, an
- * ISkinnedMesh will be returned by this importer. |
- *
- *
- * Cartography shop 4 (.csm) |
- * Cartography Shop is a modeling program for creating
- * architecture and calculating lighting. Irrlicht can
- * directly import .csm files thanks to the IrrCSM library
- * created by Saurav Mohapatra which is now integrated
- * directly in Irrlicht.
- * |
- *
- * Delgine DeleD (.dmf) |
- * DeleD (delgine.com) is a 3D editor and level-editor
- * combined into one and is specifically designed for 3D
- * game-development. With this loader, it is possible to
- * directly load all geometry is as well as textures and
- * lightmaps from .dmf files. To set texture and
- * material paths, see scene::DMF_USE_MATERIALS_DIRS.
- * It is also possible to flip the alpha texture by setting
- * scene::DMF_FLIP_ALPHA_TEXTURES to true and to set the
- * material transparent reference value by setting
- * scene::DMF_ALPHA_CHANNEL_REF to a float between 0 and
- * 1. The loader is based on Salvatore Russo's .dmf
- * loader, I just changed some parts of it. Thanks to
- * Salvatore for his work and for allowing me to use his
- * code in Irrlicht and put it under Irrlicht's license.
- * For newer and more enhanced versions of the loader,
- * take a look at delgine.com.
- * |
- *
- *
- * DirectX (.x) |
- * Platform independent importer (so not D3D-only) for
- * .x files. Most 3D packages can export these natively
- * and there are several tools for them available, e.g.
- * the Maya exporter included in the DX SDK.
- * .x files can include skeletal animations and Irrlicht
- * is able to play and display them, users can manipulate
- * the joints via the ISkinnedMesh interface. Currently,
- * Irrlicht only supports uncompressed .x files. |
- *
- *
- * Half-Life model (.mdl) |
- * This loader opens Half-life 1 models, it was contributed
- * by Fabio Concas and adapted by Thomas Alten. |
- *
- *
- * LightWave (.lwo) |
- * Native to NewTek's LightWave 3D, the LWO format is well
- * known and supported by many exporters. This loader will
- * import LWO2 models including lightmaps, bumpmaps and
- * reflection textures. |
- *
- *
- * Maya (.obj) |
- * Most 3D software can create .obj files which contain
- * static geometry without material data. The material
- * files .mtl are also supported. This importer for
- * Irrlicht can load them directly. |
- *
- *
- * Milkshape (.ms3d) |
- * .MS3D files contain models and sometimes skeletal
- * animations from the Milkshape 3D modeling and animation
- * software. Like the other skeletal mesh loaders, joints
- * are exposed via the ISkinnedMesh animated mesh type. |
- *
- *
- * My3D (.my3d) |
- * .my3D is a flexible 3D file format. The My3DTools
- * contains plug-ins to export .my3D files from several
- * 3D packages. With this built-in importer, Irrlicht
- * can read and display those files directly. This
- * loader was written by Zhuck Dimitry who also created
- * the whole My3DTools package.
- * |
- *
- *
- * OCT (.oct) |
- * The oct file format contains 3D geometry and
- * lightmaps and can be loaded directly by Irrlicht. OCT
- * files can be created by FSRad, Paul Nette's
- * radiosity processor or exported from Blender using
- * OCTTools which can be found in the exporters/OCTTools
- * directory of the SDK. Thanks to Murphy McCauley for
- * creating all this. |
- *
- *
- * OGRE Meshes (.mesh) |
- * Ogre .mesh files contain 3D data for the OGRE 3D
- * engine. Irrlicht can read and display them directly
- * with this importer. To define materials for the mesh,
- * copy a .material file named like the corresponding
- * .mesh file where the .mesh file is. (For example
- * ogrehead.material for ogrehead.mesh). Thanks to
- * Christian Stehno who wrote and contributed this
- * loader. |
- *
- *
- * Pulsar LMTools (.lmts) |
- * LMTools is a set of tools (Windows & Linux) for
- * creating lightmaps. Irrlicht can directly read .lmts
- * files thanks to the importer created by Jonas
- * Petersen.
- * Notes for this version of the loader:
- * - It does not recognize/support user data in the
- * *.lmts files.
- * - The TGAs generated by LMTools don't work in
- * Irrlicht for some reason (the textures are upside
- * down). Opening and resaving them in a graphics app
- * will solve the problem. |
- *
- *
- * Quake 3 levels (.bsp) |
- * Quake 3 is a popular game by IDSoftware, and .pk3
- * files contain .bsp files and textures/lightmaps
- * describing huge prelighted levels. Irrlicht can read
- * .pk3 and .bsp files directly and thus render Quake 3
- * levels directly. Written by Nikolaus Gebhardt
- * enhanced by Dean P. Macri with the curved surfaces
- * feature. |
- *
- *
- * Quake 2 models (.md2) |
- * Quake 2 models are characters with morph target
- * animation. Irrlicht can read, display and animate
- * them directly with this importer. |
- *
- *
- * Quake 3 models (.md3) |
- * Quake 3 models are characters with morph target
- * animation, they contain mount points for weapons and body
- * parts and are typically made of several sections which are
- * manually joined together. |
- *
- *
- * Stanford Triangle (.ply) |
- * Invented by Stanford University and known as the native
- * format of the infamous "Stanford Bunny" model, this is a
- * popular static mesh format used by 3D scanning hardware
- * and software. This loader supports extremely large models
- * in both ASCII and binary format, but only has rudimentary
- * material support in the form of vertex colors and texture
- * coordinates. |
- *
- *
- * Stereolithography (.stl) |
- * The STL format is used for rapid prototyping and
- * computer-aided manufacturing, thus has no support for
- * materials. |
- *
*
*
* To load and display a mesh quickly, just do this:
* \code
* SceneManager->addAnimatedMeshSceneNode(
- * SceneManager->getMesh("yourmesh.3ds"));
+ * SceneManager->getMesh("yourmesh.gltf"));
* \endcode
* If you would like to implement and add your own file format loader to Irrlicht,
* see addExternalMeshLoader().
@@ -570,7 +398,7 @@ namespace scene
//! Get interface to the parameters set in this scene.
/** String parameters can be used by plugins and mesh loaders.
- See COLLADA_CREATE_SCENE_INSTANCES and DMF_USE_MATERIALS_DIRS */
+ See COLLADA_CREATE_SCENE_INSTANCES */
virtual io::IAttributes* getParameters() = 0;
//! Get current render pass.
@@ -603,10 +431,6 @@ namespace scene
See IReferenceCounted::drop() for more information. */
virtual ISceneManager* createNewSceneManager(bool cloneContent=false) = 0;
- //! Get a mesh writer implementation if available
- /** Note: You need to drop() the pointer after use again, see IReferenceCounted::drop()
- for details. */
- virtual IMeshWriter* createMeshWriter(EMESH_WRITER_TYPE type) = 0;
//! Get a skinned mesh, which is not available as header-only code
/** Note: You need to drop() the pointer after use again, see IReferenceCounted::drop()
diff --git a/include/SceneParameters.h b/include/SceneParameters.h
index b5c5fc1c6..9c7a931d8 100644
--- a/include/SceneParameters.h
+++ b/include/SceneParameters.h
@@ -31,23 +31,6 @@ namespace scene
**/
const c8* const ALLOW_ZWRITE_ON_TRANSPARENT = "Allow_ZWrite_On_Transparent";
- //! Flag to avoid loading group structures in .obj files
- /** Use it like this:
- \code
- SceneManager->getParameters()->setAttribute(scene::OBJ_LOADER_IGNORE_GROUPS, true);
- \endcode
- **/
- const c8* const OBJ_LOADER_IGNORE_GROUPS = "OBJ_IgnoreGroups";
-
-
- //! Flag to avoid loading material .mtl file for .obj files
- /** Use it like this:
- \code
- SceneManager->getParameters()->setAttribute(scene::OBJ_LOADER_IGNORE_MATERIAL_FILES, true);
- \endcode
- **/
- const c8* const OBJ_LOADER_IGNORE_MATERIAL_FILES = "OBJ_IgnoreMaterialFiles";
-
} // end namespace scene
} // end namespace irr
diff --git a/include/irrlicht.h b/include/irrlicht.h
index d7aba073e..94119b8f1 100644
--- a/include/irrlicht.h
+++ b/include/irrlicht.h
@@ -42,7 +42,6 @@
#include "EHardwareBufferFlags.h"
#include "EMaterialProps.h"
#include "EMaterialTypes.h"
-#include "EMeshWriterEnums.h"
#include "ESceneNodeTypes.h"
#include "fast_atof.h"
#include "IAnimatedMesh.h"
@@ -88,7 +87,6 @@
#include "IMeshLoader.h"
#include "IMeshManipulator.h"
#include "IMeshSceneNode.h"
-#include "IMeshWriter.h"
#include "IOSOperator.h"
#include "IReadFile.h"
#include "IReferenceCounted.h"
@@ -183,9 +181,9 @@
*
* device->setWindowCaption(L"Hello World!");
*
- * // load and show quake2 .md2 model
+ * // load and show b3d model
* scene::ISceneNode* node = scenemgr->addAnimatedMeshSceneNode(
- * scenemgr->getMesh("quake2model.md2"));
+ * scenemgr->getMesh("quake2model.b3d"));
*
* // if everything worked, add a texture and disable lighting
* if (node)
@@ -220,9 +218,9 @@
* // add .pk3 archive to the file system
* device->getFileSystem()->addZipFileArchive("quake3map.pk3");
*
- * // load .bsp file and show it using an octree
+ * // load .b3d file and show it using an octree
* scenemgr->addOctreeSceneNode(
- * scenemgr->getMesh("quake3map.bsp"));
+ * scenemgr->getMesh("quake3map.b3d"));
* \endcode
*
* As you can see, the engine uses namespaces. Everything in the engine is
diff --git a/source/Irrlicht/CB3DMeshFileLoader.cpp b/source/Irrlicht/CB3DMeshFileLoader.cpp
deleted file mode 100644
index f4b261907..000000000
--- a/source/Irrlicht/CB3DMeshFileLoader.cpp
+++ /dev/null
@@ -1,1059 +0,0 @@
-// 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 "CB3DMeshFileLoader.h"
-
-#include "IVideoDriver.h"
-#include "IFileSystem.h"
-#include "os.h"
-
-#ifdef _DEBUG
-#define _B3D_READER_DEBUG
-#endif
-
-namespace irr
-{
-namespace scene
-{
-
-//! Constructor
-CB3DMeshFileLoader::CB3DMeshFileLoader(scene::ISceneManager* smgr)
-: AnimatedMesh(0), B3DFile(0), VerticesStart(0), NormalsInFile(false),
- HasVertexColors(false), ShowWarning(true)
-{
- #ifdef _DEBUG
- setDebugName("CB3DMeshFileLoader");
- #endif
-}
-
-
-//! returns true if the file maybe is able to be loaded by this class
-//! based on the file extension (e.g. ".bsp")
-bool CB3DMeshFileLoader::isALoadableFileExtension(const io::path& filename) const
-{
- return core::hasFileExtension ( filename, "b3d" );
-}
-
-
-//! creates/loads an animated mesh from the file.
-//! \return Pointer to the created mesh. Returns 0 if loading failed.
-//! If you no longer need the mesh, you should call IAnimatedMesh::drop().
-//! See IReferenceCounted::drop() for more information.
-IAnimatedMesh* CB3DMeshFileLoader::createMesh(io::IReadFile* file)
-{
- if (!file)
- return 0;
-
- B3DFile = file;
- AnimatedMesh = new scene::CSkinnedMesh();
- ShowWarning = true; // If true a warning is issued if too many textures are used
- VerticesStart=0;
-
- if ( load() )
- {
- AnimatedMesh->finalize();
- }
- else
- {
- AnimatedMesh->drop();
- AnimatedMesh = 0;
- }
-
- return AnimatedMesh;
-}
-
-
-bool CB3DMeshFileLoader::load()
-{
- B3dStack.clear();
-
- NormalsInFile=false;
- HasVertexColors=false;
-
- //------ Get header ------
-
- SB3dChunkHeader header;
- B3DFile->read(&header, sizeof(header));
-#ifdef __BIG_ENDIAN__
- header.size = os::Byteswap::byteswap(header.size);
-#endif
-
- if ( strncmp( header.name, "BB3D", 4 ) != 0 )
- {
- os::Printer::log("File is not a b3d file. Loading failed (No header found)", B3DFile->getFileName(), ELL_ERROR);
- return false;
- }
-
- // Add main chunk...
- B3dStack.push_back(SB3dChunk(header, B3DFile->getPos()-8));
-
- // Get file version, but ignore it, as it's not important with b3d files...
- s32 fileVersion;
- B3DFile->read(&fileVersion, sizeof(fileVersion));
-#ifdef __BIG_ENDIAN__
- fileVersion = os::Byteswap::byteswap(fileVersion);
-#endif
-
- //------ Read main chunk ------
-
- while ( (B3dStack.getLast().startposition + B3dStack.getLast().length) > B3DFile->getPos() )
- {
- B3DFile->read(&header, sizeof(header));
-#ifdef __BIG_ENDIAN__
- header.size = os::Byteswap::byteswap(header.size);
-#endif
- B3dStack.push_back(SB3dChunk(header, B3DFile->getPos()-8));
-
- if ( strncmp( B3dStack.getLast().name, "TEXS", 4 ) == 0 )
- {
- if (!readChunkTEXS())
- return false;
- }
- else if ( strncmp( B3dStack.getLast().name, "BRUS", 4 ) == 0 )
- {
- if (!readChunkBRUS())
- return false;
- }
- else if ( strncmp( B3dStack.getLast().name, "NODE", 4 ) == 0 )
- {
- if (!readChunkNODE((CSkinnedMesh::SJoint*)0) )
- return false;
- }
- else
- {
- os::Printer::log("Unknown chunk found in mesh base - skipping");
- if (!B3DFile->seek(B3dStack.getLast().startposition + B3dStack.getLast().length))
- return false;
- B3dStack.erase(B3dStack.size()-1);
- }
- }
-
- B3dStack.clear();
-
- BaseVertices.clear();
- AnimatedVertices_VertexID.clear();
- AnimatedVertices_BufferID.clear();
-
- Materials.clear();
- Textures.clear();
-
- return true;
-}
-
-
-bool CB3DMeshFileLoader::readChunkNODE(CSkinnedMesh::SJoint *inJoint)
-{
- CSkinnedMesh::SJoint *joint = AnimatedMesh->addJoint(inJoint);
- readString(joint->Name);
-
-#ifdef _B3D_READER_DEBUG
- core::stringc logStr;
- for ( u32 i=1; i < B3dStack.size(); ++i )
- logStr += "-";
- logStr += "read ChunkNODE";
- os::Printer::log(logStr.c_str(), joint->Name.c_str(), ELL_DEBUG);
-#endif
-
- f32 position[3], scale[3], rotation[4];
-
- readFloats(position, 3);
- readFloats(scale, 3);
- readFloats(rotation, 4);
-
- joint->Animatedposition = core::vector3df(position[0],position[1],position[2]) ;
- joint->Animatedscale = core::vector3df(scale[0],scale[1],scale[2]);
- joint->Animatedrotation = core::quaternion(rotation[1], rotation[2], rotation[3], rotation[0]);
-
- //Build LocalMatrix:
-
- core::matrix4 positionMatrix;
- positionMatrix.setTranslation( joint->Animatedposition );
- core::matrix4 scaleMatrix;
- scaleMatrix.setScale( joint->Animatedscale );
- core::matrix4 rotationMatrix;
- joint->Animatedrotation.getMatrix_transposed(rotationMatrix);
-
- joint->LocalMatrix = positionMatrix * rotationMatrix * scaleMatrix;
-
- if (inJoint)
- joint->GlobalMatrix = inJoint->GlobalMatrix * joint->LocalMatrix;
- else
- joint->GlobalMatrix = joint->LocalMatrix;
-
- while(B3dStack.getLast().startposition + B3dStack.getLast().length > B3DFile->getPos()) // this chunk repeats
- {
- SB3dChunkHeader header;
- B3DFile->read(&header, sizeof(header));
-#ifdef __BIG_ENDIAN__
- header.size = os::Byteswap::byteswap(header.size);
-#endif
-
- B3dStack.push_back(SB3dChunk(header, B3DFile->getPos()-8));
-
- if ( strncmp( B3dStack.getLast().name, "NODE", 4 ) == 0 )
- {
- if (!readChunkNODE(joint))
- return false;
- }
- else if ( strncmp( B3dStack.getLast().name, "MESH", 4 ) == 0 )
- {
- VerticesStart=BaseVertices.size();
- if (!readChunkMESH(joint))
- return false;
- }
- else if ( strncmp( B3dStack.getLast().name, "BONE", 4 ) == 0 )
- {
- if (!readChunkBONE(joint))
- return false;
- }
- else if ( strncmp( B3dStack.getLast().name, "KEYS", 4 ) == 0 )
- {
- if(!readChunkKEYS(joint))
- return false;
- }
- else if ( strncmp( B3dStack.getLast().name, "ANIM", 4 ) == 0 )
- {
- if (!readChunkANIM())
- return false;
- }
- else
- {
- os::Printer::log("Unknown chunk found in node chunk - skipping");
- if (!B3DFile->seek(B3dStack.getLast().startposition + B3dStack.getLast().length))
- return false;
- B3dStack.erase(B3dStack.size()-1);
- }
- }
-
- B3dStack.erase(B3dStack.size()-1);
-
- return true;
-}
-
-
-bool CB3DMeshFileLoader::readChunkMESH(CSkinnedMesh::SJoint *inJoint)
-{
-#ifdef _B3D_READER_DEBUG
- core::stringc logStr;
- for ( u32 i=1; i < B3dStack.size(); ++i )
- logStr += "-";
- logStr += "read ChunkMESH";
- os::Printer::log(logStr.c_str(), ELL_DEBUG);
-#endif
-
- s32 brushID;
- B3DFile->read(&brushID, sizeof(brushID));
-#ifdef __BIG_ENDIAN__
- brushID = os::Byteswap::byteswap(brushID);
-#endif
-
- NormalsInFile=false;
- HasVertexColors=false;
-
- while((B3dStack.getLast().startposition + B3dStack.getLast().length) > B3DFile->getPos()) //this chunk repeats
- {
- SB3dChunkHeader header;
- B3DFile->read(&header, sizeof(header));
-#ifdef __BIG_ENDIAN__
- header.size = os::Byteswap::byteswap(header.size);
-#endif
-
- B3dStack.push_back(SB3dChunk(header, B3DFile->getPos()-8));
-
- if ( strncmp( B3dStack.getLast().name, "VRTS", 4 ) == 0 )
- {
- if (!readChunkVRTS(inJoint))
- return false;
- }
- else if ( strncmp( B3dStack.getLast().name, "TRIS", 4 ) == 0 )
- {
- scene::SSkinMeshBuffer *meshBuffer = AnimatedMesh->addMeshBuffer();
-
- if (brushID == -1)
- { /* ok */ }
- else if (brushID < 0 || (u32)brushID >= Materials.size())
- {
- os::Printer::log("Illegal brush ID found", B3DFile->getFileName(), ELL_ERROR);
- return false;
- }
- else
- {
- meshBuffer->Material=Materials[brushID].Material;
- }
-
- if(readChunkTRIS(meshBuffer,AnimatedMesh->getMeshBuffers().size()-1, VerticesStart)==false)
- return false;
-
- if (!NormalsInFile)
- {
- s32 i;
-
- for ( i=0; i<(s32)meshBuffer->Indices.size(); i+=3)
- {
- core::plane3df p(meshBuffer->getVertex(meshBuffer->Indices[i+0])->Pos,
- meshBuffer->getVertex(meshBuffer->Indices[i+1])->Pos,
- meshBuffer->getVertex(meshBuffer->Indices[i+2])->Pos);
-
- meshBuffer->getVertex(meshBuffer->Indices[i+0])->Normal += p.Normal;
- meshBuffer->getVertex(meshBuffer->Indices[i+1])->Normal += p.Normal;
- meshBuffer->getVertex(meshBuffer->Indices[i+2])->Normal += p.Normal;
- }
-
- for ( i = 0; i<(s32)meshBuffer->getVertexCount(); ++i )
- {
- meshBuffer->getVertex(i)->Normal.normalize();
- BaseVertices[VerticesStart+i].Normal=meshBuffer->getVertex(i)->Normal;
- }
- }
- }
- else
- {
- os::Printer::log("Unknown chunk found in mesh - skipping");
- if (!B3DFile->seek(B3dStack.getLast().startposition + B3dStack.getLast().length))
- return false;
- B3dStack.erase(B3dStack.size()-1);
- }
- }
-
- B3dStack.erase(B3dStack.size()-1);
-
- return true;
-}
-
-
-/*
-VRTS:
- int flags ;1=normal values present, 2=rgba values present
- int tex_coord_sets ;texture coords per vertex (eg: 1 for simple U/V) max=8
- but we only support 3
- int tex_coord_set_size ;components per set (eg: 2 for simple U/V) max=4
- {
- float x,y,z ;always present
- float nx,ny,nz ;vertex normal: present if (flags&1)
- float red,green,blue,alpha ;vertex color: present if (flags&2)
- float tex_coords[tex_coord_sets][tex_coord_set_size] ;tex coords
- }
-*/
-bool CB3DMeshFileLoader::readChunkVRTS(CSkinnedMesh::SJoint *inJoint)
-{
-#ifdef _B3D_READER_DEBUG
- core::stringc logStr;
- for ( u32 i=1; i < B3dStack.size(); ++i )
- logStr += "-";
- logStr += "ChunkVRTS";
- os::Printer::log(logStr.c_str(), ELL_DEBUG);
-#endif
-
- const s32 max_tex_coords = 3;
- s32 flags, tex_coord_sets, tex_coord_set_size;
-
- B3DFile->read(&flags, sizeof(flags));
- B3DFile->read(&tex_coord_sets, sizeof(tex_coord_sets));
- B3DFile->read(&tex_coord_set_size, sizeof(tex_coord_set_size));
-#ifdef __BIG_ENDIAN__
- flags = os::Byteswap::byteswap(flags);
- tex_coord_sets = os::Byteswap::byteswap(tex_coord_sets);
- tex_coord_set_size = os::Byteswap::byteswap(tex_coord_set_size);
-#endif
-
- if (tex_coord_sets < 0 || tex_coord_set_size < 0 ||
- tex_coord_sets >= max_tex_coords || tex_coord_set_size >= 4) // Something is wrong
- {
- os::Printer::log("tex_coord_sets or tex_coord_set_size too big", B3DFile->getFileName(), ELL_ERROR);
- return false;
- }
-
- //------ Allocate Memory, for speed -----------//
-
- s32 numberOfReads = 3;
-
- if (flags & 1)
- {
- NormalsInFile = true;
- numberOfReads += 3;
- }
- if (flags & 2)
- {
- numberOfReads += 4;
- HasVertexColors=true;
- }
-
- numberOfReads += tex_coord_sets*tex_coord_set_size;
-
- const s32 memoryNeeded = (B3dStack.getLast().length / sizeof(f32)) / numberOfReads;
-
- BaseVertices.reallocate(memoryNeeded + BaseVertices.size() + 1);
- AnimatedVertices_VertexID.reallocate(memoryNeeded + AnimatedVertices_VertexID.size() + 1);
-
- //--------------------------------------------//
-
- while( (B3dStack.getLast().startposition + B3dStack.getLast().length) > B3DFile->getPos()) // this chunk repeats
- {
- f32 position[3];
- f32 normal[3]={0.f, 0.f, 0.f};
- f32 color[4]={1.0f, 1.0f, 1.0f, 1.0f};
- f32 tex_coords[max_tex_coords][4];
-
- readFloats(position, 3);
-
- if (flags & 1)
- readFloats(normal, 3);
- if (flags & 2)
- readFloats(color, 4);
-
- for (s32 i=0; i= 1 && tex_coord_set_size >= 2)
- {
- tu=tex_coords[0][0];
- tv=tex_coords[0][1];
- }
-
- f32 tu2=0.0f, tv2=0.0f;
- if (tex_coord_sets>1 && tex_coord_set_size>1)
- {
- tu2=tex_coords[1][0];
- tv2=tex_coords[1][1];
- }
-
- // Create Vertex...
- video::S3DVertex2TCoords Vertex(position[0], position[1], position[2],
- normal[0], normal[1], normal[2],
- video::SColorf(color[0], color[1], color[2], color[3]).toSColor(),
- tu, tv, tu2, tv2);
-
- // Transform the Vertex position by nested node...
- inJoint->GlobalMatrix.transformVect(Vertex.Pos);
- inJoint->GlobalMatrix.rotateVect(Vertex.Normal);
-
- //Add it...
- BaseVertices.push_back(Vertex);
-
- AnimatedVertices_VertexID.push_back(-1);
- AnimatedVertices_BufferID.push_back(-1);
- }
-
- B3dStack.erase(B3dStack.size()-1);
-
- return true;
-}
-
-
-bool CB3DMeshFileLoader::readChunkTRIS(scene::SSkinMeshBuffer *meshBuffer, u32 meshBufferID, s32 vertices_Start)
-{
-#ifdef _B3D_READER_DEBUG
- core::stringc logStr;
- for ( u32 i=1; i < B3dStack.size(); ++i )
- logStr += "-";
- logStr += "ChunkTRIS";
- os::Printer::log(logStr.c_str(), ELL_DEBUG);
-#endif
-
- bool showVertexWarning=false;
-
- s32 triangle_brush_id; // Note: Irrlicht can't have different brushes for each triangle (using a workaround)
- B3DFile->read(&triangle_brush_id, sizeof(triangle_brush_id));
-#ifdef __BIG_ENDIAN__
- triangle_brush_id = os::Byteswap::byteswap(triangle_brush_id);
-#endif
-
- SB3dMaterial *B3dMaterial;
-
- if (triangle_brush_id == -1)
- B3dMaterial = 0;
- else if (triangle_brush_id < 0 || (u32)triangle_brush_id >= Materials.size())
- {
- os::Printer::log("Illegal material index found", B3DFile->getFileName(), ELL_ERROR);
- return false;
- }
- else
- {
- B3dMaterial = &Materials[triangle_brush_id];
- meshBuffer->Material = B3dMaterial->Material;
- }
-
- const s32 memoryNeeded = B3dStack.getLast().length / sizeof(s32);
- meshBuffer->Indices.reallocate(memoryNeeded + meshBuffer->Indices.size() + 1);
-
- while((B3dStack.getLast().startposition + B3dStack.getLast().length) > B3DFile->getPos()) // this chunk repeats
- {
- s32 vertex_id[3];
-
- B3DFile->read(vertex_id, 3*sizeof(s32));
-#ifdef __BIG_ENDIAN__
- vertex_id[0] = os::Byteswap::byteswap(vertex_id[0]);
- vertex_id[1] = os::Byteswap::byteswap(vertex_id[1]);
- vertex_id[2] = os::Byteswap::byteswap(vertex_id[2]);
-#endif
-
- //Make Ids global:
- vertex_id[0] += vertices_Start;
- vertex_id[1] += vertices_Start;
- vertex_id[2] += vertices_Start;
-
- for(s32 i=0; i<3; ++i)
- {
- if ((u32)vertex_id[i] >= AnimatedVertices_VertexID.size())
- {
- os::Printer::log("Illegal vertex index found", B3DFile->getFileName(), ELL_ERROR);
- return false;
- }
-
- if (AnimatedVertices_VertexID[ vertex_id[i] ] != -1)
- {
- if ( AnimatedVertices_BufferID[ vertex_id[i] ] != (s32)meshBufferID ) //If this vertex is linked in a different meshbuffer
- {
- AnimatedVertices_VertexID[ vertex_id[i] ] = -1;
- AnimatedVertices_BufferID[ vertex_id[i] ] = -1;
- showVertexWarning=true;
- }
- }
- if (AnimatedVertices_VertexID[ vertex_id[i] ] == -1) //If this vertex is not in the meshbuffer
- {
- //Check for lightmapping:
- if (BaseVertices[ vertex_id[i] ].TCoords2 != core::vector2df(0.f,0.f))
- meshBuffer->convertTo2TCoords(); //Will only affect the meshbuffer the first time this is called
-
- //Add the vertex to the meshbuffer:
- if (meshBuffer->VertexType == video::EVT_STANDARD)
- meshBuffer->Vertices_Standard.push_back( BaseVertices[ vertex_id[i] ] );
- else
- meshBuffer->Vertices_2TCoords.push_back(BaseVertices[ vertex_id[i] ] );
-
- //create vertex id to meshbuffer index link:
- AnimatedVertices_VertexID[ vertex_id[i] ] = meshBuffer->getVertexCount()-1;
- AnimatedVertices_BufferID[ vertex_id[i] ] = meshBufferID;
-
- if (B3dMaterial)
- {
- // Apply Material/Color/etc...
- video::S3DVertex *Vertex=meshBuffer->getVertex(meshBuffer->getVertexCount()-1);
-
- if (!HasVertexColors)
- Vertex->Color=B3dMaterial->Material.DiffuseColor;
- else if (Vertex->Color.getAlpha() == 255)
- Vertex->Color.setAlpha( (s32)(B3dMaterial->alpha * 255.0f) );
-
- // Use texture's scale
- if (B3dMaterial->Textures[0])
- {
- Vertex->TCoords.X *= B3dMaterial->Textures[0]->Xscale;
- Vertex->TCoords.Y *= B3dMaterial->Textures[0]->Yscale;
- }
- /*
- if (B3dMaterial->Textures[1])
- {
- Vertex->TCoords2.X *=B3dMaterial->Textures[1]->Xscale;
- Vertex->TCoords2.Y *=B3dMaterial->Textures[1]->Yscale;
- }
- */
- }
- }
- }
-
- meshBuffer->Indices.push_back( AnimatedVertices_VertexID[ vertex_id[0] ] );
- meshBuffer->Indices.push_back( AnimatedVertices_VertexID[ vertex_id[1] ] );
- meshBuffer->Indices.push_back( AnimatedVertices_VertexID[ vertex_id[2] ] );
- }
-
- B3dStack.erase(B3dStack.size()-1);
-
- if (showVertexWarning)
- os::Printer::log("B3dMeshLoader: Warning, different meshbuffers linking to the same vertex, this will cause problems with animated meshes");
-
- return true;
-}
-
-
-bool CB3DMeshFileLoader::readChunkBONE(CSkinnedMesh::SJoint *inJoint)
-{
-#ifdef _B3D_READER_DEBUG
- core::stringc logStr;
- for ( u32 i=1; i < B3dStack.size(); ++i )
- logStr += "-";
- logStr += "read ChunkBONE";
- os::Printer::log(logStr.c_str(), ELL_DEBUG);
-#endif
-
- if (B3dStack.getLast().length > 8)
- {
- while((B3dStack.getLast().startposition + B3dStack.getLast().length) > B3DFile->getPos()) // this chunk repeats
- {
- u32 globalVertexID;
- f32 strength;
- B3DFile->read(&globalVertexID, sizeof(globalVertexID));
- B3DFile->read(&strength, sizeof(strength));
-#ifdef __BIG_ENDIAN__
- globalVertexID = os::Byteswap::byteswap(globalVertexID);
- strength = os::Byteswap::byteswap(strength);
-#endif
- globalVertexID += VerticesStart;
-
- if (globalVertexID >= AnimatedVertices_VertexID.size())
- {
- os::Printer::log("Illegal vertex index found", B3DFile->getFileName(), ELL_ERROR);
- return false;
- }
-
- if (AnimatedVertices_VertexID[globalVertexID]==-1)
- {
- os::Printer::log("B3dMeshLoader: Weight has bad vertex id (no link to meshbuffer index found)");
- }
- else if (strength >0)
- {
- CSkinnedMesh::SWeight *weight=AnimatedMesh->addWeight(inJoint);
- weight->strength=strength;
- //Find the meshbuffer and Vertex index from the Global Vertex ID:
- weight->vertex_id = AnimatedVertices_VertexID[globalVertexID];
- weight->buffer_id = AnimatedVertices_BufferID[globalVertexID];
- }
- }
- }
-
- B3dStack.erase(B3dStack.size()-1);
- return true;
-}
-
-
-bool CB3DMeshFileLoader::readChunkKEYS(CSkinnedMesh::SJoint *inJoint)
-{
-#ifdef _B3D_READER_DEBUG
- // Only print first, that's just too much output otherwise
- if ( !inJoint || (inJoint->PositionKeys.empty() && inJoint->ScaleKeys.empty() && inJoint->RotationKeys.empty()) )
- {
- core::stringc logStr;
- for ( u32 i=1; i < B3dStack.size(); ++i )
- logStr += "-";
- logStr += "read ChunkKEYS";
- os::Printer::log(logStr.c_str(), ELL_DEBUG);
- }
-#endif
-
- s32 flags;
- B3DFile->read(&flags, sizeof(flags));
-#ifdef __BIG_ENDIAN__
- flags = os::Byteswap::byteswap(flags);
-#endif
-
- CSkinnedMesh::SPositionKey *oldPosKey=0;
- core::vector3df oldPos[2];
- CSkinnedMesh::SScaleKey *oldScaleKey=0;
- core::vector3df oldScale[2];
- CSkinnedMesh::SRotationKey *oldRotKey=0;
- core::quaternion oldRot[2];
- bool isFirst[3]={true,true,true};
- while((B3dStack.getLast().startposition + B3dStack.getLast().length) > B3DFile->getPos()) //this chunk repeats
- {
- s32 frame;
-
- B3DFile->read(&frame, sizeof(frame));
- #ifdef __BIG_ENDIAN__
- frame = os::Byteswap::byteswap(frame);
- #endif
-
- // Add key frames, frames in Irrlicht are zero-based
- f32 data[4];
- if (flags & 1)
- {
- readFloats(data, 3);
- if ((oldPosKey!=0) && (oldPos[0]==oldPos[1]))
- {
- const core::vector3df pos(data[0], data[1], data[2]);
- if (oldPos[1]==pos)
- oldPosKey->frame = (f32)frame-1;
- else
- {
- oldPos[0]=oldPos[1];
- oldPosKey=AnimatedMesh->addPositionKey(inJoint);
- oldPosKey->frame = (f32)frame-1;
- oldPos[1].set(oldPosKey->position.set(pos));
- }
- }
- else if (oldPosKey==0 && isFirst[0])
- {
- oldPosKey=AnimatedMesh->addPositionKey(inJoint);
- oldPosKey->frame = (f32)frame-1;
- oldPos[0].set(oldPosKey->position.set(data[0], data[1], data[2]));
- oldPosKey=0;
- isFirst[0]=false;
- }
- else
- {
- if (oldPosKey!=0)
- oldPos[0]=oldPos[1];
- oldPosKey=AnimatedMesh->addPositionKey(inJoint);
- oldPosKey->frame = (f32)frame-1;
- oldPos[1].set(oldPosKey->position.set(data[0], data[1], data[2]));
- }
- }
- if (flags & 2)
- {
- readFloats(data, 3);
- if ((oldScaleKey!=0) && (oldScale[0]==oldScale[1]))
- {
- const core::vector3df scale(data[0], data[1], data[2]);
- if (oldScale[1]==scale)
- oldScaleKey->frame = (f32)frame-1;
- else
- {
- oldScale[0]=oldScale[1];
- oldScaleKey=AnimatedMesh->addScaleKey(inJoint);
- oldScaleKey->frame = (f32)frame-1;
- oldScale[1].set(oldScaleKey->scale.set(scale));
- }
- }
- else if (oldScaleKey==0 && isFirst[1])
- {
- oldScaleKey=AnimatedMesh->addScaleKey(inJoint);
- oldScaleKey->frame = (f32)frame-1;
- oldScale[0].set(oldScaleKey->scale.set(data[0], data[1], data[2]));
- oldScaleKey=0;
- isFirst[1]=false;
- }
- else
- {
- if (oldScaleKey!=0)
- oldScale[0]=oldScale[1];
- oldScaleKey=AnimatedMesh->addScaleKey(inJoint);
- oldScaleKey->frame = (f32)frame-1;
- oldScale[1].set(oldScaleKey->scale.set(data[0], data[1], data[2]));
- }
- }
- if (flags & 4)
- {
- readFloats(data, 4);
- if ((oldRotKey!=0) && (oldRot[0]==oldRot[1]))
- {
- // meant to be in this order since b3d stores W first
- const core::quaternion rot(data[1], data[2], data[3], data[0]);
- if (oldRot[1]==rot)
- oldRotKey->frame = (f32)frame-1;
- else
- {
- oldRot[0]=oldRot[1];
- oldRotKey=AnimatedMesh->addRotationKey(inJoint);
- oldRotKey->frame = (f32)frame-1;
- oldRot[1].set(oldRotKey->rotation.set(data[1], data[2], data[3], data[0]));
- oldRot[1].normalize();
- }
- }
- else if (oldRotKey==0 && isFirst[2])
- {
- oldRotKey=AnimatedMesh->addRotationKey(inJoint);
- oldRotKey->frame = (f32)frame-1;
- // meant to be in this order since b3d stores W first
- oldRot[0].set(oldRotKey->rotation.set(data[1], data[2], data[3], data[0]));
- oldRot[0].normalize();
- oldRotKey=0;
- isFirst[2]=false;
- }
- else
- {
- if (oldRotKey!=0)
- oldRot[0]=oldRot[1];
- oldRotKey=AnimatedMesh->addRotationKey(inJoint);
- oldRotKey->frame = (f32)frame-1;
- // meant to be in this order since b3d stores W first
- oldRot[1].set(oldRotKey->rotation.set(data[1], data[2], data[3], data[0]));
- oldRot[1].normalize();
- }
- }
- }
-
- B3dStack.erase(B3dStack.size()-1);
- return true;
-}
-
-
-bool CB3DMeshFileLoader::readChunkANIM()
-{
-#ifdef _B3D_READER_DEBUG
- core::stringc logStr;
- for ( u32 i=1; i < B3dStack.size(); ++i )
- logStr += "-";
- logStr += "read ChunkANIM";
- os::Printer::log(logStr.c_str(), ELL_DEBUG);
-#endif
-
- s32 animFlags; //not stored\used
- s32 animFrames;//not stored\used
- f32 animFPS; //not stored\used
-
- B3DFile->read(&animFlags, sizeof(s32));
- B3DFile->read(&animFrames, sizeof(s32));
- readFloats(&animFPS, 1);
- if (animFPS>0.f)
- AnimatedMesh->setAnimationSpeed(animFPS);
- os::Printer::log("FPS", io::path((double)animFPS), ELL_DEBUG);
-
- #ifdef __BIG_ENDIAN__
- animFlags = os::Byteswap::byteswap(animFlags);
- animFrames = os::Byteswap::byteswap(animFrames);
- #endif
-
- B3dStack.erase(B3dStack.size()-1);
- return true;
-}
-
-
-bool CB3DMeshFileLoader::readChunkTEXS()
-{
-#ifdef _B3D_READER_DEBUG
- core::stringc logStr;
- for ( u32 i=1; i < B3dStack.size(); ++i )
- logStr += "-";
- logStr += "read ChunkTEXS";
- os::Printer::log(logStr.c_str(), ELL_DEBUG);
-#endif
-
- while((B3dStack.getLast().startposition + B3dStack.getLast().length) > B3DFile->getPos()) //this chunk repeats
- {
- Textures.push_back(SB3dTexture());
- SB3dTexture& B3dTexture = Textures.getLast();
-
- readString(B3dTexture.TextureName);
- B3dTexture.TextureName.replace('\\','/');
-#ifdef _B3D_READER_DEBUG
- os::Printer::log("read Texture", B3dTexture.TextureName.c_str(), ELL_DEBUG);
-#endif
-
- B3DFile->read(&B3dTexture.Flags, sizeof(s32));
- B3DFile->read(&B3dTexture.Blend, sizeof(s32));
-#ifdef __BIG_ENDIAN__
- B3dTexture.Flags = os::Byteswap::byteswap(B3dTexture.Flags);
- B3dTexture.Blend = os::Byteswap::byteswap(B3dTexture.Blend);
-#endif
-#ifdef _B3D_READER_DEBUG
- os::Printer::log("Flags", core::stringc(B3dTexture.Flags).c_str(), ELL_DEBUG);
- os::Printer::log("Blend", core::stringc(B3dTexture.Blend).c_str(), ELL_DEBUG);
-#endif
- readFloats(&B3dTexture.Xpos, 1);
- readFloats(&B3dTexture.Ypos, 1);
- readFloats(&B3dTexture.Xscale, 1);
- readFloats(&B3dTexture.Yscale, 1);
- readFloats(&B3dTexture.Angle, 1);
- }
-
- B3dStack.erase(B3dStack.size()-1);
-
- return true;
-}
-
-
-bool CB3DMeshFileLoader::readChunkBRUS()
-{
-#ifdef _B3D_READER_DEBUG
- core::stringc logStr;
- for ( u32 i=1; i < B3dStack.size(); ++i )
- logStr += "-";
- logStr += "read ChunkBRUS";
- os::Printer::log(logStr.c_str(), ELL_DEBUG);
-#endif
-
- u32 n_texs;
- B3DFile->read(&n_texs, sizeof(u32));
-#ifdef __BIG_ENDIAN__
- n_texs = os::Byteswap::byteswap(n_texs);
-#endif
-
- // number of texture ids read for Irrlicht
- const u32 num_textures = core::min_(n_texs, video::MATERIAL_MAX_TEXTURES);
- // number of bytes to skip (for ignored texture ids)
- const u32 n_texs_offset = (num_textures B3DFile->getPos()) //this chunk repeats
- {
- // This is what blitz basic calls a brush, like a Irrlicht Material
-
- core::stringc name;
- readString(name);
-#ifdef _B3D_READER_DEBUG
- os::Printer::log("read Material", name, ELL_DEBUG);
-#endif
- Materials.push_back(SB3dMaterial());
- SB3dMaterial& B3dMaterial=Materials.getLast();
-
- readFloats(&B3dMaterial.red, 1);
- readFloats(&B3dMaterial.green, 1);
- readFloats(&B3dMaterial.blue, 1);
- readFloats(&B3dMaterial.alpha, 1);
- readFloats(&B3dMaterial.shininess, 1);
-
- B3DFile->read(&B3dMaterial.blend, sizeof(B3dMaterial.blend));
- B3DFile->read(&B3dMaterial.fx, sizeof(B3dMaterial.fx));
-#ifdef __BIG_ENDIAN__
- B3dMaterial.blend = os::Byteswap::byteswap(B3dMaterial.blend);
- B3dMaterial.fx = os::Byteswap::byteswap(B3dMaterial.fx);
-#endif
-#ifdef _B3D_READER_DEBUG
- os::Printer::log("Blend", core::stringc(B3dMaterial.blend).c_str(), ELL_DEBUG);
- os::Printer::log("FX", core::stringc(B3dMaterial.fx).c_str(), ELL_DEBUG);
-#endif
-
- u32 i;
- for (i=0; iread(&texture_id, sizeof(s32));
-#ifdef __BIG_ENDIAN__
- texture_id = os::Byteswap::byteswap(texture_id);
-#endif
- //--- Get pointers to the texture, based on the IDs ---
- if ((u32)texture_id < Textures.size())
- {
- B3dMaterial.Textures[i]=&Textures[texture_id];
-#ifdef _B3D_READER_DEBUG
- os::Printer::log("Layer", core::stringc(i).c_str(), ELL_DEBUG);
- os::Printer::log("using texture", Textures[texture_id].TextureName.c_str(), ELL_DEBUG);
-#endif
- }
- else
- B3dMaterial.Textures[i]=0;
- }
- // skip other texture ids
- for (i=0; iread(&texture_id, sizeof(s32));
-#ifdef __BIG_ENDIAN__
- texture_id = os::Byteswap::byteswap(texture_id);
-#endif
- if (ShowWarning && (texture_id != -1) && (n_texs>video::MATERIAL_MAX_TEXTURES))
- {
- os::Printer::log("Too many textures used in one material", B3DFile->getFileName(), ELL_WARNING);
- ShowWarning = false;
- }
- }
-
- //Fixes problems when the lightmap is on the first texture:
- if (B3dMaterial.Textures[0] != 0)
- {
- if (B3dMaterial.Textures[0]->Flags & 65536) // 65536 = secondary UV
- {
- SB3dTexture *TmpTexture;
- TmpTexture = B3dMaterial.Textures[1];
- B3dMaterial.Textures[1] = B3dMaterial.Textures[0];
- B3dMaterial.Textures[0] = TmpTexture;
- }
- }
-
- //If a preceeding texture slot is empty move the others down:
- for (i=num_textures; i>0; --i)
- {
- for (u32 j=i-1; jFlags & 0x2) //(Alpha mapped)
- {
- B3dMaterial.Material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
- B3dMaterial.Material.ZWriteEnable = video::EZW_OFF;
- }
- else if (B3dMaterial.Textures[0]->Flags & 0x4) //(Masked)
- B3dMaterial.Material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; // TODO: create color key texture
- else if (B3dMaterial.alpha == 1.f)
- B3dMaterial.Material.MaterialType = video::EMT_SOLID;
- else
- {
- B3dMaterial.Material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
- B3dMaterial.Material.ZWriteEnable = video::EZW_OFF;
- }
- }
- else //No texture:
- {
- if (B3dMaterial.alpha == 1.f)
- B3dMaterial.Material.MaterialType = video::EMT_SOLID;
- else
- {
- B3dMaterial.Material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
- B3dMaterial.Material.ZWriteEnable = video::EZW_OFF;
- }
- }
-
- B3dMaterial.Material.DiffuseColor = video::SColorf(B3dMaterial.red, B3dMaterial.green, B3dMaterial.blue, B3dMaterial.alpha).toSColor();
- B3dMaterial.Material.ColorMaterial=video::ECM_NONE;
-
- //------ Material fx ------
-
- if (B3dMaterial.fx & 1) //full-bright
- {
- B3dMaterial.Material.AmbientColor = video::SColor(255, 255, 255, 255);
- B3dMaterial.Material.Lighting = false;
- }
- else
- B3dMaterial.Material.AmbientColor = B3dMaterial.Material.DiffuseColor;
-
- if (B3dMaterial.fx & 2) //use vertex colors instead of brush color
- B3dMaterial.Material.ColorMaterial=video::ECM_DIFFUSE_AND_AMBIENT;
-
- if (B3dMaterial.fx & 4) //flatshaded
- B3dMaterial.Material.GouraudShading = false;
-
- if (B3dMaterial.fx & 16) //disable backface culling
- B3dMaterial.Material.BackfaceCulling = false;
-
- if (B3dMaterial.fx & 32) //force vertex alpha-blending
- {
- B3dMaterial.Material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
- B3dMaterial.Material.ZWriteEnable = video::EZW_OFF;
- }
-
- B3dMaterial.Material.Shininess = B3dMaterial.shininess;
- }
-
- B3dStack.erase(B3dStack.size()-1);
-
- return true;
-}
-
-
-void CB3DMeshFileLoader::readString(core::stringc& newstring)
-{
- newstring="";
- while (true)
- {
- c8 character;
- if (B3DFile->read(&character, sizeof(character)) == 0)
- return; // eof
- if (character==0)
- return;
- newstring.append(character);
- }
-}
-
-
-void CB3DMeshFileLoader::readFloats(f32* vec, u32 count)
-{
- B3DFile->read(vec, count*sizeof(f32));
- #ifdef __BIG_ENDIAN__
- for (u32 n=0; n B3dStack;
-
- core::array Materials;
- core::array Textures;
-
- core::array AnimatedVertices_VertexID;
-
- core::array AnimatedVertices_BufferID;
-
- core::array BaseVertices;
-
- CSkinnedMesh* AnimatedMesh;
- io::IReadFile* B3DFile;
-
- //B3Ds have Vertex ID's local within the mesh I don't want this
- // Variable needs to be class member due to recursion in calls
- u32 VerticesStart;
-
- bool NormalsInFile;
- bool HasVertexColors;
- bool ShowWarning;
-};
-
-
-} // end namespace scene
-} // end namespace irr
diff --git a/source/Irrlicht/CB3DMeshWriter.cpp b/source/Irrlicht/CB3DMeshWriter.cpp
deleted file mode 100644
index ea0399d99..000000000
--- a/source/Irrlicht/CB3DMeshWriter.cpp
+++ /dev/null
@@ -1,530 +0,0 @@
-// 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 "CB3DMeshWriter.h"
-#include "os.h"
-#include "ISkinnedMesh.h"
-#include "IMeshBuffer.h"
-#include "IWriteFile.h"
-#include "ITexture.h"
-
-
-namespace irr
-{
-namespace scene
-{
-
-using namespace core;
-using namespace video;
-
-CB3DMeshWriter::CB3DMeshWriter()
-{
- #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
-
- file->write("BB3D", 4);
- file->write("size", 4); // BB3D chunk size, updated later
-
- const u32 version = 1;
- file->write(&version, 4);
-
- //
-
- const u32 numMeshBuffers = mesh->getMeshBufferCount();
- array texs;
- std::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 < numMeshBuffers; 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;
- }
- }
- }
-
- file->write("TEXS", 4);
- file->write(&texsizes, 4);
-
- u32 numTexture = texs.size();
- for (u32 i = 0; i < numTexture; i++)
- {
- file->write(texs[i].TextureName.c_str(), (size_t)texs[i].TextureName.size() + 1);
- file->write(&texs[i].Flags, 7*4);
- }
-
- //
-
- file->write("BRUS", 4);
- const u32 brushSizeAdress = file->getPos();
- file->write(&brushSizeAdress, 4); // BRUSH chunk size, updated later
-
- const u32 usedtex = MATERIAL_MAX_TEXTURES;
- file->write(&usedtex, 4);
-
- for (u32 i = 0; i < numMeshBuffers; i++)
- {
- const IMeshBuffer * const mb = mesh->getMeshBuffer(i);
- const SMaterial &mat = mb->getMaterial();
-
- file->write("", 1);
-
- float f = 1;
- file->write(&f, 4);
- file->write(&f, 4);
- file->write(&f, 4);
- file->write(&f, 4);
-
- f = 0;
- file->write(&f, 4);
-
- u32 tmp = 1;
- file->write(&tmp, 4);
- tmp = 0;
- file->write(&tmp, 4);
-
- for (u32 j = 0; j < MATERIAL_MAX_TEXTURES; j++)
- {
- s32 id = -1;
- if (mat.getTexture(j))
- {
- id = tex2id[mat.getTexture(j)];
- }
- file->write(&id, 4);
- }
- }
- writeSizeFrom(file, brushSizeAdress+4, brushSizeAdress); // BRUSH chunk size
-
- file->write("NODE", 4);
- u32 nodeSizeAdress = file->getPos();
- file->write(&nodeSizeAdress, 4); // NODE chunk size, updated later
-
- // Node
- file->write("", 1);
-
- // position
- writeVector3(file, core::vector3df(0.f, 0.f, 0.f));
-
- // scale
- writeVector3(file, core::vector3df(1.f, 1.f, 1.f));
-
- // rotation
- writeQuaternion(file, core::quaternion(0.f, 0.f, 0.f, 1.f));
-
- // Mesh
- file->write("MESH", 4);
- const u32 meshSizeAdress = file->getPos();
- file->write(&meshSizeAdress, 4); // MESH chunk size, updated later
-
- s32 brushID = -1;
- file->write(&brushID, 4);
-
-
-
- // Verts
- file->write("VRTS", 4);
- const u32 verticesSizeAdress = file->getPos();
- file->write(&verticesSizeAdress, 4);
-
- u32 flagsB3D = 3; // 1=normal values present, 2=rgba values present
- file->write(&flagsB3D, 4);
-
- const u32 texcoordsCount = getUVlayerCount(mesh);
- file->write(&texcoordsCount, 4);
- flagsB3D = 2;
- file->write(&flagsB3D, 4);
-
- for (u32 i = 0; i < numMeshBuffers; i++)
- {
- const IMeshBuffer * const mb = mesh->getMeshBuffer(i);
- const u32 numVertices = mb->getVertexCount();
- for (u32 j = 0; j < numVertices; j++)
- {
- const vector3df &pos = mb->getPosition(j);
- writeVector3(file, pos);
-
- const vector3df &n = mb->getNormal(j);
- writeVector3(file, n);
-
- switch (mb->getVertexType())
- {
- case EVT_STANDARD:
- {
- S3DVertex *v = (S3DVertex *) mb->getVertices();
- const SColorf col(v[j].Color);
- writeColor(file, col);
-
- const core::vector2df uv1 = v[j].TCoords;
- writeVector2(file, uv1);
- if (texcoordsCount == 2)
- {
- writeVector2(file, core::vector2df(0.f, 0.f));
- }
- }
- break;
- case EVT_2TCOORDS:
- {
- S3DVertex2TCoords *v = (S3DVertex2TCoords *) mb->getVertices();
- const SColorf col(v[j].Color);
- writeColor(file, col);
-
- const core::vector2df uv1 = v[j].TCoords;
- writeVector2(file, uv1);
- const core::vector2df uv2 = v[j].TCoords;
- writeVector2(file, uv2);
- }
- break;
- case EVT_TANGENTS:
- {
- S3DVertexTangents *v = (S3DVertexTangents *) mb->getVertices();
- const SColorf col(v[j].Color);
- writeColor(file, col);
-
- const core::vector2df uv1 = v[j].TCoords;
- writeVector2(file, uv1);
- if (texcoordsCount == 2)
- {
- writeVector2(file, core::vector2df(0.f, 0.f));
- }
- }
- break;
- }
- }
- }
- writeSizeFrom(file, verticesSizeAdress+4, verticesSizeAdress); // VERT chunk size
-
-
- u32 currentMeshBufferIndex = 0;
- // Tris
- for (u32 i = 0; i < numMeshBuffers; i++)
- {
- const IMeshBuffer * const mb = mesh->getMeshBuffer(i);
- file->write("TRIS", 4);
- const u32 trisSizeAdress = file->getPos();
- file->write(&trisSizeAdress, 4); // TRIS chunk size, updated later
-
- file->write(&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;
- file->write(&tmp, sizeof(u32));
-
- tmp = idx[j + 1] + currentMeshBufferIndex;
- file->write(&tmp, sizeof(u32));
-
- tmp = idx[j + 2] + currentMeshBufferIndex;
- file->write(&tmp, sizeof(u32));
- }
- writeSizeFrom(file, trisSizeAdress+4, trisSizeAdress); // TRIS chunk size
-
- currentMeshBufferIndex += mb->getVertexCount();
- }
- writeSizeFrom(file, meshSizeAdress+4, meshSizeAdress); // MESH chunk size
-
-
- if(ISkinnedMesh *skinnedMesh = getSkinned(mesh))
- {
- // Write animation data
- f32 animationSpeedMultiplier = 1.f;
- if (!skinnedMesh->isStatic())
- {
- file->write("ANIM", 4);
-
- const u32 animsize = 12;
- file->write(&animsize, 4);
-
- const u32 flags = 0;
- f32 fps = skinnedMesh->getAnimationSpeed();
-
- /* B3D file format use integer as keyframe, so there is some potential issues if the model use float as keyframe (Irrlicht use float) with a low animation FPS value
- So we define a minimum animation FPS value to multiply the frame and FPS value if the FPS of the animation is too low to store the keyframe with integers */
- const int minimumAnimationFPS = 60;
-
- if (fps < minimumAnimationFPS)
- {
- animationSpeedMultiplier = minimumAnimationFPS / fps;
- fps = minimumAnimationFPS;
- }
- const u32 frames = static_cast(skinnedMesh->getFrameCount() * animationSpeedMultiplier);
-
- file->write(&flags, 4);
- file->write(&frames, 4);
- file->write(&fps, 4);
- }
-
- // Write joints
- core::array rootJoints = getRootJoints(skinnedMesh);
-
- for (u32 i = 0; i < rootJoints.size(); i++)
- {
- writeJointChunk(file, skinnedMesh, rootJoints[i], animationSpeedMultiplier);
- }
- }
-
- writeSizeFrom(file, nodeSizeAdress+4, nodeSizeAdress); // Node chunk size
- writeSizeFrom(file, 8, 4); // BB3D chunk size
-
- return true;
-}
-
-
-
-void CB3DMeshWriter::writeJointChunk(io::IWriteFile* file, ISkinnedMesh* mesh, ISkinnedMesh::SJoint* joint, f32 animationSpeedMultiplier)
-{
- // Node
- file->write("NODE", 4);
- const u32 nodeSizeAdress = file->getPos();
- file->write(&nodeSizeAdress, 4);
-
-
- core::stringc name = joint->Name;
- file->write(name.c_str(), name.size());
- file->write("", 1);
-
- // Position
- const core::vector3df pos = joint->Animatedposition;
- writeVector3(file, pos);
-
- // Scale
- core::vector3df scale = joint->Animatedscale;
- if (scale == core::vector3df(0, 0, 0))
- scale = core::vector3df(1, 1, 1);
-
- writeVector3(file, scale);
-
- // Rotation
- const core::quaternion quat = joint->Animatedrotation;
- writeQuaternion(file, quat);
-
- // Bone
- file->write("BONE", 4);
- u32 bonesize = 8 * joint->Weights.size();
- file->write(&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();
- }
-
- file->write(&b3dVertexID, 4);
- file->write(&weight, 4);
- }
- // ---------------------------
-
- f32 floatBuffer[5];
- // Animation keys
- if (joint->PositionKeys.size())
- {
- file->write("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
- file->write(&keysSize, 4);
-
- u32 flag = 1; // 1 = flag for position keys
- file->write(&flag, 4);
-
- for (u32 i = 0; i < joint->PositionKeys.size(); i++)
- {
- const s32 frame = static_cast(joint->PositionKeys[i].frame * animationSpeedMultiplier);
- file->write(&frame, 4);
-
- const core::vector3df pos = joint->PositionKeys[i].position;
- pos.getAs3Values(floatBuffer);
- file->write(floatBuffer, 12);
- }
- }
- if (joint->RotationKeys.size())
- {
- file->write("KEYS", 4);
- u32 keysSize = 4 * joint->RotationKeys.size() * 5; // W, X, Y and Z rot + frame
- keysSize += 4; // Flag
- file->write(&keysSize, 4);
-
- u32 flag = 4;
- file->write(&flag, 4);
-
- for (u32 i = 0; i < joint->RotationKeys.size(); i++)
- {
- const s32 frame = static_cast(joint->RotationKeys[i].frame * animationSpeedMultiplier);
- const core::quaternion rot = joint->RotationKeys[i].rotation;
-
- memcpy(floatBuffer, &frame, 4);
- floatBuffer[1] = rot.W;
- floatBuffer[2] = rot.X;
- floatBuffer[3] = rot.Y;
- floatBuffer[4] = rot.Z;
- file->write(floatBuffer, 20);
- }
- }
- if (joint->ScaleKeys.size())
- {
- file->write("KEYS", 4);
- u32 keysSize = 4 * joint->ScaleKeys.size() * 4; // X, Y and Z scale + frame
- keysSize += 4; // Flag
- file->write(&keysSize, 4);
-
- u32 flag = 2;
- file->write(&flag, 4);
-
- for (u32 i = 0; i < joint->ScaleKeys.size(); i++)
- {
- const s32 frame = static_cast(joint->ScaleKeys[i].frame * animationSpeedMultiplier);
- file->write(&frame, 4);
-
- const core::vector3df scale = joint->ScaleKeys[i].scale;
- scale.getAs3Values(floatBuffer);
- file->write(floatBuffer, 12);
- }
- }
-
- for (u32 i = 0; i < joint->Children.size(); i++)
- {
- writeJointChunk(file, mesh, joint->Children[i], animationSpeedMultiplier);
- }
-
- writeSizeFrom(file, nodeSizeAdress+4, nodeSizeAdress); // NODE chunk size
-}
-
-
-ISkinnedMesh* CB3DMeshWriter::getSkinned (IMesh *mesh)
-{
- if (mesh->getMeshType() == EAMT_SKINNED)
- {
- return static_cast(mesh);
- }
- return 0;
-}
-
-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(const 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::writeVector2(io::IWriteFile* file, const core::vector2df& vec2)
-{
- f32 buffer[2] = {vec2.X, vec2.Y};
- file->write(buffer, 8);
-}
-
-void CB3DMeshWriter::writeVector3(io::IWriteFile* file, const core::vector3df& vec3)
-{
- f32 buffer[3];
- vec3.getAs3Values(buffer);
- file->write(buffer, 12);
-}
-
-void CB3DMeshWriter::writeQuaternion(io::IWriteFile* file, const core::quaternion& quat)
-{
- f32 buffer[4] = {quat.W, quat.X, quat.Y, quat.Z};
- file->write(buffer, 16);
-}
-
-void CB3DMeshWriter::writeColor(io::IWriteFile* file, const video::SColorf& color)
-{
- f32 buffer[4] = {color.r, color.g, color.b, color.a};
- file->write(buffer, 16);
-}
-
-// Write the size from a given position to current position at a specific position in the file
-void CB3DMeshWriter::writeSizeFrom(io::IWriteFile* file, const u32 from, const u32 adressToWrite)
-{
- const long back = file->getPos();
- file->seek(adressToWrite);
- const u32 sizeToWrite = back - from;
- file->write(&sizeToWrite, 4);
- file->seek(back);
-}
-
-} // end namespace
-} // end namespace
diff --git a/source/Irrlicht/CB3DMeshWriter.h b/source/Irrlicht/CB3DMeshWriter.h
deleted file mode 100644
index 47065d788..000000000
--- a/source/Irrlicht/CB3DMeshWriter.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// 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
-
-#pragma once
-
-#include "IMeshWriter.h"
-#include "IWriteFile.h"
-#include "SB3DStructs.h"
-#include "ISkinnedMesh.h"
-
-
-
-namespace irr
-{
-namespace scene
-{
-
-//! class to write B3D mesh files
-class CB3DMeshWriter : public IMeshWriter
-{
-public:
-
- CB3DMeshWriter();
-
- //! Returns the type of the mesh writer
- EMESH_WRITER_TYPE getType() const override;
-
- //! writes a mesh
- bool writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32 flags=EMWF_NONE) override;
-
-private:
- void writeJointChunk(io::IWriteFile* file, ISkinnedMesh* mesh , ISkinnedMesh::SJoint* joint, f32 animationSpeedMultiplier);
- u32 getJointChunkSize(const ISkinnedMesh* mesh, ISkinnedMesh::SJoint* joint);
- core::array getRootJoints(const ISkinnedMesh* mesh);
-
- u32 getUVlayerCount(const IMesh *mesh);
- ISkinnedMesh* getSkinned (IMesh *mesh);
-
- inline void writeVector2(io::IWriteFile* file, const core::vector2df& vec);
- inline void writeVector3(io::IWriteFile* file, const core::vector3df& vec);
- inline void writeQuaternion(io::IWriteFile* file, const core::quaternion& quat);
- inline void writeColor(io::IWriteFile* file, const video::SColorf& color);
- void writeSizeFrom(io::IWriteFile* file, const u32 from, const u32 adressToWrite);
-};
-
-} // end namespace
-} // end namespace
-
diff --git a/source/Irrlicht/CGLTFMeshFileLoader.cpp b/source/Irrlicht/CGLTFMeshFileLoader.cpp
new file mode 100644
index 000000000..e9c6a6bdc
--- /dev/null
+++ b/source/Irrlicht/CGLTFMeshFileLoader.cpp
@@ -0,0 +1,350 @@
+#include "CGLTFMeshFileLoader.h"
+#include "CMeshBuffer.h"
+#include "coreutil.h"
+#include "IAnimatedMesh.h"
+#include "ILogger.h"
+#include "IReadFile.h"
+#include "irrTypes.h"
+#include "os.h"
+#include "path.h"
+#include "S3DVertex.h"
+#include "SAnimatedMesh.h"
+#include "SColor.h"
+#include "SMesh.h"
+#include "vector3d.h"
+
+#define STB_IMAGE_IMPLEMENTATION
+#define STB_IMAGE_WRITE_IMPLEMENTATION
+#define TINYGLTF_IMPLEMENTATION
+#include "tinygltf/tiny_gltf.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* Notes on the coordinate system.
+ *
+ * glTF uses a right-handed coordinate system where +Z is the
+ * front-facing axis, and Irrlicht uses a left-handed coordinate
+ * system where -Z is the front-facing axis.
+ * We convert between them by reflecting the mesh across the X axis.
+ * Doing this correctly requires negating the Z coordinate on
+ * vertex positions and normals, and reversing the winding order
+ * of the vertex indices.
+ */
+
+
+namespace irr {
+namespace scene {
+
+CGLTFMeshFileLoader::BufferOffset::BufferOffset(
+ const std::vector& buf,
+ const std::size_t offset)
+ : m_buf(buf)
+ , m_offset(offset)
+{
+}
+
+CGLTFMeshFileLoader::BufferOffset::BufferOffset(
+ const CGLTFMeshFileLoader::BufferOffset& other,
+ const std::size_t fromOffset)
+ : m_buf(other.m_buf)
+ , m_offset(other.m_offset + fromOffset)
+{
+}
+
+unsigned char CGLTFMeshFileLoader::BufferOffset::at(
+ const std::size_t fromOffset) const
+{
+ return m_buf.at(m_offset + fromOffset);
+}
+
+CGLTFMeshFileLoader::CGLTFMeshFileLoader() noexcept
+{
+}
+
+bool CGLTFMeshFileLoader::isALoadableFileExtension(
+ const io::path& filename) const
+{
+ return core::hasFileExtension(filename, "gltf");
+}
+
+IAnimatedMesh* CGLTFMeshFileLoader::createMesh(io::IReadFile* file)
+{
+ tinygltf::Model model {};
+ if (file->getSize() <= 0 || !tryParseGLTF(file, model)) {
+ return nullptr;
+ }
+
+ MeshExtractor parser(std::move(model));
+ SMesh* baseMesh(new SMesh {});
+ loadPrimitives(parser, baseMesh);
+
+ SAnimatedMesh* animatedMesh(new SAnimatedMesh {});
+ animatedMesh->addMesh(baseMesh);
+
+ return animatedMesh;
+}
+
+void CGLTFMeshFileLoader::loadPrimitives(
+ const MeshExtractor& parser,
+ SMesh* mesh)
+{
+ for (std::size_t i = 0; i < parser.getMeshCount(); ++i) {
+ for (std::size_t j = 0; j < parser.getPrimitiveCount(i); ++j) {
+ auto indices = parser.getIndices(i, j);
+ auto vertices = parser.getVertices(i, j);
+
+ SMeshBuffer* meshbuf(new SMeshBuffer {});
+ meshbuf->append(vertices.data(), vertices.size(),
+ indices.data(), indices.size());
+ mesh->addMeshBuffer(meshbuf);
+ }
+ }
+}
+
+CGLTFMeshFileLoader::MeshExtractor::MeshExtractor(
+ const tinygltf::Model& model) noexcept
+ : m_model(model)
+{
+}
+
+CGLTFMeshFileLoader::MeshExtractor::MeshExtractor(
+ const tinygltf::Model&& model) noexcept
+ : m_model(model)
+{
+}
+
+std::vector CGLTFMeshFileLoader::MeshExtractor::getIndices(
+ const std::size_t meshIdx,
+ const std::size_t primitiveIdx) const
+{
+ const auto accessorIdx = getIndicesAccessorIdx(meshIdx, primitiveIdx);
+ const auto& buf = getBuffer(accessorIdx);
+
+ std::vector indices{};
+ const auto count = getElemCount(accessorIdx);
+ for (std::size_t i = 0; i < count; ++i) {
+ std::size_t elemIdx = count - i - 1;
+ indices.push_back(readPrimitive(
+ BufferOffset(buf, elemIdx * sizeof(u16))));
+ }
+
+ return indices;
+}
+
+std::vector CGLTFMeshFileLoader::MeshExtractor::getVertices(
+ const std::size_t meshIdx,
+ const std::size_t primitiveIdx) const
+{
+ const auto positionAccessorIdx = getPositionAccessorIdx(
+ meshIdx, primitiveIdx);
+ std::vector vertices{};
+ vertices.resize(getElemCount(positionAccessorIdx));
+ copyPositions(positionAccessorIdx, vertices);
+
+ const auto normalAccessorIdx = getNormalAccessorIdx(
+ meshIdx, primitiveIdx);
+ if (normalAccessorIdx != static_cast(-1)) {
+ copyNormals(normalAccessorIdx, vertices);
+ }
+
+ const auto tCoordAccessorIdx = getTCoordAccessorIdx(
+ meshIdx, primitiveIdx);
+ if (tCoordAccessorIdx != static_cast(-1)) {
+ copyTCoords(tCoordAccessorIdx, vertices);
+ }
+
+ return vertices;
+}
+
+std::size_t CGLTFMeshFileLoader::MeshExtractor::getMeshCount() const
+{
+ return m_model.meshes.size();
+}
+
+std::size_t CGLTFMeshFileLoader::MeshExtractor::getPrimitiveCount(
+ const std::size_t meshIdx) const
+{
+ return m_model.meshes[meshIdx].primitives.size();
+}
+
+
+template
+T CGLTFMeshFileLoader::MeshExtractor::readPrimitive(
+ const BufferOffset& readFrom)
+{
+ unsigned char d[sizeof(T)]{};
+ for (std::size_t i = 0; i < sizeof(T); ++i) {
+ d[i] = readFrom.at(i);
+ }
+ T dest;
+ std::memcpy(&dest, d, sizeof(dest));
+ return dest;
+}
+
+core::vector2df CGLTFMeshFileLoader::MeshExtractor::readVec2DF(
+ const CGLTFMeshFileLoader::BufferOffset& readFrom)
+{
+ return core::vector2df(readPrimitive(readFrom),
+ readPrimitive(BufferOffset(readFrom, sizeof(float))));
+
+}
+
+core::vector3df CGLTFMeshFileLoader::MeshExtractor::readVec3DF(
+ const BufferOffset& readFrom,
+ const float scale)
+{
+ return core::vector3df(
+ scale * readPrimitive(readFrom),
+ scale * readPrimitive(BufferOffset(readFrom, sizeof(float))),
+ -scale * readPrimitive(BufferOffset(readFrom, 2 *
+ sizeof(float))));
+}
+
+void CGLTFMeshFileLoader::MeshExtractor::copyPositions(
+ const std::size_t accessorIdx,
+ std::vector& vertices) const
+{
+
+ const auto& buffer = getBuffer(accessorIdx);
+ const auto count = getElemCount(accessorIdx);
+
+ for (std::size_t i = 0; i < count; i++) {
+ const auto v = readVec3DF(BufferOffset(buffer,
+ 3 * sizeof(float) * i), getScale());
+ vertices[i].Pos = v;
+ }
+}
+
+void CGLTFMeshFileLoader::MeshExtractor::copyNormals(
+ const std::size_t accessorIdx,
+ std::vector& vertices) const
+{
+ const auto& buffer = getBuffer(accessorIdx);
+ const auto count = getElemCount(accessorIdx);
+
+ for (std::size_t i = 0; i < count; i++) {
+ const auto n = readVec3DF(BufferOffset(buffer,
+ 3 * sizeof(float) * i));
+ vertices[i].Normal = n;
+ }
+}
+
+void CGLTFMeshFileLoader::MeshExtractor::copyTCoords(
+ const std::size_t accessorIdx,
+ std::vector& vertices) const
+{
+ const auto& buffer = getBuffer(accessorIdx);
+ const auto count = getElemCount(accessorIdx);
+
+ for (std::size_t i = 0; i < count; ++i) {
+ const auto t = readVec2DF(BufferOffset(buffer,
+ 2 * sizeof(float) * i));
+ vertices[i].TCoords = t;
+ }
+}
+
+float CGLTFMeshFileLoader::MeshExtractor::getScale() const
+{
+ if (m_model.nodes[0].scale.size() > 0) {
+ return static_cast(m_model.nodes[0].scale[0]);
+ }
+
+ return 1.0f;
+}
+
+std::size_t CGLTFMeshFileLoader::MeshExtractor::getElemCount(
+ const std::size_t accessorIdx) const
+{
+ return m_model.accessors[accessorIdx].count;
+}
+
+CGLTFMeshFileLoader::BufferOffset CGLTFMeshFileLoader::MeshExtractor::getBuffer(
+ const std::size_t accessorIdx) const
+{
+ const auto& accessor = m_model.accessors[accessorIdx];
+ const auto& view = m_model.bufferViews[accessor.bufferView];
+ const auto& buffer = m_model.buffers[view.buffer];
+
+ return BufferOffset(buffer.data, view.byteOffset);
+}
+
+std::size_t CGLTFMeshFileLoader::MeshExtractor::getIndicesAccessorIdx(
+ const std::size_t meshIdx,
+ const std::size_t primitiveIdx) const
+{
+ return m_model.meshes[meshIdx].primitives[primitiveIdx].indices;
+}
+
+std::size_t CGLTFMeshFileLoader::MeshExtractor::getPositionAccessorIdx(
+ const std::size_t meshIdx,
+ const std::size_t primitiveIdx) const
+{
+ return m_model.meshes[meshIdx].primitives[primitiveIdx]
+ .attributes.find("POSITION")->second;
+}
+
+std::size_t CGLTFMeshFileLoader::MeshExtractor::getNormalAccessorIdx(
+ const std::size_t meshIdx,
+ const std::size_t primitiveIdx) const
+{
+ const auto& attributes = m_model.meshes[meshIdx]
+ .primitives[primitiveIdx].attributes;
+ const auto result = attributes.find("NORMAL");
+
+ if (result == attributes.end()) {
+ return -1;
+ } else {
+ return result->second;
+ }
+}
+
+std::size_t CGLTFMeshFileLoader::MeshExtractor::getTCoordAccessorIdx(
+ const std::size_t meshIdx,
+ const std::size_t primitiveIdx) const
+{
+ const auto& attributes = m_model.meshes[meshIdx]
+ .primitives[primitiveIdx].attributes;
+ const auto result = attributes.find("TEXCOORD_0");
+
+ if (result == attributes.end()) {
+ return -1;
+ } else {
+ return result->second;
+ }
+}
+
+bool CGLTFMeshFileLoader::tryParseGLTF(io::IReadFile* file,
+ tinygltf::Model& model)
+{
+ tinygltf::TinyGLTF loader {};
+
+ // Stop embedded textures from making model fail to load
+ loader.SetImageLoader(nullptr, nullptr);
+
+ std::string err {};
+ std::string warn {};
+
+ auto buf = std::make_unique(file->getSize());
+ file->read(buf.get(), file->getSize());
+
+ if (warn != "") {
+ os::Printer::log(warn.c_str(), ELL_WARNING);
+ }
+
+ if (err != "") {
+ os::Printer::log(err.c_str(), ELL_ERROR);
+ return false;
+ }
+
+ return loader.LoadASCIIFromString(&model, &err, &warn, buf.get(),
+ file->getSize(), "", 1);
+}
+
+} // namespace scene
+
+} // namespace irr
\ No newline at end of file
diff --git a/source/Irrlicht/CGLTFMeshFileLoader.h b/source/Irrlicht/CGLTFMeshFileLoader.h
new file mode 100644
index 000000000..c893c12ae
--- /dev/null
+++ b/source/Irrlicht/CGLTFMeshFileLoader.h
@@ -0,0 +1,140 @@
+#ifndef __C_GLTF_MESH_FILE_LOADER_INCLUDED__
+#define __C_GLTF_MESH_FILE_LOADER_INCLUDED__
+
+#include "IAnimatedMesh.h"
+#include "IMeshLoader.h"
+#include "IReadFile.h"
+#include "irrTypes.h"
+#include "path.h"
+#include "S3DVertex.h"
+#include "SMesh.h"
+#include "vector2d.h"
+#include "vector3d.h"
+
+#include "tinygltf/tiny_gltf.h"
+
+#include
+#include
+
+namespace irr
+{
+
+namespace scene
+{
+
+class CGLTFMeshFileLoader : public IMeshLoader
+{
+public:
+ CGLTFMeshFileLoader() noexcept;
+
+ bool isALoadableFileExtension(const io::path& filename) const override;
+
+ IAnimatedMesh* createMesh(io::IReadFile* file) override;
+
+private:
+ class BufferOffset
+ {
+ public:
+ BufferOffset(const std::vector& buf,
+ const std::size_t offset);
+
+ BufferOffset(const BufferOffset& other,
+ const std::size_t fromOffset);
+
+ unsigned char at(const std::size_t fromOffset) const;
+ private:
+ const std::vector& m_buf;
+ std::size_t m_offset;
+ int m_filesize;
+ };
+
+ class MeshExtractor {
+ public:
+ using vertex_t = video::S3DVertex;
+
+ MeshExtractor(const tinygltf::Model& model) noexcept;
+
+ MeshExtractor(const tinygltf::Model&& model) noexcept;
+
+ /* Gets indices for the given mesh/primitive.
+ *
+ * Values are return in Irrlicht winding order.
+ */
+ std::vector getIndices(const std::size_t meshIdx,
+ const std::size_t primitiveIdx) const;
+
+ std::vector getVertices(std::size_t meshIdx,
+ const std::size_t primitiveIdx) const;
+
+ std::size_t getMeshCount() const;
+
+ std::size_t getPrimitiveCount(const std::size_t meshIdx) const;
+
+ private:
+ tinygltf::Model m_model;
+
+ template
+ static T readPrimitive(const BufferOffset& readFrom);
+
+ static core::vector2df readVec2DF(
+ const BufferOffset& readFrom);
+
+ /* Read a vec3df from a buffer with transformations applied.
+ *
+ * Values are returned in Irrlicht coordinates.
+ */
+ static core::vector3df readVec3DF(
+ const BufferOffset& readFrom,
+ const float scale = 1.0f);
+
+ void copyPositions(const std::size_t accessorIdx,
+ std::vector& vertices) const;
+
+ void copyNormals(const std::size_t accessorIdx,
+ std::vector& vertices) const;
+
+ void copyTCoords(const std::size_t accessorIdx,
+ std::vector& vertices) const;
+
+ /* Get the scale factor from the glTF mesh information.
+ *
+ * Returns 1.0f if no scale factor is present.
+ */
+ float getScale() const;
+
+ std::size_t getElemCount(const std::size_t accessorIdx) const;
+
+ BufferOffset getBuffer(const std::size_t accessorIdx) const;
+
+ std::size_t getIndicesAccessorIdx(const std::size_t meshIdx,
+ const std::size_t primitiveIdx) const;
+
+ std::size_t getPositionAccessorIdx(const std::size_t meshIdx,
+ const std::size_t primitiveIdx) const;
+
+ /* Get the accessor id of the normals of a primitive.
+ *
+ * -1 is returned if none are present.
+ */
+ std::size_t getNormalAccessorIdx(const std::size_t meshIdx,
+ const std::size_t primitiveIdx) const;
+
+ /* Get the accessor id for the tcoords of a primitive.
+ *
+ * -1 is returned if none are present.
+ */
+ std::size_t getTCoordAccessorIdx(const std::size_t meshIdx,
+ const std::size_t primitiveIdx) const;
+ };
+
+ void loadPrimitives(const MeshExtractor& parser, SMesh* mesh);
+
+ static bool tryParseGLTF(io::IReadFile* file,
+ tinygltf::Model& model);
+};
+
+} // namespace scene
+
+} // namespace irr
+
+#endif // __C_GLTF_MESH_FILE_LOADER_INCLUDED__
\ No newline at end of file
diff --git a/source/Irrlicht/CMakeLists.txt b/source/Irrlicht/CMakeLists.txt
index 630970ae2..09bee2686 100644
--- a/source/Irrlicht/CMakeLists.txt
+++ b/source/Irrlicht/CMakeLists.txt
@@ -328,9 +328,7 @@ set(link_libs
# Source files
set(IRRMESHLOADER
- CB3DMeshFileLoader.cpp
- COBJMeshFileLoader.cpp
- CXMeshFileLoader.cpp
+ CGLTFMeshFileLoader.cpp
)
add_library(IRRMESHOBJ OBJECT
diff --git a/source/Irrlicht/COBJMeshFileLoader.cpp b/source/Irrlicht/COBJMeshFileLoader.cpp
deleted file mode 100644
index 6649b7bc3..000000000
--- a/source/Irrlicht/COBJMeshFileLoader.cpp
+++ /dev/null
@@ -1,614 +0,0 @@
-// Copyright (C) 2002-2012 Nikolaus Gebhardt
-// This file is part of the "Irrlicht Engine".
-// For conditions of distribution and use, see copyright notice in irrlicht.h
-
-#include "COBJMeshFileLoader.h"
-#include "IMeshManipulator.h"
-#include "IVideoDriver.h"
-#include "SMesh.h"
-#include "SMeshBuffer.h"
-#include "SAnimatedMesh.h"
-#include "IReadFile.h"
-#include "IAttributes.h"
-#include "fast_atof.h"
-#include "coreutil.h"
-#include "os.h"
-
-namespace irr
-{
-namespace scene
-{
-
-#ifdef _DEBUG
-#define _IRR_DEBUG_OBJ_LOADER_
-#endif
-
-//! Constructor
-COBJMeshFileLoader::COBJMeshFileLoader(scene::ISceneManager* smgr)
-: SceneManager(smgr)
-{
- #ifdef _DEBUG
- setDebugName("COBJMeshFileLoader");
- #endif
-}
-
-
-//! destructor
-COBJMeshFileLoader::~COBJMeshFileLoader()
-{
-}
-
-
-//! returns true if the file maybe is able to be loaded by this class
-//! based on the file extension (e.g. ".bsp")
-bool COBJMeshFileLoader::isALoadableFileExtension(const io::path& filename) const
-{
- return core::hasFileExtension ( filename, "obj" );
-}
-
-
-//! creates/loads an animated mesh from the file.
-//! \return Pointer to the created mesh. Returns 0 if loading failed.
-//! If you no longer need the mesh, you should call IAnimatedMesh::drop().
-//! See IReferenceCounted::drop() for more information.
-IAnimatedMesh* COBJMeshFileLoader::createMesh(io::IReadFile* file)
-{
- if (!file)
- return 0;
-
- const long filesize = file->getSize();
- if (!filesize)
- return 0;
-
- const u32 WORD_BUFFER_LENGTH = 512;
-
- core::array vertexBuffer(1000);
- core::array normalsBuffer(1000);
- core::array textureCoordBuffer(1000);
-
- SObjMtl * currMtl = new SObjMtl();
- Materials.push_back(currMtl);
- u32 smoothingGroup=0;
-
- const io::path fullName = file->getFileName();
-
- c8* buf = new c8[filesize+1]; // plus null-terminator
- memset(buf, 0, filesize+1);
- file->read((void*)buf, filesize);
- const c8* const bufEnd = buf+filesize;
-
- // Process obj information
- const c8* bufPtr = buf;
- core::stringc grpName, mtlName;
- bool mtlChanged=false;
- bool useGroups = !SceneManager->getParameters()->getAttributeAsBool(OBJ_LOADER_IGNORE_GROUPS);
- bool useMaterials = !SceneManager->getParameters()->getAttributeAsBool(OBJ_LOADER_IGNORE_MATERIAL_FILES);
- [[maybe_unused]] irr::u32 lineNr = 1; // only counts non-empty lines, still useful in debugging to locate errors
- core::array faceCorners;
- faceCorners.reallocate(32); // should be large enough
- const core::stringc TAG_OFF = "off";
- irr::u32 degeneratedFaces = 0;
-
- while(bufPtr != bufEnd)
- {
- switch(bufPtr[0])
- {
- case 'm': // mtllib (material)
- {
- if (useMaterials)
- {
- c8 name[WORD_BUFFER_LENGTH];
- bufPtr = goAndCopyNextWord(name, bufPtr, WORD_BUFFER_LENGTH, bufEnd);
-#ifdef _IRR_DEBUG_OBJ_LOADER_
- os::Printer::log("Ignoring material file",name);
-#endif
- }
- }
- break;
-
- case 'v': // v, vn, vt
- switch(bufPtr[1])
- {
- case ' ': // vertex
- {
- core::vector3df vec;
- bufPtr = readVec3(bufPtr, vec, bufEnd);
- vertexBuffer.push_back(vec);
- }
- break;
-
- case 'n': // normal
- {
- core::vector3df vec;
- bufPtr = readVec3(bufPtr, vec, bufEnd);
- normalsBuffer.push_back(vec);
- }
- break;
-
- case 't': // texcoord
- {
- core::vector2df vec;
- bufPtr = readUV(bufPtr, vec, bufEnd);
- textureCoordBuffer.push_back(vec);
- }
- break;
- }
- break;
-
- case 'g': // group name
- {
- c8 grp[WORD_BUFFER_LENGTH];
- bufPtr = goAndCopyNextWord(grp, bufPtr, WORD_BUFFER_LENGTH, bufEnd);
-#ifdef _IRR_DEBUG_OBJ_LOADER_
- os::Printer::log("Loaded group start",grp, ELL_DEBUG);
-#endif
- if (useGroups)
- {
- if (0 != grp[0])
- grpName = grp;
- else
- grpName = "default";
- }
- mtlChanged=true;
- }
- break;
-
- case 's': // smoothing can be a group or off (equiv. to 0)
- {
- c8 smooth[WORD_BUFFER_LENGTH];
- bufPtr = goAndCopyNextWord(smooth, bufPtr, WORD_BUFFER_LENGTH, bufEnd);
-#ifdef _IRR_DEBUG_OBJ_LOADER_
- os::Printer::log("Loaded smoothing group start",smooth, ELL_DEBUG);
-#endif
- if (TAG_OFF==smooth)
- smoothingGroup=0;
- else
- smoothingGroup=core::strtoul10(smooth);
-
- (void)smoothingGroup; // disable unused variable warnings
- }
- break;
-
- case 'u': // usemtl
- // get name of material
- {
- c8 matName[WORD_BUFFER_LENGTH];
- bufPtr = goAndCopyNextWord(matName, bufPtr, WORD_BUFFER_LENGTH, bufEnd);
-#ifdef _IRR_DEBUG_OBJ_LOADER_
- os::Printer::log("Loaded material start",matName, ELL_DEBUG);
-#endif
- mtlName=matName;
- mtlChanged=true;
- }
- break;
-
- case 'f': // face
- {
- c8 vertexWord[WORD_BUFFER_LENGTH]; // for retrieving vertex data
- video::S3DVertex v;
- // Assign vertex color from currently active material's diffuse color
- if (mtlChanged)
- {
- // retrieve the material
- SObjMtl *useMtl = findMtl(mtlName, grpName);
- // only change material if we found it
- if (useMtl)
- currMtl = useMtl;
- mtlChanged=false;
- }
- if (currMtl)
- v.Color = currMtl->Meshbuffer->Material.DiffuseColor;
-
- // get all vertices data in this face (current line of obj file)
- const core::stringc wordBuffer = copyLine(bufPtr, bufEnd);
- const c8* linePtr = wordBuffer.c_str();
- const c8* const endPtr = linePtr+wordBuffer.size();
-
- faceCorners.set_used(0); // fast clear
-
- // read in all vertices
- linePtr = goNextWord(linePtr, endPtr);
- while (0 != linePtr[0])
- {
- // Array to communicate with retrieveVertexIndices()
- // sends the buffer sizes and gets the actual indices
- // if index not set returns -1
- s32 Idx[3];
- Idx[0] = Idx[1] = Idx[2] = -1;
-
- // read in next vertex's data
- u32 wlength = copyWord(vertexWord, linePtr, WORD_BUFFER_LENGTH, endPtr);
- // this function will also convert obj's 1-based index to c++'s 0-based index
- retrieveVertexIndices(vertexWord, Idx, vertexWord+wlength+1, vertexBuffer.size(), textureCoordBuffer.size(), normalsBuffer.size());
- if ( Idx[0] >= 0 && Idx[0] < (irr::s32)vertexBuffer.size() )
- v.Pos = vertexBuffer[Idx[0]];
- else
- {
- os::Printer::log("Invalid vertex index in this line", wordBuffer.c_str(), ELL_ERROR);
- delete [] buf;
- cleanUp();
- return 0;
- }
- if ( Idx[1] >= 0 && Idx[1] < (irr::s32)textureCoordBuffer.size() )
- v.TCoords = textureCoordBuffer[Idx[1]];
- else
- v.TCoords.set(0.0f,0.0f);
- if ( Idx[2] >= 0 && Idx[2] < (irr::s32)normalsBuffer.size() )
- v.Normal = normalsBuffer[Idx[2]];
- else
- {
- v.Normal.set(0.0f,0.0f,0.0f);
- currMtl->RecalculateNormals=true;
- }
-
- int vertLocation;
- auto n = currMtl->VertMap.find(v);
- if (n != currMtl->VertMap.end())
- {
- vertLocation = n->second;
- }
- else
- {
- currMtl->Meshbuffer->Vertices.push_back(v);
- vertLocation = currMtl->Meshbuffer->Vertices.size() -1;
- currMtl->VertMap.emplace(v, vertLocation);
- }
-
- faceCorners.push_back(vertLocation);
-
- // go to next vertex
- linePtr = goNextWord(linePtr, endPtr);
- }
-
- if (faceCorners.size() < 3)
- {
- os::Printer::log("Too few vertices in this line", wordBuffer.c_str(), ELL_ERROR);
- delete [] buf;
- cleanUp();
- return 0;
- }
-
- // triangulate the face
- const int c = faceCorners[0];
- for ( u32 i = 1; i < faceCorners.size() - 1; ++i )
- {
- // Add a triangle
- const int a = faceCorners[i + 1];
- const int b = faceCorners[i];
- if (a != b && a != c && b != c) // ignore degenerated faces. We can get them when we merge vertices above in the VertMap.
- {
- currMtl->Meshbuffer->Indices.push_back(a);
- currMtl->Meshbuffer->Indices.push_back(b);
- currMtl->Meshbuffer->Indices.push_back(c);
- }
- else
- {
- ++degeneratedFaces;
- }
- }
- }
- break;
-
- case '#': // comment
- default:
- break;
- } // end switch(bufPtr[0])
- // eat up rest of line
- bufPtr = goNextLine(bufPtr, bufEnd);
- ++lineNr;
- } // end while(bufPtr && (bufPtr-buf 0 )
- {
- irr::core::stringc log(degeneratedFaces);
- log += " degenerated faces removed in ";
- log += irr::core::stringc(fullName);
- os::Printer::log(log.c_str(), ELL_INFORMATION);
- }
-
- SMesh* mesh = new SMesh();
-
- // Combine all the groups (meshbuffers) into the mesh
- for ( u32 m = 0; m < Materials.size(); ++m )
- {
- if ( Materials[m]->Meshbuffer->getIndexCount() > 0 )
- {
- Materials[m]->Meshbuffer->recalculateBoundingBox();
- if (Materials[m]->RecalculateNormals)
- SceneManager->getMeshManipulator()->recalculateNormals(Materials[m]->Meshbuffer);
- mesh->addMeshBuffer( Materials[m]->Meshbuffer );
- }
- }
-
- // Create the Animated mesh if there's anything in the mesh
- SAnimatedMesh* animMesh = 0;
- if ( 0 != mesh->getMeshBufferCount() )
- {
- mesh->recalculateBoundingBox();
- animMesh = new SAnimatedMesh();
- animMesh->Type = EAMT_OBJ;
- animMesh->addMesh(mesh);
- animMesh->recalculateBoundingBox();
- }
-
- // Clean up the allocate obj file contents
- delete [] buf;
- // more cleaning up
- cleanUp();
- mesh->drop();
-
- return animMesh;
-}
-
-//! Read RGB color
-const c8* COBJMeshFileLoader::readColor(const c8* bufPtr, video::SColor& color, const c8* const bufEnd)
-{
- const u32 COLOR_BUFFER_LENGTH = 16;
- c8 colStr[COLOR_BUFFER_LENGTH];
-
- bufPtr = goAndCopyNextWord(colStr, bufPtr, COLOR_BUFFER_LENGTH, bufEnd);
- color.setRed((u32)core::round32(core::fast_atof(colStr)*255.f));
- bufPtr = goAndCopyNextWord(colStr, bufPtr, COLOR_BUFFER_LENGTH, bufEnd);
- color.setGreen((u32)core::round32(core::fast_atof(colStr)*255.f));
- bufPtr = goAndCopyNextWord(colStr, bufPtr, COLOR_BUFFER_LENGTH, bufEnd);
- color.setBlue((u32)core::round32(core::fast_atof(colStr)*255.f));
- return bufPtr;
-}
-
-
-//! Read 3d vector of floats
-const c8* COBJMeshFileLoader::readVec3(const c8* bufPtr, core::vector3df& vec, const c8* const bufEnd)
-{
- const u32 WORD_BUFFER_LENGTH = 256;
- c8 wordBuffer[WORD_BUFFER_LENGTH];
-
- bufPtr = goAndCopyNextWord(wordBuffer, bufPtr, WORD_BUFFER_LENGTH, bufEnd);
- vec.X=-core::fast_atof(wordBuffer); // change handedness
- bufPtr = goAndCopyNextWord(wordBuffer, bufPtr, WORD_BUFFER_LENGTH, bufEnd);
- vec.Y=core::fast_atof(wordBuffer);
- bufPtr = goAndCopyNextWord(wordBuffer, bufPtr, WORD_BUFFER_LENGTH, bufEnd);
- vec.Z=core::fast_atof(wordBuffer);
- return bufPtr;
-}
-
-
-//! Read 2d vector of floats
-const c8* COBJMeshFileLoader::readUV(const c8* bufPtr, core::vector2df& vec, const c8* const bufEnd)
-{
- const u32 WORD_BUFFER_LENGTH = 256;
- c8 wordBuffer[WORD_BUFFER_LENGTH];
-
- bufPtr = goAndCopyNextWord(wordBuffer, bufPtr, WORD_BUFFER_LENGTH, bufEnd);
- vec.X=core::fast_atof(wordBuffer);
- bufPtr = goAndCopyNextWord(wordBuffer, bufPtr, WORD_BUFFER_LENGTH, bufEnd);
- vec.Y=1-core::fast_atof(wordBuffer); // change handedness
- return bufPtr;
-}
-
-
-//! Read boolean value represented as 'on' or 'off'
-const c8* COBJMeshFileLoader::readBool(const c8* bufPtr, bool& tf, const c8* const bufEnd)
-{
- const u32 BUFFER_LENGTH = 8;
- c8 tfStr[BUFFER_LENGTH];
-
- bufPtr = goAndCopyNextWord(tfStr, bufPtr, BUFFER_LENGTH, bufEnd);
- tf = strcmp(tfStr, "off") != 0;
- return bufPtr;
-}
-
-
-COBJMeshFileLoader::SObjMtl* COBJMeshFileLoader::findMtl(const core::stringc& mtlName, const core::stringc& grpName)
-{
- COBJMeshFileLoader::SObjMtl* defMaterial = 0;
- // search existing Materials for best match
- // exact match does return immediately, only name match means a new group
- for (u32 i = 0; i < Materials.size(); ++i)
- {
- if ( Materials[i]->Name == mtlName )
- {
- if ( Materials[i]->Group == grpName )
- return Materials[i];
- else
- defMaterial = Materials[i];
- }
- }
- // we found a partial match
- if (defMaterial)
- {
- Materials.push_back(new SObjMtl(*defMaterial));
- Materials.getLast()->Group = grpName;
- return Materials.getLast();
- }
- // we found a new group for a non-existent material
- else if (grpName.size())
- {
- Materials.push_back(new SObjMtl(*Materials[0]));
- Materials.getLast()->Group = grpName;
- return Materials.getLast();
- }
- return 0;
-}
-
-
-//! skip space characters and stop on first non-space
-const c8* COBJMeshFileLoader::goFirstWord(const c8* buf, const c8* const bufEnd, bool acrossNewlines)
-{
- // skip space characters
- if (acrossNewlines)
- while((buf != bufEnd) && core::isspace(*buf))
- ++buf;
- else
- while((buf != bufEnd) && core::isspace(*buf) && (*buf != '\n'))
- ++buf;
-
- return buf;
-}
-
-
-//! skip current word and stop at beginning of next one
-const c8* COBJMeshFileLoader::goNextWord(const c8* buf, const c8* const bufEnd, bool acrossNewlines)
-{
- // skip current word
- while(( buf != bufEnd ) && !core::isspace(*buf))
- ++buf;
-
- return goFirstWord(buf, bufEnd, acrossNewlines);
-}
-
-
-//! Read until line break is reached and stop at the next non-space character
-const c8* COBJMeshFileLoader::goNextLine(const c8* buf, const c8* const bufEnd)
-{
- // look for newline characters
- while(buf != bufEnd)
- {
- // found it, so leave
- if (*buf=='\n' || *buf=='\r')
- break;
- ++buf;
- }
- return goFirstWord(buf, bufEnd);
-}
-
-
-u32 COBJMeshFileLoader::copyWord(c8* outBuf, const c8* const inBuf, u32 outBufLength, const c8* const bufEnd)
-{
- if (!outBufLength)
- return 0;
- if (!inBuf)
- {
- *outBuf = 0;
- return 0;
- }
-
- u32 i = 0;
- while(inBuf[i])
- {
- if (core::isspace(inBuf[i]) || &(inBuf[i]) == bufEnd)
- break;
- ++i;
- }
-
- u32 length = core::min_(i, outBufLength-1);
- for (u32 j=0; j= BUFFER_LENGTH )
- {
- return false;
- }
- if ( ( core::isdigit(*p)) || (*p == '-') )
- {
- // build up the number
- word[i++] = *p;
- }
- else if ( *p == '/' || *p == ' ' || *p == '\0' )
- {
- // number is completed. Convert and store it
- word[i] = '\0';
- // if no number was found index will become 0 and later on -1 by decrement
- idx[idxType] = core::strtol10(word);
- if (idx[idxType]<0)
- {
- switch (idxType)
- {
- case 0:
- idx[idxType] += vbsize;
- break;
- case 1:
- idx[idxType] += vtsize;
- break;
- case 2:
- idx[idxType] += vnsize;
- break;
- }
- }
- else
- idx[idxType]-=1;
-
- // reset the word
- word[0] = '\0';
- i = 0;
-
- // go to the next kind of index type
- if (*p == '/')
- {
- if ( ++idxType > 2 )
- {
- // error checking, shouldn't reach here unless file is wrong
- idxType = 0;
- }
- }
- else
- {
- // set all missing values to disable (=-1)
- while (++idxType < 3)
- idx[idxType]=-1;
- ++p;
- break; // while
- }
- }
-
- // go to the next char
- ++p;
- }
-
- return true;
-}
-
-
-void COBJMeshFileLoader::cleanUp()
-{
- for (u32 i=0; i < Materials.size(); ++i )
- {
- Materials[i]->Meshbuffer->drop();
- delete Materials[i];
- }
-
- Materials.clear();
-}
-
-
-} // end namespace scene
-} // end namespace irr
diff --git a/source/Irrlicht/COBJMeshFileLoader.h b/source/Irrlicht/COBJMeshFileLoader.h
deleted file mode 100644
index fb06e3295..000000000
--- a/source/Irrlicht/COBJMeshFileLoader.h
+++ /dev/null
@@ -1,110 +0,0 @@
-// Copyright (C) 2002-2012 Nikolaus Gebhardt
-// This file is part of the "Irrlicht Engine".
-// For conditions of distribution and use, see copyright notice in irrlicht.h
-
-#pragma once
-
-#include