MshFile.cpp 19.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

5

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


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

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

MshFile::~MshFile()
{
}


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

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

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

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

	// evaulate HEDR subchunks (= find MSH2)
	for (ChunkHeader* it : tmp_mainChunks)
	{
Anakin's avatar
Anakin committed
42
		if ("MSH2" == it->name)
Anakin's avatar
Anakin committed
43 44
		{
			// get all subchunks
Anakin's avatar
Anakin committed
45
			QList<ChunkHeader*> tmp_msh2Chunks;
Anakin's avatar
Anakin committed
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
			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
70
void MshFile::loadChunks(QList<ChunkHeader*>& destination, qint64 start, const quint32 length)
Anakin's avatar
Anakin committed
71 72
{
	// jump to first chunk
Anakin's avatar
Anakin committed
73
	m_file.seek(start);
Anakin's avatar
Anakin committed
74 75 76

	do
	{
Anakin's avatar
Anakin committed
77 78 79 80 81 82 83 84 85
		// 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
86 87
		ChunkHeader* tmp_header = new ChunkHeader();

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

		// store information
		destination.push_back(tmp_header);

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

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

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

			// evaluate SINF subchunks
			for (auto& it : tmp_sinfChunks)
			{
Anakin's avatar
Anakin committed
118
				if ("BBOX" == it->name)
Anakin's avatar
Anakin committed
119
				{
Anakin's avatar
Anakin committed
120
					m_file.seek(it->position);
Anakin's avatar
Anakin committed
121 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

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

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

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

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

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

			// get all MODL subchunks
Anakin's avatar
Anakin committed
202
			QList<ChunkHeader*> tmp_chunks;
Anakin's avatar
Anakin committed
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
			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
222
void MshFile::analyseMatdChunks(QList<ChunkHeader*>& chunkList)
Anakin's avatar
Anakin committed
223 224 225
{
	for (auto& it : chunkList)
	{
Anakin's avatar
Anakin committed
226
		// name
Anakin's avatar
Anakin committed
227
		if ("NAME" == it->name)
Anakin's avatar
Anakin committed
228
		{
Anakin's avatar
Anakin committed
229
			m_file.seek(it->position);
C-Fu's avatar
C-Fu committed
230 231 232 233 234
			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
235 236 237
		}

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

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

Anakin's avatar
Anakin committed
264
			// read the attributes
Anakin's avatar
Anakin committed
265 266
			m_file.seek(it->position);
			quint8 flag;
Anakin's avatar
Anakin committed
267
			m_file.read(F2V(flag), sizeof(flag));
Anakin's avatar
Anakin committed
268 269 270
			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
271

Anakin's avatar
Anakin committed
272 273 274 275 276 277 278 279 280 281 282
			// 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
283
				curMat->flags[i] = (quint8)(flag << (7 - i)) >> 7;
Anakin's avatar
Anakin committed
284

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

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

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

		// texture 1
Anakin's avatar
Anakin committed
305
		else if ("TX1D" == it->name)
306 307
		{
			// get the texture name
Anakin's avatar
Anakin committed
308
			m_file.seek(it->position);
309 310 311 312 313 314
			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
315 316
			if (!m_materials->back().tx1d.isEmpty())
				loadTexture(m_materials->back().texture1, m_filepath, m_materials->back().tx1d);
317 318 319
		}

		// texture 2
Anakin's avatar
Anakin committed
320
		else if ("TX2D" == it->name)
321 322
		{
			// get the texture name
Anakin's avatar
Anakin committed
323
			m_file.seek(it->position);
324 325 326 327 328 329 330 331
			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
332
		else if ("TX3D" == it->name)
333 334
		{
			// get the texture name
Anakin's avatar
Anakin committed
335
			m_file.seek(it->position);
336 337 338 339 340
			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
341 342 343 344
		}
	}
}

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

		// parent name
Anakin's avatar
Anakin committed
359
		else if ("PRNT" == it->name)
Anakin's avatar
Anakin committed
360
		{
Anakin's avatar
Anakin committed
361
			m_file.seek(it->position);
Anakin's avatar
Anakin committed
362 363 364 365 366 367 368 369
			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
370
		else if ("NAME" == it->name)
Anakin's avatar
Anakin committed
371
		{
Anakin's avatar
Anakin committed
372
			m_file.seek(it->position);
Anakin's avatar
Anakin committed
373 374 375 376 377 378 379 380
			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
381
		else if ("FLGS" == it->name)
Anakin's avatar
Anakin committed
382
		{
Anakin's avatar
Anakin committed
383
			m_file.seek(it->position);
384
			m_file.read(F2V(m_currentRenderFlag), sizeof(m_currentRenderFlag));
Anakin's avatar
Anakin committed
385 386 387
		}

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

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

			// 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
406
			// modify the matrix and quaternion
Anakin's avatar
Anakin committed
407 408
			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
409 410
			dataDestination->quadRotation.setVector(QVector3D(tmp_rotation[0], tmp_rotation[1], tmp_rotation[2]));
			dataDestination->quadRotation.setScalar(tmp_rotation[3]);
Anakin's avatar
Anakin committed
411

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

		// geometry data
Anakin's avatar
Anakin committed
417
		else if ("GEOM" == it->name)
Anakin's avatar
Anakin committed
418
		{
Anakin's avatar
Anakin committed
419 420 421 422
			// 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
423
			// get all GEOM subchunks
Anakin's avatar
Anakin committed
424
			QList<ChunkHeader*> tmp_geomChunks;
Anakin's avatar
Anakin committed
425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440
			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
441
void MshFile::analyseGeomChunks(Model * dataDestination, QList<ChunkHeader*>& chunkList)
Anakin's avatar
Anakin committed
442 443 444 445
{
	for (auto& it : chunkList)
	{
		// segment
Anakin's avatar
Anakin committed
446
		if ("SEGM" == it->name)
Anakin's avatar
Anakin committed
447 448
		{
			// get all SEGM subchunks
Anakin's avatar
Anakin committed
449
			QList<ChunkHeader*> tmp_segmChunks;
Anakin's avatar
Anakin committed
450 451 452 453 454 455 456 457 458 459 460 461 462 463 464
			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
465
		else if ("CLTH" == it->name)
Anakin's avatar
Anakin committed
466 467
		{
			// get all CLTH subchunks
Anakin's avatar
Anakin committed
468
			QList<ChunkHeader*> tmp_clthChunks;
Anakin's avatar
Anakin committed
469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484
			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
485
void MshFile::analyseSegmChunks(Model * dataDestination, QList<ChunkHeader*>& chunkList)
Anakin's avatar
Anakin committed
486 487 488 489 490 491
{
	Segment* new_segment = new Segment;

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

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

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

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

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

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

		}
Anakin's avatar
Anakin committed
530 531

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

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

			// jump to the data section and read the size;
Anakin's avatar
Anakin committed
542 543
			quint32 tmp_size;
			m_file.seek(it->position);
Anakin's avatar
Anakin committed
544 545 546 547 548 549 550 551
			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
552
				quint16 tmp_value;
Anakin's avatar
Anakin committed
553 554 555 556 557 558 559
				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
560
					tmp_value = (quint16(tmp_value << 1) >> 1);
Anakin's avatar
Anakin committed
561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583
				}

				// 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
584
								new_segment->indices.push_back(tmp_buffer[(tri + triEdge - ((tri % 2) * (triEdge - 1) * 2))]);
Anakin's avatar
Anakin committed
585 586

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

				}	// 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
606
						new_segment->indices.push_back(tmp_buffer[(tri + triEdge - ((tri % 2) * (triEdge - 1) * 2))]);
Anakin's avatar
Anakin committed
607 608 609 610 611 612 613
			}
		}
	}

	dataDestination->segmList.push_back(new_segment);
}

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

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

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

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

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

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

			delete[] buffer;
		}

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

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

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

			// for every triangle..
			for (unsigned int i = 0; i < tmp_size * 3; i++)
			{
Anakin's avatar
Anakin committed
667 668
				quint32 tmp_value;
				m_file.read(F2V(tmp_value), sizeof(quint32));
Anakin's avatar
Anakin committed
669 670 671 672 673 674 675 676 677

				new_segment->indices.push_back((GLuint)tmp_value);
			}
		}
	}

	dataDestination->segmList.push_back(new_segment);
}

Anakin's avatar
Anakin committed
678
void MshFile::readVertex(Segment * dataDestination, qint64 position)
Anakin's avatar
Anakin committed
679
{
Anakin's avatar
Anakin committed
680 681
	quint32 tmp_size;
	m_file.seek(position);
Anakin's avatar
Anakin committed
682 683 684 685 686 687 688 689 690 691 692 693 694 695 696
	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
697
void MshFile::readUV(Segment * dataDestination, qint64 position)
Anakin's avatar
Anakin committed
698
{
Anakin's avatar
Anakin committed
699 700
	quint32 tmp_size;
	m_file.seek(position);
Anakin's avatar
Anakin committed
701 702
	m_file.read(F2V(tmp_size), sizeof(tmp_size));

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

707 708 709
		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
710
	}
Anakin's avatar
Anakin committed
711
	else if (tmp_size > (unsigned) dataDestination->vertices.size())
Anakin's avatar
Anakin committed
712
	{
713
		OutputDevice::getInstance()->print("WARNING: too many UVs " + QString::number(tmp_size) + " > " + QString::number(dataDestination->vertices.size()), 1);
Anakin's avatar
Anakin committed
714 715 716 717 718 719
		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
720 721
}

Anakin's avatar
Anakin committed
722
void MshFile::loadTexture(QOpenGLTexture *& destination, QString filepath, QString& filename)
723 724
{
	bool loadSuccess(false);
725

Anakin's avatar
Anakin committed
726
	QImage img = loadTga(filepath + "/" + filename, loadSuccess);
727 728

	if (!loadSuccess)
C-Fu's avatar
C-Fu committed
729
	{
730
		OutputDevice::getInstance()->print("WARNING: texture not found or corrupted: " + filename, 1);
Anakin's avatar
Anakin committed
731 732 733
		
		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
734
		filename += " *";
C-Fu's avatar
C-Fu committed
735 736
	}
	
737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752
	// 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
753
QMatrix4x4 MshFile::getParentMatrix(QString parent) const
Anakin's avatar
Anakin committed
754 755 756 757 758
{
	QMatrix4x4 matrix;

	for (auto& it : *m_models)
	{
Anakin's avatar
Anakin committed
759
		if (parent == it->name)
Anakin's avatar
Anakin committed
760 761 762 763 764 765 766 767
		{
			matrix = getParentMatrix(it->parent) * it->m4x4Translation;
			break;
		}
	}

	return matrix;
}
Anakin's avatar
Anakin committed
768

Anakin's avatar
Anakin committed
769
QQuaternion MshFile::getParentRotation(QString parent) const
Anakin's avatar
Anakin committed
770 771 772 773 774
{
	QQuaternion rotation;

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

	return rotation;
}