Added PLY reader, currently only supports ascii and little-endian binary files.
Added mesh writer flag for binary export, not used yet. git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@2251 dfc29bdd-3216-0410-991c-e03cc46cb475master
parent
00be4fed05
commit
ce44c10fa4
|
@ -1,6 +1,6 @@
|
|||
Changes in 1.6
|
||||
|
||||
- Added PLY mesh writer
|
||||
- Added PLY mesh reader and writer
|
||||
|
||||
- Ensure ListBox on combo box doesn't hang off the bottom of the GUI root, by Matthias Specht
|
||||
|
||||
|
|
|
@ -45,7 +45,10 @@ namespace scene
|
|||
EMWF_WRITE_LIGHTMAPS = 0x1,
|
||||
|
||||
//! write in a way that consumes less disk space
|
||||
EMWF_WRITE_COMPRESSED = 0x2
|
||||
EMWF_WRITE_COMPRESSED = 0x2,
|
||||
|
||||
//! write in binary format rather than text
|
||||
EMWF_WRITE_BINARY = 0x4
|
||||
};
|
||||
|
||||
} // end namespace scene
|
||||
|
|
|
@ -264,10 +264,12 @@ B3D, MS3D or X meshes */
|
|||
#define _IRR_COMPILE_WITH_OGRE_LOADER_
|
||||
//! Define _IRR_COMPILE_WITH_LWO_LOADER_ if you want to load Lightwave3D files
|
||||
#define _IRR_COMPILE_WITH_LWO_LOADER_
|
||||
//! Define _IRR_COMPILE_WITH_STL_LOADER_ if you want to load .stl files
|
||||
//! Define _IRR_COMPILE_WITH_STL_LOADER_ if you want to load stereolithography files
|
||||
#define _IRR_COMPILE_WITH_STL_LOADER_
|
||||
//! Define _IRR_COMPILE_WITH_PLY_LOADER_ if you want to load Polygon (Stanford Triangle) files
|
||||
#define _IRR_COMPILE_WITH_PLY_LOADER_
|
||||
|
||||
//! Define _IRR_COMPILE_WITH_IRR_WRITER_ if you want to write static .irr files
|
||||
//! Define _IRR_COMPILE_WITH_IRR_WRITER_ if you want to write static .irrMesh files
|
||||
#define _IRR_COMPILE_WITH_IRR_WRITER_
|
||||
//! Define _IRR_COMPILE_WITH_COLLADA_WRITER_ if you want to write Collada files
|
||||
#define _IRR_COMPILE_WITH_COLLADA_WRITER_
|
||||
|
|
|
@ -0,0 +1,745 @@
|
|||
// Copyright (C) 2009 Gaz Davidson
|
||||
// This file is part of the "Irrlicht Engine".
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
|
||||
#include "IrrCompileConfig.h"
|
||||
#ifdef _IRR_COMPILE_WITH_PLY_LOADER_
|
||||
|
||||
#include "CPLYMeshFileLoader.h"
|
||||
#include "IMeshManipulator.h"
|
||||
#include "SMesh.h"
|
||||
#include "CDynamicMeshBuffer.h"
|
||||
#include "SAnimatedMesh.h"
|
||||
#include "IReadFile.h"
|
||||
#include "fast_atof.h"
|
||||
#include "os.h"
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace scene
|
||||
{
|
||||
|
||||
// input buffer must be at least twice as long as the longest line in the file
|
||||
#define PLY_INPUT_BUFFER_SIZE 51200 // file is loaded in 50k chunks
|
||||
|
||||
// constructor
|
||||
CPLYMeshFileLoader::CPLYMeshFileLoader()
|
||||
: File(0), Buffer(0)
|
||||
{
|
||||
}
|
||||
|
||||
CPLYMeshFileLoader::~CPLYMeshFileLoader()
|
||||
{
|
||||
// delete the buffer in case we didn't earlier
|
||||
// (we do, but this could be disabled to increase the speed of loading hundreds of meshes)
|
||||
if (Buffer)
|
||||
{
|
||||
delete Buffer;
|
||||
Buffer = 0;
|
||||
}
|
||||
|
||||
// Destroy the element list if it exists
|
||||
for (u32 i=0; i<ElementList.size(); ++i)
|
||||
delete ElementList[i];
|
||||
ElementList.clear();
|
||||
}
|
||||
|
||||
//! returns true if the file maybe is able to be loaded by this class
|
||||
bool CPLYMeshFileLoader::isALoadableFileExtension(const core::string<c16>& filename) const
|
||||
{
|
||||
return core::hasFileExtension(filename, "ply" );
|
||||
}
|
||||
|
||||
|
||||
//! creates/loads an animated mesh from the file.
|
||||
IAnimatedMesh* CPLYMeshFileLoader::createMesh(io::IReadFile* file)
|
||||
{
|
||||
if (!file)
|
||||
return 0;
|
||||
|
||||
File = file;
|
||||
File->grab();
|
||||
|
||||
// attempt to allocate the buffer and fill with data
|
||||
if (!allocateBuffer())
|
||||
{
|
||||
File->drop();
|
||||
File = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// start with empty mesh
|
||||
SAnimatedMesh* animMesh = 0;
|
||||
|
||||
// Currently only supports ASCII meshes
|
||||
if (strcmp(getNextLine(), "ply"))
|
||||
{
|
||||
os::Printer::log("Not a valid PLY file", file->getFileName().c_str(), ELL_ERROR);
|
||||
}
|
||||
else
|
||||
{
|
||||
// cut the next line out
|
||||
c8 *line = getNextLine();
|
||||
// grab the word from this line
|
||||
c8 *word = getNextWord();
|
||||
|
||||
// ignore comments
|
||||
while (strcmp(word, "comment") == 0)
|
||||
{
|
||||
line = getNextLine();
|
||||
word = getNextWord();
|
||||
}
|
||||
|
||||
bool readingHeader = true;
|
||||
bool continueReading = true;
|
||||
IsBinaryFile = false;
|
||||
IsWrongEndian= false;
|
||||
|
||||
do
|
||||
{
|
||||
if (strcmp(word, "format") == 0)
|
||||
{
|
||||
word = getNextWord();
|
||||
|
||||
if (strcmp(word, "binary_little_endian") == 0)
|
||||
{
|
||||
IsBinaryFile = true;
|
||||
// todo: endian swap
|
||||
}
|
||||
else if (strcmp(word, "binary_big_endian") == 0)
|
||||
{
|
||||
IsBinaryFile = true;
|
||||
// todo: endian swap
|
||||
}
|
||||
else if (strcmp(word, "ascii"))
|
||||
{
|
||||
// abort if this isn't an ascii or a binary mesh
|
||||
os::Printer::log("Unsupported PLY mesh format", word, ELL_ERROR);
|
||||
continueReading = false;
|
||||
}
|
||||
|
||||
if (continueReading)
|
||||
{
|
||||
word = getNextWord();
|
||||
if (strcmp(word, "1.0"))
|
||||
{
|
||||
os::Printer::log("Unsupported PLY mesh version", word, ELL_WARNING);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (strcmp(word, "property") == 0)
|
||||
{
|
||||
word = getNextWord();
|
||||
|
||||
if (!ElementList.size())
|
||||
{
|
||||
os::Printer::log("PLY property found before element", word, ELL_WARNING);
|
||||
}
|
||||
else
|
||||
{
|
||||
// get element
|
||||
SPLYElement* el = ElementList[ElementList.size()-1];
|
||||
|
||||
// fill property struct
|
||||
SPLYProperty prop;
|
||||
prop.Type = getPropertyType(word);
|
||||
el->KnownSize += prop.size();
|
||||
|
||||
if (prop.Type == EPLYPT_LIST)
|
||||
{
|
||||
el->IsFixedWidth = false;
|
||||
|
||||
word = getNextWord();
|
||||
|
||||
prop.Data.List.CountType = getPropertyType(word);
|
||||
if (IsBinaryFile && prop.Data.List.CountType == EPLYPT_UNKNOWN)
|
||||
{
|
||||
os::Printer::log("Cannot read binary PLY file containing data types of unknown length", word, ELL_ERROR);
|
||||
continueReading = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
word = getNextWord();
|
||||
prop.Data.List.ItemType = getPropertyType(word);
|
||||
if (IsBinaryFile && prop.Data.List.ItemType == EPLYPT_UNKNOWN)
|
||||
{
|
||||
os::Printer::log("Cannot read binary PLY file containing data types of unknown length", word, ELL_ERROR);
|
||||
continueReading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (IsBinaryFile && prop.Type == EPLYPT_UNKNOWN)
|
||||
{
|
||||
os::Printer::log("Cannot read binary PLY file containing data types of unknown length", word, ELL_ERROR);
|
||||
continueReading = false;
|
||||
}
|
||||
|
||||
prop.Name = getNextWord();
|
||||
|
||||
// add property to element
|
||||
el->Properties.push_back(prop);
|
||||
}
|
||||
}
|
||||
else if (strcmp(word, "element") == 0)
|
||||
{
|
||||
SPLYElement* el = new SPLYElement;
|
||||
el->Name = getNextWord();
|
||||
el->Count = atoi(getNextWord());
|
||||
el->IsFixedWidth = true;
|
||||
el->KnownSize = 0;
|
||||
ElementList.push_back(el);
|
||||
}
|
||||
else if (strcmp(word, "end_header") == 0)
|
||||
{
|
||||
readingHeader = false;
|
||||
}
|
||||
else if (strcmp(word, "comment") == 0)
|
||||
{
|
||||
// ignore line
|
||||
}
|
||||
else
|
||||
{
|
||||
os::Printer::log("Unknown item in PLY file", word, ELL_WARNING);
|
||||
}
|
||||
|
||||
if (readingHeader && continueReading)
|
||||
{
|
||||
line = getNextLine();
|
||||
word = getNextWord();
|
||||
}
|
||||
}
|
||||
while (readingHeader && continueReading);
|
||||
|
||||
// now to read the actual data from the file
|
||||
if (continueReading)
|
||||
{
|
||||
// create a mesh buffer
|
||||
CDynamicMeshBuffer *mb = new CDynamicMeshBuffer(video::EVT_STANDARD, video::EIT_32BIT);
|
||||
mb->setHardwareMappingHint(EHM_STATIC);
|
||||
|
||||
// loop through each of the elements
|
||||
for (u32 i=0; i<ElementList.size(); ++i)
|
||||
{
|
||||
// do we want this element type?
|
||||
if (ElementList[i]->Name == "vertex")
|
||||
{
|
||||
// loop through vertex properties
|
||||
for (u32 j=0; j < ElementList[i]->Count; ++j)
|
||||
readVertex(*ElementList[i], mb);
|
||||
}
|
||||
else if (ElementList[i]->Name == "face")
|
||||
{
|
||||
// read faces
|
||||
for (u32 j=0; j < ElementList[i]->Count; ++j)
|
||||
readFace(*ElementList[i], mb);
|
||||
}
|
||||
else
|
||||
{
|
||||
// skip these elements
|
||||
for (u32 j=0; j < ElementList[i]->Count; ++j)
|
||||
skipElement(*ElementList[i]);
|
||||
}
|
||||
}
|
||||
mb->recalculateBoundingBox();
|
||||
SMesh* m = new SMesh();
|
||||
m->addMeshBuffer(mb);
|
||||
mb->drop();
|
||||
animMesh = new SAnimatedMesh();
|
||||
animMesh->addMesh(m);
|
||||
m->drop();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// free the buffer
|
||||
delete Buffer;
|
||||
Buffer = 0;
|
||||
File->drop();
|
||||
File = 0;
|
||||
|
||||
// if we managed to create a mesh, return it
|
||||
return animMesh;
|
||||
}
|
||||
|
||||
bool CPLYMeshFileLoader::readVertex(const SPLYElement &Element, scene::CDynamicMeshBuffer* mb)
|
||||
{
|
||||
if (!IsBinaryFile)
|
||||
getNextLine();
|
||||
|
||||
video::S3DVertex vert;
|
||||
vert.Color.set(255,255,255,255);
|
||||
vert.TCoords.X = 0.0f;
|
||||
vert.TCoords.Y = 0.0f;
|
||||
vert.Normal.X = 0.0f;
|
||||
vert.Normal.Y = 1.0f;
|
||||
vert.Normal.Z = 0.0f;
|
||||
|
||||
for (u32 i=0; i < Element.Properties.size(); ++i)
|
||||
{
|
||||
E_PLY_PROPERTY_TYPE t = Element.Properties[i].Type;
|
||||
|
||||
if (Element.Properties[i].Name == "x")
|
||||
vert.Pos.X = getFloat(t);
|
||||
else if (Element.Properties[i].Name == "y")
|
||||
vert.Pos.Z = getFloat(t);
|
||||
else if (Element.Properties[i].Name == "z")
|
||||
vert.Pos.Y = getFloat(t);
|
||||
else if (Element.Properties[i].Name == "nx")
|
||||
vert.Normal.X = getFloat(t);
|
||||
else if (Element.Properties[i].Name == "ny")
|
||||
vert.Normal.Z = getFloat(t);
|
||||
else if (Element.Properties[i].Name == "nz")
|
||||
vert.Normal.Y = getFloat(t);
|
||||
else if (Element.Properties[i].Name == "u")
|
||||
vert.TCoords.X = getFloat(t);
|
||||
else if (Element.Properties[i].Name == "v")
|
||||
vert.TCoords.Y = getFloat(t);
|
||||
else if (Element.Properties[i].Name == "red")
|
||||
{
|
||||
u32 value = Element.Properties[i].isFloat() ? (u32)(getFloat(t)*255.0f) : getInt(t);
|
||||
vert.Color.setRed(value);
|
||||
}
|
||||
else if (Element.Properties[i].Name == "green")
|
||||
{
|
||||
u32 value = Element.Properties[i].isFloat() ? (u32)(getFloat(t)*255.0f) : getInt(t);
|
||||
vert.Color.setGreen(value);
|
||||
}
|
||||
else if (Element.Properties[i].Name == "blue")
|
||||
{
|
||||
u32 value = Element.Properties[i].isFloat() ? (u32)(getFloat(t)*255.0f) : getInt(t);
|
||||
vert.Color.setBlue(value);
|
||||
}
|
||||
else if (Element.Properties[i].Name == "alpha")
|
||||
{
|
||||
u32 value = Element.Properties[i].isFloat() ? (u32)(getFloat(t)*255.0f) : getInt(t);
|
||||
vert.Color.setAlpha(value);
|
||||
}
|
||||
else
|
||||
skipProperty(Element.Properties[i]);
|
||||
}
|
||||
|
||||
mb->getVertexBuffer().push_back(vert);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CPLYMeshFileLoader::readFace(const SPLYElement &Element, scene::CDynamicMeshBuffer* mb)
|
||||
{
|
||||
if (!IsBinaryFile)
|
||||
getNextLine();
|
||||
|
||||
for (u32 i=0; i < Element.Properties.size(); ++i)
|
||||
{
|
||||
if ( (Element.Properties[i].Name == "vertex_indices" ||
|
||||
Element.Properties[i].Name == "vertex_index") && Element.Properties[i].Type == EPLYPT_LIST)
|
||||
{
|
||||
// get count
|
||||
s32 count = getInt(Element.Properties[i].Data.List.CountType);
|
||||
u32 a = getInt(Element.Properties[i].Data.List.ItemType),
|
||||
b = getInt(Element.Properties[i].Data.List.ItemType),
|
||||
c = getInt(Element.Properties[i].Data.List.ItemType);
|
||||
s32 j = 3;
|
||||
|
||||
mb->getIndexBuffer().push_back(a);
|
||||
mb->getIndexBuffer().push_back(c);
|
||||
mb->getIndexBuffer().push_back(b);
|
||||
|
||||
for (; j < count; ++j)
|
||||
{
|
||||
b = c;
|
||||
c = getInt(Element.Properties[i].Data.List.ItemType);
|
||||
mb->getIndexBuffer().push_back(a);
|
||||
mb->getIndexBuffer().push_back(c);
|
||||
mb->getIndexBuffer().push_back(b);
|
||||
}
|
||||
}
|
||||
else if (Element.Properties[i].Name == "intensity")
|
||||
{
|
||||
// todo: face intensity
|
||||
skipProperty(Element.Properties[i]);
|
||||
}
|
||||
else
|
||||
skipProperty(Element.Properties[i]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// skips an element and all properties. return false on EOF
|
||||
void CPLYMeshFileLoader::skipElement(const SPLYElement &Element)
|
||||
{
|
||||
if (IsBinaryFile)
|
||||
if (Element.IsFixedWidth)
|
||||
moveForward(Element.KnownSize);
|
||||
else
|
||||
for (u32 i=0; i < Element.Properties.size(); ++i)
|
||||
skipProperty(Element.Properties[i]);
|
||||
else
|
||||
getNextLine();
|
||||
}
|
||||
|
||||
void CPLYMeshFileLoader::skipProperty(const SPLYProperty &Property)
|
||||
{
|
||||
if (Property.Type == EPLYPT_LIST)
|
||||
{
|
||||
s32 count = getInt(Property.Data.List.CountType);
|
||||
|
||||
for (s32 i=0; i < count; ++i)
|
||||
getInt(Property.Data.List.CountType);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsBinaryFile)
|
||||
moveForward(Property.size());
|
||||
else
|
||||
getNextWord();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool CPLYMeshFileLoader::allocateBuffer()
|
||||
{
|
||||
// Destroy the element list if it exists
|
||||
for (u32 i=0; i<ElementList.size(); ++i)
|
||||
delete ElementList[i];
|
||||
ElementList.clear();
|
||||
|
||||
if (!Buffer)
|
||||
Buffer = new c8[PLY_INPUT_BUFFER_SIZE];
|
||||
|
||||
// not enough memory?
|
||||
if (!Buffer)
|
||||
return false;
|
||||
|
||||
// blank memory
|
||||
memset(Buffer, 0, PLY_INPUT_BUFFER_SIZE);
|
||||
|
||||
StartPointer = Buffer;
|
||||
EndPointer = Buffer;
|
||||
LineEndPointer = Buffer-1;
|
||||
WordLength = -1;
|
||||
EndOfFile = false;
|
||||
|
||||
// get data from the file
|
||||
fillBuffer();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// gets more data from the file. returns false on EOF
|
||||
void CPLYMeshFileLoader::fillBuffer()
|
||||
{
|
||||
if (EndOfFile)
|
||||
return;
|
||||
|
||||
u32 length = EndPointer - StartPointer;
|
||||
if (length && StartPointer != Buffer)
|
||||
{
|
||||
// copy the remaining data to the start of the buffer
|
||||
memcpy(Buffer, StartPointer, length);
|
||||
}
|
||||
// reset start position
|
||||
StartPointer = Buffer;
|
||||
EndPointer = StartPointer + length;
|
||||
|
||||
if (File->getPos() == File->getSize())
|
||||
{
|
||||
EndOfFile = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// read data from the file
|
||||
s32 count = File->read(EndPointer, PLY_INPUT_BUFFER_SIZE - length);
|
||||
|
||||
// increment the end pointer by the number of bytes read
|
||||
EndPointer = EndPointer + count;
|
||||
|
||||
// if we didn't completely fill the buffer
|
||||
if (count != PLY_INPUT_BUFFER_SIZE - length)
|
||||
{
|
||||
// blank the rest of the memory
|
||||
memset(EndPointer, 0, Buffer + PLY_INPUT_BUFFER_SIZE - EndPointer);
|
||||
|
||||
// end of file
|
||||
EndOfFile = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// skips x bytes in the file, getting more data if required
|
||||
void CPLYMeshFileLoader::moveForward(u32 bytes)
|
||||
{
|
||||
if (StartPointer + bytes >= EndPointer)
|
||||
fillBuffer();
|
||||
if (StartPointer + bytes < EndPointer)
|
||||
StartPointer += bytes;
|
||||
else
|
||||
StartPointer = EndPointer;
|
||||
}
|
||||
|
||||
CPLYMeshFileLoader::E_PLY_PROPERTY_TYPE CPLYMeshFileLoader::getPropertyType(const c8* typeString) const
|
||||
{
|
||||
if (strcmp(typeString, "char") == 0 ||
|
||||
strcmp(typeString, "uchar") == 0 ||
|
||||
strcmp(typeString, "int8") == 0 ||
|
||||
strcmp(typeString, "uint8") == 0)
|
||||
{
|
||||
return EPLYPT_INT8;
|
||||
}
|
||||
else if (strcmp(typeString, "int") == 0 ||
|
||||
strcmp(typeString, "uint") == 0 ||
|
||||
strcmp(typeString, "int16") == 0 ||
|
||||
strcmp(typeString, "uint16") == 0 ||
|
||||
strcmp(typeString, "short") == 0 ||
|
||||
strcmp(typeString, "ushort") == 0)
|
||||
{
|
||||
return EPLYPT_INT16;
|
||||
}
|
||||
else if (strcmp(typeString, "long") == 0 ||
|
||||
strcmp(typeString, "ulong") == 0 ||
|
||||
strcmp(typeString, "int32") == 0 ||
|
||||
strcmp(typeString, "uint32") == 0)
|
||||
{
|
||||
return EPLYPT_INT32;
|
||||
}
|
||||
else if (strcmp(typeString, "float") == 0 ||
|
||||
strcmp(typeString, "float32") == 0)
|
||||
{
|
||||
return EPLYPT_FLOAT32;
|
||||
}
|
||||
else if (strcmp(typeString, "float64") == 0 ||
|
||||
strcmp(typeString, "double") == 0)
|
||||
{
|
||||
return EPLYPT_FLOAT64;
|
||||
}
|
||||
else if ( strcmp(typeString, "list") == 0 )
|
||||
{
|
||||
return EPLYPT_LIST;
|
||||
}
|
||||
else
|
||||
{
|
||||
// unsupported type.
|
||||
// cannot be loaded in binary mode
|
||||
return EPLYPT_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Split the string data into a line in place by terminating it instead of copying.
|
||||
c8* CPLYMeshFileLoader::getNextLine()
|
||||
{
|
||||
// move the start pointer along
|
||||
StartPointer = LineEndPointer + 1;
|
||||
|
||||
// crlf split across buffer move
|
||||
if (*StartPointer == '\n')
|
||||
{
|
||||
*StartPointer = '\0';
|
||||
++StartPointer;
|
||||
}
|
||||
|
||||
// begin at the start of the next line
|
||||
c8* pos = StartPointer;
|
||||
while (*pos && pos < EndPointer && *pos != '\r' && *pos != '\n')
|
||||
++pos;
|
||||
|
||||
if ( pos < EndPointer && ( *(pos+1) == '\r' || *(pos+1) == '\n') )
|
||||
{
|
||||
*pos = '\0';
|
||||
++pos;
|
||||
}
|
||||
|
||||
// we have reached the end of the buffer
|
||||
if (pos >= EndPointer)
|
||||
{
|
||||
// get data from the file
|
||||
if (File->getPos() < File->getSize())
|
||||
{
|
||||
fillBuffer();
|
||||
// reset line end pointer
|
||||
LineEndPointer = StartPointer - 1;
|
||||
|
||||
if (StartPointer != EndPointer)
|
||||
return getNextLine();
|
||||
else
|
||||
return Buffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
// EOF
|
||||
StartPointer = EndPointer-1;
|
||||
*StartPointer = '\0';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// null terminate the string in place
|
||||
*pos = '\0';
|
||||
LineEndPointer = pos;
|
||||
WordLength = -1;
|
||||
// return pointer to the start of the line
|
||||
return StartPointer;
|
||||
}
|
||||
}
|
||||
// null terminate the next word on the previous line and move the next word pointer along
|
||||
// since we already have a full line in the buffer, we never need to retrieve more data
|
||||
c8* CPLYMeshFileLoader::getNextWord()
|
||||
{
|
||||
// move the start pointer along
|
||||
StartPointer += WordLength + 1;
|
||||
|
||||
if (StartPointer == LineEndPointer)
|
||||
{
|
||||
WordLength = -1; //
|
||||
return LineEndPointer;
|
||||
}
|
||||
// begin at the start of the next word
|
||||
c8* pos = StartPointer;
|
||||
while (*pos && pos < LineEndPointer && pos < EndPointer && *pos != ' ' && *pos != '\t')
|
||||
++pos;
|
||||
|
||||
// null terminate the string in place
|
||||
*pos = '\0';
|
||||
WordLength = pos-StartPointer;
|
||||
// return pointer to the start of the word
|
||||
return StartPointer;
|
||||
}
|
||||
// read the next float from the file and move the start pointer along
|
||||
f32 CPLYMeshFileLoader::getFloat(CPLYMeshFileLoader::E_PLY_PROPERTY_TYPE t)
|
||||
{
|
||||
f32 retVal = 0.0f;
|
||||
|
||||
if (IsBinaryFile)
|
||||
{
|
||||
if (EndPointer - StartPointer < 8)
|
||||
fillBuffer();
|
||||
|
||||
if (EndPointer - StartPointer > 0)
|
||||
{
|
||||
switch (t)
|
||||
{
|
||||
case EPLYPT_INT8:
|
||||
retVal = *StartPointer;
|
||||
StartPointer++;
|
||||
break;
|
||||
case EPLYPT_INT16:
|
||||
retVal = *(reinterpret_cast<s16*>(StartPointer));
|
||||
StartPointer += 2;
|
||||
break;
|
||||
case EPLYPT_INT32:
|
||||
retVal = *(reinterpret_cast<s32*>(StartPointer));
|
||||
StartPointer += 4;
|
||||
break;
|
||||
case EPLYPT_FLOAT32:
|
||||
retVal = *(reinterpret_cast<f32*>(StartPointer));
|
||||
StartPointer += 4;
|
||||
break;
|
||||
case EPLYPT_FLOAT64:
|
||||
retVal = *(reinterpret_cast<f64*>(StartPointer));
|
||||
StartPointer += 8;
|
||||
break;
|
||||
case EPLYPT_LIST:
|
||||
case EPLYPT_UNKNOWN:
|
||||
default:
|
||||
retVal = 0.0f;
|
||||
StartPointer++; // ouch!
|
||||
}
|
||||
}
|
||||
else
|
||||
return 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
c8* word = getNextWord();
|
||||
switch (t)
|
||||
{
|
||||
case EPLYPT_INT8:
|
||||
case EPLYPT_INT16:
|
||||
case EPLYPT_INT32:
|
||||
retVal = f32(atoi(word));
|
||||
break;
|
||||
case EPLYPT_FLOAT32:
|
||||
case EPLYPT_FLOAT64:
|
||||
retVal = atof(word);
|
||||
break;
|
||||
case EPLYPT_LIST:
|
||||
case EPLYPT_UNKNOWN:
|
||||
default:
|
||||
retVal = 0.0f;
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
// read the next int from the file and move the start pointer along
|
||||
u32 CPLYMeshFileLoader::getInt(CPLYMeshFileLoader::E_PLY_PROPERTY_TYPE t)
|
||||
{
|
||||
u32 retVal = 0;
|
||||
|
||||
if (IsBinaryFile)
|
||||
{
|
||||
if (!EndOfFile && EndPointer - StartPointer < 8)
|
||||
fillBuffer();
|
||||
|
||||
if (EndPointer - StartPointer)
|
||||
{
|
||||
switch (t)
|
||||
{
|
||||
case EPLYPT_INT8:
|
||||
retVal = *StartPointer;
|
||||
StartPointer++;
|
||||
break;
|
||||
case EPLYPT_INT16:
|
||||
retVal = *(reinterpret_cast<u16*>(StartPointer));
|
||||
StartPointer += 2;
|
||||
break;
|
||||
case EPLYPT_INT32:
|
||||
retVal = *(reinterpret_cast<u32*>(StartPointer));
|
||||
StartPointer += 4;
|
||||
break;
|
||||
case EPLYPT_FLOAT32:
|
||||
retVal = *(reinterpret_cast<f32*>(StartPointer));
|
||||
StartPointer += 4;
|
||||
break;
|
||||
case EPLYPT_FLOAT64:
|
||||
retVal = *(reinterpret_cast<f64*>(StartPointer));
|
||||
StartPointer += 8;
|
||||
break;
|
||||
case EPLYPT_LIST:
|
||||
case EPLYPT_UNKNOWN:
|
||||
default:
|
||||
retVal = 0.0f;
|
||||
StartPointer++; // ouch!
|
||||
}
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
c8* word = getNextWord();
|
||||
switch (t)
|
||||
{
|
||||
case EPLYPT_INT8:
|
||||
case EPLYPT_INT16:
|
||||
case EPLYPT_INT32:
|
||||
retVal = atoi(word);
|
||||
break;
|
||||
case EPLYPT_FLOAT32:
|
||||
case EPLYPT_FLOAT64:
|
||||
retVal = u32(atof(word));
|
||||
break;
|
||||
case EPLYPT_LIST:
|
||||
case EPLYPT_UNKNOWN:
|
||||
default:
|
||||
retVal = 0;
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // end namespace scene
|
||||
} // end namespace irr
|
||||
|
||||
#endif // _IRR_COMPILE_WITH_PLY_LOADER_
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
// Copyright (C) 2009 Gaz Davidson
|
||||
// This file is part of the "Irrlicht Engine".
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
|
||||
#ifndef __C_PLY_MESH_FILE_LOADER_H_INCLUDED__
|
||||
#define __C_PLY_MESH_FILE_LOADER_H_INCLUDED__
|
||||
|
||||
#include "IMeshLoader.h"
|
||||
#include "CDynamicMeshBuffer.h"
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace scene
|
||||
{
|
||||
|
||||
//! Meshloader capable of loading obj meshes.
|
||||
class CPLYMeshFileLoader : public IMeshLoader
|
||||
{
|
||||
public:
|
||||
|
||||
//! Constructor
|
||||
CPLYMeshFileLoader();
|
||||
|
||||
//! Destructor
|
||||
virtual ~CPLYMeshFileLoader();
|
||||
|
||||
//! returns true if the file maybe is able to be loaded by this class
|
||||
//! based on the file extension (e.g. ".ply")
|
||||
virtual bool isALoadableFileExtension(const core::string<c16>& filename) const;
|
||||
|
||||
//! creates/loads an animated mesh from the file.
|
||||
virtual IAnimatedMesh* createMesh(io::IReadFile* file);
|
||||
|
||||
private:
|
||||
|
||||
enum E_PLY_PROPERTY_TYPE
|
||||
{
|
||||
EPLYPT_INT8 = 0,
|
||||
EPLYPT_INT16,
|
||||
EPLYPT_INT32,
|
||||
EPLYPT_FLOAT32,
|
||||
EPLYPT_FLOAT64,
|
||||
EPLYPT_LIST,
|
||||
EPLYPT_UNKNOWN
|
||||
};
|
||||
|
||||
struct SPLYProperty
|
||||
{
|
||||
core::stringc Name;
|
||||
E_PLY_PROPERTY_TYPE Type;
|
||||
union
|
||||
{
|
||||
u8 Int8;
|
||||
u16 Int16;
|
||||
u32 Int32;
|
||||
f32 Float32;
|
||||
f64 Double;
|
||||
struct SPLYListProperty
|
||||
{
|
||||
E_PLY_PROPERTY_TYPE CountType;
|
||||
E_PLY_PROPERTY_TYPE ItemType;
|
||||
} List;
|
||||
|
||||
} Data;
|
||||
|
||||
inline u32 size() const
|
||||
{
|
||||
switch(Type)
|
||||
{
|
||||
case EPLYPT_INT8:
|
||||
return 1;
|
||||
case EPLYPT_INT16:
|
||||
return 2;
|
||||
case EPLYPT_INT32:
|
||||
case EPLYPT_FLOAT32:
|
||||
return 4;
|
||||
case EPLYPT_FLOAT64:
|
||||
return 8;
|
||||
case EPLYPT_LIST:
|
||||
case EPLYPT_UNKNOWN:
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool isFloat() const
|
||||
{
|
||||
switch(Type)
|
||||
{
|
||||
case EPLYPT_FLOAT32:
|
||||
case EPLYPT_FLOAT64:
|
||||
return true;
|
||||
case EPLYPT_INT8:
|
||||
case EPLYPT_INT16:
|
||||
case EPLYPT_INT32:
|
||||
case EPLYPT_LIST:
|
||||
case EPLYPT_UNKNOWN:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct SPLYElement
|
||||
{
|
||||
// name of the element. We only want "vertex" and "face" elements
|
||||
// but we have to parse the others anyway.
|
||||
core::stringc Name;
|
||||
// The number of elements in the file
|
||||
u32 Count;
|
||||
// Properties of this element
|
||||
core::array<SPLYProperty> Properties;
|
||||
// in binary files, true if this is a fixed size
|
||||
bool IsFixedWidth;
|
||||
// known size in bytes, 0 if unknown
|
||||
u32 KnownSize;
|
||||
};
|
||||
|
||||
bool allocateBuffer();
|
||||
c8* getNextLine();
|
||||
c8* getNextWord();
|
||||
void fillBuffer();
|
||||
E_PLY_PROPERTY_TYPE getPropertyType(const c8* typeString) const;
|
||||
|
||||
bool readVertex(const SPLYElement &Element, scene::CDynamicMeshBuffer* mb);
|
||||
bool readFace(const SPLYElement &Element, scene::CDynamicMeshBuffer* mb);
|
||||
void skipElement(const SPLYElement &Element);
|
||||
void skipProperty(const SPLYProperty &Property);
|
||||
f32 getFloat(E_PLY_PROPERTY_TYPE t);
|
||||
u32 getInt(E_PLY_PROPERTY_TYPE t);
|
||||
void moveForward(u32 bytes);
|
||||
|
||||
core::array<SPLYElement*> ElementList;
|
||||
|
||||
io::IReadFile *File;
|
||||
c8 *Buffer;
|
||||
bool IsBinaryFile, IsWrongEndian, EndOfFile;
|
||||
s32 LineLength, WordLength;
|
||||
c8 *StartPointer, *EndPointer, *LineEndPointer;
|
||||
};
|
||||
|
||||
} // end namespace scene
|
||||
} // end namespace irr
|
||||
|
||||
#endif
|
||||
|
|
@ -123,9 +123,9 @@ bool CPLYMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32 fla
|
|||
snprintf(outLine, 1024,
|
||||
"%f %f %f %f %f %f\n",// %u %u %u %u %f %f\n",
|
||||
pos.X, pos.Z, pos.Y, // Y and Z are flipped
|
||||
n.X, n.Z, n.Y,
|
||||
col.getRed(), col.getGreen(), col.getBlue(), col.getAlpha(),
|
||||
tc.X, tc.Y);
|
||||
n.X, n.Z, n.Y);
|
||||
/*col.getRed(), col.getGreen(), col.getBlue(), col.getAlpha(),
|
||||
tc.X, tc.Y);*/
|
||||
|
||||
// write the line
|
||||
file->write(outLine, strlen(outLine));
|
||||
|
@ -179,5 +179,5 @@ bool CPLYMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32 fla
|
|||
} // end namespace
|
||||
} // end namespace
|
||||
|
||||
#endif
|
||||
#endif // _IRR_COMPILE_WITH_PLY_WRITER_
|
||||
|
||||
|
|
|
@ -89,6 +89,10 @@
|
|||
#include "CSTLMeshFileLoader.h"
|
||||
#endif
|
||||
|
||||
#ifdef _IRR_COMPILE_WITH_PLY_LOADER_
|
||||
#include "CPLYMeshFileLoader.h"
|
||||
#endif
|
||||
|
||||
#ifdef _IRR_COMPILE_WITH_COLLADA_WRITER_
|
||||
#include "CColladaMeshWriter.h"
|
||||
#endif
|
||||
|
@ -252,6 +256,9 @@ CSceneManager::CSceneManager(video::IVideoDriver* driver, io::IFileSystem* fs,
|
|||
#ifdef _IRR_COMPILE_WITH_STL_LOADER_
|
||||
MeshLoaderList.push_back(new CSTLMeshFileLoader());
|
||||
#endif
|
||||
#ifdef _IRR_COMPILE_WITH_PLY_LOADER_
|
||||
MeshLoaderList.push_back(new CPLYMeshFileLoader());
|
||||
#endif
|
||||
|
||||
// factories
|
||||
ISceneNodeFactory* factory = new CDefaultSceneNodeFactory(this);
|
||||
|
|
|
@ -584,6 +584,8 @@
|
|||
<Unit filename="COpenGLShaderMaterialRenderer.h" />
|
||||
<Unit filename="COpenGLTexture.cpp" />
|
||||
<Unit filename="COpenGLTexture.h" />
|
||||
<Unit filename="CPLYMeshFileLoader.cpp" />
|
||||
<Unit filename="CPLYMeshFileLoader.h" />
|
||||
<Unit filename="CPLYMeshWriter.cpp" />
|
||||
<Unit filename="CPLYMeshWriter.h" />
|
||||
<Unit filename="CPakReader.cpp" />
|
||||
|
|
|
@ -9,7 +9,7 @@ CppCompiler=-D__GNUWIN32__ -W -DWIN32 -DNDEBUG -D_WINDOWS -D_MBCS -D_USRDLL -DIR
|
|||
Includes=..\..\include;zlib
|
||||
Linker=-lkernel32 -luser32 -lgdi32 -lwinspool -lcomdlg32 -ladvapi32 -lshell32 -lole32 -loleaut32 -luuid -lwinmm -lopengl32_@@_
|
||||
Libs=
|
||||
UnitCount=615
|
||||
UnitCount=617
|
||||
Folders=doc,gui_impl,include,include/core,include/gui,include/io,include/scene,include/video,io_impl,other_impl,other_impl/extern,other_impl/extern/jpeglib,other_impl/extern/libpng,other_impl/extern/zlib,scene_impl,scene_impl/animators,scene_impl/collision,scene_impl/mesh,scene_impl/mesh/loaders,scene_impl/mesh/writers,scene_impl/nodes,scene_impl/nodes/particles,video_impl,"video_impl/Burning Video",video_impl/DirectX8,video_impl/DirectX9,video_impl/Null,video_impl/OpenGL,video_impl/Software
|
||||
ObjFiles=
|
||||
PrivateResource=
|
||||
|
@ -6197,3 +6197,23 @@ Priority=1000
|
|||
OverrideBuildCmd=0
|
||||
BuildCmd=
|
||||
|
||||
[Unit616]
|
||||
FileName=CPLYMeshFileLoader.cpp
|
||||
CompileCpp=1
|
||||
Folder=scene_impl/mesh/loaders
|
||||
Compile=1
|
||||
Link=1
|
||||
Priority=1000
|
||||
OverrideBuildCmd=0
|
||||
BuildCmd=
|
||||
|
||||
[Unit617]
|
||||
FileName=CPLYMeshFileLoader.h
|
||||
CompileCpp=1
|
||||
Folder=scene_impl/mesh/loaders
|
||||
Compile=1
|
||||
Link=1
|
||||
Priority=1000
|
||||
OverrideBuildCmd=0
|
||||
BuildCmd=
|
||||
|
||||
|
|
|
@ -1583,6 +1583,12 @@
|
|||
<File
|
||||
RelativePath=".\COgreMeshFileLoader.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\CPLYMeshFileLoader.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\CPLYMeshFileLoader.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\CQ3LevelMesh.cpp">
|
||||
</File>
|
||||
|
|
|
@ -2213,6 +2213,14 @@
|
|||
RelativePath=".\COgreMeshFileLoader.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\CPLYMeshFileLoader.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\CPLYMeshFileLoader.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\COgreMeshFileLoader.h"
|
||||
>
|
||||
|
|
|
@ -2193,6 +2193,14 @@
|
|||
RelativePath="COgreMeshFileLoader.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="CPLYMeshFileLoader.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="CPLYMeshFileLoader.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="CQ3LevelMesh.cpp"
|
||||
>
|
||||
|
|
|
@ -1868,6 +1868,14 @@
|
|||
RelativePath="COgreMeshFileLoader.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="CPLYMeshFileLoader.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="CPLYMeshFileLoader.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="CQ3LevelMesh.cpp"
|
||||
>
|
||||
|
|
|
@ -1114,6 +1114,12 @@
|
|||
<File
|
||||
RelativePath=".\COgreMeshFileLoader.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\CPLYMeshFileLoader.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\CPLYMeshFileLoader.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\COSOperator.cpp">
|
||||
</File>
|
||||
|
|
|
@ -19,7 +19,7 @@ VERSION = 1.5
|
|||
#
|
||||
|
||||
#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
|
||||
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
|
||||
IRRMESHWRITER = CColladaMeshWriter.o CIrrMeshWriter.o CSTLMeshWriter.o COBJMeshWriter.o CPLYMeshWriter.o
|
||||
IRRMESHOBJ = $(IRRMESHLOADER) $(IRRMESHWRITER) \
|
||||
CSkinnedMesh.o CBoneSceneNode.o CMeshSceneNode.o \
|
||||
|
|
Loading…
Reference in New Issue