1 // ==============================================================
2 //	This file is part of Glest Shared Library (www.glest.org)
3 //
4 //	Copyright (C) 2001-2008 Martiño Figueroa
5 //
6 //	You can redistribute this code and/or modify it under
7 //	the terms of the GNU General Public License as published
8 //	by the Free Software Foundation; either version 2 of the
9 //	License, or (at your option) any later version
10 // ==============================================================
11 
12 #include "model.h"
13 
14 #include <cstdio>
15 #include <cassert>
16 #include <stdexcept>
17 
18 #include "interpolation.h"
19 #include "conversion.h"
20 #include "util.h"
21 #include "platform_common.h"
22 #include "opengl.h"
23 #include "platform_util.h"
24 //#include <memory>
25 #include <map>
26 #include <vector>
27 #include "leak_dumper.h"
28 
29 using namespace Shared::Platform;
30 using namespace Shared::PlatformCommon;
31 using namespace Shared::Graphics::Gl;
32 
33 using namespace std;
34 using namespace Shared::Util;
35 
36 namespace Shared{ namespace Graphics{
37 
38 using namespace Util;
39 
40 // Utils methods for endianness conversion
toEndianFileHeader(FileHeader & header)41 void toEndianFileHeader(FileHeader &header) {
42 	static bool bigEndianSystem = Shared::PlatformByteOrder::isBigEndian();
43 	if(bigEndianSystem == true) {
44 		for(unsigned int i = 0; i < 3; ++i) {
45 			header.id[i] = Shared::PlatformByteOrder::toCommonEndian(header.id[i]);
46 		}
47 		header.version = Shared::PlatformByteOrder::toCommonEndian(header.version);
48 	}
49 }
fromEndianFileHeader(FileHeader & header)50 void fromEndianFileHeader(FileHeader &header) {
51 	static bool bigEndianSystem = Shared::PlatformByteOrder::isBigEndian();
52 	if(bigEndianSystem == true) {
53 		for(unsigned int i = 0; i < 3; ++i) {
54 			header.id[i] = Shared::PlatformByteOrder::fromCommonEndian(header.id[i]);
55 		}
56 		header.version = Shared::PlatformByteOrder::fromCommonEndian(header.version);
57 	}
58 }
59 
toEndianModelHeader(ModelHeader & header)60 void toEndianModelHeader(ModelHeader &header) {
61 	static bool bigEndianSystem = Shared::PlatformByteOrder::isBigEndian();
62 	if(bigEndianSystem == true) {
63 		header.type = Shared::PlatformByteOrder::toCommonEndian(header.type);
64 		header.meshCount = Shared::PlatformByteOrder::toCommonEndian(header.meshCount);
65 	}
66 }
fromEndianModelHeader(ModelHeader & header)67 void fromEndianModelHeader(ModelHeader &header) {
68 	static bool bigEndianSystem = Shared::PlatformByteOrder::isBigEndian();
69 	if(bigEndianSystem == true) {
70 		header.type = Shared::PlatformByteOrder::toCommonEndian(header.type);
71 		header.meshCount = Shared::PlatformByteOrder::toCommonEndian(header.meshCount);
72 	}
73 }
74 
toEndianMeshHeader(MeshHeader & header)75 void toEndianMeshHeader(MeshHeader &header) {
76 	static bool bigEndianSystem = Shared::PlatformByteOrder::isBigEndian();
77 	if(bigEndianSystem == true) {
78 		for(unsigned int i = 0; i < meshNameSize; ++i) {
79 			header.name[i] = Shared::PlatformByteOrder::toCommonEndian(header.name[i]);
80 		}
81 		header.frameCount = Shared::PlatformByteOrder::toCommonEndian(header.frameCount);
82 		header.vertexCount = Shared::PlatformByteOrder::toCommonEndian(header.vertexCount);
83 		header.indexCount = Shared::PlatformByteOrder::toCommonEndian(header.indexCount);
84 		for(unsigned int i = 0; i < 3; ++i) {
85 			header.diffuseColor[i] = Shared::PlatformByteOrder::toCommonEndian(header.diffuseColor[i]);
86 			header.specularColor[i] = Shared::PlatformByteOrder::toCommonEndian(header.specularColor[i]);
87 		}
88 		header.specularPower = Shared::PlatformByteOrder::toCommonEndian(header.specularPower);
89 		header.opacity = Shared::PlatformByteOrder::toCommonEndian(header.opacity);
90 		header.properties = Shared::PlatformByteOrder::toCommonEndian(header.properties);
91 		header.textures = Shared::PlatformByteOrder::toCommonEndian(header.textures);
92 	}
93 }
94 
fromEndianMeshHeader(MeshHeader & header)95 void fromEndianMeshHeader(MeshHeader &header) {
96 	static bool bigEndianSystem = Shared::PlatformByteOrder::isBigEndian();
97 	if(bigEndianSystem == true) {
98 		for(unsigned int i = 0; i < meshNameSize; ++i) {
99 			header.name[i] = Shared::PlatformByteOrder::fromCommonEndian(header.name[i]);
100 		}
101 		header.frameCount = Shared::PlatformByteOrder::fromCommonEndian(header.frameCount);
102 		header.vertexCount = Shared::PlatformByteOrder::fromCommonEndian(header.vertexCount);
103 		header.indexCount = Shared::PlatformByteOrder::fromCommonEndian(header.indexCount);
104 		for(unsigned int i = 0; i < 3; ++i) {
105 			header.diffuseColor[i] = Shared::PlatformByteOrder::fromCommonEndian(header.diffuseColor[i]);
106 			header.specularColor[i] = Shared::PlatformByteOrder::fromCommonEndian(header.specularColor[i]);
107 		}
108 		header.specularPower = Shared::PlatformByteOrder::fromCommonEndian(header.specularPower);
109 		header.opacity = Shared::PlatformByteOrder::fromCommonEndian(header.opacity);
110 		header.properties = Shared::PlatformByteOrder::fromCommonEndian(header.properties);
111 		header.textures = Shared::PlatformByteOrder::fromCommonEndian(header.textures);
112 	}
113 }
114 
toEndianModelHeaderV3(ModelHeaderV3 & header)115 void toEndianModelHeaderV3(ModelHeaderV3 &header) {
116 	static bool bigEndianSystem = Shared::PlatformByteOrder::isBigEndian();
117 	if(bigEndianSystem == true) {
118 		header.meshCount = Shared::PlatformByteOrder::toCommonEndian(header.meshCount);
119 	}
120 }
fromEndianModelHeaderV3(ModelHeaderV3 & header)121 void fromEndianModelHeaderV3(ModelHeaderV3 &header) {
122 	static bool bigEndianSystem = Shared::PlatformByteOrder::isBigEndian();
123 	if(bigEndianSystem == true) {
124 		header.meshCount = Shared::PlatformByteOrder::fromCommonEndian(header.meshCount);
125 	}
126 }
127 
toEndianMeshHeaderV3(MeshHeaderV3 & header)128 void toEndianMeshHeaderV3(MeshHeaderV3 &header) {
129 	static bool bigEndianSystem = Shared::PlatformByteOrder::isBigEndian();
130 	if(bigEndianSystem == true) {
131 		header.vertexFrameCount = Shared::PlatformByteOrder::toCommonEndian(header.vertexFrameCount);
132 		header.normalFrameCount = Shared::PlatformByteOrder::toCommonEndian(header.normalFrameCount);
133 		header.texCoordFrameCount = Shared::PlatformByteOrder::toCommonEndian(header.texCoordFrameCount);
134 		header.colorFrameCount = Shared::PlatformByteOrder::toCommonEndian(header.colorFrameCount);
135 		header.pointCount = Shared::PlatformByteOrder::toCommonEndian(header.pointCount);
136 		header.indexCount = Shared::PlatformByteOrder::toCommonEndian(header.indexCount);
137 		header.properties = Shared::PlatformByteOrder::toCommonEndian(header.properties);
138 		for(unsigned int i = 0; i < 64; ++i) {
139 			header.texName[i] = Shared::PlatformByteOrder::toCommonEndian(header.texName[i]);
140 		}
141 	}
142 }
143 
fromEndianMeshHeaderV3(MeshHeaderV3 & header)144 void fromEndianMeshHeaderV3(MeshHeaderV3 &header) {
145 	static bool bigEndianSystem = Shared::PlatformByteOrder::isBigEndian();
146 	if(bigEndianSystem == true) {
147 		header.vertexFrameCount = Shared::PlatformByteOrder::fromCommonEndian(header.vertexFrameCount);
148 		header.normalFrameCount = Shared::PlatformByteOrder::fromCommonEndian(header.normalFrameCount);
149 		header.texCoordFrameCount = Shared::PlatformByteOrder::fromCommonEndian(header.texCoordFrameCount);
150 		header.colorFrameCount = Shared::PlatformByteOrder::fromCommonEndian(header.colorFrameCount);
151 		header.pointCount = Shared::PlatformByteOrder::fromCommonEndian(header.pointCount);
152 		header.indexCount = Shared::PlatformByteOrder::fromCommonEndian(header.indexCount);
153 		header.properties = Shared::PlatformByteOrder::fromCommonEndian(header.properties);
154 		for(unsigned int i = 0; i < 64; ++i) {
155 			header.texName[i] = Shared::PlatformByteOrder::fromCommonEndian(header.texName[i]);
156 		}
157 	}
158 }
159 
toEndianMeshHeaderV2(MeshHeaderV2 & header)160 void toEndianMeshHeaderV2(MeshHeaderV2 &header) {
161 	static bool bigEndianSystem = Shared::PlatformByteOrder::isBigEndian();
162 	if(bigEndianSystem == true) {
163 		header.vertexFrameCount = Shared::PlatformByteOrder::toCommonEndian(header.vertexFrameCount);
164 		header.normalFrameCount = Shared::PlatformByteOrder::toCommonEndian(header.normalFrameCount);
165 		header.texCoordFrameCount = Shared::PlatformByteOrder::toCommonEndian(header.texCoordFrameCount);
166 		header.colorFrameCount = Shared::PlatformByteOrder::toCommonEndian(header.colorFrameCount);
167 		header.pointCount = Shared::PlatformByteOrder::toCommonEndian(header.pointCount);
168 		header.indexCount = Shared::PlatformByteOrder::toCommonEndian(header.indexCount);
169 		header.hasTexture = Shared::PlatformByteOrder::toCommonEndian(header.hasTexture);
170 		header.primitive = Shared::PlatformByteOrder::toCommonEndian(header.primitive);
171 		header.cullFace = Shared::PlatformByteOrder::toCommonEndian(header.cullFace);
172 
173 		for(unsigned int i = 0; i < 64; ++i) {
174 			header.texName[i] = Shared::PlatformByteOrder::toCommonEndian(header.texName[i]);
175 		}
176 	}
177 }
178 
fromEndianMeshHeaderV2(MeshHeaderV2 & header)179 void fromEndianMeshHeaderV2(MeshHeaderV2 &header) {
180 	static bool bigEndianSystem = Shared::PlatformByteOrder::isBigEndian();
181 	if(bigEndianSystem == true) {
182 		header.vertexFrameCount = Shared::PlatformByteOrder::fromCommonEndian(header.vertexFrameCount);
183 		header.normalFrameCount = Shared::PlatformByteOrder::fromCommonEndian(header.normalFrameCount);
184 		header.texCoordFrameCount = Shared::PlatformByteOrder::fromCommonEndian(header.texCoordFrameCount);
185 		header.colorFrameCount = Shared::PlatformByteOrder::fromCommonEndian(header.colorFrameCount);
186 		header.pointCount = Shared::PlatformByteOrder::fromCommonEndian(header.pointCount);
187 		header.indexCount = Shared::PlatformByteOrder::fromCommonEndian(header.indexCount);
188 		header.hasTexture = Shared::PlatformByteOrder::fromCommonEndian(header.hasTexture);
189 		header.primitive = Shared::PlatformByteOrder::fromCommonEndian(header.primitive);
190 		header.cullFace = Shared::PlatformByteOrder::fromCommonEndian(header.cullFace);
191 
192 		for(unsigned int i = 0; i < 64; ++i) {
193 			header.texName[i] = Shared::PlatformByteOrder::fromCommonEndian(header.texName[i]);
194 		}
195 	}
196 }
197 
198 // =====================================================
199 //	class Mesh
200 // =====================================================
201 
202 // ==================== constructor & destructor ====================
203 
Mesh()204 Mesh::Mesh() {
205 	textureManager = NULL;
206 	frameCount= 0;
207 	vertexCount= 0;
208 	indexCount= 0;
209 	texCoordFrameCount = 0;
210 	opacity = 0.0f;
211 	specularPower = 0.0f;
212 
213 	vertices= NULL;
214 	normals= NULL;
215 	texCoords= NULL;
216 	tangents= NULL;
217 	indices= NULL;
218 	interpolationData= NULL;
219 
220 	for(int i=0; i<meshTextureCount; ++i){
221 		textures[i]= NULL;
222 		texturesOwned[i]=false;
223 	}
224 
225 	twoSided= false;
226 	customColor= false;
227 	noSelect= false;
228 	glow= false;
229 
230 	textureFlags=0;
231 
232 	hasBuiltVBOs = false;
233 	// Vertex Buffer Object Names
234 	m_nVBOVertices	= 0;
235 	m_nVBOTexCoords	= 0;
236 	m_nVBONormals	= 0;
237 	m_nVBOIndexes	= 0;
238 }
239 
~Mesh()240 Mesh::~Mesh() {
241 	end();
242 }
243 
init()244 void Mesh::init() {
245 	try {
246 		vertices= new Vec3f[frameCount*vertexCount];
247 	}
248 	catch(bad_alloc& ba) {
249 		char szBuf[8096]="";
250 		snprintf(szBuf,8096,"Error on line: %d size: %d msg: %s\n",__LINE__,(frameCount*vertexCount),ba.what());
251 		throw megaglest_runtime_error(szBuf);
252 	}
253 	try {
254 		normals= new Vec3f[frameCount*vertexCount];
255 	}
256 	catch(bad_alloc& ba) {
257 		char szBuf[8096]="";
258 		snprintf(szBuf,8096,"Error on line: %d size: %d msg: %s\n",__LINE__,(frameCount*vertexCount),ba.what());
259 		throw megaglest_runtime_error(szBuf);
260 	}
261 	try {
262 		texCoords= new Vec2f[vertexCount];
263 	}
264 	catch(bad_alloc& ba) {
265 		char szBuf[8096]="";
266 		snprintf(szBuf,8096,"Error on line: %d size: %d msg: %s\n",__LINE__,vertexCount,ba.what());
267 		throw megaglest_runtime_error(szBuf);
268 	}
269 	try {
270 		indices= new uint32[indexCount];
271 	}
272 	catch(bad_alloc& ba) {
273 		char szBuf[8096]="";
274 		snprintf(szBuf,8096,"Error on line: %d size: %d msg: %s\n",__LINE__,indexCount,ba.what());
275 		throw megaglest_runtime_error(szBuf);
276 	}
277 }
278 
end()279 void Mesh::end() {
280 	ReleaseVBOs();
281 
282 	delete [] vertices;
283 	vertices=NULL;
284 	delete [] normals;
285 	normals=NULL;
286 	delete [] texCoords;
287 	texCoords=NULL;
288 	delete [] tangents;
289 	tangents=NULL;
290 	delete [] indices;
291 	indices=NULL;
292 
293 	cleanupInterpolationData();
294 
295 	if(textureManager != NULL) {
296 		for(int i = 0; i < meshTextureCount; ++i) {
297 			if(texturesOwned[i] == true && textures[i] != NULL) {
298 				//printf("Deleting Texture [%s] i = %d\n",textures[i]->getPath().c_str(),i);
299 				textureManager->endTexture(textures[i]);
300 				textures[i] = NULL;
301 			}
302 		}
303 	}
304 	textureManager = NULL;
305 }
306 
307 // ========================== shadows & interpolation =========================
308 
buildInterpolationData()309 void Mesh::buildInterpolationData(){
310 	if(interpolationData != NULL) {
311 		printf("**WARNING possible memory leak [Mesh::buildInterpolationData()]\n");
312 	}
313 	interpolationData= new InterpolationData(this);
314 }
315 
cleanupInterpolationData()316 void Mesh::cleanupInterpolationData() {
317 	delete interpolationData;
318 	interpolationData=NULL;
319 }
320 
updateInterpolationData(float t,bool cycle)321 void Mesh::updateInterpolationData(float t, bool cycle) {
322 	if(interpolationData != NULL) {
323 		interpolationData->update(t, cycle);
324 	}
325 }
326 
updateInterpolationVertices(float t,bool cycle)327 void Mesh::updateInterpolationVertices(float t, bool cycle) {
328 	if(interpolationData != NULL) {
329 		interpolationData->updateVertices(t, cycle);
330 	}
331 }
332 
BuildVBOs()333 void Mesh::BuildVBOs() {
334 	if(getVBOSupported() == true) {
335 		if(hasBuiltVBOs == false) {
336 			//printf("In [%s::%s Line: %d] setting up a VBO...\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
337 
338 			// Generate And Bind The Vertex Buffer
339 			glGenBuffersARB( 1,(GLuint*) &m_nVBOVertices );					// Get A Valid Name
340 			glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nVBOVertices );			// Bind The Buffer
341 			// Load The Data
342 			glBufferDataARB( GL_ARRAY_BUFFER_ARB,  sizeof(Vec3f)*frameCount*vertexCount, vertices, GL_STATIC_DRAW_ARB );
343 			glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
344 
345 			// Generate And Bind The Texture Coordinate Buffer
346 			glGenBuffersARB( 1, (GLuint*)&m_nVBOTexCoords );					// Get A Valid Name
347 			glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nVBOTexCoords );		// Bind The Buffer
348 			// Load The Data
349 			glBufferDataARB( GL_ARRAY_BUFFER_ARB, sizeof(Vec2f)*vertexCount, texCoords, GL_STATIC_DRAW_ARB );
350 			glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
351 
352 			// Generate And Bind The Normal Buffer
353 			glGenBuffersARB( 1, (GLuint*)&m_nVBONormals );					// Get A Valid Name
354 			glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nVBONormals );			// Bind The Buffer
355 			// Load The Data
356 			glBufferDataARB( GL_ARRAY_BUFFER_ARB,  sizeof(Vec3f)*frameCount*vertexCount, normals, GL_STATIC_DRAW_ARB );
357 			glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
358 
359 			// Generate And Bind The Index Buffer
360 			glGenBuffersARB( 1, (GLuint*)&m_nVBOIndexes );					// Get A Valid Name
361 			glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, m_nVBOIndexes );			// Bind The Buffer
362 			// Load The Data
363 			glBufferDataARB( GL_ELEMENT_ARRAY_BUFFER_ARB,  sizeof(uint32)*indexCount, indices, GL_STATIC_DRAW_ARB );
364 			glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
365 
366 			// Our Copy Of The Data Is No Longer Necessary, It Is Safe In The Graphics Card
367 			delete [] vertices; vertices = NULL;
368 			delete [] texCoords; texCoords = NULL;
369 			delete [] normals; normals = NULL;
370 			delete [] indices; indices = NULL;
371 
372 			delete interpolationData;
373 			interpolationData = NULL;
374 
375 			hasBuiltVBOs = true;
376 		}
377 	}
378 }
379 
ReleaseVBOs()380 void Mesh::ReleaseVBOs() {
381 	if(getVBOSupported() == true) {
382 		if(hasBuiltVBOs == true) {
383 			glDeleteBuffersARB( 1, (GLuint*)&m_nVBOVertices );					// Get A Valid Name
384 			glDeleteBuffersARB( 1, (GLuint*)&m_nVBOTexCoords );					// Get A Valid Name
385 			glDeleteBuffersARB( 1, (GLuint*)&m_nVBONormals );					// Get A Valid Name
386 			glDeleteBuffersARB( 1, (GLuint*)&m_nVBOIndexes );					// Get A Valid Name
387 			hasBuiltVBOs = false;
388 		}
389 	}
390 }
391 
392 // ==================== load ====================
393 
findAlternateTexture(vector<string> conversionList,string textureFile)394 string Mesh::findAlternateTexture(vector<string> conversionList, string textureFile) {
395 	string result = textureFile;
396 	string fileExt = extractExtension(textureFile);
397 
398 	for(unsigned int i = 0; i < conversionList.size(); ++i) {
399 		string convertTo = conversionList[i];
400 		if(fileExt != convertTo) {
401 			string alternateTexture = textureFile;
402 			replaceAll(alternateTexture, "." + fileExt, "." + convertTo);
403 			if(fileExists(alternateTexture) == true) {
404 				result = alternateTexture;
405 				break;
406 			}
407 		}
408 	}
409 	return result;
410 }
411 
loadV2(int meshIndex,const string & dir,FILE * f,TextureManager * textureManager,bool deletePixMapAfterLoad,std::map<string,vector<pair<string,string>>> * loadedFileList,string sourceLoader,string modelFile)412 void Mesh::loadV2(int meshIndex, const string &dir, FILE *f, TextureManager *textureManager,
413 		bool deletePixMapAfterLoad, std::map<string,vector<pair<string, string> > > *loadedFileList,
414 		string sourceLoader,string modelFile) {
415 	this->textureManager = textureManager;
416 	//read header
417 	MeshHeaderV2 meshHeader;
418 	size_t readBytes = fread(&meshHeader, sizeof(MeshHeaderV2), 1, f);
419 	if(readBytes != 1) {
420 		char szBuf[8096]="";
421 		snprintf(szBuf,8096,"fread returned wrong size = " MG_SIZE_T_SPECIFIER " on line: %d.",readBytes,__LINE__);
422 		throw megaglest_runtime_error(szBuf);
423 	}
424 	fromEndianMeshHeaderV2(meshHeader);
425 
426 	if(meshHeader.normalFrameCount != meshHeader.vertexFrameCount) {
427 		char szBuf[8096]="";
428 		snprintf(szBuf,8096,"Old v2 model: vertex frame count different from normal frame count [v = %d, n = %d] meshIndex = %d modelFile [%s]",meshHeader.vertexFrameCount,meshHeader.normalFrameCount,meshIndex,modelFile.c_str());
429 		throw megaglest_runtime_error(szBuf,true);
430 	}
431 
432 	if(meshHeader.texCoordFrameCount != 1) {
433 		char szBuf[8096]="";
434 		snprintf(szBuf,8096,"Old v2 model: texture coord frame count is not 1 [t = %d] meshIndex = %d modelFile [%s]",meshHeader.texCoordFrameCount,meshIndex,modelFile.c_str());
435 		throw megaglest_runtime_error(szBuf,true);
436 	}
437 
438 	//init
439 	frameCount= meshHeader.vertexFrameCount;
440 	vertexCount= meshHeader.pointCount;
441 	indexCount= meshHeader.indexCount;
442 	texCoordFrameCount = meshHeader.texCoordFrameCount;
443 
444 	init();
445 
446 	//misc
447 	twoSided= false;
448 	customColor= false;
449 	noSelect= false;
450 	glow= false;
451 
452 	if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Load v2, this = %p Found meshHeader.hasTexture = %d, texName [%s] mtDiffuse = %d meshIndex = %d modelFile [%s]\n",this,meshHeader.hasTexture,toLower(reinterpret_cast<char*>(meshHeader.texName)).c_str(),mtDiffuse,meshIndex,modelFile.c_str());
453 
454 	textureFlags= 0;
455 	if(meshHeader.hasTexture) {
456 		textureFlags= 1;
457 	}
458 
459 	//texture
460 	if(meshHeader.hasTexture && textureManager!=NULL){
461 		texturePaths[mtDiffuse]= toLower(reinterpret_cast<char*>(meshHeader.texName));
462 		string texPath= dir;
463         if(texPath != "") {
464         	endPathWithSlash(texPath);
465         }
466 		texPath += texturePaths[mtDiffuse];
467 
468 		if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d] v2 model texture [%s] meshIndex = %d modelFile [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,texPath.c_str(),meshIndex,modelFile.c_str());
469 
470 		textures[mtDiffuse]= dynamic_cast<Texture2D*>(textureManager->getTexture(texPath));
471 		if(textures[mtDiffuse] == NULL) {
472 			if(fileExists(texPath) == false) {
473 				vector<string> conversionList;
474 				conversionList.push_back("png");
475 				conversionList.push_back("jpg");
476 				conversionList.push_back("tga");
477 				conversionList.push_back("bmp");
478 				texPath = findAlternateTexture(conversionList, texPath);
479 			}
480 			if(fileExists(texPath) == true) {
481 				if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d] v2 model texture [%s] meshIndex = %d modelFile [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,texPath.c_str(),meshIndex,modelFile.c_str());
482 
483 				textures[mtDiffuse]= textureManager->newTexture2D();
484 				textures[mtDiffuse]->load(texPath);
485 				if(loadedFileList) {
486 					(*loadedFileList)[texPath].push_back(make_pair(sourceLoader,sourceLoader));
487 				}
488 				texturesOwned[mtDiffuse]=true;
489 				textures[mtDiffuse]->init(textureManager->getTextureFilter(),textureManager->getMaxAnisotropy());
490 				if(deletePixMapAfterLoad == true) {
491 					textures[mtDiffuse]->deletePixels();
492 				}
493 			}
494 			else {
495 				SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error v2 model is missing texture [%s] meshIndex = %d modelFile [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,texPath.c_str(),meshIndex,modelFile.c_str());
496 			}
497 		}
498 	}
499 
500 	//read data
501 	readBytes = fread(vertices, sizeof(Vec3f)*frameCount*vertexCount, 1, f);
502 	if(readBytes != 1 && (frameCount * vertexCount) != 0) {
503 		char szBuf[8096]="";
504 		snprintf(szBuf,8096,"fread returned wrong size = " MG_SIZE_T_SPECIFIER " [%u][%u] on line: %d.",readBytes,frameCount,vertexCount,__LINE__);
505 		throw megaglest_runtime_error(szBuf);
506 	}
507 	fromEndianVecArray<Vec3f>(vertices, frameCount*vertexCount);
508 
509 	readBytes = fread(normals, sizeof(Vec3f)*frameCount*vertexCount, 1, f);
510 	if(readBytes != 1 && (frameCount * vertexCount) != 0) {
511 		char szBuf[8096]="";
512 		snprintf(szBuf,8096,"fread returned wrong size = " MG_SIZE_T_SPECIFIER " [%u][%u] on line: %d.",readBytes,frameCount,vertexCount,__LINE__);
513 		throw megaglest_runtime_error(szBuf);
514 	}
515 	fromEndianVecArray<Vec3f>(normals, frameCount*vertexCount);
516 
517 	if(textureFlags & (1<<mtDiffuse)) {
518 		readBytes = fread(texCoords, sizeof(Vec2f)*vertexCount, 1, f);
519 		if(readBytes != 1 && vertexCount != 0) {
520 			char szBuf[8096]="";
521 			snprintf(szBuf,8096,"fread returned wrong size = " MG_SIZE_T_SPECIFIER " [%u][%u] on line: %d.",readBytes,frameCount,vertexCount,__LINE__);
522 			throw megaglest_runtime_error(szBuf);
523 		}
524 		fromEndianVecArray<Vec2f>(texCoords, vertexCount);
525 	}
526 	readBytes = fread(&diffuseColor, sizeof(Vec3f), 1, f);
527 	if(readBytes != 1) {
528 		char szBuf[8096]="";
529 		snprintf(szBuf,8096,"fread returned wrong size = " MG_SIZE_T_SPECIFIER " on line: %d.",readBytes,__LINE__);
530 		throw megaglest_runtime_error(szBuf);
531 	}
532 	fromEndianVecArray<Vec3f>(&diffuseColor, 1);
533 
534 	readBytes = fread(&opacity, sizeof(float32), 1, f);
535 	if(readBytes != 1) {
536 		char szBuf[8096]="";
537 		snprintf(szBuf,8096,"fread returned wrong size = " MG_SIZE_T_SPECIFIER " on line: %d.",readBytes,__LINE__);
538 		throw megaglest_runtime_error(szBuf);
539 	}
540 	opacity = Shared::PlatformByteOrder::fromCommonEndian(opacity);
541 
542 	int seek_result = fseek(f, sizeof(Vec4f)*(meshHeader.colorFrameCount-1), SEEK_CUR);
543 	if(seek_result != 0) {
544 		char szBuf[8096]="";
545 		snprintf(szBuf,8096,"fseek returned failure = %d [%u] on line: %d.",seek_result,indexCount,__LINE__);
546 		throw megaglest_runtime_error(szBuf);
547 	}
548 	readBytes = fread(indices, sizeof(uint32)*indexCount, 1, f);
549 	if(readBytes != 1 && indexCount != 0) {
550 		char szBuf[8096]="";
551 		snprintf(szBuf,8096,"fread returned wrong size = " MG_SIZE_T_SPECIFIER " [%u] on line: %d.",readBytes,indexCount,__LINE__);
552 		throw megaglest_runtime_error(szBuf);
553 	}
554 	Shared::PlatformByteOrder::fromEndianTypeArray<uint32>(indices, indexCount);
555 }
556 
loadV3(int meshIndex,const string & dir,FILE * f,TextureManager * textureManager,bool deletePixMapAfterLoad,std::map<string,vector<pair<string,string>>> * loadedFileList,string sourceLoader,string modelFile)557 void Mesh::loadV3(int meshIndex, const string &dir, FILE *f,
558 		TextureManager *textureManager,bool deletePixMapAfterLoad,
559 		std::map<string,vector<pair<string, string> > > *loadedFileList,
560 		string sourceLoader,string modelFile) {
561 	this->textureManager = textureManager;
562 
563 	//read header
564 	MeshHeaderV3 meshHeader;
565 	size_t readBytes = fread(&meshHeader, sizeof(MeshHeaderV3), 1, f);
566 	if(readBytes != 1) {
567 		char szBuf[8096]="";
568 		snprintf(szBuf,8096,"fread returned wrong size = " MG_SIZE_T_SPECIFIER " on line: %d.",readBytes,__LINE__);
569 		throw megaglest_runtime_error(szBuf);
570 	}
571 	fromEndianMeshHeaderV3(meshHeader);
572 
573 	if(meshHeader.normalFrameCount != meshHeader.vertexFrameCount) {
574 		char szBuf[8096]="";
575 		snprintf(szBuf,8096,"Old v3 model: vertex frame count different from normal frame count [v = %d, n = %d] meshIndex = %d modelFile [%s]",meshHeader.vertexFrameCount,meshHeader.normalFrameCount,meshIndex,modelFile.c_str());
576 		throw megaglest_runtime_error(szBuf,true);
577 	}
578 
579 	//init
580 	frameCount= meshHeader.vertexFrameCount;
581 	vertexCount= meshHeader.pointCount;
582 	indexCount= meshHeader.indexCount;
583 	texCoordFrameCount = meshHeader.texCoordFrameCount;
584 
585 	init();
586 
587 	//misc
588 	twoSided= (meshHeader.properties & mp3TwoSided) != 0;
589 	customColor= (meshHeader.properties & mp3CustomColor) != 0;
590 	noSelect = false;
591 	glow = false;
592 
593 	textureFlags= 0;
594 	if((meshHeader.properties & mp3NoTexture) != mp3NoTexture) {
595 		textureFlags= 1;
596 	}
597 
598 	if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Load v3, this = %p Found meshHeader.properties = %d, textureFlags = %d, texName [%s] mtDiffuse = %d meshIndex = %d modelFile [%s]\n",this,meshHeader.properties,textureFlags,toLower(reinterpret_cast<char*>(meshHeader.texName)).c_str(),mtDiffuse,meshIndex,modelFile.c_str());
599 
600 	//texture
601 	if((meshHeader.properties & mp3NoTexture) != mp3NoTexture && textureManager!=NULL){
602 		texturePaths[mtDiffuse]= toLower(reinterpret_cast<char*>(meshHeader.texName));
603 
604 		string texPath= dir;
605         if(texPath != "") {
606         	endPathWithSlash(texPath);
607         }
608 		texPath += texturePaths[mtDiffuse];
609 
610 		if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d] v3 model texture [%s] meshIndex = %d modelFile [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,texPath.c_str(),meshIndex,modelFile.c_str());
611 
612 		textures[mtDiffuse]= dynamic_cast<Texture2D*>(textureManager->getTexture(texPath));
613 		if(textures[mtDiffuse] == NULL) {
614 			if(fileExists(texPath) == false) {
615 				vector<string> conversionList;
616 				conversionList.push_back("png");
617 				conversionList.push_back("jpg");
618 				conversionList.push_back("tga");
619 				conversionList.push_back("bmp");
620 				texPath = findAlternateTexture(conversionList, texPath);
621 			}
622 
623 			if(fileExists(texPath) == true) {
624 				if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d] v3 model texture [%s] meshIndex = %d modelFile [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,texPath.c_str(),meshIndex,modelFile.c_str());
625 
626 				textures[mtDiffuse]= textureManager->newTexture2D();
627 				textures[mtDiffuse]->load(texPath);
628 				if(loadedFileList) {
629 					(*loadedFileList)[texPath].push_back(make_pair(sourceLoader,sourceLoader));
630 				}
631 
632 				texturesOwned[mtDiffuse]=true;
633 				textures[mtDiffuse]->init(textureManager->getTextureFilter(),textureManager->getMaxAnisotropy());
634 				if(deletePixMapAfterLoad == true) {
635 					textures[mtDiffuse]->deletePixels();
636 				}
637 			}
638 			else {
639 				SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error v3 model is missing texture [%s] meshHeader.properties = %d meshIndex = %d modelFile [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,texPath.c_str(),meshHeader.properties,meshIndex,modelFile.c_str());
640 			}
641 		}
642 	}
643 
644 	//read data
645 	readBytes = fread(vertices, sizeof(Vec3f)*frameCount*vertexCount, 1, f);
646 	if(readBytes != 1 && (frameCount * vertexCount) != 0) {
647 		char szBuf[8096]="";
648 		snprintf(szBuf,8096,"fread returned wrong size = " MG_SIZE_T_SPECIFIER " [%u][%u] on line: %d.",readBytes,frameCount,vertexCount,__LINE__);
649 		throw megaglest_runtime_error(szBuf);
650 	}
651 	fromEndianVecArray<Vec3f>(vertices, frameCount*vertexCount);
652 
653 	readBytes = fread(normals, sizeof(Vec3f)*frameCount*vertexCount, 1, f);
654 	if(readBytes != 1 && (frameCount * vertexCount) != 0) {
655 		char szBuf[8096]="";
656 		snprintf(szBuf,8096,"fread returned wrong size = " MG_SIZE_T_SPECIFIER " [%u][%u] on line: %d.",readBytes,frameCount,vertexCount,__LINE__);
657 		throw megaglest_runtime_error(szBuf);
658 	}
659 	fromEndianVecArray<Vec3f>(normals, frameCount*vertexCount);
660 
661 	if(textureFlags & (1<<mtDiffuse)) {
662 		for(unsigned int i=0; i<meshHeader.texCoordFrameCount; ++i){
663 			readBytes = fread(texCoords, sizeof(Vec2f)*vertexCount, 1, f);
664 			if(readBytes != 1 && vertexCount != 0) {
665 				char szBuf[8096]="";
666 				snprintf(szBuf,8096,"fread returned wrong size = " MG_SIZE_T_SPECIFIER " [%u][%u] on line: %d.",readBytes,frameCount,vertexCount,__LINE__);
667 				throw megaglest_runtime_error(szBuf);
668 			}
669 			fromEndianVecArray<Vec2f>(texCoords, vertexCount);
670 		}
671 	}
672 	readBytes = fread(&diffuseColor, sizeof(Vec3f), 1, f);
673 	if(readBytes != 1) {
674 		char szBuf[8096]="";
675 		snprintf(szBuf,8096,"fread returned wrong size = " MG_SIZE_T_SPECIFIER " on line: %d.",readBytes,__LINE__);
676 		throw megaglest_runtime_error(szBuf);
677 	}
678 	fromEndianVecArray<Vec3f>(&diffuseColor, 1);
679 
680 	readBytes = fread(&opacity, sizeof(float32), 1, f);
681 	if(readBytes != 1) {
682 		char szBuf[8096]="";
683 		snprintf(szBuf,8096,"fread returned wrong size = " MG_SIZE_T_SPECIFIER " on line: %d.",readBytes,__LINE__);
684 		throw megaglest_runtime_error(szBuf);
685 	}
686 	opacity = Shared::PlatformByteOrder::fromCommonEndian(opacity);
687 
688 	int seek_result = fseek(f, sizeof(Vec4f)*(meshHeader.colorFrameCount-1), SEEK_CUR);
689 	if(seek_result != 0) {
690 		char szBuf[8096]="";
691 		snprintf(szBuf,8096,"fseek returned failure = %d [%u] on line: %d.",seek_result,indexCount,__LINE__);
692 		throw megaglest_runtime_error(szBuf);
693 	}
694 
695 	readBytes = fread(indices, sizeof(uint32)*indexCount, 1, f);
696 	if(readBytes != 1 && indexCount != 0) {
697 		char szBuf[8096]="";
698 		snprintf(szBuf,8096,"fread returned wrong size = " MG_SIZE_T_SPECIFIER " [%u] on line: %d.",readBytes,indexCount,__LINE__);
699 		throw megaglest_runtime_error(szBuf);
700 	}
701 	Shared::PlatformByteOrder::fromEndianTypeArray<uint32>(indices, indexCount);
702 }
703 
loadMeshTexture(int meshIndex,int textureIndex,TextureManager * textureManager,string textureFile,int textureChannelCount,bool & textureOwned,bool deletePixMapAfterLoad,std::map<string,vector<pair<string,string>>> * loadedFileList,string sourceLoader,string modelFile)704 Texture2D* Mesh::loadMeshTexture(int meshIndex, int textureIndex,
705 		TextureManager *textureManager, string textureFile,
706 		int textureChannelCount, bool &textureOwned, bool deletePixMapAfterLoad,
707 		std::map<string,vector<pair<string, string> > > *loadedFileList,
708 		string sourceLoader,string modelFile) {
709 
710 	if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s] #1 load texture [%s] modelFile [%s]\n",__FUNCTION__,textureFile.c_str(),modelFile.c_str());
711 
712 	Texture2D* texture = dynamic_cast<Texture2D*>(textureManager->getTexture(textureFile));
713 	if(texture == NULL) {
714 		if(fileExists(textureFile) == false) {
715 			vector<string> conversionList;
716 			conversionList.push_back("png");
717 			conversionList.push_back("jpg");
718 			conversionList.push_back("tga");
719 			conversionList.push_back("bmp");
720 			textureFile = findAlternateTexture(conversionList, textureFile);
721 
722 			if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s] #2 load texture [%s]\n",__FUNCTION__,textureFile.c_str());
723 		}
724 
725 		if(fileExists(textureFile) == true) {
726 			if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s] #3 load texture [%s] modelFile [%s]\n",__FUNCTION__,textureFile.c_str(),modelFile.c_str());
727 			//if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s] texture exists loading [%s]\n",__FUNCTION__,textureFile.c_str());
728 
729 			texture = textureManager->newTexture2D();
730 			if(textureChannelCount != -1) {
731 				texture->getPixmap()->init(textureChannelCount);
732 			}
733 			texture->load(textureFile);
734 			if(loadedFileList) {
735 				(*loadedFileList)[textureFile].push_back(make_pair(sourceLoader,sourceLoader));
736 			}
737 
738 			//if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s] texture loaded [%s]\n",__FUNCTION__,textureFile.c_str());
739 
740 			textureOwned = true;
741 			texture->init(textureManager->getTextureFilter(),textureManager->getMaxAnisotropy());
742 			if(deletePixMapAfterLoad == true) {
743 				texture->deletePixels();
744 			}
745 
746 			//if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s] texture inited [%s]\n",__FUNCTION__,textureFile.c_str());
747 		}
748 		else {
749 			if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s] #3 cannot load texture [%s] modelFile [%s]\n",__FUNCTION__,textureFile.c_str(),modelFile.c_str());
750 			SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error v4 model is missing texture [%s] textureFlags = %d meshIndex = %d textureIndex = %d modelFile [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,textureFile.c_str(),textureFlags,meshIndex,textureIndex,modelFile.c_str());
751 		}
752 	}
753 
754 	return texture;
755 }
756 
load(int meshIndex,const string & dir,FILE * f,TextureManager * textureManager,bool deletePixMapAfterLoad,std::map<string,vector<pair<string,string>>> * loadedFileList,string sourceLoader,string modelFile)757 void Mesh::load(int meshIndex, const string &dir, FILE *f, TextureManager *textureManager,
758 				bool deletePixMapAfterLoad,std::map<string,vector<pair<string, string> > > *loadedFileList,
759 				string sourceLoader,string modelFile) {
760 	this->textureManager = textureManager;
761 
762 	//read header
763 	MeshHeader meshHeader;
764 	size_t readBytes = fread(&meshHeader, sizeof(MeshHeader), 1, f);
765 	if(readBytes != 1) {
766 		char szBuf[8096]="";
767 		snprintf(szBuf,8096,"fread returned wrong size = " MG_SIZE_T_SPECIFIER " on line: %d.",readBytes,__LINE__);
768 		throw megaglest_runtime_error(szBuf);
769 	}
770 	fromEndianMeshHeader(meshHeader);
771 
772 	name = reinterpret_cast<char*>(meshHeader.name);
773 
774 	//printf("Load, Found meshTextureCount = %d, meshHeader.textures = %d\n",meshTextureCount,meshHeader.textures);
775 
776 	//init
777 	frameCount= meshHeader.frameCount;
778 	vertexCount= meshHeader.vertexCount;
779 	indexCount= meshHeader.indexCount;
780 
781 	init();
782 
783 	//properties
784 	customColor= (meshHeader.properties & mpfCustomColor) != 0;
785 	twoSided= (meshHeader.properties & mpfTwoSided) != 0;
786 	noSelect= (meshHeader.properties & mpfNoSelect) != 0;
787 	glow= (meshHeader.properties & mpfGlow) != 0;
788 
789 	//material
790 	diffuseColor= Vec3f(meshHeader.diffuseColor);
791 	specularColor= Vec3f(meshHeader.specularColor);
792 	specularPower= meshHeader.specularPower;
793 	opacity= meshHeader.opacity;
794 	if(opacity==0){
795 		if(SystemFlags::VERBOSE_MODE_ENABLED) printf("found a mesh with opacity=0 in header, using opacity=1 to see it now \n");
796 		if(SystemFlags::VERBOSE_MODE_ENABLED) printf("file: %s\n",modelFile.c_str());
797 		opacity=1.0f;
798 	}
799 	textureFlags= meshHeader.textures;
800 
801 	if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Load v4, this = %p Found meshHeader.textures = %d meshIndex = %d\n",this,meshHeader.textures,meshIndex);
802 
803 	//maps
804 	uint32 flag= 1;
805 	for(int i = 0; i < meshTextureCount; ++i) {
806 		if(meshHeader.textures & flag) {
807 			uint8 cMapPath[mapPathSize+1];
808 			memset(&cMapPath[0],0,mapPathSize+1);
809 			readBytes = fread(cMapPath, mapPathSize, 1, f);
810 			cMapPath[mapPathSize] = 0;
811 			if(readBytes != 1 && mapPathSize != 0) {
812 				char szBuf[8096]="";
813 				snprintf(szBuf,8096,"fread returned wrong size = " MG_SIZE_T_SPECIFIER " [%u] on line: %d.",readBytes,mapPathSize,__LINE__);
814 				throw megaglest_runtime_error(szBuf);
815 			}
816 			Shared::PlatformByteOrder::fromEndianTypeArray<uint8>(cMapPath, mapPathSize);
817 
818 			char mapPathString[mapPathSize+1]="";
819 			memset(&mapPathString[0],0,mapPathSize+1);
820 			memcpy(&mapPathString[0],reinterpret_cast<char*>(cMapPath),mapPathSize);
821 			string mapPath= toLower(mapPathString);
822 
823 			if(SystemFlags::VERBOSE_MODE_ENABLED) printf("mapPath [%s] meshHeader.textures = %d flag = %d (meshHeader.textures & flag) = %d meshIndex = %d i = %d\n",mapPath.c_str(),meshHeader.textures,flag,(meshHeader.textures & flag),meshIndex,i);
824 
825 			string mapFullPath= dir;
826 			if(mapFullPath != "") {
827 				endPathWithSlash(mapFullPath);
828 			}
829 			mapFullPath += mapPath;
830 			if(textureManager) {
831 				textures[i] = loadMeshTexture(meshIndex, i, textureManager, mapFullPath,
832 						meshTextureChannelCount[i],texturesOwned[i],
833 						deletePixMapAfterLoad, loadedFileList, sourceLoader,modelFile);
834 			}
835 		}
836 		flag *= 2;
837 	}
838 
839 	//read data
840 	readBytes = fread(vertices, sizeof(Vec3f)*frameCount*vertexCount, 1, f);
841 	if(readBytes != 1 && (frameCount * vertexCount) != 0) {
842 		char szBuf[8096]="";
843 		snprintf(szBuf,8096,"fread returned wrong size = " MG_SIZE_T_SPECIFIER " [%u][%u] on line: %d.",readBytes,frameCount,vertexCount,__LINE__);
844 		throw megaglest_runtime_error(szBuf);
845 	}
846 	fromEndianVecArray<Vec3f>(vertices, frameCount*vertexCount);
847 
848 	readBytes = fread(normals, sizeof(Vec3f)*frameCount*vertexCount, 1, f);
849 	if(readBytes != 1 && (frameCount * vertexCount) != 0) {
850 		char szBuf[8096]="";
851 		snprintf(szBuf,8096,"fread returned wrong size = " MG_SIZE_T_SPECIFIER " [%u][%u] on line: %d.",readBytes,frameCount,vertexCount,__LINE__);
852 		throw megaglest_runtime_error(szBuf);
853 	}
854 	fromEndianVecArray<Vec3f>(normals, frameCount*vertexCount);
855 
856 	if(meshHeader.textures!=0){
857 		readBytes = fread(texCoords, sizeof(Vec2f)*vertexCount, 1, f);
858 		if(readBytes != 1 && vertexCount != 0) {
859 			char szBuf[8096]="";
860 			snprintf(szBuf,8096,"fread returned wrong size = " MG_SIZE_T_SPECIFIER " [%u][%u] on line: %d.",readBytes,frameCount,vertexCount,__LINE__);
861 			throw megaglest_runtime_error(szBuf);
862 		}
863 		fromEndianVecArray<Vec2f>(texCoords, vertexCount);
864 	}
865 	readBytes = fread(indices, sizeof(uint32)*indexCount, 1, f);
866 	if(readBytes != 1 && indexCount != 0) {
867 		char szBuf[8096]="";
868 		snprintf(szBuf,8096,"fread returned wrong size = " MG_SIZE_T_SPECIFIER " [%u] on line: %d.",readBytes,indexCount,__LINE__);
869 		throw megaglest_runtime_error(szBuf);
870 	}
871 	Shared::PlatformByteOrder::fromEndianTypeArray<uint32>(indices, indexCount);
872 
873 	//tangents
874 	if(textures[mtNormal]!=NULL){
875 		computeTangents();
876 	}
877 }
878 
save(int meshIndex,const string & dir,FILE * f,TextureManager * textureManager,string convertTextureToFormat,std::map<string,int> & textureDeleteList,bool keepsmallest,string modelFile)879 void Mesh::save(int meshIndex, const string &dir, FILE *f, TextureManager *textureManager,
880 		string convertTextureToFormat, std::map<string,int> &textureDeleteList,
881 		bool keepsmallest,string modelFile) {
882 	MeshHeader meshHeader;
883 	memset(&meshHeader, 0, sizeof(struct MeshHeader));
884 
885 	strncpy((char*)meshHeader.name, (char*)name.c_str(), name.length());
886 	meshHeader.frameCount= frameCount;
887 	meshHeader.vertexCount= vertexCount;
888 	meshHeader.indexCount = indexCount;
889 
890 	//material
891 	memcpy((float32*)meshHeader.diffuseColor, (float32*)diffuseColor.ptr(), sizeof(float32) * 3);
892 	memcpy((float32*)meshHeader.specularColor, (float32*)specularColor.ptr(), sizeof(float32) * 3);
893 	meshHeader.specularPower = specularPower;
894 	meshHeader.opacity = opacity;
895 
896 	//properties
897 	meshHeader.properties = 0;
898 	if(customColor) {
899 		meshHeader.properties |= mpfCustomColor;
900 	}
901 	if(twoSided) {
902 		meshHeader.properties |= mpfTwoSided;
903 	}
904 	if(noSelect) {
905 		meshHeader.properties |= mpfNoSelect;
906 	}
907 	if(glow) {
908 		meshHeader.properties |= mpfGlow;
909 	}
910 
911 	meshHeader.textures = textureFlags;
912 	fwrite(&meshHeader, sizeof(MeshHeader), 1, f);
913 
914 	if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Save, this = %p, Found meshTextureCount = %d, meshHeader.textures = %d meshIndex = %d\n",this,meshTextureCount,meshHeader.textures,meshIndex);
915 
916 	//maps
917 	uint32 flag= 1;
918 	for(int i = 0; i < meshTextureCount; ++i) {
919 		if((meshHeader.textures & flag)) {
920 			uint8 cMapPath[mapPathSize];
921 			memset(&cMapPath[0],0,mapPathSize);
922 
923 			Texture2D *texture = textures[i];
924 
925 			if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Save, [%d] mesh texture ptr [%p]\n",i,texture);
926 
927 			if(texture != NULL) {
928 				string file = toLower(texture->getPath());
929 
930 				if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Save, Found mesh texture [%s]\n",file.c_str());
931 
932 				if(toLower(convertTextureToFormat) != "" &&
933 					EndsWith(file, "." + convertTextureToFormat) == false) {
934 					long originalSize 	= getFileSize(file);
935 					long newSize 		= originalSize;
936 
937 					string fileExt = extractExtension(file);
938 					replaceAll(file, "." + fileExt, "." + convertTextureToFormat);
939 
940 					if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Save, Convert from [%s] to [%s]\n",texture->getPath().c_str(),file.c_str());
941 
942 					if(convertTextureToFormat == "tga") {
943 						texture->getPixmap()->saveTga(file);
944 						newSize = getFileSize(file);
945 						if(keepsmallest == false || newSize <= originalSize) {
946 							textureDeleteList[texture->getPath()] = textureDeleteList[texture->getPath()] + 1;
947 						}
948 						else {
949 							printf("Texture will not be converted, keeping smallest texture [%s]\n",texture->getPath().c_str());
950 							textureDeleteList[file] = textureDeleteList[file] + 1;
951 						}
952 					}
953 					else if(convertTextureToFormat == "bmp") {
954 						texture->getPixmap()->saveBmp(file);
955 						newSize = getFileSize(file);
956 						if(keepsmallest == false || newSize <= originalSize) {
957 							textureDeleteList[texture->getPath()] = textureDeleteList[texture->getPath()] + 1;
958 						}
959 						else {
960 							printf("Texture will not be converted, keeping smallest texture [%s]\n",texture->getPath().c_str());
961 							textureDeleteList[file] = textureDeleteList[file] + 1;
962 						}
963 					}
964 					else if(convertTextureToFormat == "jpg") {
965 						texture->getPixmap()->saveJpg(file);
966 						newSize = getFileSize(file);
967 						if(keepsmallest == false || newSize <= originalSize) {
968 							textureDeleteList[texture->getPath()] = textureDeleteList[texture->getPath()] + 1;
969 						}
970 						else {
971 							printf("Texture will not be converted, keeping smallest texture [%s]\n",texture->getPath().c_str());
972 							textureDeleteList[file] = textureDeleteList[file] + 1;
973 						}
974 					}
975 					else  if(convertTextureToFormat == "png") {
976 						texture->getPixmap()->savePng(file);
977 						newSize = getFileSize(file);
978 						if(keepsmallest == false || newSize <= originalSize) {
979 							textureDeleteList[texture->getPath()] = textureDeleteList[texture->getPath()] + 1;
980 						}
981 						else {
982 							printf("Texture will not be converted, keeping smallest texture [%s]\n",texture->getPath().c_str());
983 							textureDeleteList[file] = textureDeleteList[file] + 1;
984 						}
985 					}
986 					else {
987 						throw megaglest_runtime_error("Unsupported texture format: [" + convertTextureToFormat + "]");
988 					}
989 
990 					//textureManager->endTexture(texture);
991 					if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Save, load new texture [%s] originalSize [%ld] newSize [%ld]\n",file.c_str(),originalSize,newSize);
992 
993 					if(keepsmallest == false || newSize <= originalSize) {
994 						texture = loadMeshTexture(meshIndex, i, textureManager,file,
995 													meshTextureChannelCount[i],
996 													texturesOwned[i],
997 													false,
998 													NULL,
999 													"",
1000 													modelFile);
1001 					}
1002 				}
1003 
1004 				file = extractFileFromDirectoryPath(texture->getPath());
1005 
1006 				if(file.length() > mapPathSize) {
1007 					throw megaglest_runtime_error("file.length() > mapPathSize, file.length() = " + intToStr(file.length()));
1008 				}
1009 				else if(file.length() == 0) {
1010 					throw megaglest_runtime_error("file.length() == 0");
1011 				}
1012 
1013 				if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Save, new texture file [%s]\n",file.c_str());
1014 
1015 				memset(&cMapPath[0],0,mapPathSize);
1016 				memcpy(&cMapPath[0],file.c_str(),file.length());
1017 			}
1018 
1019 			fwrite(cMapPath, mapPathSize, 1, f);
1020 		}
1021 		flag*= 2;
1022 	}
1023 
1024 	//read data
1025 	fwrite(vertices, sizeof(Vec3f)*frameCount*vertexCount, 1, f);
1026 	fwrite(normals, sizeof(Vec3f)*frameCount*vertexCount, 1, f);
1027 	if(meshHeader.textures != 0) {
1028 		fwrite(texCoords, sizeof(Vec2f)*vertexCount, 1, f);
1029 	}
1030 	fwrite(indices, sizeof(uint32)*indexCount, 1, f);
1031 }
1032 
computeTangents()1033 void Mesh::computeTangents(){
1034 	delete [] tangents;
1035 	try {
1036 		tangents= new Vec3f[vertexCount];
1037 	}
1038 	catch(bad_alloc& ba) {
1039 		char szBuf[8096]="";
1040 		snprintf(szBuf,8096,"Error on line: %d size: %d msg: %s\n",__LINE__,vertexCount,ba.what());
1041 		throw megaglest_runtime_error(szBuf);
1042 	}
1043 
1044 	for(unsigned int i=0; i<vertexCount; ++i){
1045 		tangents[i]= Vec3f(0.f);
1046 	}
1047 
1048 	for(unsigned int i=0; i<indexCount; i+=3){
1049 		for(int j=0; j<3; ++j){
1050 			uint32 i0= indices[i+j];
1051 			uint32 i1= indices[i+(j+1)%3];
1052 			uint32 i2= indices[i+(j+2)%3];
1053 
1054 			Vec3f p0= vertices[i0];
1055 			Vec3f p1= vertices[i1];
1056 			Vec3f p2= vertices[i2];
1057 
1058 			float u0= texCoords[i0].x;
1059 			float u1= texCoords[i1].x;
1060 			float u2= texCoords[i2].x;
1061 
1062 			float v0= texCoords[i0].y;
1063 			float v1= texCoords[i1].y;
1064 			float v2= texCoords[i2].y;
1065 
1066 			tangents[i0]+=
1067 				((p2-p0)*(v1-v0)-(p1-p0)*(v2-v0))/
1068 				((u2-u0)*(v1-v0)-(u1-u0)*(v2-v0));
1069 		}
1070 	}
1071 
1072 	for(unsigned int i=0; i<vertexCount; ++i){
1073 		/*Vec3f binormal= normals[i].cross(tangents[i]);
1074 		tangents[i]+= binormal.cross(normals[i]);*/
1075 		tangents[i].normalize();
1076 	}
1077 }
1078 
deletePixels()1079 void Mesh::deletePixels() {
1080 	for(int i = 0; i < meshTextureCount; ++i) {
1081 		if(textures[i] != NULL) {
1082 			textures[i]->deletePixels();
1083 		}
1084 	}
1085 }
1086 
1087 // ===============================================
1088 //	class Model
1089 // ===============================================
1090 
1091 // ==================== constructor & destructor ====================
1092 
Model()1093 Model::Model() {
1094 	if(GlobalStaticFlags::getIsNonGraphicalModeEnabled() == true) {
1095 		throw megaglest_runtime_error("Loading graphics in headless server mode not allowed!");
1096 	}
1097 
1098 	meshCount		= 0;
1099 	meshes			= NULL;
1100 	fileVersion		= 0;
1101 	textureManager	= NULL;
1102 	lastTData		= -1;
1103 	lastCycleData	= false;
1104 	lastTVertex		= -1;
1105 	lastCycleVertex	= false;
1106 }
1107 
~Model()1108 Model::~Model() {
1109 	if(meshes) delete [] meshes;
1110 	meshes = NULL;
1111 }
1112 
1113 // ==================== data ====================
1114 
buildInterpolationData() const1115 void Model::buildInterpolationData() const{
1116 	for(unsigned int i=0; i<meshCount; ++i){
1117 		meshes[i].buildInterpolationData();
1118 	}
1119 }
1120 
updateInterpolationData(float t,bool cycle)1121 void Model::updateInterpolationData(float t, bool cycle) {
1122 	if(lastTData != t || lastCycleData != cycle) {
1123 		for(unsigned int i = 0; i < meshCount; ++i) {
1124 			meshes[i].updateInterpolationData(t, cycle);
1125 		}
1126 		lastTData 		= t;
1127 		lastCycleData 	= cycle;
1128 	}
1129 }
1130 
updateInterpolationVertices(float t,bool cycle)1131 void Model::updateInterpolationVertices(float t, bool cycle) {
1132 	if(lastTVertex != t || lastCycleVertex != cycle) {
1133 		for(unsigned int i = 0; i < meshCount; ++i) {
1134 			meshes[i].updateInterpolationVertices(t, cycle);
1135 		}
1136 		lastTVertex 	= t;
1137 		lastCycleVertex = cycle;
1138 	}
1139 }
1140 
1141 // ==================== get ====================
1142 
getTriangleCount() const1143 uint32 Model::getTriangleCount() const {
1144 	uint32 triangleCount= 0;
1145 	for(uint32 i = 0; i < meshCount; ++i) {
1146 		triangleCount += meshes[i].getIndexCount()/3;
1147 	}
1148 	return triangleCount;
1149 }
1150 
getVertexCount() const1151 uint32 Model::getVertexCount() const {
1152 	uint32 vertexCount= 0;
1153 	for(uint32 i = 0; i < meshCount; ++i) {
1154 		vertexCount += meshes[i].getVertexCount();
1155 	}
1156 	return vertexCount;
1157 }
1158 
1159 // ==================== io ====================
1160 
load(const string & path,bool deletePixMapAfterLoad,std::map<string,vector<pair<string,string>>> * loadedFileList,string * sourceLoader)1161 void Model::load(const string &path, bool deletePixMapAfterLoad,
1162 		std::map<string,vector<pair<string, string> > > *loadedFileList, string *sourceLoader) {
1163 
1164 	this->sourceLoader = (sourceLoader != NULL ? *sourceLoader : "");
1165 	this->fileName = path;
1166 
1167 	if(GlobalStaticFlags::getIsNonGraphicalModeEnabled() == true) {
1168 		return;
1169 	}
1170 	string extension= path.substr(path.find_last_of('.') + 1);
1171 	if(extension=="g3d" || extension=="G3D") {
1172 		loadG3d(path,deletePixMapAfterLoad,loadedFileList, this->sourceLoader);
1173 	}
1174 	else {
1175 		throw megaglest_runtime_error("Unknown model format: " + extension);
1176 	}
1177 }
1178 
save(const string & path,string convertTextureToFormat,bool keepsmallest)1179 void Model::save(const string &path, string convertTextureToFormat,
1180 		bool keepsmallest) {
1181 	string extension= path.substr(path.find_last_of('.')+1);
1182 	if(extension=="g3d" ||extension=="G3D") {
1183 		saveG3d(path,convertTextureToFormat,keepsmallest);
1184 	}
1185 	else {
1186 		throw megaglest_runtime_error("Unknown model format: " + extension);
1187 	}
1188 }
1189 
1190 //load a model from a g3d file
loadG3d(const string & path,bool deletePixMapAfterLoad,std::map<string,vector<pair<string,string>>> * loadedFileList,string sourceLoader)1191 void Model::loadG3d(const string &path, bool deletePixMapAfterLoad,
1192 		std::map<string,vector<pair<string, string> > > *loadedFileList,
1193 		string sourceLoader) {
1194 
1195     try{
1196 #ifdef WIN32
1197 		FILE *f= _wfopen(utf8_decode(path).c_str(), L"rb");
1198 #else
1199 		FILE *f=fopen(path.c_str(),"rb");
1200 #endif
1201 		if (f == NULL) {
1202 		    printf("In [%s::%s] cannot load file = [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,path.c_str());
1203 			throw megaglest_runtime_error("Error opening g3d model file [" + path + "]",true);
1204 		}
1205 
1206 		if(loadedFileList) {
1207 			(*loadedFileList)[path].push_back(make_pair(sourceLoader,sourceLoader));
1208 		}
1209 
1210 		string dir= extractDirectoryPathFromFile(path);
1211 
1212 		//file header
1213 		FileHeader fileHeader;
1214 		size_t readBytes = fread(&fileHeader, sizeof(FileHeader), 1, f);
1215 		if(readBytes != 1) {
1216 			fclose(f);
1217 			char szBuf[8096]="";
1218 			snprintf(szBuf,8096,"fread returned wrong size = " MG_SIZE_T_SPECIFIER " on line: %d.",readBytes,__LINE__);
1219 			throw megaglest_runtime_error(szBuf);
1220 		}
1221 		fromEndianFileHeader(fileHeader);
1222 
1223 		char fileId[4] = "";
1224 		memset(&fileId[0],0,4);
1225 		memcpy(&fileId[0],reinterpret_cast<char*>(fileHeader.id),3);
1226 
1227 		if(strncmp(fileId, "G3D", 3) != 0) {
1228 			fclose(f);
1229 			f = NULL;
1230 		    printf("In [%s::%s] file = [%s] fileheader.id = [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,path.c_str(),fileId);
1231 			throw megaglest_runtime_error("Not a valid G3D model",true);
1232 		}
1233 		fileVersion= fileHeader.version;
1234 
1235 		if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Load model, fileVersion = %d\n",fileVersion);
1236 
1237 		//version 4
1238 		if(fileHeader.version == 4) {
1239 			//model header
1240 			ModelHeader modelHeader;
1241 			readBytes = fread(&modelHeader, sizeof(ModelHeader), 1, f);
1242 			if(readBytes != 1) {
1243 				char szBuf[8096]="";
1244 				snprintf(szBuf,8096,"fread returned wrong size = " MG_SIZE_T_SPECIFIER " on line: %d.",readBytes,__LINE__);
1245 				throw megaglest_runtime_error(szBuf);
1246 			}
1247 			fromEndianModelHeader(modelHeader);
1248 
1249 			meshCount= modelHeader.meshCount;
1250 
1251 			if(SystemFlags::VERBOSE_MODE_ENABLED) printf("meshCount = %d\n",meshCount);
1252 
1253 			if(modelHeader.type != mtMorphMesh) {
1254 				throw megaglest_runtime_error("Invalid model type");
1255 			}
1256 
1257 			//load meshes
1258 			try {
1259 				meshes= new Mesh[meshCount];
1260 			}
1261 			catch(bad_alloc& ba) {
1262 				char szBuf[8096]="";
1263 				snprintf(szBuf,8096,"Error on line: %d size: %d msg: %s\n",__LINE__,meshCount,ba.what());
1264 				throw megaglest_runtime_error(szBuf);
1265 			}
1266 
1267 			for(uint32 i = 0; i < meshCount; ++i) {
1268 				meshes[i].load(i, dir, f, textureManager,deletePixMapAfterLoad,
1269 						loadedFileList,sourceLoader,path);
1270 				meshes[i].buildInterpolationData();
1271 			}
1272 		}
1273 		//version 3
1274 		else if(fileHeader.version == 3) {
1275 			readBytes = fread(&meshCount, sizeof(meshCount), 1, f);
1276 			if(readBytes != 1 && meshCount != 0) {
1277 				char szBuf[8096]="";
1278 				snprintf(szBuf,8096,"fread returned wrong size = " MG_SIZE_T_SPECIFIER " [%u] on line: %d.",readBytes,meshCount,__LINE__);
1279 				throw megaglest_runtime_error(szBuf);
1280 			}
1281 			meshCount = Shared::PlatformByteOrder::fromCommonEndian(meshCount);
1282 
1283 			if(SystemFlags::VERBOSE_MODE_ENABLED) printf("meshCount = %u\n",meshCount);
1284 
1285 			try {
1286 				meshes= new Mesh[meshCount];
1287 			}
1288 			catch(bad_alloc& ba) {
1289 				char szBuf[8096]="";
1290 				snprintf(szBuf,8096,"Error on line: %d size: %d msg: %s\n",__LINE__,meshCount,ba.what());
1291 				throw megaglest_runtime_error(szBuf);
1292 			}
1293 
1294 			for(uint32 i = 0; i < meshCount; ++i) {
1295 				meshes[i].loadV3(i, dir, f, textureManager,deletePixMapAfterLoad,
1296 						loadedFileList,sourceLoader,path);
1297 				meshes[i].buildInterpolationData();
1298 			}
1299 		}
1300 		//version 2
1301 		else if(fileHeader.version == 2) {
1302 			readBytes = fread(&meshCount, sizeof(meshCount), 1, f);
1303 			if(readBytes != 1 && meshCount != 0) {
1304 				char szBuf[8096]="";
1305 				snprintf(szBuf,8096,"fread returned wrong size = " MG_SIZE_T_SPECIFIER " [%u] on line: %d.",readBytes,meshCount,__LINE__);
1306 				throw megaglest_runtime_error(szBuf);
1307 			}
1308 			meshCount = Shared::PlatformByteOrder::fromCommonEndian(meshCount);
1309 
1310 
1311 			if(SystemFlags::VERBOSE_MODE_ENABLED) printf("meshCount = %d\n",meshCount);
1312 
1313 			try {
1314 				meshes= new Mesh[meshCount];
1315 			}
1316 			catch(bad_alloc& ba) {
1317 				char szBuf[8096]="";
1318 				snprintf(szBuf,8096,"Error on line: %d size: %d msg: %s\n",__LINE__,meshCount,ba.what());
1319 				throw megaglest_runtime_error(szBuf);
1320 			}
1321 
1322 			for(uint32 i = 0; i < meshCount; ++i){
1323 				meshes[i].loadV2(i,dir, f, textureManager,deletePixMapAfterLoad,
1324 						loadedFileList,sourceLoader,path);
1325 				meshes[i].buildInterpolationData();
1326 			}
1327 		}
1328 		else {
1329 			throw megaglest_runtime_error("Invalid model version: "+ intToStr(fileHeader.version));
1330 		}
1331 
1332 		fclose(f);
1333 
1334 		autoJoinMeshFrames();
1335     }
1336     catch(megaglest_runtime_error& ex) {
1337     	//printf("1111111 ex.wantStackTrace() = %d\n",ex.wantStackTrace());
1338 		SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
1339 		//printf("2222222\n");
1340 		throw megaglest_runtime_error("Exception caught loading 3d file: " + path +"\n"+ ex.what(),!ex.wantStackTrace());
1341     }
1342 	catch(exception &e){
1343 		//abort();
1344 		SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,e.what());
1345 		throw megaglest_runtime_error("Exception caught loading 3d file: " + path +"\n"+ e.what());
1346 	}
1347 }
1348 
1349 //save a model to a g3d file
saveG3d(const string & path,string convertTextureToFormat,bool keepsmallest)1350 void Model::saveG3d(const string &path, string convertTextureToFormat,
1351 		bool keepsmallest) {
1352 	string tempModelFilename = path + "cvt";
1353 
1354 #ifdef WIN32
1355 	FILE *f= _wfopen(utf8_decode(tempModelFilename).c_str(), L"wb");
1356 #else
1357 	FILE *f= fopen(tempModelFilename.c_str(), "wb");
1358 #endif
1359 	if(f == NULL) {
1360 		throw megaglest_runtime_error("Cant open file for writing: [" + tempModelFilename + "]");
1361 	}
1362 
1363 	convertTextureToFormat = toLower(convertTextureToFormat);
1364 
1365 	//file header
1366 	FileHeader fileHeader;
1367 	fileHeader.id[0]= 'G';
1368 	fileHeader.id[1]= '3';
1369 	fileHeader.id[2]= 'D';
1370 	fileHeader.version= 4;
1371 
1372 	fwrite(&fileHeader, sizeof(FileHeader), 1, f);
1373 
1374 	// file versions
1375 	if(fileHeader.version == 4 || fileHeader.version == 3 || fileHeader.version == 2) {
1376 		//model header
1377 		ModelHeader modelHeader;
1378 		modelHeader.meshCount = meshCount;
1379 		modelHeader.type = mtMorphMesh;
1380 
1381 		fwrite(&modelHeader, sizeof(ModelHeader), 1, f);
1382 
1383 		std::map<string,int> textureDeleteList;
1384 		for(uint32 i = 0; i < meshCount; ++i) {
1385 			meshes[i].save(i,tempModelFilename, f, textureManager,
1386 					convertTextureToFormat,textureDeleteList,
1387 					keepsmallest,path);
1388 		}
1389 
1390 		removeFile(path);
1391 		if(renameFile(tempModelFilename,path) == true) {
1392 			// Now delete old textures since they were converted to a new format
1393 			for(std::map<string,int>::iterator iterMap = textureDeleteList.begin();
1394 				iterMap != textureDeleteList.end(); ++iterMap) {
1395 				removeFile(iterMap->first);
1396 			}
1397 		}
1398 	}
1399 	else {
1400 		throw megaglest_runtime_error("Invalid model version: "+ intToStr(fileHeader.version));
1401 	}
1402 
1403 	fclose(f);
1404 }
1405 
deletePixels()1406 void Model::deletePixels() {
1407 	for(uint32 i = 0; i < meshCount; ++i) {
1408 		meshes[i].deletePixels();
1409 	}
1410 }
1411 
1412 class MeshContainer {
1413 protected:
1414 	int indexValue;
1415 	std::vector<Mesh *> meshes;
1416 
1417 public:
1418 
MeshContainer()1419 	MeshContainer() {
1420 		this->indexValue = -1;
1421 	}
add(int index,Mesh * mesh)1422 	void add(int index, Mesh *mesh) {
1423 		if(this->indexValue < 0) {
1424 			this->indexValue = index;
1425 		}
1426 		meshes.push_back(mesh);
1427 	}
index()1428 	int index() {
1429 		return indexValue;
1430 	}
size()1431 	int size() {
1432 		return (int)meshes.size();
1433 	}
get()1434 	std::vector<Mesh *>  get() {
1435 		return meshes;
1436 	}
1437 };
1438 
setVertices(Vec3f * data,uint32 count)1439 void Mesh::setVertices(Vec3f *data, uint32 count) {
1440 	delete [] this->vertices;
1441 	this->vertices = data;
1442 
1443 	this->vertexCount = count;
1444 }
setNormals(Vec3f * data,uint32 count)1445 void Mesh::setNormals(Vec3f *data, uint32 count) {
1446 	delete [] this->normals;
1447 	this->normals = data;
1448 
1449 	this->vertexCount = count;
1450 }
1451 
setTexCoords(Vec2f * data,uint32 count)1452 void Mesh::setTexCoords(Vec2f *data, uint32 count) {
1453 	delete [] this->texCoords;
1454 	this->texCoords = data;
1455 
1456 	this->vertexCount = count;
1457 }
1458 
setIndices(uint32 * data,uint32 count)1459 void Mesh::setIndices(uint32 *data, uint32 count) {
1460 	delete [] this->indices;
1461 	this->indices = data;
1462 
1463 	this->indexCount = count;
1464 }
1465 
copyInto(Mesh * dest,bool ignoreInterpolationData,bool destinationOwnsTextures)1466 void Mesh::copyInto(Mesh *dest, bool ignoreInterpolationData,
1467 								bool destinationOwnsTextures) {
1468 
1469 	for(int index = 0; index < meshTextureCount; ++index){
1470 		dest->textures[index] 		= this->textures[index];
1471 		dest->texturesOwned[index] 	= this->texturesOwned[index];
1472 		dest->texturePaths[index] 	= this->texturePaths[index];
1473 
1474 		if(destinationOwnsTextures == true) {
1475 			this->texturesOwned[index] = false;
1476 		}
1477 	}
1478 
1479 	dest->name = this->name;
1480 	//vertex data counts
1481 	dest->frameCount 			= this->frameCount;
1482 	dest->vertexCount 			= this->vertexCount;
1483 	dest->indexCount 			= this->indexCount;
1484 	dest->texCoordFrameCount 	= this->texCoordFrameCount;
1485 
1486 	//vertex data
1487 	if(dest->vertices != NULL) {
1488 		delete [] dest->vertices;
1489 		dest->vertices = NULL;
1490 	}
1491 	if(this->vertices != NULL) {
1492 		dest->vertices = new Vec3f[this->frameCount * this->vertexCount];
1493 		memcpy(&dest->vertices[0],&this->vertices[0],this->frameCount * this->vertexCount * sizeof(Vec3f));
1494 	}
1495 
1496 	if(dest->normals != NULL) {
1497 		delete [] dest->normals;
1498 		dest->normals = NULL;
1499 	}
1500 	if(this->normals != NULL) {
1501 		dest->normals = new Vec3f[this->frameCount * this->vertexCount];
1502 		memcpy(&dest->normals[0],&this->normals[0],this->frameCount * this->vertexCount * sizeof(Vec3f));
1503 	}
1504 
1505 	if(dest->texCoords != NULL) {
1506 		delete [] dest->texCoords;
1507 		dest->texCoords = NULL;
1508 	}
1509 	if(this->texCoords != NULL) {
1510 		dest->texCoords = new Vec2f[this->vertexCount];
1511 		memcpy(&dest->texCoords[0],&this->texCoords[0],this->vertexCount * sizeof(Vec2f));
1512 	}
1513 
1514 	if(dest->tangents != NULL) {
1515 		delete [] dest->tangents;
1516 		dest->tangents = NULL;
1517 	}
1518 	if(this->tangents != NULL) {
1519 		dest->tangents = new Vec3f[this->vertexCount];
1520 		memcpy(&dest->tangents[0],&this->tangents[0],this->vertexCount * sizeof(Vec3f));
1521 	}
1522 
1523 	if(dest->indices != NULL) {
1524 		delete [] dest->indices;
1525 		dest->indices = NULL;
1526 	}
1527 	if(this->indices != NULL) {
1528 		dest->indices = new uint32[this->indexCount];
1529 		memcpy(&dest->indices[0],&this->indices[0],this->indexCount * sizeof(uint32));
1530 	}
1531 
1532 	//material data
1533 	dest->diffuseColor 	= this->diffuseColor;
1534 	dest->specularColor = this->specularColor;
1535 	dest->specularPower = this->specularPower;
1536 	dest->opacity 		= this->opacity;
1537 
1538 	//properties
1539 	dest->twoSided 		= this->twoSided;
1540 	dest->customColor 	= this->customColor;
1541 	dest->noSelect 		= this->noSelect;
1542 	dest->glow 			= this->glow;
1543 
1544 	dest->textureFlags 	= this->textureFlags;
1545 
1546 	if(ignoreInterpolationData == false) {
1547 		dest->interpolationData = this->interpolationData;
1548 	}
1549 	dest->textureManager = this->textureManager;
1550 
1551 	// Vertex Buffer Object Names
1552 	dest->hasBuiltVBOs 		= this->hasBuiltVBOs;
1553 	dest->m_nVBOVertices 	= this-> m_nVBOVertices;
1554 	dest->m_nVBOTexCoords 	= this->m_nVBOTexCoords;
1555 	dest->m_nVBONormals 	= this->m_nVBONormals;
1556 	dest->m_nVBOIndexes 	= this->m_nVBOIndexes;
1557 }
1558 
autoJoinMeshFrames()1559 void Model::autoJoinMeshFrames() {
1560 
1561 /*
1562 	print "auto-joining compatible meshes..."
1563         meshes = {}
1564         for mesh in self.meshes:
1565             key = (mesh.texture,mesh.frame_count,mesh.twoSided|mesh.customColour)
1566             if key in meshes:
1567                 meshes[key].append(mesh)
1568             else:
1569                 meshes[key] = [mesh]
1570         for joinable in meshes.values():
1571             if len(joinable) < 2: continue
1572             base = joinable[0]
1573             print "\tjoining to",base
1574             for mesh in joinable[1:]:
1575                 if base.index_count+mesh.index_count > 0xffff:
1576                     base = mesh
1577                     print "\tjoining to",base
1578                     continue
1579                 print "\t\t",mesh
1580                 for a,b in zip(base.frames,mesh.frames):
1581                     a.vertices.extend(b.vertices)
1582                     a.normals.extend(b.normals)
1583                 if base.texture:
1584                     base.textures.extend(mesh.textures)
1585                 base.indices.extend(index+base.vertex_count for index in mesh.indices)
1586                 base.vertex_count += mesh.vertex_count
1587                 base.index_count += mesh.index_count
1588                 self.meshes.remove(mesh)
1589 */
1590 
1591 
1592 
1593 	bool haveJoinedMeshes = false;
1594 
1595 	// First looks for meshes with same texture in the same frame
1596 	std::map<std::string,MeshContainer> joinedMeshes;
1597 	for(uint32 index = 0; index < meshCount; ++index) {
1598 		Mesh &mesh = meshes[index];
1599 
1600 		// Duplicate mesh vertices are considered to be those with the same
1601 		// 1. texture 2. framecount 3. twosided flag value 4. same custom texture color
1602 
1603 //		It's possible the texture is missing and will be NULL
1604 //		if(mesh.getTextureFlags() & 1) {
1605 //			printf("Mesh has textures:\n");
1606 //			for(unsigned int meshTexIndex = 0; meshTexIndex < meshTextureCount; ++meshTexIndex) {
1607 //				printf("Mesh texture index: %d [%p] [%s]\n",meshTexIndex,mesh.getTexture(meshTexIndex),(mesh.getTexture(meshTexIndex) != NULL ? mesh.getTexture(meshTexIndex)->getPath().c_str() : "n/a"));
1608 //			}
1609 //		}
1610 		string mesh_key = ((mesh.getTextureFlags() & 1) && mesh.getTexture(0) ? mesh.getTexture(0)->getPath() : "none");
1611 		       mesh_key += string("_") + intToStr(mesh.getFrameCount()) +
1612 		    		       string("_") + intToStr(mesh.getTwoSided()) +
1613 				           string("_") + intToStr(mesh.getCustomTexture()) +
1614 				           string("_") + intToStr(mesh.getNoSelect()) +
1615 				           string("_") + floatToStr(mesh.getOpacity()) +
1616 				           string("_") + floatToStr(mesh.getGlow()) +
1617 				           string("_") + mesh.getDiffuseColor().getString() +
1618 				           string("_") + mesh.getSpecularColor().getString() +
1619 				           string("_") + floatToStr(mesh.getSpecularPower());
1620 
1621 		joinedMeshes[mesh_key].add(index,&mesh);
1622 		if(haveJoinedMeshes == false && joinedMeshes[mesh_key].size() > 1) {
1623 			haveJoinedMeshes = true;
1624 		}
1625 	}
1626 	if(haveJoinedMeshes == true) {
1627 		//printf("*** Detected Joined meshes for model [%s]\n",fileName.c_str());
1628 
1629 		// We have mesh data to join we now create a list in the same order
1630 		// as the original meshes but each index will have 1 or more meshes
1631 		// This is done to maintain original mesh ordering
1632 		std::map<int, std::vector<Mesh *> > orderedMeshes;
1633 		for(std::map<std::string,MeshContainer >::iterator iterMap = joinedMeshes.begin();
1634 				iterMap != joinedMeshes.end(); ++iterMap) {
1635 			orderedMeshes[iterMap->second.index()] = iterMap->second.get();
1636 
1637 			//if(iterMap->second.size() > 1) {
1638 			//	printf("Key [%s] joined meshes: %d\n",iterMap->first.c_str(),iterMap->second.size());
1639 			//}
1640 		}
1641 
1642 		// Now the real work of creating a new list of joined mesh data
1643 		Mesh *joinedMeshList = new Mesh[joinedMeshes.size()];
1644 
1645 		int index = 0;
1646 		for(std::map<int, std::vector<Mesh *> >::iterator iterMap = orderedMeshes.begin();
1647 				iterMap != orderedMeshes.end(); ++iterMap) {
1648 			//printf("Join index: %d joincount: %d\n",index,iterMap->second.size());
1649 
1650 			Mesh *base = &joinedMeshList[index];
1651 
1652 			// Deep copy mesh data
1653 			iterMap->second[0]->copyInto(base, true, true);
1654 
1655 			if(iterMap->second.size() > 1) {
1656 				// Time to join mesh data for this mesh
1657 				for(unsigned int joinIndex = 1;
1658 						joinIndex < iterMap->second.size(); ++joinIndex) {
1659 					Mesh *mesh = iterMap->second[joinIndex];
1660 					//if(base->getIndexCount() + mesh->getIndexCount() > 0xffff) {
1661 					//	printf("Not exactly sure what this IF statement is for?\n");
1662 					//	mesh->copyInto(base, true, true);
1663 					//}
1664 					//else {
1665 						// Need to add verticies for each from from mesh to base
1666 						uint32 originalBaseVertexCount = base->getVertexCount();
1667 
1668 						uint32 newVertexCount =
1669 								base->getVertexCount() + mesh->getVertexCount();
1670 
1671 						uint32 newVertexFrameCount =
1672 								(base->getFrameCount() * newVertexCount);
1673 
1674 						Vec3f *joined_vertices = new Vec3f[newVertexFrameCount];
1675 						Vec3f *joined_normals = new Vec3f[newVertexFrameCount];
1676 						uint32 join_index = 0;
1677 
1678 						// Join mesh vertices and normals
1679 						for(unsigned int frameIndex = 0;
1680 								frameIndex < base->getFrameCount(); ++frameIndex) {
1681 							uint32 baseIndex = frameIndex * originalBaseVertexCount;
1682 							uint32 meshIndex = frameIndex * mesh->getVertexCount();
1683 							//uint32 appendBaseJoinIndex = frameIndex * newVertexCount;
1684 
1685 							// first original mesh values get copied
1686 							memcpy(&joined_vertices[join_index],
1687 									&base->getVertices()[baseIndex],
1688 									originalBaseVertexCount * sizeof(Vec3f));
1689 							memcpy(&joined_normals[join_index],
1690 									&base->getNormals()[baseIndex],
1691 									originalBaseVertexCount * sizeof(Vec3f));
1692 							join_index += originalBaseVertexCount;
1693 
1694 							// second joined mesh values get copied
1695 							memcpy(&joined_vertices[join_index],
1696 									&mesh->getVertices()[meshIndex],
1697 									mesh->getVertexCount() * sizeof(Vec3f));
1698 							memcpy(&joined_normals[join_index],
1699 									&mesh->getNormals()[meshIndex],
1700 									mesh->getVertexCount() * sizeof(Vec3f));
1701 							join_index += mesh->getVertexCount();
1702 						}
1703 
1704 						// update vertex and normal buffers with joined mesh data
1705 						base->setVertices(joined_vertices, newVertexCount);
1706 						base->setNormals(joined_normals, newVertexCount);
1707 
1708 						// If we have texture coords join them
1709 						if(base->getTextureFlags() & 1) {
1710 							Vec2f *joined_texCoords = new Vec2f[newVertexCount];
1711 
1712 							// update texture coord buffers with joined mesh data
1713 							memcpy(&joined_texCoords[0],
1714 									&base->getTexCoords()[0],
1715 									originalBaseVertexCount * sizeof(Vec2f));
1716 							memcpy(&joined_texCoords[originalBaseVertexCount],
1717 									&mesh->getTexCoords()[0],
1718 									mesh->getVertexCount() * sizeof(Vec2f));
1719 
1720 							base->setTexCoords(joined_texCoords, newVertexCount);
1721 						}
1722 
1723 						// update index buffers with joined mesh data
1724 						uint32 newindexCount = base->getIndexCount() + mesh->getIndexCount();
1725 						uint32 *joined_indexes = new uint32[newindexCount];
1726 
1727 						uint32 join_index_index = 0;
1728 						memcpy(&joined_indexes[join_index_index],
1729 								&base->getIndices()[0],
1730 								base->getIndexCount() * sizeof(uint32));
1731 						join_index_index += base->getIndexCount();
1732 
1733 						for(unsigned int meshIndex = 0;
1734 								meshIndex < mesh->getIndexCount(); ++meshIndex) {
1735 							uint32 index_value = mesh->getIndices()[meshIndex];
1736 
1737 							// join index values
1738 							joined_indexes[join_index_index] = index_value + originalBaseVertexCount;
1739 							join_index_index++;
1740 						}
1741 						base->setIndices(joined_indexes, newindexCount);
1742 					//}
1743 				}
1744 			}
1745 			base->buildInterpolationData();
1746 
1747 			index++;
1748 		}
1749 
1750 		delete [] meshes;
1751 		meshes = joinedMeshList;
1752 		meshCount = (uint32)joinedMeshes.size();
1753 	}
1754 }
1755 
1756 // ----------------------------------------------------------------------------
1757 
1758 bool PixelBufferWrapper::isPBOEnabled 	= false;
1759 int PixelBufferWrapper::index 			= 0;
1760 vector<unsigned int> PixelBufferWrapper::pboIds;
1761 
PixelBufferWrapper(int pboCount,int bufferSize)1762 PixelBufferWrapper::PixelBufferWrapper(int pboCount,int bufferSize) {
1763 	this->bufferSize = bufferSize;
1764 	//if(isGlExtensionSupported("GL_ARB_pixel_buffer_object") == true &&
1765 	if(GLEW_ARB_pixel_buffer_object) {
1766 		PixelBufferWrapper::isPBOEnabled = true;
1767 		cleanup();
1768 		// For some wacky reason this fails in VC++ 2008
1769 		//pboIds.reserve(pboCount);
1770 		//glGenBuffersARB(pboCount, (GLuint*)&pboIds[0]);
1771 		//
1772 
1773 		/*
1774 		for(int i = 0; i < pboCount; ++i) {
1775 			if(SystemFlags::VERBOSE_MODE_ENABLED) printf("PBO Gen i = %d\n",i);
1776 
1777 			pboIds.push_back(0);
1778 			glGenBuffersARB(1, (GLuint*)&pboIds[i]);
1779 			// create pixel buffer objects, you need to delete them when program exits.
1780 			// glBufferDataARB with NULL pointer reserves only memory space.
1781 			glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pboIds[i]);
1782 			glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, bufferSize, 0, GL_STREAM_READ_ARB);
1783 		}
1784 		glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
1785 		*/
1786 		addBuffersToPixelBuf(pboCount);
1787 	}
1788 }
1789 
addBuffersToPixelBuf(int pboCount)1790 void PixelBufferWrapper::addBuffersToPixelBuf(int pboCount) {
1791 	int iStartIndex = pboIds.size();
1792 	for(int i = 0; i < pboCount; ++i) {
1793 		if(SystemFlags::VERBOSE_MODE_ENABLED) printf("PBO Gen i = %d\n",i);
1794 
1795 		pboIds.push_back(0);
1796 		glGenBuffersARB(1, (GLuint*)&pboIds[i+iStartIndex]);
1797 		// create pixel buffer objects, you need to delete them when program exits.
1798 		// glBufferDataARB with NULL pointer reserves only memory space.
1799 		glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pboIds[i+iStartIndex]);
1800 		glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, bufferSize, 0, GL_STREAM_READ_ARB);
1801 	}
1802 	glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
1803 }
1804 
getPixelBufferFor(int x,int y,int w,int h,int colorComponents)1805 Pixmap2D *PixelBufferWrapper::getPixelBufferFor(int x,int y,int w,int h, int colorComponents) {
1806 	Pixmap2D *pixmapScreenShot = NULL;
1807 	if(PixelBufferWrapper::isPBOEnabled == true) {
1808 		string codeSection = "A";
1809 		if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
1810 		try {
1811 			// increment current index first then get the next index
1812 			// "index" is used to read pixels from a framebuffer to a PBO
1813 			// "nextIndex" is used to process pixels in the other PBO
1814 			index = (index + 1) % 2;
1815 
1816 			codeSection = "B";
1817 			if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
1818 			// Check for out of range
1819 			if(index >= (int)pboIds.size()) {
1820 				char szBuf[8096]="";
1821 				snprintf(szBuf,8096,"Error / Warning in [%s::%s] on line: %d pixel buffer out of range, index: %d size: %d, attempting to expand buffer...\n",__FILE__,__FUNCTION__,__LINE__,index, (int)pboIds.size());
1822 				//throw megaglest_runtime_error(szBuf);
1823 				SystemFlags::OutputDebug(SystemFlags::debugError,"%s",szBuf);
1824 				if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d] szBuf: %s\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,szBuf);
1825 
1826 				codeSection = "C";
1827 				if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
1828 				addBuffersToPixelBuf((index - pboIds.size()) + 1);
1829 			}
1830 			// pbo index used for next frame
1831 			//int nextIndex = (index + 1) % 2;
1832 
1833 			codeSection = "D";
1834 			if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
1835 			// read framebuffer ///////////////////////////////
1836 			// copy pixels from framebuffer to PBO
1837 			// Use offset instead of pointer.
1838 			// OpenGL should perform asynch DMA transfer, so glReadPixels() will return immediately.
1839 			glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pboIds[index]);
1840 			//glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pboIds[nextIndex]);
1841 
1842 			codeSection = "E";
1843 			if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
1844 			//glPixelStorei(GL_PACK_ALIGNMENT, 1);
1845 			glReadPixels(x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, 0);
1846 			//glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1847 
1848 			// measure the time reading framebuffer
1849 			//t1.stop();
1850 			//readTime = t1.getElapsedTimeInMilliSec();
1851 
1852 			// process pixel data /////////////////////////////
1853 			//t1.start();
1854 
1855 			codeSection = "F";
1856 			if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
1857 			// map the PBO that contain framebuffer pixels before processing it
1858 			//glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pboIds[nextIndex]);
1859 			glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pboIds[index]);
1860 
1861 			codeSection = "G";
1862 			if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
1863 			GLubyte* src = (GLubyte*)glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB);
1864 			if(src) {
1865 				codeSection = "H";
1866 				if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
1867 				pixmapScreenShot = new Pixmap2D(w, h, colorComponents);
1868 
1869 				codeSection = "I";
1870 				if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
1871 				memcpy(pixmapScreenShot->getPixels(),src,pixmapScreenShot->getPixelByteCount());
1872 
1873 				codeSection = "J";
1874 				if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
1875 				glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);     // release pointer to the mapped buffer
1876 				//pixmapScreenShot->save("debugPBO.png");
1877 			}
1878 			codeSection = "K";
1879 			if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
1880 			// measure the time reading framebuffer
1881 			//t1.stop();
1882 			//processTime = t1.getElapsedTimeInMilliSec();
1883 			glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
1884 
1885 			if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
1886 		}
1887 	    catch(megaglest_runtime_error& ex) {
1888 			SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] codeSection [%s] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,codeSection.c_str(),ex.what());
1889 			throw megaglest_runtime_error("Exception caught in getPixelBufferFor codeSection: " + codeSection +"\n"+ ex.what(),!ex.wantStackTrace());
1890 	    }
1891 		catch(exception &e){
1892 			SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] codeSection [%s] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,codeSection.c_str(),e.what());
1893 			throw megaglest_runtime_error("Exception caught in getPixelBufferFor codeSection: " + codeSection +"\n"+ e.what());
1894 		}
1895 		catch(...){
1896 			SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] codeSection [%s] UNKNOWN Error!",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,codeSection.c_str());
1897 			throw megaglest_runtime_error("UNKNOWN Exception caught in getPixelBufferFor codeSection: " + codeSection +"\n");
1898 		}
1899 		if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
1900 	}
1901 
1902 	return pixmapScreenShot;
1903 }
1904 
begin()1905 void PixelBufferWrapper::begin() {
1906 	if(PixelBufferWrapper::isPBOEnabled == true) {
1907 		// set the framebuffer to read
1908 		//glReadBuffer(GL_FRONT);
1909 	}
1910 }
1911 
end()1912 void PixelBufferWrapper::end() {
1913 	if(PixelBufferWrapper::isPBOEnabled == true) {
1914 		// set the framebuffer to read
1915 		//glReadBuffer(GL_BACK);
1916 	}
1917 }
1918 
cleanup()1919 void PixelBufferWrapper::cleanup() {
1920 	if(PixelBufferWrapper::isPBOEnabled == true) {
1921 		if(pboIds.empty() == false) {
1922 			if(SystemFlags::VERBOSE_MODE_ENABLED) printf("PBO Delete size = %d\n",(int)pboIds.size());
1923 
1924 			glDeleteBuffersARB((int)pboIds.size(), &pboIds[0]);
1925 			pboIds.clear();
1926 
1927 			glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
1928 		}
1929 	}
1930 }
1931 
~PixelBufferWrapper()1932 PixelBufferWrapper::~PixelBufferWrapper() {
1933 	cleanup();
1934 }
1935 
1936 // ---------------------------------------------------------------------------
1937 
1938 int BaseColorPickEntity::bufferSizeRequired = -1;
1939 const unsigned int BaseColorPickEntity::p = 64007;
1940 const unsigned int BaseColorPickEntity::k = 43067;
1941 unsigned int BaseColorPickEntity::nextColorRGB = BaseColorPickEntity::k;
1942 
1943 unsigned char BaseColorPickEntity::nextColorID[COLOR_COMPONENTS] = { 1, 1, 1, 0 };
1944 auto_ptr<PixelBufferWrapper> BaseColorPickEntity::pbo;
1945 //auto_ptr<Pixmap2D> BaseColorPickEntity::cachedPixels;
1946 
1947 map<string,bool> BaseColorPickEntity::usedColorIDList;
1948 bool BaseColorPickEntity::trackColorUse = true;
1949 
1950 vector<vector<unsigned char> > BaseColorPickEntity::nextColorIDReuseList;
1951 
1952 bool BaseColorPickEntity::using_loop_method = false;
1953 
BaseColorPickEntity()1954 BaseColorPickEntity::BaseColorPickEntity() {
1955 	if(BaseColorPickEntity::bufferSizeRequired != -1) {
1956 		BaseColorPickEntity::init(BaseColorPickEntity::bufferSizeRequired);
1957 	}
1958 	uniqueColorID[0] = 0;
1959 	uniqueColorID[1] = 0;
1960 	uniqueColorID[2] = 0;
1961 	uniqueColorID[3] = 0;
1962 	assign_color();
1963 }
1964 
get_next_assign_color(unsigned char * assign_to)1965 bool BaseColorPickEntity::get_next_assign_color(unsigned char *assign_to) {
1966 
1967 	 if(assign_to == NULL) {
1968 		 throw megaglest_runtime_error("assign_to == NULL");
1969 	 }
1970 
1971 	 if(BaseColorPickEntity::using_loop_method == true) {
1972 		 assign_color_using_loop(assign_to);
1973 	 }
1974 	 else {
1975 		 assign_color_using_prime(assign_to);
1976 	 }
1977 
1978 	 bool isDuplicate = false;
1979 	 if(BaseColorPickEntity::trackColorUse == true) {
1980 		 string color_key = getColorDescription();
1981 		 //printf("Assigned color [%s]\n",color_key.c_str());
1982 
1983 		 if(usedColorIDList.find(color_key) == usedColorIDList.end()) {
1984 			 usedColorIDList[color_key] = true;
1985 
1986 			 //printf("Color added to used list [%s] usedColorIDList = %d nextColorIDReuseList = %d!\n",color_key.c_str(),(int)usedColorIDList.size(),(int)nextColorIDReuseList.size());
1987 		 }
1988 		 else {
1989 			 isDuplicate = true;
1990 			 printf("Line ref: %d *WARNING* color [%s] used count: %d using_loop: %d ALREADY in history list!\n",__LINE__,color_key.c_str(),(int)usedColorIDList.size(),BaseColorPickEntity::using_loop_method);
1991 		 }
1992 	 }
1993 	 return isDuplicate;
1994 }
1995 
assign_color()1996 void BaseColorPickEntity::assign_color() {
1997 	get_next_assign_color(&uniqueColorID[0]);
1998 }
1999 
assign_color_using_prime(unsigned char * assign_to)2000 void BaseColorPickEntity::assign_color_using_prime(unsigned char *assign_to) {
2001 	 nextColorRGB = (nextColorRGB * k) % p;
2002 
2003 	 // nextColorID is a 16-bit (hi)colour (for players with 16-bit display depths)
2004 	 // we expand it to true-color for use with OpenGL
2005 
2006 	 const unsigned int
2007 	 	r = (nextColorRGB >> 11) & ((1<<5)-1),
2008 	 	g = (nextColorRGB >> 5) & ((1<<6)-1),
2009 	 	b = nextColorRGB & ((1<<5)-1);
2010 
2011 	 assign_to[0] = r << 3;
2012 	 assign_to[1] = g << 2;
2013 	 assign_to[2] = b << 3;
2014 }
2015 
assign_color_using_loop(unsigned char * assign_to)2016 void BaseColorPickEntity::assign_color_using_loop(unsigned char *assign_to) {
2017 	if(nextColorIDReuseList.empty() == false) {
2018 		//printf("Color being reused [%u.%u.%u] usedColorIDList = %d nextColorIDReuseList = %d!\n",nextColorIDReuseList.back()[0],nextColorIDReuseList.back()[1],nextColorIDReuseList.back()[2],(int)usedColorIDList.size(),(int)nextColorIDReuseList.size());
2019 
2020 		assign_to[0] = nextColorIDReuseList.back()[0];
2021 		assign_to[1] = nextColorIDReuseList.back()[1];
2022 		assign_to[2] = nextColorIDReuseList.back()[2];
2023 
2024 		nextColorIDReuseList.pop_back();
2025 
2026 		string color_key = getColorDescription();
2027 		if(usedColorIDList.find(color_key) == usedColorIDList.end()) {
2028 			//usedColorIDList[color_key] = true;
2029 			//printf("Color added to used list [%s] usedColorIDList = %d nextColorIDReuseList = %d!\n",color_key.c_str(),(int)usedColorIDList.size(),(int)nextColorIDReuseList.size());
2030 		}
2031 		else {
2032 			printf("Line ref: %d *WARNING* color [%s] ALREADY FOUND in history list!\n",__LINE__,color_key.c_str());
2033 			assign_color_using_loop(assign_to);
2034 		}
2035 	}
2036 	else {
2037 		assign_to[0] = nextColorID[0];
2038 		assign_to[1] = nextColorID[1];
2039 		assign_to[2] = nextColorID[2];
2040 
2041 		const int colorSpacing = 8;
2042 
2043 		if((int)(nextColorID[0] + colorSpacing) <= 255) {
2044 			nextColorID[0] += colorSpacing;
2045 		}
2046 		else {
2047 			nextColorID[0] = 1;
2048 			if((int)(nextColorID[1] + colorSpacing) <= 255) {
2049 				nextColorID[1] += colorSpacing;
2050 			}
2051 			else {
2052 				nextColorID[1] = 1;
2053 				if((int)(nextColorID[2] + colorSpacing) <= 255) {
2054 					nextColorID[2] += colorSpacing;
2055 				}
2056 				else {
2057 
2058 					printf("Color rolled over on 3rd level usedColorIDList = %d!\n",(int)usedColorIDList.size());
2059 
2060 					nextColorID[0] = 1;
2061 					nextColorID[1] = 1;
2062 					nextColorID[2] = 1;
2063 
2064 
2065 				//               nextColorID[2] = 1;
2066 				//               nextColorID[3]+=colorSpacing;
2067 				//
2068 				//               if(nextColorID[3] > 255) {
2069 				//                   nextColorID[0] = 1;
2070 				//                   nextColorID[1] = 1;
2071 				//                   nextColorID[2] = 1;
2072 				//                   nextColorID[3] = 1;
2073 				//               }
2074 				}
2075 			}
2076 		}
2077 	}
2078 }
2079 
recycleUniqueColor()2080 void BaseColorPickEntity::recycleUniqueColor() {
2081 
2082 	vector<unsigned char> reUseColor;
2083 	reUseColor.push_back(uniqueColorID[0]);
2084 	reUseColor.push_back(uniqueColorID[1]);
2085 	reUseColor.push_back(uniqueColorID[2]);
2086 	nextColorIDReuseList.push_back(reUseColor);
2087 
2088 	//printf("RECYCLE Color [%u.%u.%u] usedColorIDList = %d nextColorIDReuseList = %d!\n",reUseColor[0],reUseColor[1],reUseColor[2],(int)usedColorIDList.size(),(int)nextColorIDReuseList.size());
2089 
2090 	if(usedColorIDList.empty() == false) {
2091 		string color_key = getColorDescription();
2092 		if(usedColorIDList.find(color_key) != usedColorIDList.end()) {
2093 			usedColorIDList.erase(color_key);
2094 
2095 			//printf("REMOVING used Color [%s] usedColorIDList = %d nextColorIDReuseList = %d!\n",color_key.c_str(),(int)usedColorIDList.size(),(int)nextColorIDReuseList.size());
2096 		}
2097 		else {
2098 			printf("Line ref: %d *WARNING* color [%s] used count: %d NOT FOUND in history list!\n",__LINE__,color_key.c_str(),(int)usedColorIDList.size());
2099 		}
2100 	}
2101 }
2102 
resetUniqueColors()2103 void BaseColorPickEntity::resetUniqueColors() {
2104    BaseColorPickEntity::nextColorRGB = BaseColorPickEntity::k;
2105 
2106    BaseColorPickEntity::nextColorID[0] = 1;
2107    BaseColorPickEntity::nextColorID[1] = 1;
2108    BaseColorPickEntity::nextColorID[2] = 1;
2109 
2110    usedColorIDList.clear();
2111    nextColorIDReuseList.clear();
2112 }
init(int bufferSize)2113 void BaseColorPickEntity::init(int bufferSize) {
2114 	 if(BaseColorPickEntity::pbo.get() == NULL) {
2115 		 //printf("BaseColorPickEntity::init pbo == null\n");
2116 		 BaseColorPickEntity::bufferSizeRequired = bufferSize;
2117 		 BaseColorPickEntity::pbo.reset(new PixelBufferWrapper(2,BaseColorPickEntity::bufferSizeRequired));
2118 	 }
2119 	 else if(bufferSize != BaseColorPickEntity::bufferSizeRequired) {
2120 		 //printf("BaseColorPickEntity::init pbo resize\n");
2121 		 cleanupPBO();
2122 		 BaseColorPickEntity::bufferSizeRequired = bufferSize;
2123 		 BaseColorPickEntity::pbo.reset(new PixelBufferWrapper(2,BaseColorPickEntity::bufferSizeRequired));
2124 	 }
2125 }
2126 
cleanupPBO()2127 void BaseColorPickEntity::cleanupPBO() {
2128 	BaseColorPickEntity::pbo.reset(0);
2129 }
2130 
getColorDescription() const2131 string BaseColorPickEntity::getColorDescription() const {
2132 	char szBuf[100]="";
2133 	snprintf(szBuf,100,"%d.%d.%d",uniqueColorID[0],uniqueColorID[1],uniqueColorID[2]);
2134 	string result = szBuf;
2135 	return result;
2136 }
2137 
beginPicking()2138 void BaseColorPickEntity::beginPicking() {
2139 	// turn off texturing, lighting and fog
2140 	//glClearColor (0.0,0.0,0.0,0.0);
2141 	//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
2142 
2143 	//reset current background. This is neeeded to get a proper black background!
2144 	//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
2145 	glClear(GL_COLOR_BUFFER_BIT);
2146 
2147 	glPushAttrib(GL_ENABLE_BIT);
2148 	//glEnable(GL_DEPTH_TEST);
2149 	glDisable(GL_TEXTURE_2D);
2150 	glDisable(GL_FOG);
2151 	glDisable(GL_LIGHTING);
2152 	glDisable(GL_BLEND);
2153 	glDisable(GL_MULTISAMPLE);
2154 	glDisable(GL_DITHER);
2155 	glDisable(GL_POLYGON_OFFSET_FILL);
2156 	glDisable(GL_NORMALIZE);
2157 
2158 	// all off, but we want depth test
2159 	glEnable(GL_DEPTH_TEST);
2160 	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
2161 
2162 	//glPushAttrib(GL_TEXTURE_2D | GL_LIGHTING | GL_BLEND | GL_MULTISAMPLE | GL_DITHER);
2163 	//glPushAttrib(GL_ENABLE_BIT | GL_LIGHTING_BIT | GL_POLYGON_BIT | GL_CURRENT_BIT | GL_TEXTURE_BIT | GL_NORMALIZE | GL_BLEND | GL_POLYGON_OFFSET_FILL);
2164 }
2165 
endPicking()2166 void BaseColorPickEntity::endPicking() {
2167 	// turn off texturing, lighting and fog
2168 	//glEnable(GL_TEXTURE_2D);
2169 	//glEnable(GL_FOG);
2170 	//glEnable(GL_LIGHTING);
2171 
2172 	//glEnable(GL_BLEND);
2173 	//glEnable(GL_MULTISAMPLE);
2174 	//glEnable(GL_DITHER);
2175 	glPopAttrib();
2176 }
2177 
getPickedList(int x,int y,int w,int h,const vector<BaseColorPickEntity * > & rendererModels)2178 vector<int> BaseColorPickEntity::getPickedList(int x,int y,int w,int h,
2179 						const vector<BaseColorPickEntity *> &rendererModels) {
2180 	vector<int> pickedModels;
2181 	pickedModels.reserve(rendererModels.size());
2182 
2183 	//printf("In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
2184 	static auto_ptr<Pixmap2D> cachedPixels;
2185 	//auto_ptr<Pixmap2D> cachedPixels;
2186 
2187 	//printf("PixelBufferWrapper::getIsPBOEnable() = %d\n",PixelBufferWrapper::getIsPBOEnable());
2188 	if(rendererModels.empty() == false) {
2189 		if(PixelBufferWrapper::getIsPBOEnable() == true) {
2190 				Pixmap2D *pixmapScreenShot = BaseColorPickEntity::pbo->getPixelBufferFor(x,y,w,h, COLOR_COMPONENTS);
2191 				//pixmapScreenShot->saveTga("/tmp/toll.tga"); //### for debugging
2192 				cachedPixels.reset(pixmapScreenShot);
2193 		}
2194 		else {
2195 				Pixmap2D *pixmapScreenShot = new Pixmap2D(w, h, COLOR_COMPONENTS);
2196 				//glPixelStorei(GL_PACK_ALIGNMENT, 1);
2197 				glReadPixels(x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixmapScreenShot->getPixels());
2198 				//pixmapScreenShot->saveTga("/tmp/toll.tga");
2199 				cachedPixels.reset(pixmapScreenShot);
2200 				//glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
2201 		}
2202 		unsigned char *pixelBuffer = cachedPixels->getPixels();
2203 
2204 		map<int,bool> modelAlreadyPickedList;
2205 		map<unsigned char,map<unsigned char, map<unsigned char,bool> > > colorAlreadyPickedList;
2206 
2207 		int skipSteps=4;
2208 		//unsigned char *oldpixel = &pixelBuffer[0];
2209 
2210 		// now we check the screenshot if we find pixels in color of unit identity
2211 		// to speedup we only check every "skipSteps" line and pixel in a row if we find such a color.
2212 		// this is exact enough for MG purpose
2213 		for(int hh = 0; hh < h && pickedModels.size() < rendererModels.size(); hh=hh+skipSteps) {
2214 			for(int ww=0;ww < w && pickedModels.size() < rendererModels.size(); ww=ww+skipSteps){
2215 
2216 				int index = (hh*w+ww) * COLOR_COMPONENTS;
2217 				unsigned char *pixel = &pixelBuffer[index];
2218 				//printf("pixel[0]=%d pixel[1]=%d pixel[2]=%d\n",pixel[0],pixel[1],pixel[2]);
2219 				if(pixel[0]==0 && pixel[1]==0 && pixel[2]==0)
2220 				{
2221 					continue;
2222 				}
2223 //				if(index>0)
2224 //				{
2225 //					oldpixel = &pixelBuffer[index-1*COLOR_COMPONENTS];
2226 //					if(memcmp(pixel,oldpixel,3)) continue;
2227 //				}
2228 
2229 				// Skip duplicate scanned colors
2230 				map<unsigned char,map<unsigned char, map<unsigned char,bool> > >::const_iterator iterFind1 = colorAlreadyPickedList.find(pixel[0]);
2231 				if(iterFind1 != colorAlreadyPickedList.end()) {
2232 					map<unsigned char, map<unsigned char,bool> >::const_iterator iterFind2 = iterFind1->second.find(pixel[1]);
2233 					if(iterFind2 != iterFind1->second.end()) {
2234 						map<unsigned char,bool>::const_iterator iterFind3 = iterFind2->second.find(pixel[2]);
2235 						if(iterFind3 != iterFind2->second.end()) {
2236 							continue;
2237 						}
2238 					}
2239 				}
2240 
2241 				for(unsigned int i = 0; i < rendererModels.size(); ++i) {
2242 					// Skip models already selected
2243 					if(modelAlreadyPickedList.find(i) != modelAlreadyPickedList.end()) {
2244 						continue;
2245 					}
2246 					const BaseColorPickEntity *model = rendererModels[i];
2247 
2248 					if( model != NULL && model->isUniquePickingColor(pixel) == true) {
2249 						//printf("Found match pixel [%d.%d.%d] for model [%s] ptr [%p][%s]\n",pixel[0],pixel[1],pixel[2],model->getColorDescription().c_str(), model,model->getUniquePickName().c_str());
2250 
2251 						pickedModels.push_back(i);
2252 						modelAlreadyPickedList[i]=true;
2253 						colorAlreadyPickedList[pixel[0]][pixel[1]][pixel[2]]=true;
2254 						break;
2255 					}
2256 				}
2257 			}
2258 		}
2259 
2260 		//printf("In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
2261 		//delete pixmapScreenShot;
2262 	}
2263 	//printf("In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
2264 	return pickedModels;
2265 }
2266 
isUniquePickingColor(unsigned char * pixel) const2267 bool BaseColorPickEntity::isUniquePickingColor(unsigned char *pixel) const {
2268 	bool result = false;
2269 	if( uniqueColorID[0] == pixel[0] &&
2270 		uniqueColorID[1] == pixel[1] &&
2271 		uniqueColorID[2] == pixel[2]) {
2272 		//uniqueColorID[3] == pixel[3]) {
2273 		result = true;
2274 	}
2275 
2276 	return result;
2277 }
2278 
setUniquePickingColor() const2279 void BaseColorPickEntity::setUniquePickingColor() const {
2280 
2281 	 glColor3ub(uniqueColorID[0],
2282 			 	uniqueColorID[1],
2283 			 	uniqueColorID[2]);
2284 
2285 /*
2286 	 glColor3f(	uniqueColorID[0] / 255.0f,
2287 			 	uniqueColorID[1] / 255.0f,
2288 			 	uniqueColorID[2] / 255.0f);
2289 			 	//uniqueColorID[3] / 255.0f);
2290 			 	 *
2291 			 	 */
2292 }
2293 
2294 
2295 }}//end namespace
2296