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