MshFile.cpp 27.6 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
				}

				// 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)
					{
575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619
						// calculate poylgon normal, tangent and bitangent
						QVector3D vec1, vec2, norm, tan, bi;
						QVector2D uv1, uv2;
						float f;

						vec1 = new_segment->vertices[tmp_buffer[0]].position - new_segment->vertices[tmp_buffer[1]].position;
						vec2 = new_segment->vertices[tmp_buffer[0]].position - new_segment->vertices[tmp_buffer[2]].position;
						uv1 = new_segment->vertices[tmp_buffer[0]].texCoord - new_segment->vertices[tmp_buffer[1]].texCoord;
						uv2 = new_segment->vertices[tmp_buffer[0]].texCoord - new_segment->vertices[tmp_buffer[2]].texCoord;
						f = 1.0f / (uv1.x() * uv2.y() - uv2.x() * uv1.y());

						norm = QVector3D::crossProduct(vec1, vec2).normalized();

						tan.setX(f * (uv2.y() * vec1.x() - uv1.y() * vec2.x()));
						tan.setY(f * (uv2.y() * vec1.y() - uv1.y() * vec2.y()));
						tan.setZ(f * (uv2.y() * vec1.z() - uv1.y() * vec2.z()));
						tan.normalize();

						bi.setX(f * (-uv2.x() * vec1.x() + uv1.x() * vec2.x()));
						bi.setY(f * (-uv2.x() * vec1.y() + uv1.x() * vec2.y()));
						bi.setZ(f * (-uv2.x() * vec1.z() + uv1.x() * vec2.z()));
						bi.normalize();

						for (int k = 0; k < 3; k++)
						{
							// polygon normal wasn't calculated before
							if (new_segment->vertices[tmp_buffer[k]].polygonNormal == QVector3D(0, 0, 0))
							{
								new_segment->vertices[tmp_buffer[k]].polygonNormal = norm;
								new_segment->vertices[tmp_buffer[k]].tangent = tan;
								new_segment->vertices[tmp_buffer[k]].bitangent = bi;

								new_segment->indices.push_back(tmp_buffer[k]);
							}
							// polygon normal already calculated so duplicate the vertex
							else 
							{
								new_segment->vertices.push_back(new_segment->vertices[tmp_buffer[k]]);
								new_segment->vertices.back().polygonNormal = norm;
								new_segment->vertices.back().tangent = tan;
								new_segment->vertices.back().bitangent = bi;
								new_segment->indices.push_back(new_segment->vertices.size() - 1);
							}
						}
						tmp_buffer.remove(0, 3);
Anakin's avatar
Anakin committed
620 621 622 623
					}
					else if (tmp_buffer.size() > 5)
					{
						unsigned int tmp_multiPolySize = tmp_buffer.size() - 2;
624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647

						// calculate poylgon normal, tangent and bitangent
						QVector3D vec1, vec2, norm, tan, bi;
						QVector2D uv1, uv2;
						float f;

						vec1 = new_segment->vertices[tmp_buffer[0]].position - new_segment->vertices[tmp_buffer[1]].position;
						vec2 = new_segment->vertices[tmp_buffer[0]].position - new_segment->vertices[tmp_buffer[2]].position;
						uv1 = new_segment->vertices[tmp_buffer[0]].texCoord - new_segment->vertices[tmp_buffer[1]].texCoord;
						uv2 = new_segment->vertices[tmp_buffer[0]].texCoord - new_segment->vertices[tmp_buffer[2]].texCoord;
						f = 1.0f / (uv1.x() * uv2.y() - uv2.x() * uv1.y());

						norm = QVector3D::crossProduct(vec1, vec2).normalized();

						tan.setX(f * (uv2.y() * vec1.x() - uv1.y() * vec2.x()));
						tan.setY(f * (uv2.y() * vec1.y() - uv1.y() * vec2.y()));
						tan.setZ(f * (uv2.y() * vec1.z() - uv1.y() * vec2.z()));
						tan.normalize();

						bi.setX(f * (-uv2.x() * vec1.x() + uv1.x() * vec2.x()));
						bi.setY(f * (-uv2.x() * vec1.y() + uv1.x() * vec2.y()));
						bi.setZ(f * (-uv2.x() * vec1.z() + uv1.x() * vec2.z()));
						bi.normalize();

Anakin's avatar
Anakin committed
648 649
						// for every triangle of the multi polygon..
						for (unsigned int tri = 0; tri < tmp_multiPolySize - 2; tri++)
650
						{
Anakin's avatar
Anakin committed
651 652
							// ..calculate the edge indices
							for (int triEdge = 0; triEdge < 3; triEdge++)
653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674
							{
								int curIndi = tmp_buffer[(tri + triEdge - ((tri % 2) * (triEdge - 1) * 2))];

								// polygon normal wasn't calculated before
								if (new_segment->vertices[curIndi].polygonNormal == QVector3D(0, 0, 0))
								{
									new_segment->vertices[curIndi].polygonNormal = norm;
									new_segment->vertices[curIndi].tangent = tan;
									new_segment->vertices[curIndi].bitangent = bi;
									new_segment->indices.push_back(curIndi);
								}
								// polygon normal already calculated so duplicate the vertex
								else
								{
									new_segment->vertices.push_back(new_segment->vertices[curIndi]);
									new_segment->vertices.back().polygonNormal = norm;
									new_segment->vertices.back().tangent = tan;
									new_segment->vertices.back().bitangent = bi;
									new_segment->indices.push_back(new_segment->vertices.size() - 1);
								}
							}
						}
Anakin's avatar
Anakin committed
675
						tmp_buffer.remove(0, tmp_multiPolySize);
Anakin's avatar
Anakin committed
676 677 678 679 680 681 682 683 684
					}

				}	// if 2 high bits are set

			}	// for all values

			// save the last polygon (no 2 high bit followed)
			if (tmp_buffer.size() == 3)
			{
685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729
				// calculate poylgon normal, tangent and bitangent
				QVector3D vec1, vec2, norm, tan, bi;
				QVector2D uv1, uv2;
				float f;

				vec1 = new_segment->vertices[tmp_buffer[0]].position - new_segment->vertices[tmp_buffer[1]].position;
				vec2 = new_segment->vertices[tmp_buffer[0]].position - new_segment->vertices[tmp_buffer[2]].position;
				uv1 = new_segment->vertices[tmp_buffer[0]].texCoord - new_segment->vertices[tmp_buffer[1]].texCoord;
				uv2 = new_segment->vertices[tmp_buffer[0]].texCoord - new_segment->vertices[tmp_buffer[2]].texCoord;
				f = 1.0f / (uv1.x() * uv2.y() - uv2.x() * uv1.y());

				norm = QVector3D::crossProduct(vec1, vec2).normalized();

				tan.setX(f * (uv2.y() * vec1.x() - uv1.y() * vec2.x()));
				tan.setY(f * (uv2.y() * vec1.y() - uv1.y() * vec2.y()));
				tan.setZ(f * (uv2.y() * vec1.z() - uv1.y() * vec2.z()));
				tan.normalize();

				bi.setX(f * (-uv2.x() * vec1.x() + uv1.x() * vec2.x()));
				bi.setY(f * (-uv2.x() * vec1.y() + uv1.x() * vec2.y()));
				bi.setZ(f * (-uv2.x() * vec1.z() + uv1.x() * vec2.z()));
				bi.normalize();

				for (int k = 0; k < 3; k++)
				{
					// polygon normal wasn't calculated before
					if (new_segment->vertices[tmp_buffer[k]].polygonNormal == QVector3D(0, 0, 0))
					{
						new_segment->vertices[tmp_buffer[k]].polygonNormal = norm;
						new_segment->vertices[tmp_buffer[k]].tangent = tan;
						new_segment->vertices[tmp_buffer[k]].bitangent = bi;

						new_segment->indices.push_back(tmp_buffer[k]);
					}
					// polygon normal already calculated so duplicate the vertex
					else
					{
						new_segment->vertices.push_back(new_segment->vertices[tmp_buffer[k]]);
						new_segment->vertices.back().polygonNormal = norm;
						new_segment->vertices.back().tangent = tan;
						new_segment->vertices.back().bitangent = bi;
						new_segment->indices.push_back(new_segment->vertices.size() - 1);
					}
				}
				tmp_buffer.remove(0, 3);
Anakin's avatar
Anakin committed
730 731 732 733
			}
			else if (tmp_buffer.size() > 3)
			{
				unsigned int tmp_multiPolySize = tmp_buffer.size();
734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757

				// calculate poylgon normal, tangent and bitangent
				QVector3D vec1, vec2, norm, tan, bi;
				QVector2D uv1, uv2;
				float f;

				vec1 = new_segment->vertices[tmp_buffer[0]].position - new_segment->vertices[tmp_buffer[1]].position;
				vec2 = new_segment->vertices[tmp_buffer[0]].position - new_segment->vertices[tmp_buffer[2]].position;
				uv1 = new_segment->vertices[tmp_buffer[0]].texCoord - new_segment->vertices[tmp_buffer[1]].texCoord;
				uv2 = new_segment->vertices[tmp_buffer[0]].texCoord - new_segment->vertices[tmp_buffer[2]].texCoord;
				f = 1.0f / (uv1.x() * uv2.y() - uv2.x() * uv1.y());

				norm = QVector3D::crossProduct(vec1, vec2).normalized();

				tan.setX(f * (uv2.y() * vec1.x() - uv1.y() * vec2.x()));
				tan.setY(f * (uv2.y() * vec1.y() - uv1.y() * vec2.y()));
				tan.setZ(f * (uv2.y() * vec1.z() - uv1.y() * vec2.z()));
				tan.normalize();

				bi.setX(f * (-uv2.x() * vec1.x() + uv1.x() * vec2.x()));
				bi.setY(f * (-uv2.x() * vec1.y() + uv1.x() * vec2.y()));
				bi.setZ(f * (-uv2.x() * vec1.z() + uv1.x() * vec2.z()));
				bi.normalize();

Anakin's avatar
Anakin committed
758 759
				// for every triangle of the multi polygon..
				for (unsigned int tri = 0; tri < tmp_multiPolySize - 2; tri++)
760
				{
Anakin's avatar
Anakin committed
761 762
					// ..calculate the edge indices
					for (int triEdge = 0; triEdge < 3; triEdge++)
763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784
					{
						int curIndi = tmp_buffer[(tri + triEdge - ((tri % 2) * (triEdge - 1) * 2))];

						// polygon normal wasn't calculated before
						if (new_segment->vertices[curIndi].polygonNormal == QVector3D(0, 0, 0))
						{
							new_segment->vertices[curIndi].polygonNormal = norm;
							new_segment->vertices[curIndi].tangent = tan;
							new_segment->vertices[curIndi].bitangent = bi;
							new_segment->indices.push_back(curIndi);
						}
						// polygon normal already calculated so duplicate the vertex
						else
						{
							new_segment->vertices.push_back(new_segment->vertices[curIndi]);
							new_segment->vertices.back().polygonNormal = norm;
							new_segment->vertices.back().tangent = tan;
							new_segment->vertices.back().bitangent = bi;
							new_segment->indices.push_back(new_segment->vertices.size() - 1);
						}
					}
				}
Anakin's avatar
Anakin committed
785 786 787 788 789 790 791
			}
		}
	}

	dataDestination->segmList.push_back(new_segment);
}

Anakin's avatar
Anakin committed
792
void MshFile::analyseClthChunks(Model * dataDestination, QList<ChunkHeader*>& chunkList)
Anakin's avatar
Anakin committed
793 794 795 796 797 798
{
	Segment* new_segment = new Segment;

	for (auto& it : chunkList)
	{
		// texture name
Anakin's avatar
Anakin committed
799
		if ("CTEX" == it->name)
Anakin's avatar
Anakin committed
800 801
		{
			// read the texture name
Anakin's avatar
Anakin committed
802
			m_file.seek(it->position);
Anakin's avatar
Anakin committed
803 804 805 806
			char* buffer = new char[it->size + 1];
			*buffer = { 0 };
			m_file.read(buffer, it->size);

807 808 809
			
			m_materials->push_back(Material());
			m_materials->back().name = "Cloth Material";
810
			m_materials->back().tx0d = QString(buffer);
Anakin's avatar
Anakin committed
811

812
			m_materials->back().shininess = 10;
813

814
			if (!m_materials->back().tx0d.isEmpty())
Anakin's avatar
Anakin committed
815
				loadTexture(m_materials->back().texture0, m_filepath, m_materials->back().tx0d);
816 817

			new_segment->textureIndex = m_materials->size() - 1;
Anakin's avatar
Anakin committed
818 819 820 821 822

			delete[] buffer;
		}

		// position list (vertex)
Anakin's avatar
Anakin committed
823
		else if ("CPOS" == it->name)
Anakin's avatar
Anakin committed
824 825 826 827 828
		{
			readVertex(new_segment, it->position);
		}

		// uv 
Anakin's avatar
Anakin committed
829
		else if ("CUV0" == it->name)
Anakin's avatar
Anakin committed
830 831 832 833 834
		{
			readUV(new_segment, it->position);
		}

		// triangles (indices into vertex/uv list)
Anakin's avatar
Anakin committed
835
		else if ("CMSH" == it->name)
Anakin's avatar
Anakin committed
836 837
		{
			// jump to the data section and read the size;
Anakin's avatar
Anakin committed
838 839
			quint32 tmp_size;
			m_file.seek(it->position);
Anakin's avatar
Anakin committed
840 841 842
			m_file.read(F2V(tmp_size), sizeof(tmp_size));

			// for every triangle..
Anakin's avatar
Anakin committed
843
			for (unsigned int i = 0; i < tmp_size; i++)
Anakin's avatar
Anakin committed
844
			{
Anakin's avatar
Anakin committed
845 846 847 848 849 850
				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
851

Anakin's avatar
Anakin committed
852 853 854 855 856 857 858 859 860 861 862
				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
863 864 865 866 867 868 869
			}
		}
	}

	dataDestination->segmList.push_back(new_segment);
}

Anakin's avatar
Anakin committed
870
void MshFile::readVertex(Segment * dataDestination, qint64 position)
Anakin's avatar
Anakin committed
871
{
Anakin's avatar
Anakin committed
872 873
	quint32 tmp_size;
	m_file.seek(position);
Anakin's avatar
Anakin committed
874 875 876 877 878 879 880 881 882 883 884 885 886 887 888
	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
889
void MshFile::readUV(Segment * dataDestination, qint64 position)
Anakin's avatar
Anakin committed
890
{
Anakin's avatar
Anakin committed
891 892
	quint32 tmp_size;
	m_file.seek(position);
Anakin's avatar
Anakin committed
893 894
	m_file.read(F2V(tmp_size), sizeof(tmp_size));

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

899 900 901
		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
902
	}
Anakin's avatar
Anakin committed
903
	else if (tmp_size > (unsigned) dataDestination->vertices.size())
Anakin's avatar
Anakin committed
904
	{
905
		OutputDevice::getInstance()->print("WARNING: too many UVs " + QString::number(tmp_size) + " > " + QString::number(dataDestination->vertices.size()), 1);
Anakin's avatar
Anakin committed
906 907 908 909 910 911
		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
912 913
}

Anakin's avatar
Anakin committed
914
void MshFile::loadTexture(QOpenGLTexture *& destination, QString filepath, QString& filename)
915 916
{
	bool loadSuccess(false);
917

Anakin's avatar
Anakin committed
918
	QImage img = loadTga(filepath + "/" + filename, loadSuccess);
919 920

	if (!loadSuccess)
C-Fu's avatar
C-Fu committed
921
	{
922
		OutputDevice::getInstance()->print("WARNING: texture not found or corrupted: " + filename, 1);
Anakin's avatar
Anakin committed
923
		//TODO: cloth use the wrong diffuse color. should be null
Anakin's avatar
Anakin committed
924 925
		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
926
		filename += " *";
C-Fu's avatar
C-Fu committed
927 928
	}
	
929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944
	// 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
945
QMatrix4x4 MshFile::getParentMatrix(QString parent) const
Anakin's avatar
Anakin committed
946 947 948 949 950
{
	QMatrix4x4 matrix;

	for (auto& it : *m_models)
	{
Anakin's avatar
Anakin committed
951
		if (parent == it->name)
Anakin's avatar
Anakin committed
952 953 954 955 956 957 958 959
		{
			matrix = getParentMatrix(it->parent) * it->m4x4Translation;
			break;
		}
	}

	return matrix;
}
Anakin's avatar
Anakin committed
960

Anakin's avatar
Anakin committed
961
QQuaternion MshFile::getParentRotation(QString parent) const
Anakin's avatar
Anakin committed
962 963 964 965 966
{
	QQuaternion rotation;

	for (auto& it : *m_models)
	{
Anakin's avatar
Anakin committed
967
		if (parent == it->name)
Anakin's avatar
Anakin committed
968 969 970 971 972 973 974 975
		{
			rotation = getParentRotation(it->parent) * it->quadRotation;
			break;
		}
	}

	return rotation;
}