495 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			495 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include "MeshManager.h"
 | |
| 
 | |
| #include "Utilities/format.h"
 | |
| #include "Utilities/Log.h"
 | |
| 
 | |
| #include "physfs.h"
 | |
| #include "trimeshloader.h"
 | |
| 
 | |
| #include <iostream>
 | |
| #include <vector>
 | |
| 
 | |
| using namespace std;
 | |
| 
 | |
| namespace BlueCore
 | |
| {
 | |
| 
 | |
| Mesh::Mesh(RenderDevice* device) :
 | |
| 	_Device(device)
 | |
| {
 | |
| }
 | |
| 
 | |
| Mesh::~Mesh()
 | |
| {
 | |
| 	clog << ">>> Mesh destructed ..."<< endline;
 | |
| }
 | |
| 
 | |
| void Mesh::render()
 | |
| {
 | |
| 
 | |
| 	glEnableClientState(GL_VERTEX_ARRAY);
 | |
| 	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
 | |
| 	glEnableClientState(GL_NORMAL_ARRAY);
 | |
| 
 | |
| 	glVertexPointer( 3, GL_FLOAT, sizeof(Vertex), &VertexBuffer[0].point.x);
 | |
| 
 | |
| 	glTexCoordPointer( 2, GL_FLOAT, sizeof(Vertex), &VertexBuffer[0].u);
 | |
| 
 | |
| 	glNormalPointer(GL_FLOAT, sizeof(Vertex), &VertexBuffer[0].normal.x);
 | |
| 
 | |
| 	glDrawElements(GL_TRIANGLES, IndexBuffer.count() * 3, GL_UNSIGNED_SHORT,
 | |
| 			IndexBuffer.data() );
 | |
| 
 | |
| 	glDisableClientState(GL_VERTEX_ARRAY);
 | |
| 	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 | |
| 	glDisableClientState(GL_NORMAL_ARRAY);
 | |
| }
 | |
| 
 | |
| #if 0
 | |
| //--------------------------------------------------------------------------
 | |
| void Mesh::createVBO()
 | |
| {
 | |
| 	if ( GLEW_ARB_vertex_buffer_object && !vbo )
 | |
| 	{
 | |
| 		glGenBuffersARB ( 1, &vbo );
 | |
| 
 | |
| 		glBindBufferARB ( GL_ARRAY_BUFFER_ARB, vbo );
 | |
| 
 | |
| 		glBufferDataARB (
 | |
| 				GL_ARRAY_BUFFER_ARB,
 | |
| 				size(),
 | |
| 				data(),
 | |
| 				GL_STATIC_DRAW_ARB );
 | |
| 	}
 | |
| }
 | |
| 
 | |
| //--------------------------------------------------------------------------
 | |
| void Mesh::releaseVBO()
 | |
| {
 | |
| 	if ( GLEW_ARB_vertex_buffer_object && vbo )
 | |
| 	{
 | |
| 		glDeleteBuffersARB ( 1, &vbo );
 | |
| 		vbo = 0;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| //--------------------------------------------------------------------------
 | |
| void Mesh::bind()
 | |
| {
 | |
| 	if ( GLEW_ARB_vertex_buffer_object && vbo )
 | |
| 	{
 | |
| 		glBindBufferARB ( GL_ARRAY_BUFFER_ARB, vbo );
 | |
| 
 | |
| 		// hardcoded offset and stride
 | |
| 		glVertexPointer ( 3, GL_FLOAT, sizeof ( Vertex ), 0 );
 | |
| 
 | |
| 		glTexCoordPointer ( 2, GL_FLOAT, sizeof ( Vertex ), ( const GLvoid* ) ( sizeof ( float ) * 3 ) );
 | |
| 
 | |
| 		glNormalPointer ( GL_FLOAT, sizeof ( Vertex ), ( const GLvoid* ) ( sizeof ( float ) * 5 ) );
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		// hardcoded offset and stride
 | |
| 		glVertexPointer ( 3, GL_FLOAT, sizeof ( Vertex ), data() );
 | |
| 		glTexCoordPointer ( 2, GL_FLOAT, sizeof ( Vertex ), data() + sizeof ( float ) * 3 );
 | |
| 		glNormalPointer ( GL_FLOAT, sizeof ( Vertex ), data() + sizeof ( float ) * 5 );
 | |
| 	}
 | |
| }
 | |
| #endif
 | |
| 
 | |
| MeshManager::MeshManager(RenderDevice* device) :
 | |
| 	_Device(device)
 | |
| {
 | |
| 	BlueCore::clog << ">>> MeshManager constructed..." << endlog;
 | |
| }
 | |
| 
 | |
| MeshManager::~MeshManager()
 | |
| {
 | |
| 	clog << ">>> MeshManager destructed ..." << endlog;
 | |
| }
 | |
| 
 | |
| bool loadTrimesh(const char* filename, Mesh *mesh)
 | |
| {
 | |
| 	PHYSFS_file* file = PHYSFS_openRead(filename);
 | |
| 	if (file != 0)
 | |
| 	{
 | |
| 		char buffer[1024];
 | |
| 		unsigned int size = 0;
 | |
| 
 | |
| 		if (tlObjCheckFileExtension(filename) == 0)
 | |
| 		{
 | |
| 			tlObjState *state = tlObjCreateState();
 | |
| 			while (PHYSFS_eof(file) == 0)
 | |
| 			{
 | |
| 				size = (unsigned int) PHYSFS_read(file, buffer, 1,
 | |
| 						sizeof(buffer));
 | |
| 				tlObjParse(state, buffer, size, size < sizeof(buffer) ? 1 : 0);
 | |
| 			}
 | |
| 
 | |
| 			mesh->VertexBuffer.create(tlObjVertexCount(state));
 | |
| 			for (unsigned int i = 0; i < mesh->VertexBuffer.count(); i++)
 | |
| 				tlObjGetVertex(state, i, &mesh->VertexBuffer[i].point.x,
 | |
| 						&mesh->VertexBuffer[i].point.y,
 | |
| 						&mesh->VertexBuffer[i].point.z,
 | |
| 						&mesh->VertexBuffer[i].u, &mesh->VertexBuffer[i].v,
 | |
| 						&mesh->VertexBuffer[i].normal.x,
 | |
| 						&mesh->VertexBuffer[i].normal.y,
 | |
| 						&mesh->VertexBuffer[i].normal.z);
 | |
| 
 | |
| 			mesh->IndexBuffer.create(tlObjFaceCount(state));
 | |
| 			for (unsigned int i = 0; i < mesh->IndexBuffer.count(); i++)
 | |
| 				tlObjGetFace(state, i, &mesh->IndexBuffer[i].a,
 | |
| 						&mesh->IndexBuffer[i].b, &mesh->IndexBuffer[i].c);
 | |
| 
 | |
| 			mesh->SubsetBuffer.create(tlObjObjectCount(state));
 | |
| 			for (unsigned int i = 0; i < mesh->SubsetBuffer.count(); i++)
 | |
| 			{
 | |
| 				mesh->SubsetBuffer[i].first = tlObjObjectFaceIndex(state, i);
 | |
| 				mesh->SubsetBuffer[i].count = tlObjObjectFaceCount(state, i);
 | |
| 			}
 | |
| 
 | |
| 			tlObjDestroyState(state);
 | |
| 		}
 | |
| 		else if (tl3dsCheckFileExtension(filename) == 0)
 | |
| 		{
 | |
| 			tl3dsState *state = tl3dsCreateState();
 | |
| 			while (PHYSFS_eof(file) == 0)
 | |
| 			{
 | |
| 				size = (unsigned int) PHYSFS_read(file, buffer, 1,
 | |
| 						sizeof(buffer));
 | |
| 				tl3dsParse(state, buffer, size, size < sizeof(buffer) ? 1 : 0);
 | |
| 			}
 | |
| 
 | |
| 			mesh->VertexBuffer.create(tl3dsVertexCount(state));
 | |
| 			for (unsigned int i = 0; i < mesh->VertexBuffer.count(); i++)
 | |
| 				tl3dsGetVertex(state, i, &mesh->VertexBuffer[i].point.x,
 | |
| 						&mesh->VertexBuffer[i].point.y,
 | |
| 						&mesh->VertexBuffer[i].point.z,
 | |
| 						&mesh->VertexBuffer[i].u, &mesh->VertexBuffer[i].v,
 | |
| 						&mesh->VertexBuffer[i].normal.x,
 | |
| 						&mesh->VertexBuffer[i].normal.y,
 | |
| 						&mesh->VertexBuffer[i].normal.z);
 | |
| 
 | |
| 			mesh->IndexBuffer.create(tl3dsFaceCount(state));
 | |
| 			for (unsigned int i = 0; i < mesh->IndexBuffer.count(); i++)
 | |
| 				tl3dsGetFace(state, i, &mesh->IndexBuffer[i].a,
 | |
| 						&mesh->IndexBuffer[i].b, &mesh->IndexBuffer[i].c);
 | |
| 
 | |
| 			mesh->SubsetBuffer.create(tl3dsObjectCount(state));
 | |
| 			for (unsigned int i = 0; i < mesh->SubsetBuffer.count(); i++)
 | |
| 			{
 | |
| 				mesh->SubsetBuffer[i].first = tl3dsObjectFaceIndex(state, i);
 | |
| 				mesh->SubsetBuffer[i].count = tl3dsObjectFaceCount(state, i);
 | |
| 			}
 | |
| 
 | |
| 			tl3dsDestroyState(state);
 | |
| 		}
 | |
| 
 | |
| 		PHYSFS_close(file);
 | |
| 
 | |
| 		// create normlas, tangents, and binomials
 | |
| 		clog << "    create normlas..." << endline;
 | |
| 
 | |
| 		for (unsigned int i = 0; i < mesh->VertexBuffer.count(); i++)
 | |
| 		{
 | |
| 			mesh->VertexBuffer[i].normal.zero();
 | |
| 		}
 | |
| 
 | |
| 		for (unsigned int i = 0; i < mesh->IndexBuffer.count(); i++)
 | |
| 		{
 | |
| 			const TriangleIndices& triangle = mesh->IndexBuffer[i];
 | |
| 
 | |
| 			Vector3Template<float> ab = mesh->VertexBuffer[ triangle.a ].point
 | |
| 					- mesh->VertexBuffer[ triangle.b ].point;
 | |
| 			Vector3Template<float> ac = mesh->VertexBuffer[ triangle.a ].point
 | |
| 					- mesh->VertexBuffer[ triangle.c ].point;
 | |
| 			Vector3Template<float> n = ab.cross(ac);
 | |
| 
 | |
| 			mesh->VertexBuffer[ triangle.a ].normal += n;
 | |
| 			mesh->VertexBuffer[ triangle.a ].normal += n;
 | |
| 			mesh->VertexBuffer[ triangle.a ].normal += n;
 | |
| 		}
 | |
| 
 | |
| 		for (unsigned int i = 0; i < mesh->VertexBuffer.count(); i ++)
 | |
| 		{
 | |
| 			mesh->VertexBuffer[i].normal.normalize();
 | |
| 		}
 | |
| 
 | |
| 		clog << "    create tangents..." << endline;
 | |
| 
 | |
| 		mesh->TangentBuffer.create(mesh->VertexBuffer.count());
 | |
| 		mesh->BitangentBuffer.create(mesh->VertexBuffer.count());
 | |
| 
 | |
| 		for (unsigned int i = 0; i < mesh->TangentBuffer.count(); i ++)
 | |
| 		{
 | |
| 			mesh->TangentBuffer[i].zero();
 | |
| 			mesh->BitangentBuffer[i].zero();
 | |
| 		}
 | |
| 
 | |
| 		for (unsigned int i = 0; i < mesh->IndexBuffer.count(); i ++)
 | |
| 		{
 | |
| 			const TriangleIndices& triangle = mesh->IndexBuffer[i];
 | |
| 
 | |
| 			const Vertex& v1 = mesh->VertexBuffer[triangle.a];
 | |
| 			const Vertex& v2 = mesh->VertexBuffer[triangle.b];
 | |
| 			const Vertex& v3 = mesh->VertexBuffer[triangle.c];
 | |
| 
 | |
| 			float x1 = v2.point.x - v1.point.x;
 | |
| 			float x2 = v3.point.x - v1.point.x;
 | |
| 			float y1 = v2.point.y - v1.point.y;
 | |
| 			float y2 = v3.point.y - v1.point.y;
 | |
| 			float z1 = v2.point.z - v1.point.z;
 | |
| 			float z2 = v3.point.z - v1.point.z;
 | |
| 			float s1 = v2.u - v1.u;
 | |
| 			float s2 = v3.u - v1.u;
 | |
| 			float t1 = v2.v - v1.v;
 | |
| 			float t2 = v3.v - v1.v;
 | |
| 			float r = 1.0f / (s1 * t2 - s2 * t1 );
 | |
| 
 | |
| 			Vector3Float sdir( (t2 * x1 - t1 * x2 ) * r, (t2 * y1 - t1 * y2 )
 | |
| 					* r, (t2 * z1 - t1 * z2 ) * r);
 | |
| 
 | |
| 			Vector3Float tdir( (s1 * x2 - s2 * x1 ) * r, (s1 * y2 - s2 * y1 )
 | |
| 					* r, (s1 * z2 - s2 * z1 ) * r);
 | |
| 
 | |
| 			mesh->TangentBuffer[triangle.a] += sdir;
 | |
| 			mesh->TangentBuffer[triangle.b] += sdir;
 | |
| 			mesh->TangentBuffer[triangle.c] += sdir;
 | |
| 
 | |
| 			mesh->BitangentBuffer[triangle.a] += tdir;
 | |
| 			mesh->BitangentBuffer[triangle.b] += tdir;
 | |
| 			mesh->BitangentBuffer[triangle.c] += tdir;
 | |
| 		}
 | |
| 
 | |
| 		for (unsigned int i = 0; i < mesh->TangentBuffer.count(); i ++)
 | |
| 		{
 | |
| 			mesh->TangentBuffer[i].normalize();
 | |
| 			mesh->BitangentBuffer[i].normalize();
 | |
| 		}
 | |
| 
 | |
| 		return 0;
 | |
| 	}
 | |
| 
 | |
| 	return 1;
 | |
| }
 | |
| 
 | |
| Mesh *MeshManager::loadMesh(const string &filename)
 | |
| {
 | |
| 	// check if this mesh is already loaded
 | |
| 	std::map<std::string, weak_ptr<Mesh> >::const_iterator result;
 | |
| 	result = _Meshes.find(filename);
 | |
| 
 | |
| 	if (result != _Meshes.end() && result->second.valid())
 | |
| 	{
 | |
| 		return result->second.pointer();
 | |
| 	}
 | |
| 
 | |
| 	Mesh *mesh = new Mesh (_Device);
 | |
| 
 | |
| 	// check cache
 | |
| 	PHYSFS_sint64 mod_file = PHYSFS_getLastModTime(filename.c_str());
 | |
| 
 | |
| 	std::string cachename = filename + ".msc";
 | |
| 	PHYSFS_sint64 mod_cache = PHYSFS_getLastModTime(cachename.c_str());
 | |
| 
 | |
| 	if ( (mod_cache > mod_file) && loadFromCache(mesh, filename) )
 | |
| 	{
 | |
| 		clog << ">>> Mesh '" << filename << "' loaded from cache." << endline;
 | |
| 
 | |
| 		_Meshes[filename] = mesh;
 | |
| 
 | |
| 		return mesh;
 | |
| 	}
 | |
| 
 | |
| 	clog << ">>> Mesh '" << filename << "': loading from file..." << endlog;
 | |
| 
 | |
| 	if (loadTrimesh(filename.c_str(), mesh) != 0)
 | |
| 	{
 | |
| 		mesh->removeReference();
 | |
| 		clog << "!!! Mesh not found!" << endline;
 | |
| 		return 0;
 | |
| 	}
 | |
| 
 | |
| #if 0		
 | |
| 	mesh->buildShadowFaceBuffer();
 | |
| 	mesh->buildTangentBuffer();
 | |
| 
 | |
| 	unsigned int counter;
 | |
| 
 | |
| 	// calculate bounding sphere
 | |
| 	clog << "    calculate bounding sphere";
 | |
| 
 | |
| 	mesh->bounding_sphere.center().zero();
 | |
| 
 | |
| 	for ( counter = 0; counter < mesh->vertex_buffer.count(); counter++ )
 | |
| 	{
 | |
| 		mesh->bounding_sphere.center() += mesh->vertex_buffer[counter].point;
 | |
| 	}
 | |
| 
 | |
| 	mesh->bounding_sphere.center() /= mesh->vertex_buffer.size();
 | |
| 
 | |
| 	mesh->bounding_sphere.radius() = 0.;
 | |
| 
 | |
| 	for ( counter = 0; counter < mesh->vertex_buffer.count(); counter++ )
 | |
| 	{
 | |
| 		Scalar distance = ( mesh->vertex_buffer[counter].point - mesh->bounding_sphere.center() ).length();
 | |
| 
 | |
| 		if ( distance > mesh->bounding_sphere.radius() )
 | |
| 		mesh->bounding_sphere.radius() = distance;
 | |
| 	}
 | |
| 
 | |
| 	clog << ": " << mesh->bounding_sphere.radius() << endline;
 | |
| 
 | |
| 	// create normlas, tangents, and binomials
 | |
| 	clog << "    create normlas, tangents, and binomials" << endline;
 | |
| 
 | |
| 	for ( counter = 0; counter < mesh->vertex_buffer.count(); counter += 1 )
 | |
| 	{
 | |
| 		mesh->vertex_buffer[counter].normal.zero();
 | |
| 	}
 | |
| 
 | |
| 	for ( counter = 0; counter < mesh->index_buffer.count(); counter += 3 )
 | |
| 	{
 | |
| 		Index a = mesh->index_buffer[counter];
 | |
| 		Index b = mesh->index_buffer[counter+1];
 | |
| 		Index c = mesh->index_buffer[counter+2];
 | |
| 
 | |
| 		Vector3Template<float> ab = mesh->vertex_buffer[ a ].point - mesh->vertex_buffer[ b ].point;
 | |
| 		Vector3Template<float> ac = mesh->vertex_buffer[ a ].point - mesh->vertex_buffer[ c ].point;
 | |
| 		Vector3Template<float> n = ab.cross ( ac );
 | |
| 
 | |
| 		mesh->vertex_buffer[ a ].normal += n;
 | |
| 		mesh->vertex_buffer[ b ].normal += n;
 | |
| 		mesh->vertex_buffer[ c ].normal += n;
 | |
| 	}
 | |
| 
 | |
| 	for ( counter = 0; counter < mesh->vertex_buffer.count(); counter += 1 )
 | |
| 	{
 | |
| 		mesh->vertex_buffer[counter].normal.normalize();
 | |
| 	}
 | |
| 
 | |
| 	clog << "    create vbos" << endline;
 | |
| 
 | |
| 	mesh->vertex_buffer.createVBO();
 | |
| 	mesh->index_buffer.createVBO();
 | |
| 	mesh->tangent_buffer.createVBO();
 | |
| 	mesh->bitangent_buffer.createVBO();
 | |
| #endif
 | |
| 
 | |
| 	_Meshes[filename] = mesh;
 | |
| 
 | |
| 	saveToCache(mesh, filename);
 | |
| 
 | |
| 	return mesh;
 | |
| }
 | |
| 
 | |
| bool MeshManager::loadFromCache(Mesh *mesh, const std::string &name)
 | |
| {
 | |
| 	std::string filename = name + ".msc";
 | |
| 
 | |
| 	PHYSFS_file *file = PHYSFS_openRead(filename.c_str());
 | |
| 
 | |
| 	if (file == 0)
 | |
| 		return false;
 | |
| 
 | |
| 	unsigned int size;
 | |
| 
 | |
| 	// read vertex_buffer
 | |
| 	PHYSFS_read(file, &size, sizeof (size ), 1);
 | |
| 	mesh->VertexBuffer.create(size);
 | |
| 	PHYSFS_read(file, mesh->VertexBuffer.data(), mesh->VertexBuffer.size(), 1);
 | |
| 
 | |
| 	// read index buffer
 | |
| 	PHYSFS_read(file, &size, sizeof (size ), 1);
 | |
| 	mesh->IndexBuffer.create(size);
 | |
| 	PHYSFS_read(file, mesh->IndexBuffer.data(), mesh->IndexBuffer.size(), 1);
 | |
| 
 | |
| 	// read subsets
 | |
| 	PHYSFS_read(file, &size, sizeof (size ), 1);
 | |
| 	mesh->SubsetBuffer.create(size);
 | |
| 	PHYSFS_read(file, mesh->SubsetBuffer.data(), mesh->SubsetBuffer.size(), 1);
 | |
| 
 | |
| 	// read tangent buffer
 | |
| 	PHYSFS_read(file, &size, sizeof (size ), 1);
 | |
| 	mesh->TangentBuffer.create(size);
 | |
| 	PHYSFS_read(file, mesh->TangentBuffer.data(), mesh->TangentBuffer.size(), 1);
 | |
| 
 | |
| 	// read bitangent buffer
 | |
| 	PHYSFS_read(file, &size, sizeof (size ), 1);
 | |
| 	mesh->BitangentBuffer.create(size);
 | |
| 	PHYSFS_read(file, mesh->BitangentBuffer.data(),
 | |
| 			mesh->BitangentBuffer.size(), 1);
 | |
| 
 | |
| #if 0
 | |
| 	// read bounding sphere
 | |
| 	PHYSFS_read ( file, &mesh->bounding_sphere, sizeof ( mesh->bounding_sphere ), 1 );
 | |
| #endif
 | |
| 
 | |
| #if 0
 | |
| 	// read bitangent buffer
 | |
| 	PHYSFS_read ( file, &size, sizeof ( size ), 1 );
 | |
| 	mesh->shadowface_buffer.create ( size );
 | |
| 	PHYSFS_read ( file, mesh->shadowface_buffer.data(), mesh->shadowface_buffer.size(), 1 );
 | |
| #endif
 | |
| 
 | |
| 	PHYSFS_close(file);
 | |
| 
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| bool MeshManager::saveToCache(Mesh *mesh, const std::string &name)
 | |
| {
 | |
| 	std::string filename = name + ".msc";
 | |
| 
 | |
| 	PHYSFS_file *file = PHYSFS_openWrite(filename.c_str() );
 | |
| 
 | |
| 	if (file == 0)
 | |
| 	{
 | |
| 		clog << ">>> cannot open cache file for mesh: " << name << endline;
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	// write vertex_buffer
 | |
| 	unsigned int size = mesh->VertexBuffer.count();
 | |
| 	PHYSFS_write(file, &size, sizeof (size ), 1);
 | |
| 	PHYSFS_write(file, mesh->VertexBuffer.data(), mesh->VertexBuffer.size(), 1);
 | |
| 
 | |
| 	// write index_buffer
 | |
| 	size = mesh->IndexBuffer.count();
 | |
| 	PHYSFS_write(file, &size, sizeof (size ), 1);
 | |
| 	PHYSFS_write(file, mesh->IndexBuffer.data(), mesh->IndexBuffer.size(), 1);
 | |
| 
 | |
| 	// write subsets
 | |
| 	size = mesh->SubsetBuffer.count();
 | |
| 	PHYSFS_write(file, &size, sizeof (size ), 1);
 | |
| 	PHYSFS_write(file, mesh->SubsetBuffer.data(), mesh->SubsetBuffer.size(), 1);
 | |
| 
 | |
| 	// write tangent_buffer
 | |
| 	size = mesh->TangentBuffer.count();
 | |
| 	PHYSFS_write(file, &size, sizeof (size ), 1);
 | |
| 	PHYSFS_write(file, mesh->TangentBuffer.data(), mesh->TangentBuffer.size(),
 | |
| 			1);
 | |
| 
 | |
| 	// write bitangent_buffer
 | |
| 	size = mesh->BitangentBuffer.count();
 | |
| 	PHYSFS_write(file, &size, sizeof (size ), 1);
 | |
| 	PHYSFS_write(file, mesh->BitangentBuffer.data(),
 | |
| 			mesh->BitangentBuffer.size(), 1);
 | |
| 
 | |
| #if 0
 | |
| 	// write bounding sphere
 | |
| 	PHYSFS_write ( file, &mesh->bounding_sphere, sizeof ( mesh->bounding_sphere ), 1 );
 | |
| 
 | |
| 	// write shadowfaces
 | |
| 	size = mesh->shadowface_buffer.count();
 | |
| 	PHYSFS_write ( file, &size, sizeof ( size ), 1 );
 | |
| 	PHYSFS_write ( file, mesh->shadowface_buffer.data(), mesh->shadowface_buffer.size(), 1 );
 | |
| #endif 
 | |
| 
 | |
| 	PHYSFS_close(file);
 | |
| 
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| } // namespace BlueCore
 | 
