MshFile.cpp 19.7 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 77 78

	do
	{
		ChunkHeader* tmp_header = new ChunkHeader();

Anakin's avatar
Anakin committed
79
		char workaround[5] = { 0 };
Anakin's avatar
Anakin committed
80
		// get information
Anakin's avatar
Anakin committed
81 82
		m_file.read(F2V(workaround[0]), sizeof(workaround) -1);
		tmp_header->name = QString(workaround);
Anakin's avatar
Anakin committed
83
		m_file.read(F2V(tmp_header->size), sizeof(tmp_header->size));
Anakin's avatar
Anakin committed
84
		tmp_header->position = m_file.pos();
Anakin's avatar
Anakin committed
85 86 87 88 89

		// store information
		destination.push_back(tmp_header);

		// jump to next header
Anakin's avatar
Anakin committed
90 91 92 93 94 95 96
		if (!m_file.seek(tmp_header->size + m_file.pos()))
		{
			OutputDevice::getInstance()->print("WARNING: corrupted file. Trying to continue..", 1);
			m_file.unsetError();
			m_file.seek(0);
			break;
		}
Anakin's avatar
Anakin committed
97 98

		// out of file. Maybe a size information is corrupted
Anakin's avatar
Anakin committed
99
		if (m_file.error() != QFileDevice::NoError)
Anakin's avatar
Anakin committed
100
		{
101
			OutputDevice::getInstance()->print("WARNING: corrupted file. Trying to continue..", 1);
Anakin's avatar
Anakin committed
102 103
			m_file.unsetError();
			m_file.seek(0);
Anakin's avatar
Anakin committed
104 105
			break;
		}
Anakin's avatar
Anakin committed
106
	} while (m_file.pos() - start != length);
Anakin's avatar
Anakin committed
107 108
}

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

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

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

			// get all MATL subchunk
Anakin's avatar
Anakin committed
161 162
			QList<ChunkHeader*> tmp_matlChunks;
			loadChunks(tmp_matlChunks, m_file.pos(), it->size - 4);
Anakin's avatar
Anakin committed
163 164 165 166 167

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

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

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

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

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

			// 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
263
		// attributes
Anakin's avatar
Anakin committed
264
		else if ("ATRB" == it->name)
Anakin's avatar
Anakin committed
265
		{
Anakin's avatar
Anakin committed
266 267 268
			// get pointer to current material
			Material* curMat = &m_materials->back();

Anakin's avatar
Anakin committed
269
			// read the attributes
Anakin's avatar
Anakin committed
270 271
			m_file.seek(it->position);
			quint8 flag;
Anakin's avatar
Anakin committed
272
			m_file.read(F2V(flag), sizeof(flag));
Anakin's avatar
Anakin committed
273 274 275
			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
276

Anakin's avatar
Anakin committed
277 278 279 280 281 282 283 284 285 286 287
			// 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
288
				curMat->flags[i] = (quint8)(flag << (7 - i)) >> 7;
Anakin's avatar
Anakin committed
289

Anakin's avatar
Anakin committed
290
			curMat->transparent = curMat->flags[2] || curMat->flags[3] || curMat->flags[4] || curMat->flags[6] || curMat->rendertype == 4;
Anakin's avatar
Anakin committed
291 292
		}

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

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

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

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

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

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

		// translation
Anakin's avatar
Anakin committed
393
		else if ("TRAN" == it->name)
Anakin's avatar
Anakin committed
394 395 396 397 398
		{
			float tmp_scale[3];
			float tmp_rotation[4];
			float tmp_trans[3];

Anakin's avatar
Anakin committed
399
			m_file.seek(it->position);
Anakin's avatar
Anakin committed
400 401 402 403 404 405 406 407 408 409 410

			// 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
411
			// modify the matrix and quaternion
Anakin's avatar
Anakin committed
412 413
			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
414 415
			dataDestination->quadRotation.setVector(QVector3D(tmp_rotation[0], tmp_rotation[1], tmp_rotation[2]));
			dataDestination->quadRotation.setScalar(tmp_rotation[3]);
Anakin's avatar
Anakin committed
416

Anakin's avatar
Anakin committed
417
			dataDestination->m4x4Translation = getParentMatrix(dataDestination->parent) * dataDestination->m4x4Translation;
Anakin's avatar
Anakin committed
418
			dataDestination->quadRotation = getParentRotation(dataDestination->parent) * dataDestination->quadRotation;
Anakin's avatar
Anakin committed
419 420 421
		}

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

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

		// position list (vertex)
Anakin's avatar
Anakin committed
504
		else if ("POSL" == it->name)
Anakin's avatar
Anakin committed
505 506 507 508 509
		{
			readVertex(new_segment, it->position);
		}

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

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

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

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

		}
Anakin's avatar
Anakin committed
535 536

		// uv
Anakin's avatar
Anakin committed
537
		else if ("UV0L" == it->name)
Anakin's avatar
Anakin committed
538 539 540 541 542
		{
			readUV(new_segment, it->position);
		}

		// polygons (indices into vertex/uv list)
Anakin's avatar
Anakin committed
543
		else if ("STRP" == it->name)
Anakin's avatar
Anakin committed
544 545 546
		{

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

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

						tmp_buffer.remove(0, tmp_multiPolySize);
Anakin's avatar
Anakin committed
592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610
					}

				}	// 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
611
						new_segment->indices.push_back(tmp_buffer[(tri + triEdge - ((tri % 2) * (triEdge - 1) * 2))]);
Anakin's avatar
Anakin committed
612 613 614 615 616 617 618
			}
		}
	}

	dataDestination->segmList.push_back(new_segment);
}

Anakin's avatar
Anakin committed
619
void MshFile::analyseClthChunks(Model * dataDestination, QList<ChunkHeader*>& chunkList)
Anakin's avatar
Anakin committed
620 621 622 623 624 625
{
	Segment* new_segment = new Segment;

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

Anakin's avatar
Anakin committed
634 635 636
			
			m_materials->push_back(Material());
			m_materials->back().name = "Cloth Material";
637
			m_materials->back().tx0d = QString(buffer);
Anakin's avatar
Anakin committed
638

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

641
			if (!m_materials->back().tx0d.isEmpty())
Anakin's avatar
Anakin committed
642
				loadTexture(m_materials->back().texture0, m_filepath, m_materials->back().tx0d);
Anakin's avatar
Anakin committed
643 644

			new_segment->textureIndex = m_materials->size() - 1;
Anakin's avatar
Anakin committed
645 646 647 648 649

			delete[] buffer;
		}

		// position list (vertex)
Anakin's avatar
Anakin committed
650
		else if ("CPOS" == it->name)
Anakin's avatar
Anakin committed
651 652 653 654 655
		{
			readVertex(new_segment, it->position);
		}

		// uv 
Anakin's avatar
Anakin committed
656
		else if ("CUV0" == it->name)
Anakin's avatar
Anakin committed
657 658 659 660 661
		{
			readUV(new_segment, it->position);
		}

		// triangles (indices into vertex/uv list)
Anakin's avatar
Anakin committed
662
		else if ("CMSH" == it->name)
Anakin's avatar
Anakin committed
663 664
		{
			// jump to the data section and read the size;
Anakin's avatar
Anakin committed
665 666
			quint32 tmp_size;
			m_file.seek(it->position);
Anakin's avatar
Anakin committed
667 668 669 670 671
			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
672 673
				quint32 tmp_value;
				m_file.read(F2V(tmp_value), sizeof(quint32));
Anakin's avatar
Anakin committed
674 675 676 677 678 679 680 681 682

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

	dataDestination->segmList.push_back(new_segment);
}

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

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

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

Anakin's avatar
Anakin committed
727
void MshFile::loadTexture(QOpenGLTexture *& destination, QString filepath, QString& filename)
728 729
{
	bool loadSuccess(false);
730

Anakin's avatar
Anakin committed
731
	QImage img = loadTga(filepath + "/" + filename, loadSuccess);
732 733

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

	for (auto& it : *m_models)
	{
Anakin's avatar
Anakin committed
764
		if (parent == it->name)
Anakin's avatar
Anakin committed
765 766 767 768 769 770 771 772
		{
			matrix = getParentMatrix(it->parent) * it->m4x4Translation;
			break;
		}
	}

	return matrix;
}
Anakin's avatar
Anakin committed
773

Anakin's avatar
Anakin committed
774
QQuaternion MshFile::getParentRotation(QString parent) const
Anakin's avatar
Anakin committed
775 776 777 778 779
{
	QQuaternion rotation;

	for (auto& it : *m_models)
	{
Anakin's avatar
Anakin committed
780
		if (parent == it->name)
Anakin's avatar
Anakin committed
781 782 783 784 785 786 787 788
		{
			rotation = getParentRotation(it->parent) * it->quadRotation;
			break;
		}
	}

	return rotation;
}