MshFile.cpp 20.2 KB
Newer Older
Anakin's avatar
Anakin committed
1
#include "..\Header\MshFile.h"
2
#include "..\Header\tga.h"
3
#include "..\Header\OutputDevice.h"
Anakin's avatar
Anakin committed
4
#include <QVector3D>
Anakin's avatar
Anakin committed
5

6

Anakin's avatar
Anakin committed
7 8 9 10 11 12 13
// helper function to save data from file to any variable type
#define F2V(variableName) reinterpret_cast<char*>(&variableName)


/////////////////////////////////////////////////////////////////////////
// public constructor/destructor

14 15
MshFile::MshFile(QString path)
	: FileInterface(path)
Anakin's avatar
Anakin committed
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
{
	import();
}

MshFile::~MshFile()
{
}


/////////////////////////////////////////////////////////////////////////
// private functions

void MshFile::import()
{
	// go to file size information
Anakin's avatar
Anakin committed
31
	m_file.seek(4);
Anakin's avatar
Anakin committed
32

Anakin's avatar
Anakin committed
33 34
	quint32 tmp_fileSize;
	QList<ChunkHeader*> tmp_mainChunks;
Anakin's avatar
Anakin committed
35 36 37

	// get all chunks under HEDR
	m_file.read(F2V(tmp_fileSize), sizeof(tmp_fileSize));
Anakin's avatar
Anakin committed
38
	loadChunks(tmp_mainChunks, m_file.pos(), tmp_fileSize);
Anakin's avatar
Anakin committed
39 40 41 42

	// evaulate HEDR subchunks (= find MSH2)
	for (ChunkHeader* it : tmp_mainChunks)
	{
Anakin's avatar
Anakin committed
43
		if ("MSH2" == it->name)
Anakin's avatar
Anakin committed
44 45
		{
			// get all subchunks
Anakin's avatar
Anakin committed
46
			QList<ChunkHeader*> tmp_msh2Chunks;
Anakin's avatar
Anakin committed
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
			loadChunks(tmp_msh2Chunks, it->position, it->size);

			// evaluate MSH2 subchunks
			analyseMsh2Chunks(tmp_msh2Chunks);

			// clean up
			while (!tmp_msh2Chunks.empty())
			{
				ChunkHeader* curs = tmp_msh2Chunks.front();
				tmp_msh2Chunks.pop_front();
				delete curs;
			}
		}
	}

	// clean up
	while (!tmp_mainChunks.empty())
	{
		ChunkHeader* cur = tmp_mainChunks.front();
		tmp_mainChunks.pop_front();
		delete cur;
	}
}

Anakin's avatar
Anakin committed
71
void MshFile::loadChunks(QList<ChunkHeader*>& destination, qint64 start, const quint32 length)
Anakin's avatar
Anakin committed
72 73
{
	// jump to first chunk
Anakin's avatar
Anakin committed
74
	m_file.seek(start);
Anakin's avatar
Anakin committed
75 76 77

	do
	{
Anakin's avatar
Anakin committed
78 79 80 81 82 83 84 85 86
		// out of file. Maybe a size information is corrupted
		if (m_file.atEnd() || m_file.error() != QFileDevice::NoError)
		{
			OutputDevice::getInstance()->print("WARNING: corrupted file. Trying to continue..", 1);
			m_file.unsetError();
			m_file.seek(0);
			break;
		}

Anakin's avatar
Anakin committed
87 88 89
		ChunkHeader* tmp_header = new ChunkHeader();

		// get information
Anakin's avatar
Anakin committed
90 91 92
		char tmpName[5] = { 0 };
		m_file.read(F2V(tmpName[0]), sizeof(tmpName) -1);
		tmp_header->name = QString(tmpName);
Anakin's avatar
Anakin committed
93
		m_file.read(F2V(tmp_header->size), sizeof(tmp_header->size));
Anakin's avatar
Anakin committed
94
		tmp_header->position = m_file.pos();
Anakin's avatar
Anakin committed
95 96 97 98 99

		// store information
		destination.push_back(tmp_header);

		// jump to next header
Anakin's avatar
Anakin committed
100
		m_file.seek(tmp_header->size + m_file.pos());
Anakin's avatar
Anakin committed
101

Anakin's avatar
Anakin committed
102
	} while (m_file.pos() - start != length);
Anakin's avatar
Anakin committed
103 104
}

Anakin's avatar
Anakin committed
105
void MshFile::analyseMsh2Chunks(QList<ChunkHeader*>& chunkList)
Anakin's avatar
Anakin committed
106 107 108 109
{
	for (auto& it : chunkList)
	{
		// scene information
Anakin's avatar
Anakin committed
110
		if ("SINF" == it->name)
Anakin's avatar
Anakin committed
111 112
		{
			// get SINF subchunks
Anakin's avatar
Anakin committed
113
			QList<ChunkHeader*> tmp_sinfChunks;
Anakin's avatar
Anakin committed
114 115 116 117 118
			loadChunks(tmp_sinfChunks, it->position, it->size);

			// evaluate SINF subchunks
			for (auto& it : tmp_sinfChunks)
			{
Anakin's avatar
Anakin committed
119
				if ("BBOX" == it->name)
Anakin's avatar
Anakin committed
120
				{
Anakin's avatar
Anakin committed
121
					m_file.seek(it->position);
Anakin's avatar
Anakin committed
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148

					// read in the quaternion
					float tmp_quat[4];
					for (int i = 0; i < 4; i++)
						m_file.read(F2V(tmp_quat[i]), sizeof(float));

					m_sceneBbox.rotation.setX(tmp_quat[0]);
					m_sceneBbox.rotation.setY(tmp_quat[1]);
					m_sceneBbox.rotation.setZ(tmp_quat[2]);
					m_sceneBbox.rotation.setScalar(tmp_quat[3]);

					//read in the center
					for (int i = 0; i < 3; i++)
						m_file.read(F2V(m_sceneBbox.center[i]), sizeof(float));

					//read in the extents
					for (int i = 0; i < 3; i++)
						m_file.read(F2V(m_sceneBbox.extents[i]), sizeof(float));
				}
			}

			// clean up SINF subchunks
			for (ChunkHeader* it : tmp_sinfChunks)
				delete it;
		}

		// material list
Anakin's avatar
Anakin committed
149
		else if ("MATL" == it->name)
Anakin's avatar
Anakin committed
150
		{
Anakin's avatar
Anakin committed
151
			OutputDevice::getInstance()->print("loading materials..", 0);
Anakin's avatar
Anakin committed
152
			// "useless" information how many MATD follow, jump over it
Anakin's avatar
Anakin committed
153 154
			m_file.seek(it->position);
			m_file.seek(sizeof(quint32) + m_file.pos());
Anakin's avatar
Anakin committed
155 156

			// get all MATL subchunk
Anakin's avatar
Anakin committed
157 158
			QList<ChunkHeader*> tmp_matlChunks;
			loadChunks(tmp_matlChunks, m_file.pos(), it->size - 4);
Anakin's avatar
Anakin committed
159 160 161 162 163

			// evaluate MATL subchunks
			for (auto& it : tmp_matlChunks)
			{
				// This shouldn't be anything else than MATD
Anakin's avatar
Anakin committed
164
				if ("MATD" == it->name)
Anakin's avatar
Anakin committed
165 166
				{
					// get all subchunks from MATD
Anakin's avatar
Anakin committed
167
					QList<ChunkHeader*> tmp_matdChunks;
Anakin's avatar
Anakin committed
168 169
					loadChunks(tmp_matdChunks, it->position, it->size);

170
					m_materials->push_back(Material());
Anakin's avatar
Anakin committed
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194

					// analyse MATD subchunks
					analyseMatdChunks(tmp_matdChunks);

					// clean up MATD subchunks
					while (!tmp_matdChunks.empty())
					{
						ChunkHeader* cur = tmp_matdChunks.front();
						tmp_matdChunks.pop_front();
						delete cur;
					}
				}
			}

			// clean up MATL subchunks
			while (!tmp_matlChunks.empty())
			{
				ChunkHeader* cur = tmp_matlChunks.front();
				tmp_matlChunks.pop_front();
				delete cur;
			}
		}

		// model
Anakin's avatar
Anakin committed
195
		else if ("MODL" == it->name)
Anakin's avatar
Anakin committed
196
		{
Anakin's avatar
Anakin committed
197
			OutputDevice::getInstance()->print("loading model..", 0);
Anakin's avatar
Anakin committed
198
			Model* new_model = new Model;
199 200
			m_currentType = ModelTyp::null;
			m_currentRenderFlag = -1;
Anakin's avatar
Anakin committed
201 202

			// get all MODL subchunks
Anakin's avatar
Anakin committed
203
			QList<ChunkHeader*> tmp_chunks;
Anakin's avatar
Anakin committed
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
			loadChunks(tmp_chunks, it->position, it->size);

			// evaluate MODL subchunks
			analyseModlChunks(new_model, tmp_chunks);

			//clean up MODL subchunks
			while (!tmp_chunks.empty())
			{
				ChunkHeader* cur = tmp_chunks.front();
				tmp_chunks.pop_front();
				delete cur;
			}

			// save Model data
			m_models->push_back(new_model);
		}
	}
}

Anakin's avatar
Anakin committed
223
void MshFile::analyseMatdChunks(QList<ChunkHeader*>& chunkList)
Anakin's avatar
Anakin committed
224 225 226
{
	for (auto& it : chunkList)
	{
Anakin's avatar
Anakin committed
227
		// name
Anakin's avatar
Anakin committed
228
		if ("NAME" == it->name)
Anakin's avatar
Anakin committed
229
		{
Anakin's avatar
Anakin committed
230
			m_file.seek(it->position);
C-Fu's avatar
C-Fu committed
231 232 233 234 235
			char* buffer = new char[it->size + 1];
			*buffer = { 0 };
			m_file.read(buffer, it->size);
			m_materials->back().name = buffer;
			delete[] buffer;
Anakin's avatar
Anakin committed
236 237 238
		}

		// data
Anakin's avatar
Anakin committed
239
		else if("DATA" == it->name)
Anakin's avatar
Anakin committed
240
		{
Anakin's avatar
Anakin committed
241
			m_file.seek(it->position);
Anakin's avatar
Anakin committed
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258

			// diffuse
			for (unsigned int i = 0; i < 4; i++)
				m_file.read(F2V(m_materials->back().diffuseColor[i]), sizeof(float));

			// specular
			for (unsigned int i = 0; i < 4; i++)
				m_file.read(F2V(m_materials->back().specularColor[i]), sizeof(float));

			// ambient
			for (unsigned int i = 0; i < 4; i++)
				m_file.read(F2V(m_materials->back().ambientColor[i]), sizeof(float));

			// shininess
			m_file.read(F2V(m_materials->back().shininess), sizeof(float));
		}

Anakin's avatar
Anakin committed
259
		// attributes
Anakin's avatar
Anakin committed
260
		else if ("ATRB" == it->name)
Anakin's avatar
Anakin committed
261
		{
Anakin's avatar
Anakin committed
262 263 264
			// get pointer to current material
			Material* curMat = &m_materials->back();

Anakin's avatar
Anakin committed
265
			// read the attributes
Anakin's avatar
Anakin committed
266 267
			m_file.seek(it->position);
			quint8 flag;
Anakin's avatar
Anakin committed
268
			m_file.read(F2V(flag), sizeof(flag));
Anakin's avatar
Anakin committed
269 270 271
			m_file.read(F2V(curMat->rendertype), sizeof(quint8));
			m_file.read(F2V(curMat->dataValues[0]), sizeof(quint8));
			m_file.read(F2V(curMat->dataValues[1]), sizeof(quint8));
Anakin's avatar
Anakin committed
272

Anakin's avatar
Anakin committed
273 274 275 276 277 278 279 280 281 282 283
			// flags
			// 0: emissive
			// 1: glow
			// 2: single-sided transparency
			// 3: double-sided transparency
			// 4: hard-edged transparency
			// 5: per-pixel lighting
			// 6: additive transparency
			// 7: specular

			for (unsigned int i = 0; i < 8; i++)
Anakin's avatar
Anakin committed
284
				curMat->flags[i] = (quint8)(flag << (7 - i)) >> 7;
Anakin's avatar
Anakin committed
285

Anakin's avatar
Anakin committed
286
			curMat->transparent = curMat->flags[2] || curMat->flags[3] || curMat->flags[4] || curMat->flags[6] || curMat->rendertype == 4;
Anakin's avatar
Anakin committed
287 288
		}

289
		// texture 0
Anakin's avatar
Anakin committed
290
		else if ("TX0D" == it->name)
Anakin's avatar
Anakin committed
291
		{
292
			// get the texture name
Anakin's avatar
Anakin committed
293
			m_file.seek(it->position);
Anakin's avatar
Anakin committed
294 295 296
			char* buffer = new char[it->size + 1];
			*buffer = { 0 };
			m_file.read(buffer, it->size);
297
			m_materials->back().tx0d = buffer;
Anakin's avatar
Anakin committed
298
			delete[] buffer;
299

C-Fu's avatar
C-Fu committed
300
			// load the texture if the name is not empty
301
			if (!m_materials->back().tx0d.isEmpty())
Anakin's avatar
Anakin committed
302
				loadTexture(m_materials->back().texture0, m_filepath, m_materials->back().tx0d);
303 304 305
		}

		// texture 1
Anakin's avatar
Anakin committed
306
		else if ("TX1D" == it->name)
307 308
		{
			// get the texture name
Anakin's avatar
Anakin committed
309
			m_file.seek(it->position);
310 311 312 313 314 315
			char* buffer = new char[it->size + 1];
			*buffer = { 0 };
			m_file.read(buffer, it->size);
			m_materials->back().tx1d = buffer;
			delete[] buffer;

Anakin's avatar
Anakin committed
316 317
			if (!m_materials->back().tx1d.isEmpty())
				loadTexture(m_materials->back().texture1, m_filepath, m_materials->back().tx1d);
318 319 320
		}

		// texture 2
Anakin's avatar
Anakin committed
321
		else if ("TX2D" == it->name)
322 323
		{
			// get the texture name
Anakin's avatar
Anakin committed
324
			m_file.seek(it->position);
325 326 327 328 329 330 331 332
			char* buffer = new char[it->size + 1];
			*buffer = { 0 };
			m_file.read(buffer, it->size);
			m_materials->back().tx2d = buffer;
			delete[] buffer;
		}

		// texture 3
Anakin's avatar
Anakin committed
333
		else if ("TX3D" == it->name)
334 335
		{
			// get the texture name
Anakin's avatar
Anakin committed
336
			m_file.seek(it->position);
337 338 339 340 341
			char* buffer = new char[it->size + 1];
			*buffer = { 0 };
			m_file.read(buffer, it->size);
			m_materials->back().tx3d = buffer;
			delete[] buffer;
Anakin's avatar
Anakin committed
342 343 344 345
		}
	}
}

Anakin's avatar
Anakin committed
346
void MshFile::analyseModlChunks(Model * dataDestination, QList<ChunkHeader*>& chunkList)
Anakin's avatar
Anakin committed
347 348 349 350
{
	for (auto& it : chunkList)
	{
		// model type
Anakin's avatar
Anakin committed
351
		if ("MTYP" == it->name)
Anakin's avatar
Anakin committed
352
		{
Anakin's avatar
Anakin committed
353 354
			m_file.seek(it->position);
			quint32 tmp_type;
Anakin's avatar
Anakin committed
355
			m_file.read(F2V(tmp_type), sizeof(tmp_type));
356
			m_currentType = (ModelTyp)tmp_type;
Anakin's avatar
Anakin committed
357 358 359
		}

		// parent name
Anakin's avatar
Anakin committed
360
		else if ("PRNT" == it->name)
Anakin's avatar
Anakin committed
361
		{
Anakin's avatar
Anakin committed
362
			m_file.seek(it->position);
Anakin's avatar
Anakin committed
363 364 365 366 367 368 369 370
			char* buffer = new char[it->size + 1];
			*buffer = { 0 };
			m_file.read(buffer, it->size);
			dataDestination->parent = buffer;
			delete[] buffer;
		}

		// model name
Anakin's avatar
Anakin committed
371
		else if ("NAME" == it->name)
Anakin's avatar
Anakin committed
372
		{
Anakin's avatar
Anakin committed
373
			m_file.seek(it->position);
Anakin's avatar
Anakin committed
374 375 376 377 378 379 380 381
			char* buffer = new char[it->size + 1];
			*buffer = { 0 };
			m_file.read(buffer, it->size);
			dataDestination->name = buffer;
			delete[] buffer;
		}

		// render flags
Anakin's avatar
Anakin committed
382
		else if ("FLGS" == it->name)
Anakin's avatar
Anakin committed
383
		{
Anakin's avatar
Anakin committed
384
			m_file.seek(it->position);
385
			m_file.read(F2V(m_currentRenderFlag), sizeof(m_currentRenderFlag));
Anakin's avatar
Anakin committed
386 387 388
		}

		// translation
Anakin's avatar
Anakin committed
389
		else if ("TRAN" == it->name)
Anakin's avatar
Anakin committed
390 391 392 393 394
		{
			float tmp_scale[3];
			float tmp_rotation[4];
			float tmp_trans[3];

Anakin's avatar
Anakin committed
395
			m_file.seek(it->position);
Anakin's avatar
Anakin committed
396 397 398 399 400 401 402 403 404 405 406

			// read in the data
			for (int i = 0; i < 3; i++)
				m_file.read(F2V(tmp_scale[i]), sizeof(float));

			for (int i = 0; i < 4; i++)
				m_file.read(F2V(tmp_rotation[i]), sizeof(float));

			for (int i = 0; i < 3; i++)
				m_file.read(F2V(tmp_trans[i]), sizeof(float));

Anakin's avatar
Anakin committed
407
			// modify the matrix and quaternion
Anakin's avatar
Anakin committed
408 409
			dataDestination->m4x4Translation.scale(tmp_scale[0], tmp_scale[1], tmp_scale[2]);
			dataDestination->m4x4Translation.translate(tmp_trans[0], tmp_trans[1], tmp_trans[2]);
Anakin's avatar
Anakin committed
410 411
			dataDestination->quadRotation.setVector(QVector3D(tmp_rotation[0], tmp_rotation[1], tmp_rotation[2]));
			dataDestination->quadRotation.setScalar(tmp_rotation[3]);
Anakin's avatar
Anakin committed
412

Anakin's avatar
Anakin committed
413
			dataDestination->m4x4Translation = getParentMatrix(dataDestination->parent) * dataDestination->m4x4Translation;
Anakin's avatar
Anakin committed
414
			dataDestination->quadRotation = getParentRotation(dataDestination->parent) * dataDestination->quadRotation;
Anakin's avatar
Anakin committed
415 416 417
		}

		// geometry data
Anakin's avatar
Anakin committed
418
		else if ("GEOM" == it->name)
Anakin's avatar
Anakin committed
419
		{
Anakin's avatar
Anakin committed
420 421 422 423
			// don't get null, bone, shadowMesh and hidden mesh indices
			if (m_currentType == null || m_currentType == bone || m_currentType == shadowMesh || m_currentRenderFlag == 1)
				continue;

Anakin's avatar
Anakin committed
424
			// get all GEOM subchunks
Anakin's avatar
Anakin committed
425
			QList<ChunkHeader*> tmp_geomChunks;
Anakin's avatar
Anakin committed
426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441
			loadChunks(tmp_geomChunks, it->position, it->size);

			// evaluate GEOM subchunks
			analyseGeomChunks(dataDestination, tmp_geomChunks);

			// clean up GEOM subchunks
			while (!tmp_geomChunks.empty())
			{
				ChunkHeader* cur = tmp_geomChunks.front();
				tmp_geomChunks.pop_front();
				delete cur;
			}
		}
	}
}

Anakin's avatar
Anakin committed
442
void MshFile::analyseGeomChunks(Model * dataDestination, QList<ChunkHeader*>& chunkList)
Anakin's avatar
Anakin committed
443 444 445 446
{
	for (auto& it : chunkList)
	{
		// segment
Anakin's avatar
Anakin committed
447
		if ("SEGM" == it->name)
Anakin's avatar
Anakin committed
448 449
		{
			// get all SEGM subchunks
Anakin's avatar
Anakin committed
450
			QList<ChunkHeader*> tmp_segmChunks;
Anakin's avatar
Anakin committed
451 452 453 454 455 456 457 458 459 460 461 462 463 464 465
			loadChunks(tmp_segmChunks, it->position, it->size);

			// evaluate SEGM subchunks
			analyseSegmChunks(dataDestination, tmp_segmChunks);

			// clean up SEGM subchunk
			while (!tmp_segmChunks.empty())
			{
				ChunkHeader* cur = tmp_segmChunks.front();
				tmp_segmChunks.pop_front();
				delete cur;
			}
		}

		// cloth
Anakin's avatar
Anakin committed
466
		else if ("CLTH" == it->name)
Anakin's avatar
Anakin committed
467 468
		{
			// get all CLTH subchunks
Anakin's avatar
Anakin committed
469
			QList<ChunkHeader*> tmp_clthChunks;
Anakin's avatar
Anakin committed
470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485
			loadChunks(tmp_clthChunks, it->position, it->size);

			// evaluate CLTH subchunks
			analyseClthChunks(dataDestination, tmp_clthChunks);

			// clean up CLTH subchunks
			while (!tmp_clthChunks.empty())
			{
				ChunkHeader* cur = tmp_clthChunks.front();
				tmp_clthChunks.pop_front();
				delete cur;
			}
		}
	}
}

Anakin's avatar
Anakin committed
486
void MshFile::analyseSegmChunks(Model * dataDestination, QList<ChunkHeader*>& chunkList)
Anakin's avatar
Anakin committed
487 488 489 490 491 492
{
	Segment* new_segment = new Segment;

	for (auto& it : chunkList)
	{
		// material index
Anakin's avatar
Anakin committed
493
		if ("MATI" == it->name)
Anakin's avatar
Anakin committed
494
		{
Anakin's avatar
Anakin committed
495
			m_file.seek(it->position);
Anakin's avatar
Anakin committed
496 497 498 499
			m_file.read(F2V(new_segment->textureIndex), sizeof(new_segment->textureIndex));
		}

		// position list (vertex)
Anakin's avatar
Anakin committed
500
		else if ("POSL" == it->name)
Anakin's avatar
Anakin committed
501 502 503 504 505
		{
			readVertex(new_segment, it->position);
		}

		// normals
Anakin's avatar
Anakin committed
506
		else if ("NRML" == it->name)
Anakin's avatar
Anakin committed
507
		{
Anakin's avatar
Anakin committed
508 509
			quint32 tmp_size;
			m_file.seek(it->position);
Anakin's avatar
Anakin committed
510
			m_file.read(F2V(tmp_size), sizeof(tmp_size));
Anakin's avatar
Anakin committed
511

Anakin's avatar
Anakin committed
512
			if (tmp_size < (unsigned) new_segment->vertices.size())
Anakin's avatar
Anakin committed
513
			{
514
				OutputDevice::getInstance()->print("WARNING: too less normals " + QString::number(tmp_size) + " < " + QString::number(new_segment->vertices.size()), 1);
Anakin's avatar
Anakin committed
515

Anakin's avatar
Anakin committed
516 517
				for (unsigned int i = new_segment->vertices.size(); i != tmp_size; i--)
					for (unsigned int j = 0; j < 3; j++)
518
						new_segment->vertices[i - 1].vertexNormal[j] = 0;
Anakin's avatar
Anakin committed
519
			}
Anakin's avatar
Anakin committed
520
			else if (tmp_size > (unsigned) new_segment->vertices.size())
Anakin's avatar
Anakin committed
521
			{
522
				OutputDevice::getInstance()->print("WARNING: too many normals " + QString::number(tmp_size) + " > " + QString::number(new_segment->vertices.size()), 1);
Anakin's avatar
Anakin committed
523 524
				tmp_size = new_segment->vertices.size();
			}
Anakin's avatar
Anakin committed
525

Anakin's avatar
Anakin committed
526 527
			for (unsigned int i = 0; i < tmp_size; i++)
				for (unsigned int j = 0; j < 3; j++)
528
					m_file.read(F2V(new_segment->vertices[i].vertexNormal[j]), sizeof(float));
Anakin's avatar
Anakin committed
529 530

		}
Anakin's avatar
Anakin committed
531 532

		// uv
Anakin's avatar
Anakin committed
533
		else if ("UV0L" == it->name)
Anakin's avatar
Anakin committed
534 535 536 537 538
		{
			readUV(new_segment, it->position);
		}

		// polygons (indices into vertex/uv list)
Anakin's avatar
Anakin committed
539
		else if ("STRP" == it->name)
Anakin's avatar
Anakin committed
540 541 542
		{

			// jump to the data section and read the size;
Anakin's avatar
Anakin committed
543 544
			quint32 tmp_size;
			m_file.seek(it->position);
Anakin's avatar
Anakin committed
545 546 547 548 549 550 551 552
			m_file.read(F2V(tmp_size), sizeof(tmp_size));

			int highBitCount(0);
			QVector<GLuint> tmp_buffer;

			for (unsigned int i = 0; i < tmp_size; i++)
			{
				// ReadData
Anakin's avatar
Anakin committed
553
				quint16 tmp_value;
Anakin's avatar
Anakin committed
554 555 556 557 558 559 560
				m_file.read(F2V(tmp_value), sizeof(tmp_value));

				// Check if highbit is set
				if (tmp_value >> 15)
				{
					highBitCount++;
					// remove the high bit, to get the actually value
Anakin's avatar
Anakin committed
561
					tmp_value = (quint16(tmp_value << 1) >> 1);
Anakin's avatar
Anakin committed
562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584
				}

				// save data
				tmp_buffer.push_back((GLuint)tmp_value);

				// if the last 2 highBits are set, it was a new poly
				if (highBitCount == 2)
				{
					// reset highBitCount
					highBitCount = 0;

					if (tmp_buffer.size() == 5)
					{
						for (size_t i = 0; i < 3; i++)
							new_segment->indices.push_back(tmp_buffer.takeFirst());
					}
					else if (tmp_buffer.size() > 5)
					{
						unsigned int tmp_multiPolySize = tmp_buffer.size() - 2;
						// for every triangle of the multi polygon..
						for (unsigned int tri = 0; tri < tmp_multiPolySize - 2; tri++)
							// ..calculate the edge indices
							for (int triEdge = 0; triEdge < 3; triEdge++)
Anakin's avatar
Anakin committed
585
								new_segment->indices.push_back(tmp_buffer[(tri + triEdge - ((tri % 2) * (triEdge - 1) * 2))]);
Anakin's avatar
Anakin committed
586 587

						tmp_buffer.remove(0, tmp_multiPolySize);
Anakin's avatar
Anakin committed
588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606
					}

				}	// if 2 high bits are set

			}	// for all values

			// save the last polygon (no 2 high bit followed)
			if (tmp_buffer.size() == 3)
			{
				for (size_t i = 0; i < 3; i++)
					new_segment->indices.push_back(tmp_buffer.takeFirst());
			}
			else if (tmp_buffer.size() > 3)
			{
				unsigned int tmp_multiPolySize = tmp_buffer.size();
				// for every triangle of the multi polygon..
				for (unsigned int tri = 0; tri < tmp_multiPolySize - 2; tri++)
					// ..calculate the edge indices
					for (int triEdge = 0; triEdge < 3; triEdge++)
Anakin's avatar
Anakin committed
607
						new_segment->indices.push_back(tmp_buffer[(tri + triEdge - ((tri % 2) * (triEdge - 1) * 2))]);
Anakin's avatar
Anakin committed
608 609 610 611 612 613 614
			}
		}
	}

	dataDestination->segmList.push_back(new_segment);
}

Anakin's avatar
Anakin committed
615
void MshFile::analyseClthChunks(Model * dataDestination, QList<ChunkHeader*>& chunkList)
Anakin's avatar
Anakin committed
616 617 618 619 620 621
{
	Segment* new_segment = new Segment;

	for (auto& it : chunkList)
	{
		// texture name
Anakin's avatar
Anakin committed
622
		if ("CTEX" == it->name)
Anakin's avatar
Anakin committed
623 624
		{
			// read the texture name
Anakin's avatar
Anakin committed
625
			m_file.seek(it->position);
Anakin's avatar
Anakin committed
626 627 628 629
			char* buffer = new char[it->size + 1];
			*buffer = { 0 };
			m_file.read(buffer, it->size);

Anakin's avatar
Anakin committed
630 631 632
			
			m_materials->push_back(Material());
			m_materials->back().name = "Cloth Material";
633
			m_materials->back().tx0d = QString(buffer);
Anakin's avatar
Anakin committed
634

Anakin's avatar
Anakin committed
635
			m_materials->back().shininess = 10;
636

637
			if (!m_materials->back().tx0d.isEmpty())
Anakin's avatar
Anakin committed
638
				loadTexture(m_materials->back().texture0, m_filepath, m_materials->back().tx0d);
Anakin's avatar
Anakin committed
639 640

			new_segment->textureIndex = m_materials->size() - 1;
Anakin's avatar
Anakin committed
641 642 643 644 645

			delete[] buffer;
		}

		// position list (vertex)
Anakin's avatar
Anakin committed
646
		else if ("CPOS" == it->name)
Anakin's avatar
Anakin committed
647 648 649 650 651
		{
			readVertex(new_segment, it->position);
		}

		// uv 
Anakin's avatar
Anakin committed
652
		else if ("CUV0" == it->name)
Anakin's avatar
Anakin committed
653 654 655 656 657
		{
			readUV(new_segment, it->position);
		}

		// triangles (indices into vertex/uv list)
Anakin's avatar
Anakin committed
658
		else if ("CMSH" == it->name)
Anakin's avatar
Anakin committed
659 660
		{
			// jump to the data section and read the size;
Anakin's avatar
Anakin committed
661 662
			quint32 tmp_size;
			m_file.seek(it->position);
Anakin's avatar
Anakin committed
663 664 665
			m_file.read(F2V(tmp_size), sizeof(tmp_size));

			// for every triangle..
Anakin's avatar
Anakin committed
666
			for (unsigned int i = 0; i < tmp_size; i++)
Anakin's avatar
Anakin committed
667
			{
Anakin's avatar
Anakin committed
668 669 670 671 672 673
				quint32 tmp_value[3];
				for (unsigned int j = 0; j < 3; j++)
				{
					m_file.read(F2V(tmp_value[j]), sizeof(quint32));
					new_segment->indices.push_back((GLuint)tmp_value[j]);
				}
Anakin's avatar
Anakin committed
674

Anakin's avatar
Anakin committed
675 676 677 678 679 680 681 682 683 684 685
				QVector3D vec1, vec2, norm;

				vec1 = new_segment->vertices[new_segment->indices[i * 3]].position - new_segment->vertices[new_segment->indices[i * 3 + 1]].position;
				vec2 = new_segment->vertices[new_segment->indices[i * 3]].position - new_segment->vertices[new_segment->indices[i * 3 + 2]].position;
				norm = QVector3D::crossProduct(vec1, vec2);

				for (int k = 0; k < 3; k++)
				{
					new_segment->vertices[new_segment->indices[i * 3 + k]].vertexNormal += norm;
					new_segment->vertices[new_segment->indices[i * 3 + k]].vertexNormal.normalize();
				}
Anakin's avatar
Anakin committed
686 687 688 689 690 691 692
			}
		}
	}

	dataDestination->segmList.push_back(new_segment);
}

Anakin's avatar
Anakin committed
693
void MshFile::readVertex(Segment * dataDestination, qint64 position)
Anakin's avatar
Anakin committed
694
{
Anakin's avatar
Anakin committed
695 696
	quint32 tmp_size;
	m_file.seek(position);
Anakin's avatar
Anakin committed
697 698 699 700 701 702 703 704 705 706 707 708 709 710 711
	m_file.read(F2V(tmp_size), sizeof(tmp_size));

	for (unsigned int i = 0; i < tmp_size; i++)
	{
		float tmp[3];
		for (unsigned int j = 0; j < 3; j++)
			m_file.read(F2V(tmp[j]), sizeof(float));
		
		VertexData new_data;
		new_data.position = QVector3D(tmp[0], tmp[1], tmp[2]);

		dataDestination->vertices.push_back(new_data);
	}
}

Anakin's avatar
Anakin committed
712
void MshFile::readUV(Segment * dataDestination, qint64 position)
Anakin's avatar
Anakin committed
713
{
Anakin's avatar
Anakin committed
714 715
	quint32 tmp_size;
	m_file.seek(position);
Anakin's avatar
Anakin committed
716 717
	m_file.read(F2V(tmp_size), sizeof(tmp_size));

Anakin's avatar
Anakin committed
718
	if (tmp_size < (unsigned) dataDestination->vertices.size())
Anakin's avatar
Anakin committed
719
	{
720
		OutputDevice::getInstance()->print("WARNING: too less UVs " + QString::number(tmp_size) + " < " + QString::number(dataDestination->vertices.size()),1);
Anakin's avatar
Anakin committed
721

722 723 724
		for (unsigned int i = dataDestination->vertices.size(); i != tmp_size; i--)
			for (unsigned int j = 0; j < 2; j++)
				dataDestination->vertices[i - 1].texCoord[j] = 0;
Anakin's avatar
Anakin committed
725
	}
Anakin's avatar
Anakin committed
726
	else if (tmp_size > (unsigned) dataDestination->vertices.size())
Anakin's avatar
Anakin committed
727
	{
728
		OutputDevice::getInstance()->print("WARNING: too many UVs " + QString::number(tmp_size) + " > " + QString::number(dataDestination->vertices.size()), 1);
Anakin's avatar
Anakin committed
729 730 731 732 733 734
		tmp_size = dataDestination->vertices.size();
	}

	for (unsigned int i = 0; i < tmp_size; i++)
		for (unsigned int j = 0; j < 2; j++)
			m_file.read(F2V(dataDestination->vertices[i].texCoord[j]), sizeof(float));
Anakin's avatar
Anakin committed
735 736
}

Anakin's avatar
Anakin committed
737
void MshFile::loadTexture(QOpenGLTexture *& destination, QString filepath, QString& filename)
738 739
{
	bool loadSuccess(false);
740

Anakin's avatar
Anakin committed
741
	QImage img = loadTga(filepath + "/" + filename, loadSuccess);
742 743

	if (!loadSuccess)
C-Fu's avatar
C-Fu committed
744
	{
745
		OutputDevice::getInstance()->print("WARNING: texture not found or corrupted: " + filename, 1);
Anakin's avatar
Anakin committed
746 747 748
		
		img = QImage(1, 1, QImage::Format_RGB32);
		img.fill(QColor(m_materials->back().diffuseColor[0] * 255, m_materials->back().diffuseColor[1] * 255, m_materials->back().diffuseColor[2] * 255));
Anakin's avatar
Anakin committed
749
		filename += " *";
C-Fu's avatar
C-Fu committed
750 751
	}
	
752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767
	// Load image to OglTexture
	QOpenGLTexture* new_texture = new QOpenGLTexture(img.mirrored());

	// Set nearest filtering mode for texture minification
	new_texture->setMinificationFilter(QOpenGLTexture::Nearest);

	// Set bilinear filtering mode for texture magnification
	new_texture->setMagnificationFilter(QOpenGLTexture::Linear);

	// Wrap texture coordinates by repeating
	// f.ex. texture coordinate (1.1, 1.2) is same as (0.1, 0.2)
	new_texture->setWrapMode(QOpenGLTexture::Repeat);

	destination = new_texture;
}

Anakin's avatar
Anakin committed
768
QMatrix4x4 MshFile::getParentMatrix(QString parent) const
Anakin's avatar
Anakin committed
769 770 771 772 773
{
	QMatrix4x4 matrix;

	for (auto& it : *m_models)
	{
Anakin's avatar
Anakin committed
774
		if (parent == it->name)
Anakin's avatar
Anakin committed
775 776 777 778 779 780 781 782
		{
			matrix = getParentMatrix(it->parent) * it->m4x4Translation;
			break;
		}
	}

	return matrix;
}
Anakin's avatar
Anakin committed
783

Anakin's avatar
Anakin committed
784
QQuaternion MshFile::getParentRotation(QString parent) const
Anakin's avatar
Anakin committed
785 786 787 788 789
{
	QQuaternion rotation;

	for (auto& it : *m_models)
	{
Anakin's avatar
Anakin committed
790
		if (parent == it->name)
Anakin's avatar
Anakin committed
791 792 793 794 795 796 797 798
		{
			rotation = getParentRotation(it->parent) * it->quadRotation;
			break;
		}
	}

	return rotation;
}