Note: I could not merge 2 OSX project files as I'm not sure how to correctly resolve their conflicts. Maybe old version for those files are still OK, as ogl-es branch got updated once before (leaving trunk behind). In case it causes problems I hope someone can send another patch for those 2 files: source/Irrlicht/Irrlicht.xcodeproj/xcshareddata/xcschemes source/Irrlicht/Irrlicht.xcodeproj/project.pbxproj git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/branches/ogl-es@6140 dfc29bdd-3216-0410-991c-e03cc46cb475
		
			
				
	
	
		
			822 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			822 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Copyright (C) 2009-2012 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(scene::ISceneManager* smgr)
 | |
| : SceneManager(smgr), 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 io::path& 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;
 | |
| 	u32 vertCount=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
 | |
| 		getNextLine();
 | |
| 		// grab the word from this line
 | |
| 		c8 *word = getNextWord();
 | |
| 
 | |
| 		// ignore comments
 | |
| 		while (strcmp(word, "comment") == 0)
 | |
| 		{
 | |
| 			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;
 | |
| #ifdef __BIG_ENDIAN__
 | |
| 					IsWrongEndian = true;
 | |
| #endif
 | |
| 
 | |
| 				}
 | |
| 				else if (strcmp(word, "binary_big_endian") == 0)
 | |
| 				{
 | |
| 					IsBinaryFile = true;
 | |
| #ifndef __BIG_ENDIAN__
 | |
| 					IsWrongEndian = true;
 | |
| #endif
 | |
| 				}
 | |
| 				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);
 | |
| 
 | |
| 				if (el->Name == "vertex")
 | |
| 					vertCount = el->Count;
 | |
| 
 | |
| 			}
 | |
| 			else if (strcmp(word, "end_header") == 0)
 | |
| 			{
 | |
| 				readingHeader = false;
 | |
| 				if (IsBinaryFile)
 | |
| 				{
 | |
| 					StartPointer = LineEndPointer + 1;
 | |
| 				}
 | |
| 			}
 | |
| 			else if (strcmp(word, "comment") == 0)
 | |
| 			{
 | |
| 				// ignore line
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				os::Printer::log("Unknown item in PLY file", word, ELL_WARNING);
 | |
| 			}
 | |
| 
 | |
| 			if (readingHeader && continueReading)
 | |
| 			{
 | |
| 				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, vertCount > 65536 ? video::EIT_32BIT : video::EIT_16BIT);
 | |
| 			mb->getVertexBuffer().reallocate(vertCount);
 | |
| 			mb->getIndexBuffer().reallocate(vertCount);
 | |
| 			mb->setHardwareMappingHint(EHM_STATIC);
 | |
| 
 | |
| 			bool hasNormals=true;
 | |
| 			// 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)
 | |
| 						hasNormals &= 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();
 | |
| 			if (!hasNormals)
 | |
| 				SceneManager->getMeshManipulator()->recalculateNormals(mb);
 | |
| 			SMesh* m = new SMesh();
 | |
| 			m->addMeshBuffer(mb);
 | |
| 			m->recalculateBoundingBox();
 | |
| 			mb->drop();
 | |
| 			animMesh = new SAnimatedMesh();
 | |
| 			animMesh->addMesh(m);
 | |
| 			animMesh->recalculateBoundingBox();
 | |
| 			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;
 | |
| 
 | |
| 	bool result=false;
 | |
| 	for (u32 i=0; i < Element.Properties.size(); ++i)
 | |
| 	{
 | |
| 		E_PLY_PROPERTY_TYPE t = Element.Properties[i].Type;
 | |
| 		const core::stringc& name = Element.Properties[i].Name;
 | |
| 
 | |
| 		if (name == "x")
 | |
| 			vert.Pos.X = getFloat(t);
 | |
| 		else if (name == "y")
 | |
| 			vert.Pos.Z = getFloat(t);
 | |
| 		else if (name == "z")
 | |
| 			vert.Pos.Y = getFloat(t);
 | |
| 		else if (name == "nx")
 | |
| 		{
 | |
| 			vert.Normal.X = getFloat(t);
 | |
| 			result=true;
 | |
| 		}
 | |
| 		else if (name == "ny")
 | |
| 		{
 | |
| 			vert.Normal.Z = getFloat(t);
 | |
| 			result=true;
 | |
| 		}
 | |
| 		else if (name == "nz")
 | |
| 		{
 | |
| 			vert.Normal.Y = getFloat(t);
 | |
| 			result=true;
 | |
| 		}
 | |
| 		 // There isn't a single convention for the UV, some software like Blender or Assimp uses "st" instead of "uv"
 | |
| 		 // Not sure which tool creates texture_u/texture_v, but those exist as well.
 | |
| 		else if (name == "u" || name == "s" || name == "texture_u")
 | |
| 			vert.TCoords.X = getFloat(t);
 | |
| 		else if (name == "v" || name == "t" || name == "texture_v")
 | |
| 			vert.TCoords.Y = getFloat(t);
 | |
| 		else if (name == "red")
 | |
| 		{
 | |
| 			u32 value = Element.Properties[i].isFloat() ? (u32)(getFloat(t)*255.0f) : getInt(t);
 | |
| 			vert.Color.setRed(value);
 | |
| 		}
 | |
| 		else if (name == "green")
 | |
| 		{
 | |
| 			u32 value = Element.Properties[i].isFloat() ? (u32)(getFloat(t)*255.0f) : getInt(t);
 | |
| 			vert.Color.setGreen(value);
 | |
| 		}
 | |
| 		else if (name == "blue")
 | |
| 		{
 | |
| 			u32 value = Element.Properties[i].isFloat() ? (u32)(getFloat(t)*255.0f) : getInt(t);
 | |
| 			vert.Color.setBlue(value);
 | |
| 		}
 | |
| 		else if (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 result;
 | |
| }
 | |
| 
 | |
| 
 | |
| bool CPLYMeshFileLoader::readFace(const SPLYElement &Element, scene::CDynamicMeshBuffer* mb)
 | |
| {
 | |
| 	if (!IsBinaryFile)
 | |
| 		getNextLine();
 | |
| 
 | |
| 	for (u32 i=0; i < Element.Properties.size(); ++i)
 | |
| 	{
 | |
| 		const SPLYProperty& property = Element.Properties[i];
 | |
| 		if ( (property.Name == "vertex_indices" || property.Name == "vertex_index")
 | |
| 			&& property.Type == EPLYPT_LIST)
 | |
| 		{
 | |
| 			// get count
 | |
| 			s32 count = getInt(property.Data.List.CountType);
 | |
| 			u32 a = getInt(property.Data.List.ItemType),
 | |
| 				b = getInt(property.Data.List.ItemType),
 | |
| 				c = getInt(property.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(property.Data.List.ItemType);
 | |
| 				mb->getIndexBuffer().push_back(a);
 | |
| 				mb->getIndexBuffer().push_back(c);
 | |
| 				mb->getIndexBuffer().push_back(b);
 | |
| 			}
 | |
| 		}
 | |
| 		else if (property.Name == "intensity")
 | |
| 		{
 | |
| 			// todo: face intensity
 | |
| 			skipProperty(property);
 | |
| 		}
 | |
| 		else
 | |
| 			skipProperty(property);
 | |
| 	}
 | |
| 	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;
 | |
| 
 | |
| 	size_t length = (size_t)(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
 | |
| 		size_t 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;
 | |
| }
 | |
| 
 | |
| 
 | |
| 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, "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, "int") == 0 ||
 | |
| 		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<EndPointer && *StartPointer == '\n')
 | |
| 	{
 | |
| 		*StartPointer = '\0';
 | |
| 		++StartPointer;
 | |
| 	}
 | |
| 
 | |
| 	// begin at the start of the next line
 | |
| 	c8* pos = StartPointer;
 | |
| 	while (pos < EndPointer && *pos && *pos != '\r' && *pos != '\n')
 | |
| 		++pos;
 | |
| 
 | |
| 	if ( (pos+1) < 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 (!EndOfFile)
 | |
| 		{
 | |
| 			fillBuffer();
 | |
| 			// reset line end pointer
 | |
| 			LineEndPointer = StartPointer - 1;
 | |
| 
 | |
| 			if (StartPointer != EndPointer)
 | |
| 				return getNextLine();
 | |
| 			else
 | |
| 				return Buffer;
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			// EOF
 | |
| 			StartPointer = EndPointer-1;
 | |
| 			*StartPointer = '\0';
 | |
| 			return StartPointer;
 | |
| 		}
 | |
| 	}
 | |
| 	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;
 | |
| 
 | |
| 	while(*pos && pos < LineEndPointer && pos < EndPointer && (*pos == ' ' || *pos == '\t') )
 | |
| 	{
 | |
| 		// null terminate the string in place
 | |
| 		*pos = '\0';
 | |
| 		++pos;
 | |
| 	}
 | |
| 	--pos;
 | |
| 	WordLength = (s32)(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(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:
 | |
| 				if (IsWrongEndian)
 | |
| 					retVal = os::Byteswap::byteswap(*(reinterpret_cast<s16*>(StartPointer)));
 | |
| 				else
 | |
| 					retVal = *(reinterpret_cast<s16*>(StartPointer));
 | |
| 				StartPointer += 2;
 | |
| 				break;
 | |
| 			case EPLYPT_INT32:
 | |
| 				if (IsWrongEndian)
 | |
| 					retVal = f32(os::Byteswap::byteswap(*(reinterpret_cast<s32*>(StartPointer))));
 | |
| 				else
 | |
| 					retVal = f32(*(reinterpret_cast<s32*>(StartPointer)));
 | |
| 				StartPointer += 4;
 | |
| 				break;
 | |
| 			case EPLYPT_FLOAT32:
 | |
| 				if (IsWrongEndian)
 | |
| 					retVal = os::Byteswap::byteswap(*(reinterpret_cast<f32*>(StartPointer)));
 | |
| 				else
 | |
| 					retVal = *(reinterpret_cast<f32*>(StartPointer));
 | |
| 				StartPointer += 4;
 | |
| 				break;
 | |
| 			case EPLYPT_FLOAT64:
 | |
| 				// todo: byteswap 64-bit
 | |
| 				retVal = f32(*(reinterpret_cast<f64*>(StartPointer)));
 | |
| 				StartPointer += 8;
 | |
| 				break;
 | |
| 			case EPLYPT_LIST:
 | |
| 			case EPLYPT_UNKNOWN:
 | |
| 			default:
 | |
| 				retVal = 0.0f;
 | |
| 				StartPointer++; // ouch!
 | |
| 			}
 | |
| 		}
 | |
| 		else
 | |
| 			retVal = 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 = f32(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(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:
 | |
| 				if (IsWrongEndian)
 | |
| 					retVal = os::Byteswap::byteswap(*(reinterpret_cast<u16*>(StartPointer)));
 | |
| 				else
 | |
| 					retVal = *(reinterpret_cast<u16*>(StartPointer));
 | |
| 				StartPointer += 2;
 | |
| 				break;
 | |
| 			case EPLYPT_INT32:
 | |
| 				if (IsWrongEndian)
 | |
| 					retVal = os::Byteswap::byteswap(*(reinterpret_cast<s32*>(StartPointer)));
 | |
| 				else
 | |
| 					retVal = *(reinterpret_cast<s32*>(StartPointer));
 | |
| 				StartPointer += 4;
 | |
| 				break;
 | |
| 			case EPLYPT_FLOAT32:
 | |
| 				if (IsWrongEndian)
 | |
| 					retVal = (u32)os::Byteswap::byteswap(*(reinterpret_cast<f32*>(StartPointer)));
 | |
| 				else
 | |
| 					retVal = (u32)(*(reinterpret_cast<f32*>(StartPointer)));
 | |
| 				StartPointer += 4;
 | |
| 				break;
 | |
| 			case EPLYPT_FLOAT64:
 | |
| 				// todo: byteswap 64-bit
 | |
| 				retVal = (u32)(*(reinterpret_cast<f64*>(StartPointer)));
 | |
| 				StartPointer += 8;
 | |
| 				break;
 | |
| 			case EPLYPT_LIST:
 | |
| 			case EPLYPT_UNKNOWN:
 | |
| 			default:
 | |
| 				retVal = 0;
 | |
| 				StartPointer++; // ouch!
 | |
| 			}
 | |
| 		}
 | |
| 		else
 | |
| 			retVal = 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_
 | |
| 
 |