Browse code

Add cpp-v2

Ingemar Ragnemalm authored on 21/02/2024 20:24:29 • Robert Cranston committed on 21/02/2024 20:24:29
Showing 1 changed files
1 1
deleted file mode 100755
... ...
@@ -1,1323 +0,0 @@
1
-// Little OBJ loader
2
-// Ingemar's little OBJ loader
3
-// Formerly named LoadOBJ or loadobj
4
-// by Ingemar Ragnemalm 2005, 2008, 2019, 2021
5
-
6
-// Original version 2005 was extremely simple and intended for use with old OpenGL immediate mode.
7
-// Additions and reorganization by Mikael Kalms 2008
8
-// 120913: Revised LoadModelPlus/DrawModel by Jens.
9
-// Partially corrected formatting. (It is a mess!)
10
-// 130227: Error reporting in DrawModel
11
-// 130422: Added ScaleModel
12
-// 150909: Frees up temporary "Mesh" memory i LoadModel. Thanks to Simon Keisala for finding this!
13
-// Added DisposeModel. Limited the number of error printouts, thanks to Rasmus Hytter for this suggestion!
14
-// 160302: Uses fopen_s on Windows, as suggested by Jesper Post. Should reduce warnings a bit.
15
-// 160510: Uses calloc instead of malloc (for safety) in many places where it could possibly cause problems.
16
-// 170406: Added "const" to string arguments to make C++ happier.
17
-// 190416: free mesh->coordStarts properly.
18
-// 191110: Finally! Multi-part OBJ files work! Renamed LoadModelPlus to LoadModel.
19
-// and added LoadModelSet! The old LoadModel was removed. Converted to use vec2/vec3
20
-// instead of arrays of float. It is now dependent on VectorUtils3. If you want to
21
-// make it independent of VectorUtils3, only a few structs and functions have to be replaced.
22
-// MTL support working! Parser totally rewritten. Officially renamed to Ingemars Little OBJ Loader,
23
-// LOL for short! And boy did I find a nice acronym!
24
-// 210125: Corrected types in LoadDataToModel. Corrected material disposal in the still badly tested DisposeModel.
25
-// 210218: Allows TAB between parts of string.
26
-// 210304: Corrected bad allocation size on row 538, found by Jens Lindgren, who also found glDeleteVertexArrays in DisposeModel.
27
-// 210422: Change by Felicia Castenbrandt, around row 415, copy path or source. This change is likely to be needed in some other places.
28
-// 210502: Dispose the material name list, omission found by Jens Lindgren.
29
-
30
-// Usage:
31
-// Load simple models with LoadModel. Multi-part models are loaded with LoadModelSet.
32
-// DrawModel will draw the model, or, for a multi-part model, one part.
33
-// If you need to modify a model on the CPU, you can do that and re-upload
34
-// with LoadDataToModel.
35
-// There is no longer any call that only loads the data, but you can
36
-// make your own by taking out the GPU upload from LoadModel.
37
-
38
-// This is free software. I appreciate credits in derivate products or
39
-// if it is used in public products.
40
-
41
-#include "LittleOBJLoader.h"
42
-#include <stdio.h>
43
-#include <stdlib.h>
44
-#include <string.h>
45
-#include <math.h>
46
-#include "VectorUtils3.h"
47
-
48
-#if defined(_WIN32)
49
-	#define sscanf sscanf_s
50
-#endif
51
-
52
-
53
-static char atLineEnd = 0;
54
-static char atFileEnd = 0;
55
-
56
-static char ParseString(char *line, int *pos, char *s)
57
-{
58
-	int i = 0;
59
-	char c;
60
-	c = line[(*pos)++];
61
-	while (c == 32 || c == 9) // Important change 210218
62
-		c = line[(*pos)++]; // Skip leading spaces
63
-	while (c != 0 && c != 32 && c != 9  && c != EOF && c != '/' && i < 254)
64
-	{
65
-		s[i++] = c;
66
-		c = line[(*pos)++];
67
-	}
68
-	atLineEnd = (c == 0);
69
-	s[i] = 0;
70
-	
71
-	return c;
72
-}
73
-
74
-static float ParseFloat(char *line, int *pos)
75
-{
76
-	float floatValue = 0.0;
77
-	char s[255];
78
-	ParseString(line, pos, s);
79
-	sscanf(s, "%f", &floatValue);
80
-	if (isnan(floatValue) || isinf(floatValue))
81
-		floatValue = 0.0;
82
-	return floatValue;
83
-}
84
-
85
-static int ParseInt(char *line, int *pos, char *endc)
86
-{
87
-	int intValue = 0;
88
-	char s[255];
89
-	char c = ParseString(line, pos, s);
90
-	if (endc != NULL) *endc = c;
91
-	if (strlen(s) == 0)
92
-		intValue = -1; // Nothing found!
93
-	else
94
-		sscanf(s, "%d", &intValue);
95
-	return intValue;
96
-}
97
-
98
-static vec3 ParseVec3(char *line, int *pos)
99
-{
100
-	vec3 v;
101
-	v.x = ParseFloat(line, pos);
102
-	v.y = ParseFloat(line, pos);
103
-	v.z = ParseFloat(line, pos);
104
-	return v;
105
-}
106
-
107
-void ParseLine(FILE *fp, char *line)
108
-{
109
-	int i, j;
110
-	char c = '_';
111
-	for (i = 0, j= 0; i < 2048; i++)
112
-	{
113
-		c = getc(fp);
114
-		if (c != 10 && c != 13)
115
-			line[j++] = c;
116
-		if (c == EOF || ((c == 10 || c == 13) && j > 0))
117
-		{
118
-			if (c == EOF)
119
-				atFileEnd = 1;
120
-			line[j] = 0;
121
-			return;
122
-		}
123
-	}
124
-	line[j] = 0;
125
-	return;
126
-}
127
-
128
-
129
-// Dispose the strings in the materials list
130
-static void DisposeMtlList(Mtl **materials)
131
-{
132
-	if (materials != NULL)
133
-	for (int i = 0; materials[i] != NULL; i++)
134
-		free(materials[i]);
135
-	free(materials);
136
-}
137
-
138
-static Mtl **ParseMTL(char *filename)
139
-{
140
-	Mtl *m;
141
-	char s[255];
142
-	char line[2048];
143
-	int pos;
144
-	Mtl **materials = NULL;
145
-	FILE *fp;
146
-
147
-	// It seems Windows/VS doesn't like fopen any more, but fopen_s is not on the others.
148
-	#if defined(_WIN32)
149
-	fopen_s(&fp, filename, "r");
150
-	#else
151
-	fp = fopen(filename, "rb"); // rw works everywhere except Windows?
152
-	#endif
153
-	if (fp == NULL)
154
-		return NULL;
155
-	atLineEnd = 0;
156
-	atFileEnd = 0;
157
-	int matcount = 0;
158
-
159
-	while (!atFileEnd)
160
-	{
161
-		ParseLine(fp, line);
162
-		pos = 0;
163
-		ParseString(line, &pos, s);
164
-		if (strcmp(s, "newmtl") == 0)
165
-			matcount++;
166
-	}
167
-	rewind(fp);
168
-
169
-	materials = (Mtl **)calloc(sizeof(MtlPtr)*(matcount+1), 1);
170
-
171
-	matcount = 0;
172
-	atLineEnd = 0;
173
-	atFileEnd = 0;
174
-	
175
-	while (!atFileEnd)
176
-	{
177
-		ParseLine(fp, line);
178
-		pos = 0;
179
-		ParseString(line, &pos, s);
180
-
181
-		// NEW MATERIAL!
182
-		if (strcmp(s, "newmtl") == 0)
183
-		{
184
-			matcount++;
185
-			materials[matcount-1] = (Mtl *)calloc(sizeof(Mtl),1);
186
-			m = materials[matcount-1];
187
-			materials[matcount] = NULL;
188
-			
189
-			ParseString(line, &pos, m->newmtl);
190
-		}
191
-
192
-		if (m != NULL)
193
-		{
194
-			if (strcmp(s, "Ka") == 0)
195
-				m->Ka = ParseVec3(line, &pos);
196
-			if (strcmp(s, "Kd") == 0)
197
-				m->Kd = ParseVec3(line, &pos);
198
-			if (strcmp(s, "Ks") == 0)
199
-				m->Ks = ParseVec3(line, &pos);
200
-			if (strcmp(s, "Ke") == 0)
201
-				m->Ke = ParseVec3(line, &pos);
202
-			if (strcmp(s, "Tr") == 0)
203
-			{
204
-				m->Tr = ParseFloat(line, &pos);
205
-				m->d = 1 - m->Tr;
206
-			}
207
-			if (strcmp(s, "d") == 0)
208
-			{
209
-				m->d = ParseFloat(line, &pos);
210
-				m->Tr = 1 - m->d;
211
-			}
212
-
213
-			if (strcmp(s, "illum") == 0)
214
-				m->illum = ParseInt(line, &pos, NULL);
215
-
216
-			if (strcmp(s, "map_Ka") == 0)
217
-				ParseString(line, &pos, m->map_Ka);
218
-			if (strcmp(s, "map_Kd") == 0)
219
-				ParseString(line, &pos, m->map_Kd);
220
-			if (strcmp(s, "map_Ks") == 0)
221
-				ParseString(line, &pos, m->map_Ks);
222
-			if (strcmp(s, "map_Ke") == 0)
223
-				ParseString(line, &pos, m->map_Ke);
224
-			if (strcmp(s, "map_d") == 0)
225
-				ParseString(line, &pos, m->map_d);
226
-			if (strcmp(s, "map_bump") == 0)
227
-				ParseString(line, &pos, m->map_bump);
228
-			if (strcmp(s, "bump") == 0)
229
-				ParseString(line, &pos, m->map_bump);
230
-		}
231
-	}
232
-	fclose(fp);
233
-
234
-	return materials;
235
-}
236
-
237
-typedef struct Mesh
238
-{
239
-	vec3	*vertices;
240
-	int		vertexCount;
241
-	vec3	*vertexNormals;
242
-	int		normalsCount;
243
-	vec2	*textureCoords;
244
-	int		texCount;
245
-	
246
-	int		*coordIndex;
247
-	int		*normalsIndex;
248
-	int		*textureIndex;
249
-	int		coordCount; // Number of indices in each index struct
250
-	
251
-	// Borders between groups
252
-	int		*coordStarts;
253
-	int		groupCount;
254
-	
255
-	char	*materialName;
256
-} Mesh, *MeshPtr;
257
-
258
-// Globals set by LoadObj
259
-static int vertCount, texCount, normalsCount, coordCount;
260
-static int zeroFix;
261
-static char hasPositionIndices;
262
-static char hasNormalIndices;
263
-static char hasTexCoordIndices;
264
-
265
-// List of materials
266
-Mtl **gMaterials;
267
-char **gMtlNameList;
268
-char *gMtlLibName = NULL;
269
-
270
-static char ParseOBJ(const char *filename, MeshPtr theMesh)
271
-{
272
-	int lastCoordCount = -1;
273
-	FILE *fp;
274
-	
275
-	// It seems Windows/VS doesn't like fopen any more, but fopen_s is not on the others.
276
-	#if defined(_WIN32)
277
-	fopen_s(&fp, filename, "r");
278
-	#else
279
-	fp = fopen(filename, "rb"); // rw works everywhere except Windows?
280
-	#endif
281
-	if (fp == NULL)
282
-		return -1;
283
-
284
-// These must be taken care of by the caller!
285
-	vertCount=0;
286
-	texCount=0;
287
-	normalsCount=0;
288
-	coordCount=0;
289
-
290
-	atLineEnd = 0;
291
-	atFileEnd = 0;
292
-		
293
-	while (!atFileEnd)
294
-	{
295
-		char line[2048];
296
-		ParseLine(fp, line);
297
-		int pos = 0;
298
-		
299
-		char s[256];
300
-		ParseString(line, &pos, s);
301
-		
302
-		if (strcmp(s, "v") == 0)
303
-		{
304
-			vec3 v = ParseVec3(line, &pos);
305
-			if (theMesh->vertices != NULL)
306
-				theMesh->vertices[vertCount++] = v;
307
-			else
308
-				vertCount += 1;
309
-		}
310
-		if (strcmp(s, "vn") == 0)
311
-		{
312
-			vec3 v = ParseVec3(line, &pos);			
313
-			if (theMesh->vertexNormals != NULL)
314
-				theMesh->vertexNormals[normalsCount++] = v;
315
-			else
316
-				normalsCount += 1;
317
-		}
318
-		if (strcmp(s, "vt") == 0)
319
-		{
320
-			vec3 v = ParseVec3(line, &pos);
321
-			if (theMesh->textureCoords != NULL)
322
-			{
323
-				theMesh->textureCoords[texCount].x = v.x;
324
-				theMesh->textureCoords[texCount++].y = v.y;
325
-			}
326
-			else
327
-				texCount += 1;
328
-		}
329
-		if (strcmp(s, "f") == 0)
330
-		{
331
-		// Unknown number of singeltons or triplets!
332
-			
333
-			int p = -1;
334
-			int i = -1;
335
-			int p1;
336
-			char *ns;
337
-			char done = 0;
338
-			for (i = pos ; !done; pos++)
339
-			{
340
-				if (line[pos] == 0)
341
-					done = 1;
342
-				if (p >= 0) // in triplet)
343
-				{
344
-					char c = line[pos];
345
-					if (c == '/' || c == ' ' || c == 0)
346
-					{
347
-						ns = &line[p1]; // Start of substring
348
-						line[pos] = 0; // End of substring
349
-						if (p1 != pos)
350
-						{
351
-							i = atoi(ns);
352
-							if (i == 0)
353
-								zeroFix = 1;
354
-							if (i < 0)
355
-							{
356
-								switch (p)
357
-								{
358
-									case 0: i = vertCount + i + 1; break;
359
-									case 1: i = texCount + i + 1; break;
360
-									case 2: i = normalsCount + i + 1; break;
361
-								}
362
-							}
363
-							i = i + zeroFix;
364
-						}
365
-						else
366
-							i = 0; // -1
367
-						
368
-						if (i > 0)
369
-						switch (p)
370
-						{
371
-							case 0:
372
-								if (theMesh->coordIndex != NULL)
373
-									theMesh->coordIndex[coordCount-1] = i-1;
374
-								break;
375
-							case 1:
376
-								if (theMesh->textureIndex != NULL)
377
-									if (i >= 0)
378
-										theMesh->textureIndex[coordCount-1] = i-1;
379
-								hasTexCoordIndices = 1;
380
-								break;
381
-							case 2:
382
-								if (theMesh->normalsIndex != NULL)
383
-									if (i >= 0)
384
-										theMesh->normalsIndex[coordCount-1] = i-1;
385
-								hasNormalIndices = 1;
386
-								break;
387
-						}
388
-						p1 = pos + 1;
389
-						p++;
390
-					}
391
-					if (c == ' ')
392
-					{
393
-						p = -1; // Next triplet
394
-					}
395
-				}
396
-				else // Wait for non-space
397
-				if (line[pos] != ' ')
398
-				{
399
-					if (!done)
400
-						coordCount++;
401
-					p = 0; // Triplet starts!
402
-					p1 = pos;
403
-				}
404
-			}
405
-			
406
-			if (theMesh->coordIndex != NULL)
407
-				theMesh->coordIndex[coordCount] = -1;
408
-			if (theMesh->textureIndex != NULL)
409
-				theMesh->textureIndex[coordCount] = -1;
410
-			if (theMesh->normalsIndex != NULL)
411
-				theMesh->normalsIndex[coordCount] = -1;
412
-			coordCount++;
413
-		}
414
-		if (strcmp(s, "mtllib") == 0)
415
-		{
416
-			// Save file name for later
417
-			char libname[256];
418
-			
419
-			// Added by Felicia Castenbrandt: Get path of main file, if any
420
-        	char temp[255];
421
-			int index = 0;
422
-
423
-			//find index of last /
424
-			for(int i = 0; i < strlen(filename); i++)
425
-				if(filename[i] == '/')
426
-					index = i;
427
-
428
-			//copy everything before the last / to temp
429
-			if (index != 0)
430
-			{
431
-				for(int i = 0; i < index+1; i++)
432
-				{
433
-					char ch = filename[i];
434
-					strncat(temp, &ch, 1);
435
-				}
436
-			}
437
-			// End of addition
438
-			
439
-			
440
-			/*char c =*/ ParseString(line, &pos, libname);
441
-			gMtlLibName = (char *)malloc(strlen(libname)+1);
442
-#if defined(_WIN32)
443
-			strcpy_s(gMtlLibName, strlen(libname) + 1, libname);
444
-#else
445
-			strcpy(gMtlLibName, libname);
446
-#endif
447
-
448
-		}
449
-		if (strcmp(s, "usemtl") == 0)
450
-		{
451
-			// Groups are only identified by usemtl!
452
-			
453
-			if (coordCount > 0) // If no data has been seen, this must be the first group!
454
-			{
455
-				if (lastCoordCount != coordCount) // must not be the same; empty group (happens if a model has both "g" and "o")
456
-				{
457
-					theMesh->groupCount += 1;
458
-					if (theMesh->coordStarts != NULL) // NULL if we are just counting
459
-						theMesh->coordStarts[theMesh->groupCount] = coordCount;
460
-
461
-					lastCoordCount = coordCount;
462
-				}
463
-				else
464
-					printf("Ignored part!\n");
465
-			}
466
-			
467
-			if (gMtlNameList != NULL)
468
-			{
469
-				// Save matname for later
470
-				char matname[255];
471
-				ParseString(line, &pos, matname);
472
-				gMtlNameList[theMesh->groupCount] = (char *)malloc(strlen(matname)+1);
473
-#if defined(_WIN32)
474
-				strcpy_s(gMtlNameList[theMesh->groupCount], strlen(matname) + 1, matname);
475
-#else
476
-				strcpy(gMtlNameList[theMesh->groupCount], matname);
477
-#endif
478
-
479
-
480
-			}
481
-		}
482
-	} // While
483
-	
484
-	// Add last groups *if* there was more data since last time!
485
-	if (coordCount > lastCoordCount)
486
-	{
487
-		theMesh->groupCount += 1; // End of last group
488
-		if (theMesh->coordStarts != NULL)
489
-			theMesh->coordStarts[theMesh->groupCount] = coordCount;
490
-	}
491
-		
492
-	fclose(fp);
493
-	
494
-	if (gMtlLibName != NULL)
495
-		gMaterials = ParseMTL(gMtlLibName);
496
-	// else try based on filename: filename.obj -> filename.mtl or filename_obj.mtl
497
-	if (gMaterials == NULL)
498
-	if (strlen(filename) > 4)
499
-	{
500
-		char tryname[255];
501
-		strcpy(tryname, filename);
502
-		tryname[strlen(tryname) - 4] = '_';
503
-		strcat(tryname, ".mtl");
504
-		gMaterials = ParseMTL(tryname);
505
-	}
506
-	if (gMaterials == NULL)
507
-	if (strlen(filename) > 4)
508
-	{
509
-		char tmpname[255];
510
-		strcpy(tmpname, filename);
511
-		tmpname[strlen(tmpname) - 4] = 0;
512
-		strcat(tmpname, ".mtl");
513
-		gMaterials = ParseMTL(tmpname);
514
-	}
515
-	return 0;
516
-}
517
-
518
-// Load raw, unprocessed OBJ data!
519
-static struct Mesh * LoadOBJ(const char *filename)
520
-{
521
-	// Reads once to find sizes, again to fill buffers
522
-	Mesh *theMesh;
523
-	
524
-	// Allocate Mesh but not the buffers
525
-	theMesh = (Mesh *)calloc(sizeof(Mesh), 1);
526
-
527
-	hasPositionIndices = 1;
528
-	hasTexCoordIndices = 0;
529
-	hasNormalIndices = 0;
530
-
531
-	theMesh->coordStarts = NULL;
532
-	theMesh->groupCount = 0;
533
-	gMtlNameList = NULL;
534
-
535
-// Dispose if they exist!
536
-	gMtlLibName = NULL;
537
-	gMaterials = NULL;
538
-
539
-	vertCount=0;
540
-	texCount=0;
541
-	normalsCount=0;
542
-	coordCount=0;
543
-	zeroFix = 0;
544
-		
545
-	// Parse for size
546
-	ParseOBJ(filename, theMesh);
547
-
548
-	// Allocate arrays!
549
-	if (vertCount > 0)
550
-		theMesh->vertices = (vec3 *)malloc(sizeof(vec3) * vertCount);
551
-	if (texCount > 0)
552
-		theMesh->textureCoords = (vec2 *)malloc(sizeof(vec2) * texCount);
553
-	if (normalsCount > 0)
554
-		theMesh->vertexNormals = (vec3 *)malloc(sizeof(vec3) * normalsCount);
555
-	if (hasPositionIndices)
556
-		theMesh->coordIndex = (int *)calloc(coordCount, sizeof(int));
557
-	if (hasNormalIndices)
558
-		theMesh->normalsIndex = (int *)calloc(coordCount, sizeof(int));
559
-	if (hasTexCoordIndices)
560
-		theMesh->textureIndex = (int *)calloc(coordCount, sizeof(int));
561
-
562
-	gMtlNameList = (char **)calloc(sizeof(char *) * (theMesh->groupCount+1), 1);
563
-	theMesh->coordStarts = (int *)calloc(sizeof(int) * (theMesh->groupCount+2), 1); // Length found on last pass
564
-	theMesh->groupCount = 0;
565
-
566
-	// Zero again
567
-	vertCount=0;
568
-	texCount=0;
569
-	normalsCount=0;
570
-	coordCount=0;
571
-
572
-	// Parse again for filling buffers
573
-	ParseOBJ(filename, theMesh);
574
-	
575
-	theMesh->vertexCount = vertCount;
576
-	theMesh->coordCount = coordCount;
577
-	theMesh->texCount = texCount;
578
-	theMesh->normalsCount = normalsCount;
579
-
580
-	return theMesh;
581
-}
582
-
583
-void DecomposeToTriangles(struct Mesh *theMesh)
584
-{
585
-	int i, vertexCount, triangleCount;
586
-	int *newCoords, *newNormalsIndex, *newTextureIndex;
587
-	int newIndex = 0; // Index in newCoords
588
-	int first = 0;
589
-
590
-	// 1.1 Calculate how big the list will become
591
-	
592
-	vertexCount = 0; // Number of vertices in current polygon
593
-	triangleCount = 0; // Resulting number of triangles
594
-	for (i = 0; i < theMesh->coordCount; i++)
595
-	{
596
-		if (theMesh->coordIndex[i] == -1)
597
-		{
598
-		if (vertexCount > 2) triangleCount += vertexCount - 2;
599
-			vertexCount = 0;
600
-		}
601
-		else
602
-		{
603
-			vertexCount = vertexCount + 1;
604
-		}
605
-	}
606
-		
607
-	newCoords = (int *)calloc(triangleCount * 3, sizeof(int));
608
-	if (theMesh->normalsIndex != NULL)
609
-		newNormalsIndex = (int *)calloc(triangleCount * 3, sizeof(int));
610
-	if (theMesh->textureIndex != NULL)
611
-		newTextureIndex = (int *)calloc(triangleCount * 3, sizeof(int));
612
-	
613
-	// 1.2 Loop through old list and write the new one
614
-	// Almost same loop but now it has space to write the result
615
-	vertexCount = 0;
616
-	for (i = 0; i < theMesh->coordCount; i++)
617
-	{
618
-		if (theMesh->coordIndex[i] == -1)
619
-		{
620
-			first = i + 1;
621
-			vertexCount = 0;
622
-		}
623
-		else
624
-		{
625
-			vertexCount = vertexCount + 1;
626
-			if (vertexCount > 2)
627
-			{
628
-				newCoords[newIndex++] = theMesh->coordIndex[first];
629
-				newCoords[newIndex++] = theMesh->coordIndex[i-1];
630
-				newCoords[newIndex++] = theMesh->coordIndex[i];
631
-				if (theMesh->normalsIndex != NULL)
632
-				{
633
-					newNormalsIndex[newIndex-3] = theMesh->normalsIndex[first];
634
-					newNormalsIndex[newIndex-2] = theMesh->normalsIndex[i-1];
635
-					newNormalsIndex[newIndex-1] = theMesh->normalsIndex[i];
636
-				}
637
-				if (theMesh->textureIndex != NULL)
638
-				{
639
-					newTextureIndex[newIndex-3] = theMesh->textureIndex[first];
640
-					newTextureIndex[newIndex-2] = theMesh->textureIndex[i-1];
641
-					newTextureIndex[newIndex-1] = theMesh->textureIndex[i];
642
-				}
643
-			}
644
-		}
645
-	}
646
-	
647
-	free(theMesh->coordIndex);
648
-	theMesh->coordIndex = newCoords;
649
-	theMesh->coordCount = triangleCount * 3;
650
-	if (theMesh->normalsIndex != NULL)
651
-	{
652
-		free(theMesh->normalsIndex);
653
-		theMesh->normalsIndex = newNormalsIndex;
654
-	}
655
-	if (theMesh->textureIndex != NULL)
656
-	{
657
-		free(theMesh->textureIndex);
658
-		theMesh->textureIndex = newTextureIndex;
659
-	}
660
-} // DecomposeToTriangles
661
-
662
-static void GenerateNormals(Mesh* mesh)
663
-{
664
-	// If model has vertices but no vertexnormals, generate normals
665
-	if (mesh->vertices && !mesh->vertexNormals)
666
-	{
667
-		int face;
668
-		int normalIndex;
669
-
670
-		mesh->vertexNormals = (vec3 *)calloc(sizeof(vec3) * mesh->vertexCount, 1);
671
-		mesh->normalsCount = mesh->vertexCount;
672
-
673
-		mesh->normalsIndex = (int *)calloc(mesh->coordCount, sizeof(GLuint));
674
-		memcpy(mesh->normalsIndex, mesh->coordIndex, sizeof(GLuint) * mesh->coordCount);
675
-
676
-		for (face = 0; face * 3 < mesh->coordCount; face++)
677
-		{
678
-			int i0 = mesh->coordIndex[face * 3 + 0];
679
-			int i1 = mesh->coordIndex[face * 3 + 1];
680
-			int i2 = mesh->coordIndex[face * 3 + 2];
681
-			
682
-			vec3 v0 = VectorSub(mesh->vertices[i1], mesh->vertices[i0]);
683
-			vec3 v1 = VectorSub(mesh->vertices[i2], mesh->vertices[i0]);
684
-			vec3 v2 = VectorSub(mesh->vertices[i2], mesh->vertices[i1]);
685
-
686
-			float sqrLen0 = dot(v0, v0);
687
-			float sqrLen1 = dot(v1, v1);
688
-			float sqrLen2 = dot(v2, v2);
689
-
690
-			float len0 = (sqrLen0 >= 1e-6f) ? sqrt(sqrLen0) : 1e-3f;
691
-			float len1 = (sqrLen1 >= 1e-6f) ? sqrt(sqrLen1) : 1e-3f;
692
-			float len2 = (sqrLen2 >= 1e-6f) ? sqrt(sqrLen2) : 1e-3f;
693
-
694
-			float influence0 = dot(v0, v1) / (len0 * len1);
695
-			float influence1 = -dot(v0, v2) / (len0 * len2);
696
-			float influence2 = dot(v1, v2) / (len1 * len2);
697
-
698
-			float angle0 = (influence0 >= 1.f) ? 0 : 
699
-				(influence0 <= -1.f) ? M_PI : acos(influence0);
700
-			float angle1 = (influence1 >= 1.f) ? 0 : 
701
-				(influence1 <= -1.f) ? M_PI : acos(influence1);
702
-			float angle2 = (influence2 >= 1.f) ? 0 : 
703
-				(influence2 <= -1.f) ? M_PI : acos(influence2);
704
-
705
-			vec3 normal = cross(v0, v1);
706
-			mesh->vertexNormals[i0] = VectorAdd(ScalarMult(normal, angle0), mesh->vertexNormals[i0]);
707
-			mesh->vertexNormals[i1] = VectorAdd(ScalarMult(normal, angle1), mesh->vertexNormals[i1]);
708
-			mesh->vertexNormals[i2] = VectorAdd(ScalarMult(normal, angle2), mesh->vertexNormals[i2]);
709
-		}
710
-
711
-		for (normalIndex = 0; normalIndex < mesh->normalsCount; normalIndex++)
712
-		{
713
-			float length = Norm(mesh->vertexNormals[normalIndex]);
714
-			if (length > 0.01f)
715
-				mesh->vertexNormals[normalIndex] = ScalarMult(mesh->vertexNormals[normalIndex], 1/length);
716
-		}
717
-	}
718
-}
719
-
720
-static Model* GenerateModel(Mesh* mesh)
721
-{
722
-	// Convert from Mesh format (multiple index lists) to Model format
723
-	// (one index list) by generating a new set of vertices/indices
724
-	// and where new vertices have been created whenever necessary
725
-
726
-	typedef struct
727
-	{
728
-		int positionIndex;
729
-		int normalIndex;
730
-		int texCoordIndex;
731
-		int newIndex;
732
-	} IndexTriplet;
733
-
734
-	int hashGap = 6;
735
-
736
-	int indexHashMapSize = (mesh->vertexCount * hashGap + mesh->coordCount);
737
-
738
-	IndexTriplet* indexHashMap = (IndexTriplet *)malloc(sizeof(IndexTriplet)
739
-							* indexHashMapSize);
740
-
741
-	int numNewVertices = 0;
742
-	int index;
743
-
744
-	int maxValue = 0;
745
-		
746
-	Model* model = (Model *)malloc(sizeof(Model));
747
-	memset(model, 0, sizeof(Model));
748
-
749
-	model->indexArray = (GLuint *)malloc(sizeof(GLuint) * mesh->coordCount);
750
-	model->numIndices = mesh->coordCount;
751
-
752
-	memset(indexHashMap, 0xff, sizeof(IndexTriplet) * indexHashMapSize);
753
-
754
-	for (index = 0; index < mesh->coordCount; index++)
755
-	{
756
-		IndexTriplet currentVertex = { -1, -1, -1, -1 };
757
-		int insertPos = 0;
758
-		if (mesh->coordIndex)
759
-			currentVertex.positionIndex = mesh->coordIndex[index];
760
-		if (mesh->normalsIndex)
761
-			currentVertex.normalIndex = mesh->normalsIndex[index];
762
-		if (mesh->textureIndex)
763
-			currentVertex.texCoordIndex = mesh->textureIndex[index];
764
-
765
-		if (maxValue < currentVertex.texCoordIndex)
766
-			maxValue = currentVertex.texCoordIndex;
767
- 
768
-		if (currentVertex.positionIndex >= 0)
769
-			insertPos = currentVertex.positionIndex * hashGap;
770
-
771
-		while (1)
772
-		{
773
-			if (indexHashMap[insertPos].newIndex == -1)
774
-				{
775
-					currentVertex.newIndex = numNewVertices++;
776
-					indexHashMap[insertPos] = currentVertex;
777
-					break;
778
-				}
779
-			else if (indexHashMap[insertPos].positionIndex
780
-				 == currentVertex.positionIndex
781
-				 && indexHashMap[insertPos].normalIndex
782
-				 == currentVertex.normalIndex
783
-				 && indexHashMap[insertPos].texCoordIndex
784
-				 == currentVertex.texCoordIndex)
785
-				{
786
-					currentVertex.newIndex = indexHashMap[insertPos].newIndex;
787
-					break;
788
-				}
789
-			else
790
-				insertPos++;
791
-		} 
792
-
793
-		model->indexArray[index] = currentVertex.newIndex;
794
-	}
795
-
796
-	if (mesh->vertices)
797
-		model->vertexArray = (vec3 *)malloc(sizeof(vec3) * numNewVertices);
798
-	if (mesh->vertexNormals)
799
-		model->normalArray = (vec3 *)malloc(sizeof(vec3) * numNewVertices);
800
-	if (mesh->textureCoords)
801
-		model->texCoordArray = (vec2 *)malloc(sizeof(vec2) * numNewVertices);
802
-	
803
-	model->numVertices = numNewVertices;
804
-
805
-	for (index = 0; index < indexHashMapSize; index++)
806
-	{
807
-		if (indexHashMap[index].newIndex != -1)
808
-		{
809
-			if (mesh->vertices)
810
-				model->vertexArray[indexHashMap[index].newIndex] = mesh->vertices[indexHashMap[index].positionIndex];
811
-			if (mesh->vertexNormals)
812
-			{
813
-				model->normalArray[indexHashMap[index].newIndex] = mesh->vertexNormals[indexHashMap[index].normalIndex];
814
-			}
815
-			if (mesh->textureCoords)
816
-				model->texCoordArray[indexHashMap[index].newIndex] = mesh->textureCoords[indexHashMap[index].texCoordIndex];
817
-		}
818
-	}
819
-
820
-	free(indexHashMap);
821
-
822
-	// If there is a material set, match materials to parts
823
-	if (gMaterials != NULL)
824
-	if (mesh->materialName != NULL)
825
-		for (int ii = 0; gMaterials[ii] != NULL; ii++)
826
-		{
827
-			Mtl *mtl = gMaterials[ii];
828
-			if (strcmp(mesh->materialName, mtl->newmtl) == 0)
829
-			{
830
-				// Copy mtl to model!
831
-				model->material = (Mtl *)malloc(sizeof(Mtl));
832
-				memcpy(model->material, mtl, sizeof(Mtl));
833
-
834
-				strcpy(model->material->map_Ka, mtl->map_Ka);
835
-				strcpy(model->material->map_Kd, mtl->map_Kd);
836
-				strcpy(model->material->map_Ks, mtl->map_Ks);
837
-				strcpy(model->material->map_Ke, mtl->map_Ke);
838
-				strcpy(model->material->map_Ns, mtl->map_Ns);
839
-				strcpy(model->material->map_d, mtl->map_d);
840
-				strcpy(model->material->map_bump, mtl->map_bump);
841
-			}
842
-		}
843
-
844
-	return model;
845
-}
846
-
847
-Mesh **SplitToMeshes(Mesh *m)
848
-{
849
-	int * mapc = (int *)malloc(m->vertexCount * sizeof(int));
850
-	int * mapt = (int *)malloc(m->texCount * sizeof(int));
851
-	int * mapn = (int *)malloc(m->normalsCount * sizeof(int));
852
-	
853
-	if (m == NULL || m ->vertices == NULL || m->vertexCount == 0)
854
-	{
855
-		printf("Illegal mesh!\n");
856
-		return NULL;
857
-	}
858
-	
859
-	Mesh **mm = (Mesh **)calloc(sizeof(Mesh *), m->groupCount+2);
860
-
861
-	for (int mi = 0; mi < m->groupCount; mi++) // For all sections
862
-	{
863
-		int from = m->coordStarts[mi];
864
-		int to = m->coordStarts[mi+1];
865
-		
866
-		mm[mi] = (Mesh *)calloc(sizeof(Mesh), 1); // allocate struct
867
-		
868
-		// Fill mapc, mapt, mapn with -1 (illegal index)
869
-		for (int ii = 0; ii < m->vertexCount; ii++)
870
-			mapc[ii] = -1;
871
-		for (int ii = 0; ii < m->texCount; ii++)
872
-			mapt[ii] = -1;
873
-		for (int ii = 0; ii < m->normalsCount; ii++)
874
-			mapn[ii] = -1;
875
-		
876
-		// Count number of entries needed
877
-		int intVertexCount = 0;
878
-		int intTexCount = 0;
879
-		int intNormalsCount = 0;
880
-		
881
-		for (int j = from; j < to; j++) // For all index triplets
882
-		{
883
-			int ix = m->coordIndex[j];
884
-			if (ix > -1)
885
-				if (mapc[ix] == -1)
886
-				{
887
-					mapc[ix] = ix;
888
-					intVertexCount++;
889
-				}
890
-			if (m->textureIndex != NULL)
891
-			{
892
-				ix = m->textureIndex[j];
893
-				if (ix > -1)
894
-					if (mapt[ix] == -1)
895
-					{
896
-						mapt[ix] = ix;
897
-						intTexCount++;
898
-					}
899
-			}
900
-			if (m->normalsIndex != NULL)
901
-			{
902
-				ix = m->normalsIndex[j];
903
-				if (ix > -1)
904
-					if (mapn[ix] == -1)
905
-					{
906
-						mapn[ix] = ix;
907
-						intNormalsCount++;
908
-					}
909
-			}
910
-		}
911
-				
912
-		// Allocate buffers
913
-		mm[mi]->coordIndex = (int *)malloc((to - from) * sizeof(int));
914
-		mm[mi]->textureIndex = (int *)malloc((to - from) * sizeof(int));
915
-		mm[mi]->normalsIndex = (int *)malloc((to - from) * sizeof(int));
916
-		if (intVertexCount > 0)
917
-			mm[mi]->vertices = (vec3 *)malloc(intVertexCount * sizeof(vec3));
918
-		if (intTexCount > 0)
919
-			mm[mi]->textureCoords = (vec2 *)malloc(intTexCount * sizeof(vec2));
920
-		if (intNormalsCount > 0)
921
-			mm[mi]->vertexNormals = (vec3 *)malloc(intNormalsCount * sizeof(vec3));
922
-		mm[mi]->vertexCount = intVertexCount;
923
-		mm[mi]->texCount = intTexCount;
924
-		mm[mi]->normalsCount = intNormalsCount;
925
-		
926
-		// Fill mapc, mapt, mapn with -1 (illegal index)
927
-		for (int ii = 0; ii < m->vertexCount; ii++)
928
-			mapc[ii] = -1;
929
-		for (int ii = 0; ii < m->texCount; ii++)
930
-			mapt[ii] = -1;
931
-		for (int ii = 0; ii < m->normalsCount; ii++)
932
-			mapn[ii] = -1;
933
-		
934
-		int mapcCount = 0;
935
-		int maptCount = 0;
936
-		int mapnCount = 0;
937
-		for (int j = from; j < to; j++) // For all index triplets
938
-		{
939
-			int ix = m->coordIndex[j];
940
-			if (ix > -1)
941
-			{
942
-				if (mapc[ix] == -1) // Unmapped
943
-				{
944
-					mapc[ix] = mapcCount++;
945
-					mm[mi]->vertices[mapc[ix]] = m->vertices[ix]; // Copy vertex to mm[i]
946
-				}
947
-				mm[mi]->coordIndex[j-from] = mapc[ix];
948
-			}
949
-			else // Separator
950
-			{
951
-				mm[mi]->coordIndex[j-from] = -1;
952
-			}
953
-
954
-			if (m->textureIndex != NULL)
955
-			if (mm[mi]->textureIndex != NULL)
956
-			{
957
-				ix = m->textureIndex[j];
958
-				if (ix > -1)
959
-				{
960
-					if (mapt[ix] == -1) // Unmapped
961
-					{
962
-						mapt[ix] = maptCount++;
963
-						mm[mi]->textureCoords[mapt[ix]] = m->textureCoords[ix]; // Copy vertex to mm[i]
964
-					}
965
-					mm[mi]->textureIndex[j-from] = mapt[ix];
966
-				}
967
-				else // Separator
968
-				{
969
-					mm[mi]->textureIndex[j-from] = -1;
970
-				}
971
-			}
972
-
973
-			if (m->normalsIndex != NULL)
974
-			if (mm[mi]->normalsIndex != NULL)
975
-			{
976
-				ix = m->normalsIndex[j];
977
-				if (ix > -1)
978
-				{
979
-					if (mapn[ix] == -1) // Unmapped
980
-					{
981
-						mapn[ix] = mapnCount++;
982
-						mm[mi]->vertexNormals[mapn[ix]] = m->vertexNormals[ix]; // Copy vertex to mm[i]
983
-					}
984
-					mm[mi]->normalsIndex[j-from] = mapn[ix];
985
-				}
986
-				else // Separator
987
-				{
988
-					mm[mi]->normalsIndex[j-from] = -1;
989
-				}
990
-			}
991
-		} // for all index triplets
992
-		mm[mi]->coordCount = to - from;
993
-		
994
-		if (gMtlNameList != NULL)
995
-		{
996
-			mm[mi]->materialName = gMtlNameList[mi];
997
-			gMtlNameList[mi] = NULL; // No longer "owned" by the gMtlNameList
998
-		}
999
-	} // for all parts
1000
-	
1001
-	return mm;
1002
-}
1003
-
1004
-
1005
-static void DisposeMesh(Mesh *mesh)
1006
-{
1007
-// Free the mesh!
1008
-	if (mesh != NULL)
1009
-	{
1010
-		if (mesh->vertices != NULL)
1011
-			free(mesh->vertices);
1012
-		if (mesh->vertexNormals != NULL)
1013
-			free(mesh->vertexNormals);
1014
-		if (mesh->textureCoords != NULL)
1015
-			free(mesh->textureCoords);
1016
-		if (mesh->coordIndex != NULL)
1017
-			free(mesh->coordIndex);
1018
-		if (mesh->normalsIndex != NULL)
1019
-			free(mesh->normalsIndex);
1020
-		if (mesh->textureIndex != NULL)
1021
-			free(mesh->textureIndex);
1022
-#if !defined(_WIN32)
1023
-// This is very disturbing, causes heap corruption on Windows. Reason not found.
1024
-		if (mesh->coordStarts != NULL)
1025
-			free(mesh->coordStarts);
1026
-#endif
1027
-		if (mesh->materialName != NULL)
1028
-			free(mesh->materialName);
1029
-
1030
-// Dispose the material name list too
1031
-		if (gMtlNameList != NULL)
1032
-		{
1033
-			for (int i = 0; i < mesh->groupCount; i++)
1034
-				if (gMtlNameList[i] != NULL)
1035
-					free(gMtlNameList[i]);
1036
-			free(gMtlNameList);
1037
-			gMtlNameList = NULL;
1038
-		}
1039
-
1040
-		free(mesh);
1041
-	}
1042
-}
1043
-
1044
-void CenterModel(Model *m)
1045
-{
1046
-	int i;
1047
-	float maxx = -1e10, maxy = -1e10, maxz = -1e10, minx = 1e10, miny = 1e10, minz = 1e10;
1048
-	
1049
-	for (i = 0; i < m->numVertices; i++)
1050
-	{
1051
-		if (m->vertexArray[i].x < minx) minx = m->vertexArray[i].x;
1052
-		if (m->vertexArray[i].x > maxx) maxx = m->vertexArray[i].x;
1053
-		if (m->vertexArray[i].y < miny) miny = m->vertexArray[i].y;
1054
-		if (m->vertexArray[i].y > maxy) maxy = m->vertexArray[i].y;
1055
-		if (m->vertexArray[i].z < minz) minz = m->vertexArray[i].z;
1056
-		if (m->vertexArray[i].z > maxz) maxz = m->vertexArray[i].z;
1057
-	}
1058
-	
1059
-	for (i = 0; i < m->numVertices; i++)
1060
-	{
1061
-		m->vertexArray[i].x -= (maxx + minx)/2.0f;
1062
-		m->vertexArray[i].y -= (maxy + miny)/2.0f;
1063
-		m->vertexArray[i].z -= (maxz + minz)/2.0f;
1064
-	}
1065
-}
1066
-
1067
-void ScaleModel(Model *m, float sx, float sy, float sz)
1068
-{
1069
-	long i;
1070
-	for (i = 0; i < m->numVertices; i++)
1071
-	{
1072
-		m->vertexArray[i].x *= sx;
1073
-		m->vertexArray[i].y *= sy;
1074
-		m->vertexArray[i].z *= sz;
1075
-	}
1076
-}
1077
-
1078
-static void ReportRerror(const char *caller, const char *name)
1079
-{
1080
-	static unsigned int draw_error_counter = 0; 
1081
-   if(draw_error_counter < NUM_DRAWMODEL_ERROR)
1082
-   {
1083
-		    fprintf(stderr, "%s warning: '%s' not found in shader!\n", caller, name);
1084
-		    draw_error_counter++;
1085
-   }
1086
-   else if(draw_error_counter == NUM_DRAWMODEL_ERROR)
1087
-   {
1088
-		    fprintf(stderr, "%s: Number of error bigger than %i. No more vill be printed.\n", caller, NUM_DRAWMODEL_ERROR);
1089
-		    draw_error_counter++;
1090
-   }
1091
-}
1092
-
1093
-// This code makes a lot of calls for rebinding variables just in case,
1094
-// and to get attribute locations. This is clearly not optimal, but the
1095
-// goal is stability.
1096
-
1097
-void DrawModel(Model *m, GLuint program, const char* vertexVariableName, const char* normalVariableName, const char* texCoordVariableName)
1098
-{
1099
-	if (m != NULL)
1100
-	{
1101
-		GLint loc;
1102
-		
1103
-		glBindVertexArray(m->vao);	// Select VAO
1104
-
1105
-		glBindBuffer(GL_ARRAY_BUFFER, m->vb);
1106
-		loc = glGetAttribLocation(program, vertexVariableName);
1107
-		if (loc >= 0)
1108
-		{
1109
-			glVertexAttribPointer(loc, 3, GL_FLOAT, GL_FALSE, 0, 0); 
1110
-			glEnableVertexAttribArray(loc);
1111
-		}
1112
-		else
1113
-			ReportRerror("DrawModel", vertexVariableName);
1114
-		
1115
-		if (normalVariableName!=NULL)
1116
-		{
1117
-			loc = glGetAttribLocation(program, normalVariableName);
1118
-			if (loc >= 0)
1119
-			{
1120
-				glBindBuffer(GL_ARRAY_BUFFER, m->nb);
1121
-				glVertexAttribPointer(loc, 3, GL_FLOAT, GL_FALSE, 0, 0);
1122
-				glEnableVertexAttribArray(loc);
1123
-			}
1124
-			else
1125
-				ReportRerror("DrawModel", normalVariableName);
1126
-		}
1127
-	
1128
-		if ((m->texCoordArray != NULL)&&(texCoordVariableName != NULL))
1129
-		{
1130
-			loc = glGetAttribLocation(program, texCoordVariableName);
1131
-			if (loc >= 0)
1132
-			{
1133
-				glBindBuffer(GL_ARRAY_BUFFER, m->tb);
1134
-				glVertexAttribPointer(loc, 2, GL_FLOAT, GL_FALSE, 0, 0);
1135
-				glEnableVertexAttribArray(loc);
1136
-			}
1137
-			else
1138
-				ReportRerror("DrawModel", texCoordVariableName);
1139
-		}
1140
-
1141
-		glDrawElements(GL_TRIANGLES, m->numIndices, GL_UNSIGNED_INT, 0L);
1142
-	}
1143
-}
1144
-
1145
-void DrawWireframeModel(Model *m, GLuint program, const char* vertexVariableName, const char* normalVariableName, const char* texCoordVariableName)
1146
-{
1147
-	if (m != NULL)
1148
-	{
1149
-		GLint loc;
1150
-		
1151
-		glBindVertexArray(m->vao);	// Select VAO
1152
-
1153
-		glBindBuffer(GL_ARRAY_BUFFER, m->vb);
1154
-		loc = glGetAttribLocation(program, vertexVariableName);
1155
-		if (loc >= 0)
1156
-		{
1157
-			glVertexAttribPointer(loc, 3, GL_FLOAT, GL_FALSE, 0, 0); 
1158
-			glEnableVertexAttribArray(loc);
1159
-		}
1160
-		else
1161
-			ReportRerror("DrawWireframeModel", vertexVariableName);
1162
-		
1163
-		if (normalVariableName!=NULL)
1164
-		{
1165
-			loc = glGetAttribLocation(program, normalVariableName);
1166
-			if (loc >= 0)
1167
-			{
1168
-				glBindBuffer(GL_ARRAY_BUFFER, m->nb);
1169
-				glVertexAttribPointer(loc, 3, GL_FLOAT, GL_FALSE, 0, 0);
1170
-				glEnableVertexAttribArray(loc);
1171
-			}
1172
-			else
1173
-				ReportRerror("DrawWireframeModel", normalVariableName);
1174
-		}
1175
-	
1176
-		if ((m->texCoordArray != NULL)&&(texCoordVariableName != NULL))
1177
-		{
1178
-			loc = glGetAttribLocation(program, texCoordVariableName);
1179
-			if (loc >= 0)
1180
-			{
1181
-				glBindBuffer(GL_ARRAY_BUFFER, m->tb);
1182
-				glVertexAttribPointer(loc, 2, GL_FLOAT, GL_FALSE, 0, 0);
1183
-				glEnableVertexAttribArray(loc);
1184
-			}
1185
-			else
1186
-				ReportRerror("DrawWireframeModel", texCoordVariableName);
1187
-		}
1188
-		glDrawElements(GL_LINE_STRIP, m->numIndices, GL_UNSIGNED_INT, 0L);
1189
-	}
1190
-}
1191
-	
1192
-// Called from LoadModel, LoadModelSet and LoadDataToModel
1193
-// VAO and VBOs must already exist!
1194
-// Useful by its own when the model changes on CPU
1195
-void ReloadModelData(Model *m)
1196
-{
1197
-	glBindVertexArray(m->vao);
1198
-	
1199
-	// VBO for vertex data
1200
-	glBindBuffer(GL_ARRAY_BUFFER, m->vb);
1201
-	glBufferData(GL_ARRAY_BUFFER, m->numVertices*3*sizeof(GLfloat), m->vertexArray, GL_STATIC_DRAW);
1202
-	
1203
-	// VBO for normal data
1204
-	glBindBuffer(GL_ARRAY_BUFFER, m->nb);
1205
-	glBufferData(GL_ARRAY_BUFFER, m->numVertices*3*sizeof(GLfloat), m->normalArray, GL_STATIC_DRAW);
1206
-	
1207
-	// VBO for texture coordinate data NEW for 5b
1208
-	if (m->texCoordArray != NULL)
1209
-	{
1210
-		glBindBuffer(GL_ARRAY_BUFFER, m->tb);
1211
-		glBufferData(GL_ARRAY_BUFFER, m->numVertices*2*sizeof(GLfloat), m->texCoordArray, GL_STATIC_DRAW);
1212
-	}
1213
-	
1214
-	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m->ib);
1215
-	glBufferData(GL_ELEMENT_ARRAY_BUFFER, m->numIndices*sizeof(GLuint), m->indexArray, GL_STATIC_DRAW);
1216
-}
1217
-
1218
-static void GenModelBuffers(Model *m)
1219
-{
1220
-	glGenVertexArrays(1, &m->vao);
1221
-	glGenBuffers(1, &m->vb);
1222
-	glGenBuffers(1, &m->ib);
1223
-	glGenBuffers(1, &m->nb);
1224
-	if (m->texCoordArray != NULL)
1225
-		glGenBuffers(1, &m->tb);
1226
-
1227
-	ReloadModelData(m);
1228
-}
1229
-
1230
-// For simple models
1231
-Model* LoadModel(const char* name)
1232
-{
1233
-	Model* model = NULL;
1234
-	Mesh* mesh = LoadOBJ(name);
1235
-	DecomposeToTriangles(mesh);
1236
-	GenerateNormals(mesh);
1237
-	model = GenerateModel(mesh);
1238
-	DisposeMesh(mesh);
1239
-
1240
-	GenModelBuffers(model);	
1241
-	return model;
1242
-}
1243
-
1244
-// For multiple part models
1245
-Model** LoadModelSet(const char* name)
1246
-{
1247
-	Mesh* mesh = LoadOBJ(name);
1248
-	Mesh **mm = SplitToMeshes(mesh);
1249
-	int i, ii;
1250
-	for (i = 0; mm[i] != NULL; i++) {}
1251
-	Model **md = (Model **)calloc(sizeof(Model *), i+1);
1252
-	for (ii = 0; mm[ii] != NULL; ii++)
1253
-	{
1254
-		DecomposeToTriangles(mm[ii]);
1255
-		GenerateNormals(mm[ii]);
1256
-		md[ii] = GenerateModel(mm[ii]);
1257
-		DisposeMesh(mm[ii]);
1258
-	}
1259
-	free(mm);
1260
-	DisposeMtlList(gMaterials);
1261
-	DisposeMesh(mesh);
1262
-	gMtlNameList = NULL;
1263
-	gMaterials = NULL;
1264
-	
1265
-	for (int i = 0; md[i] != NULL; i++)
1266
-		GenModelBuffers(md[i]);
1267
-
1268
-	return md;
1269
-}
1270
-
1271
-// Loader for inline data to Model (almost same as LoadModelPlus)
1272
-Model* LoadDataToModel(
1273
-			vec3 *vertices,
1274
-			vec3 *normals,
1275
-			vec2 *texCoords,
1276
-			vec3 *colors,
1277
-			GLuint *indices,
1278
-			int numVert,
1279
-			int numInd)
1280
-{
1281
-	Model* m = (Model *)malloc(sizeof(Model));
1282
-	memset(m, 0, sizeof(Model));
1283
-	
1284
-	m->vertexArray = vertices;
1285
-	m->texCoordArray = texCoords;
1286
-	m->normalArray = normals;
1287
-	m->indexArray = indices;
1288
-	m->numVertices = numVert;
1289
-	m->numIndices = numInd;
1290
-	
1291
-	GenModelBuffers(m);
1292
-	
1293
-	return m;
1294
-}
1295
-
1296
-// Cleanup function, not tested!
1297
-void DisposeModel(Model *m)
1298
-{
1299
-	if (m != NULL)
1300
-	{
1301
-		if (m->vertexArray != NULL)
1302
-			free(m->vertexArray);
1303
-		if (m->normalArray != NULL)
1304
-			free(m->normalArray);
1305
-		if (m->texCoordArray != NULL)
1306
-			free(m->texCoordArray);
1307
-		if (m->colorArray != NULL) // obsolete?
1308
-			free(m->colorArray);
1309
-		if (m->indexArray != NULL)
1310
-			free(m->indexArray);
1311
-		
1312
-		// Lazy error checking here since "glDeleteBuffers silently ignores 0's and names that do not correspond to existing buffer objects."
1313
-		glDeleteBuffers(1, &m->vb);
1314
-		glDeleteBuffers(1, &m->ib);
1315
-		glDeleteBuffers(1, &m->nb);
1316
-		glDeleteBuffers(1, &m->tb);
1317
-		glDeleteVertexArrays(1, &m->vao);
1318
-		
1319
-		if (m->material != NULL)
1320
-			free(m->material);
1321
-	}
1322
-	free(m);
1323
-}
Browse code

Add cpp-v1

Ingemar Ragnemalm authored on 21/02/2024 20:24:28 • Robert Cranston committed on 21/02/2024 20:24:28
Showing 1 changed files
1 1
new file mode 100755
... ...
@@ -0,0 +1,1323 @@
1
+// Little OBJ loader
2
+// Ingemar's little OBJ loader
3
+// Formerly named LoadOBJ or loadobj
4
+// by Ingemar Ragnemalm 2005, 2008, 2019, 2021
5
+
6
+// Original version 2005 was extremely simple and intended for use with old OpenGL immediate mode.
7
+// Additions and reorganization by Mikael Kalms 2008
8
+// 120913: Revised LoadModelPlus/DrawModel by Jens.
9
+// Partially corrected formatting. (It is a mess!)
10
+// 130227: Error reporting in DrawModel
11
+// 130422: Added ScaleModel
12
+// 150909: Frees up temporary "Mesh" memory i LoadModel. Thanks to Simon Keisala for finding this!
13
+// Added DisposeModel. Limited the number of error printouts, thanks to Rasmus Hytter for this suggestion!
14
+// 160302: Uses fopen_s on Windows, as suggested by Jesper Post. Should reduce warnings a bit.
15
+// 160510: Uses calloc instead of malloc (for safety) in many places where it could possibly cause problems.
16
+// 170406: Added "const" to string arguments to make C++ happier.
17
+// 190416: free mesh->coordStarts properly.
18
+// 191110: Finally! Multi-part OBJ files work! Renamed LoadModelPlus to LoadModel.
19
+// and added LoadModelSet! The old LoadModel was removed. Converted to use vec2/vec3
20
+// instead of arrays of float. It is now dependent on VectorUtils3. If you want to
21
+// make it independent of VectorUtils3, only a few structs and functions have to be replaced.
22
+// MTL support working! Parser totally rewritten. Officially renamed to Ingemars Little OBJ Loader,
23
+// LOL for short! And boy did I find a nice acronym!
24
+// 210125: Corrected types in LoadDataToModel. Corrected material disposal in the still badly tested DisposeModel.
25
+// 210218: Allows TAB between parts of string.
26
+// 210304: Corrected bad allocation size on row 538, found by Jens Lindgren, who also found glDeleteVertexArrays in DisposeModel.
27
+// 210422: Change by Felicia Castenbrandt, around row 415, copy path or source. This change is likely to be needed in some other places.
28
+// 210502: Dispose the material name list, omission found by Jens Lindgren.
29
+
30
+// Usage:
31
+// Load simple models with LoadModel. Multi-part models are loaded with LoadModelSet.
32
+// DrawModel will draw the model, or, for a multi-part model, one part.
33
+// If you need to modify a model on the CPU, you can do that and re-upload
34
+// with LoadDataToModel.
35
+// There is no longer any call that only loads the data, but you can
36
+// make your own by taking out the GPU upload from LoadModel.
37
+
38
+// This is free software. I appreciate credits in derivate products or
39
+// if it is used in public products.
40
+
41
+#include "LittleOBJLoader.h"
42
+#include <stdio.h>
43
+#include <stdlib.h>
44
+#include <string.h>
45
+#include <math.h>
46
+#include "VectorUtils3.h"
47
+
48
+#if defined(_WIN32)
49
+	#define sscanf sscanf_s
50
+#endif
51
+
52
+
53
+static char atLineEnd = 0;
54
+static char atFileEnd = 0;
55
+
56
+static char ParseString(char *line, int *pos, char *s)
57
+{
58
+	int i = 0;
59
+	char c;
60
+	c = line[(*pos)++];
61
+	while (c == 32 || c == 9) // Important change 210218
62
+		c = line[(*pos)++]; // Skip leading spaces
63
+	while (c != 0 && c != 32 && c != 9  && c != EOF && c != '/' && i < 254)
64
+	{
65
+		s[i++] = c;
66
+		c = line[(*pos)++];
67
+	}
68
+	atLineEnd = (c == 0);
69
+	s[i] = 0;
70
+	
71
+	return c;
72
+}
73
+
74
+static float ParseFloat(char *line, int *pos)
75
+{
76
+	float floatValue = 0.0;
77
+	char s[255];
78
+	ParseString(line, pos, s);
79
+	sscanf(s, "%f", &floatValue);
80
+	if (isnan(floatValue) || isinf(floatValue))
81
+		floatValue = 0.0;
82
+	return floatValue;
83
+}
84
+
85
+static int ParseInt(char *line, int *pos, char *endc)
86
+{
87
+	int intValue = 0;
88
+	char s[255];
89
+	char c = ParseString(line, pos, s);
90
+	if (endc != NULL) *endc = c;
91
+	if (strlen(s) == 0)
92
+		intValue = -1; // Nothing found!
93
+	else
94
+		sscanf(s, "%d", &intValue);
95
+	return intValue;
96
+}
97
+
98
+static vec3 ParseVec3(char *line, int *pos)
99
+{
100
+	vec3 v;
101
+	v.x = ParseFloat(line, pos);
102
+	v.y = ParseFloat(line, pos);
103
+	v.z = ParseFloat(line, pos);
104
+	return v;
105
+}
106
+
107
+void ParseLine(FILE *fp, char *line)
108
+{
109
+	int i, j;
110
+	char c = '_';
111
+	for (i = 0, j= 0; i < 2048; i++)
112
+	{
113
+		c = getc(fp);
114
+		if (c != 10 && c != 13)
115
+			line[j++] = c;
116
+		if (c == EOF || ((c == 10 || c == 13) && j > 0))
117
+		{
118
+			if (c == EOF)
119
+				atFileEnd = 1;
120
+			line[j] = 0;
121
+			return;
122
+		}
123
+	}
124
+	line[j] = 0;
125
+	return;
126
+}
127
+
128
+
129
+// Dispose the strings in the materials list
130
+static void DisposeMtlList(Mtl **materials)
131
+{
132
+	if (materials != NULL)
133
+	for (int i = 0; materials[i] != NULL; i++)
134
+		free(materials[i]);
135
+	free(materials);
136
+}
137
+
138
+static Mtl **ParseMTL(char *filename)
139
+{
140
+	Mtl *m;
141
+	char s[255];
142
+	char line[2048];
143
+	int pos;
144
+	Mtl **materials = NULL;
145
+	FILE *fp;
146
+
147
+	// It seems Windows/VS doesn't like fopen any more, but fopen_s is not on the others.
148
+	#if defined(_WIN32)
149
+	fopen_s(&fp, filename, "r");
150
+	#else
151
+	fp = fopen(filename, "rb"); // rw works everywhere except Windows?
152
+	#endif
153
+	if (fp == NULL)
154
+		return NULL;
155
+	atLineEnd = 0;
156
+	atFileEnd = 0;
157
+	int matcount = 0;
158
+
159
+	while (!atFileEnd)
160
+	{
161
+		ParseLine(fp, line);
162
+		pos = 0;
163
+		ParseString(line, &pos, s);
164
+		if (strcmp(s, "newmtl") == 0)
165
+			matcount++;
166
+	}
167
+	rewind(fp);
168
+
169
+	materials = (Mtl **)calloc(sizeof(MtlPtr)*(matcount+1), 1);
170
+
171
+	matcount = 0;
172
+	atLineEnd = 0;
173
+	atFileEnd = 0;
174
+	
175
+	while (!atFileEnd)
176
+	{
177
+		ParseLine(fp, line);
178
+		pos = 0;
179
+		ParseString(line, &pos, s);
180
+
181
+		// NEW MATERIAL!
182
+		if (strcmp(s, "newmtl") == 0)
183
+		{
184
+			matcount++;
185
+			materials[matcount-1] = (Mtl *)calloc(sizeof(Mtl),1);
186
+			m = materials[matcount-1];
187
+			materials[matcount] = NULL;
188
+			
189
+			ParseString(line, &pos, m->newmtl);
190
+		}
191
+
192
+		if (m != NULL)
193
+		{
194
+			if (strcmp(s, "Ka") == 0)
195
+				m->Ka = ParseVec3(line, &pos);
196
+			if (strcmp(s, "Kd") == 0)
197
+				m->Kd = ParseVec3(line, &pos);
198
+			if (strcmp(s, "Ks") == 0)
199
+				m->Ks = ParseVec3(line, &pos);
200
+			if (strcmp(s, "Ke") == 0)
201
+				m->Ke = ParseVec3(line, &pos);
202
+			if (strcmp(s, "Tr") == 0)
203
+			{
204
+				m->Tr = ParseFloat(line, &pos);
205
+				m->d = 1 - m->Tr;
206
+			}
207
+			if (strcmp(s, "d") == 0)
208
+			{
209
+				m->d = ParseFloat(line, &pos);
210
+				m->Tr = 1 - m->d;
211
+			}
212
+
213
+			if (strcmp(s, "illum") == 0)
214
+				m->illum = ParseInt(line, &pos, NULL);
215
+
216
+			if (strcmp(s, "map_Ka") == 0)
217
+				ParseString(line, &pos, m->map_Ka);
218
+			if (strcmp(s, "map_Kd") == 0)
219
+				ParseString(line, &pos, m->map_Kd);
220
+			if (strcmp(s, "map_Ks") == 0)
221
+				ParseString(line, &pos, m->map_Ks);
222
+			if (strcmp(s, "map_Ke") == 0)
223
+				ParseString(line, &pos, m->map_Ke);
224
+			if (strcmp(s, "map_d") == 0)
225
+				ParseString(line, &pos, m->map_d);
226
+			if (strcmp(s, "map_bump") == 0)
227
+				ParseString(line, &pos, m->map_bump);
228
+			if (strcmp(s, "bump") == 0)
229
+				ParseString(line, &pos, m->map_bump);
230
+		}
231
+	}
232
+	fclose(fp);
233
+
234
+	return materials;
235
+}
236
+
237
+typedef struct Mesh
238
+{
239
+	vec3	*vertices;
240
+	int		vertexCount;
241
+	vec3	*vertexNormals;
242
+	int		normalsCount;
243
+	vec2	*textureCoords;
244
+	int		texCount;
245
+	
246
+	int		*coordIndex;
247
+	int		*normalsIndex;
248
+	int		*textureIndex;
249
+	int		coordCount; // Number of indices in each index struct
250
+	
251
+	// Borders between groups
252
+	int		*coordStarts;
253
+	int		groupCount;
254
+	
255
+	char	*materialName;
256
+} Mesh, *MeshPtr;
257
+
258
+// Globals set by LoadObj
259
+static int vertCount, texCount, normalsCount, coordCount;
260
+static int zeroFix;
261
+static char hasPositionIndices;
262
+static char hasNormalIndices;
263
+static char hasTexCoordIndices;
264
+
265
+// List of materials
266
+Mtl **gMaterials;
267
+char **gMtlNameList;
268
+char *gMtlLibName = NULL;
269
+
270
+static char ParseOBJ(const char *filename, MeshPtr theMesh)
271
+{
272
+	int lastCoordCount = -1;
273
+	FILE *fp;
274
+	
275
+	// It seems Windows/VS doesn't like fopen any more, but fopen_s is not on the others.
276
+	#if defined(_WIN32)
277
+	fopen_s(&fp, filename, "r");
278
+	#else
279
+	fp = fopen(filename, "rb"); // rw works everywhere except Windows?
280
+	#endif
281
+	if (fp == NULL)
282
+		return -1;
283
+
284
+// These must be taken care of by the caller!
285
+	vertCount=0;
286
+	texCount=0;
287
+	normalsCount=0;
288
+	coordCount=0;
289
+
290
+	atLineEnd = 0;
291
+	atFileEnd = 0;
292
+		
293
+	while (!atFileEnd)
294
+	{
295
+		char line[2048];
296
+		ParseLine(fp, line);
297
+		int pos = 0;
298
+		
299
+		char s[256];
300
+		ParseString(line, &pos, s);
301
+		
302
+		if (strcmp(s, "v") == 0)
303
+		{
304
+			vec3 v = ParseVec3(line, &pos);
305
+			if (theMesh->vertices != NULL)
306
+				theMesh->vertices[vertCount++] = v;
307
+			else
308
+				vertCount += 1;
309
+		}
310
+		if (strcmp(s, "vn") == 0)
311
+		{
312
+			vec3 v = ParseVec3(line, &pos);			
313
+			if (theMesh->vertexNormals != NULL)
314
+				theMesh->vertexNormals[normalsCount++] = v;
315
+			else
316
+				normalsCount += 1;
317
+		}
318
+		if (strcmp(s, "vt") == 0)
319
+		{
320
+			vec3 v = ParseVec3(line, &pos);
321
+			if (theMesh->textureCoords != NULL)
322
+			{
323
+				theMesh->textureCoords[texCount].x = v.x;
324
+				theMesh->textureCoords[texCount++].y = v.y;
325
+			}
326
+			else
327
+				texCount += 1;
328
+		}
329
+		if (strcmp(s, "f") == 0)
330
+		{
331
+		// Unknown number of singeltons or triplets!
332
+			
333
+			int p = -1;
334
+			int i = -1;
335
+			int p1;
336
+			char *ns;
337
+			char done = 0;
338
+			for (i = pos ; !done; pos++)
339
+			{
340
+				if (line[pos] == 0)
341
+					done = 1;
342
+				if (p >= 0) // in triplet)
343
+				{
344
+					char c = line[pos];
345
+					if (c == '/' || c == ' ' || c == 0)
346
+					{
347
+						ns = &line[p1]; // Start of substring
348
+						line[pos] = 0; // End of substring
349
+						if (p1 != pos)
350
+						{
351
+							i = atoi(ns);
352
+							if (i == 0)
353
+								zeroFix = 1;
354
+							if (i < 0)
355
+							{
356
+								switch (p)
357
+								{
358
+									case 0: i = vertCount + i + 1; break;
359
+									case 1: i = texCount + i + 1; break;
360
+									case 2: i = normalsCount + i + 1; break;
361
+								}
362
+							}
363
+							i = i + zeroFix;
364
+						}
365
+						else
366
+							i = 0; // -1
367
+						
368
+						if (i > 0)
369
+						switch (p)
370
+						{
371
+							case 0:
372
+								if (theMesh->coordIndex != NULL)
373
+									theMesh->coordIndex[coordCount-1] = i-1;
374
+								break;
375
+							case 1:
376
+								if (theMesh->textureIndex != NULL)
377
+									if (i >= 0)
378
+										theMesh->textureIndex[coordCount-1] = i-1;
379
+								hasTexCoordIndices = 1;
380
+								break;
381
+							case 2:
382
+								if (theMesh->normalsIndex != NULL)
383
+									if (i >= 0)
384
+										theMesh->normalsIndex[coordCount-1] = i-1;
385
+								hasNormalIndices = 1;
386
+								break;
387
+						}
388
+						p1 = pos + 1;
389
+						p++;
390
+					}
391
+					if (c == ' ')
392
+					{
393
+						p = -1; // Next triplet
394
+					}
395
+				}
396
+				else // Wait for non-space
397
+				if (line[pos] != ' ')
398
+				{
399
+					if (!done)
400
+						coordCount++;
401
+					p = 0; // Triplet starts!
402
+					p1 = pos;
403
+				}
404
+			}
405
+			
406
+			if (theMesh->coordIndex != NULL)
407
+				theMesh->coordIndex[coordCount] = -1;
408
+			if (theMesh->textureIndex != NULL)
409
+				theMesh->textureIndex[coordCount] = -1;
410
+			if (theMesh->normalsIndex != NULL)
411
+				theMesh->normalsIndex[coordCount] = -1;
412
+			coordCount++;
413
+		}
414
+		if (strcmp(s, "mtllib") == 0)
415
+		{
416
+			// Save file name for later
417
+			char libname[256];
418
+			
419
+			// Added by Felicia Castenbrandt: Get path of main file, if any
420
+        	char temp[255];
421
+			int index = 0;
422
+
423
+			//find index of last /
424
+			for(int i = 0; i < strlen(filename); i++)
425
+				if(filename[i] == '/')
426
+					index = i;
427
+
428
+			//copy everything before the last / to temp
429
+			if (index != 0)
430
+			{
431
+				for(int i = 0; i < index+1; i++)
432
+				{
433
+					char ch = filename[i];
434
+					strncat(temp, &ch, 1);
435
+				}
436
+			}
437
+			// End of addition
438
+			
439
+			
440
+			/*char c =*/ ParseString(line, &pos, libname);
441
+			gMtlLibName = (char *)malloc(strlen(libname)+1);
442
+#if defined(_WIN32)
443
+			strcpy_s(gMtlLibName, strlen(libname) + 1, libname);
444
+#else
445
+			strcpy(gMtlLibName, libname);
446
+#endif
447
+
448
+		}
449
+		if (strcmp(s, "usemtl") == 0)
450
+		{
451
+			// Groups are only identified by usemtl!
452
+			
453
+			if (coordCount > 0) // If no data has been seen, this must be the first group!
454
+			{
455
+				if (lastCoordCount != coordCount) // must not be the same; empty group (happens if a model has both "g" and "o")
456
+				{
457
+					theMesh->groupCount += 1;
458
+					if (theMesh->coordStarts != NULL) // NULL if we are just counting
459
+						theMesh->coordStarts[theMesh->groupCount] = coordCount;
460
+
461
+					lastCoordCount = coordCount;
462
+				}
463
+				else
464
+					printf("Ignored part!\n");
465
+			}
466
+			
467
+			if (gMtlNameList != NULL)
468
+			{
469
+				// Save matname for later
470
+				char matname[255];
471
+				ParseString(line, &pos, matname);
472
+				gMtlNameList[theMesh->groupCount] = (char *)malloc(strlen(matname)+1);
473
+#if defined(_WIN32)
474
+				strcpy_s(gMtlNameList[theMesh->groupCount], strlen(matname) + 1, matname);
475
+#else
476
+				strcpy(gMtlNameList[theMesh->groupCount], matname);
477
+#endif
478
+
479
+
480
+			}
481
+		}
482
+	} // While
483
+	
484
+	// Add last groups *if* there was more data since last time!
485
+	if (coordCount > lastCoordCount)
486
+	{
487
+		theMesh->groupCount += 1; // End of last group
488
+		if (theMesh->coordStarts != NULL)
489
+			theMesh->coordStarts[theMesh->groupCount] = coordCount;
490
+	}
491
+		
492
+	fclose(fp);
493
+	
494
+	if (gMtlLibName != NULL)
495
+		gMaterials = ParseMTL(gMtlLibName);
496
+	// else try based on filename: filename.obj -> filename.mtl or filename_obj.mtl
497
+	if (gMaterials == NULL)
498
+	if (strlen(filename) > 4)
499
+	{
500
+		char tryname[255];
501
+		strcpy(tryname, filename);
502
+		tryname[strlen(tryname) - 4] = '_';
503
+		strcat(tryname, ".mtl");
504
+		gMaterials = ParseMTL(tryname);
505
+	}
506
+	if (gMaterials == NULL)
507
+	if (strlen(filename) > 4)
508
+	{
509
+		char tmpname[255];
510
+		strcpy(tmpname, filename);
511
+		tmpname[strlen(tmpname) - 4] = 0;
512
+		strcat(tmpname, ".mtl");
513
+		gMaterials = ParseMTL(tmpname);
514
+	}
515
+	return 0;
516
+}
517
+
518
+// Load raw, unprocessed OBJ data!
519
+static struct Mesh * LoadOBJ(const char *filename)
520
+{
521
+	// Reads once to find sizes, again to fill buffers
522
+	Mesh *theMesh;
523
+	
524
+	// Allocate Mesh but not the buffers
525
+	theMesh = (Mesh *)calloc(sizeof(Mesh), 1);
526
+
527
+	hasPositionIndices = 1;
528
+	hasTexCoordIndices = 0;
529
+	hasNormalIndices = 0;
530
+
531
+	theMesh->coordStarts = NULL;
532
+	theMesh->groupCount = 0;
533
+	gMtlNameList = NULL;
534
+
535
+// Dispose if they exist!
536
+	gMtlLibName = NULL;
537
+	gMaterials = NULL;
538
+
539
+	vertCount=0;
540
+	texCount=0;
541
+	normalsCount=0;
542
+	coordCount=0;
543
+	zeroFix = 0;
544
+		
545
+	// Parse for size
546
+	ParseOBJ(filename, theMesh);
547
+
548
+	// Allocate arrays!
549
+	if (vertCount > 0)
550
+		theMesh->vertices = (vec3 *)malloc(sizeof(vec3) * vertCount);
551
+	if (texCount > 0)
552
+		theMesh->textureCoords = (vec2 *)malloc(sizeof(vec2) * texCount);
553
+	if (normalsCount > 0)
554
+		theMesh->vertexNormals = (vec3 *)malloc(sizeof(vec3) * normalsCount);
555
+	if (hasPositionIndices)
556
+		theMesh->coordIndex = (int *)calloc(coordCount, sizeof(int));
557
+	if (hasNormalIndices)
558
+		theMesh->normalsIndex = (int *)calloc(coordCount, sizeof(int));
559
+	if (hasTexCoordIndices)
560
+		theMesh->textureIndex = (int *)calloc(coordCount, sizeof(int));
561
+
562
+	gMtlNameList = (char **)calloc(sizeof(char *) * (theMesh->groupCount+1), 1);
563
+	theMesh->coordStarts = (int *)calloc(sizeof(int) * (theMesh->groupCount+2), 1); // Length found on last pass
564
+	theMesh->groupCount = 0;
565
+
566
+	// Zero again
567
+	vertCount=0;
568
+	texCount=0;
569
+	normalsCount=0;
570
+	coordCount=0;
571
+
572
+	// Parse again for filling buffers
573
+	ParseOBJ(filename, theMesh);
574
+	
575
+	theMesh->vertexCount = vertCount;
576
+	theMesh->coordCount = coordCount;
577
+	theMesh->texCount = texCount;
578
+	theMesh->normalsCount = normalsCount;
579
+
580
+	return theMesh;
581
+}
582
+
583
+void DecomposeToTriangles(struct Mesh *theMesh)
584
+{
585
+	int i, vertexCount, triangleCount;
586
+	int *newCoords, *newNormalsIndex, *newTextureIndex;
587
+	int newIndex = 0; // Index in newCoords
588
+	int first = 0;
589
+
590
+	// 1.1 Calculate how big the list will become
591
+	
592
+	vertexCount = 0; // Number of vertices in current polygon
593
+	triangleCount = 0; // Resulting number of triangles
594
+	for (i = 0; i < theMesh->coordCount; i++)
595
+	{
596
+		if (theMesh->coordIndex[i] == -1)
597
+		{
598
+		if (vertexCount > 2) triangleCount += vertexCount - 2;
599
+			vertexCount = 0;
600
+		}
601
+		else
602
+		{
603
+			vertexCount = vertexCount + 1;
604
+		}
605
+	}
606
+		
607
+	newCoords = (int *)calloc(triangleCount * 3, sizeof(int));
608
+	if (theMesh->normalsIndex != NULL)
609
+		newNormalsIndex = (int *)calloc(triangleCount * 3, sizeof(int));
610
+	if (theMesh->textureIndex != NULL)
611
+		newTextureIndex = (int *)calloc(triangleCount * 3, sizeof(int));
612
+	
613
+	// 1.2 Loop through old list and write the new one
614
+	// Almost same loop but now it has space to write the result
615
+	vertexCount = 0;
616
+	for (i = 0; i < theMesh->coordCount; i++)
617
+	{
618
+		if (theMesh->coordIndex[i] == -1)
619
+		{
620
+			first = i + 1;
621
+			vertexCount = 0;
622
+		}
623
+		else
624
+		{
625
+			vertexCount = vertexCount + 1;
626
+			if (vertexCount > 2)
627
+			{
628
+				newCoords[newIndex++] = theMesh->coordIndex[first];
629
+				newCoords[newIndex++] = theMesh->coordIndex[i-1];
630
+				newCoords[newIndex++] = theMesh->coordIndex[i];
631
+				if (theMesh->normalsIndex != NULL)
632
+				{
633
+					newNormalsIndex[newIndex-3] = theMesh->normalsIndex[first];
634
+					newNormalsIndex[newIndex-2] = theMesh->normalsIndex[i-1];
635
+					newNormalsIndex[newIndex-1] = theMesh->normalsIndex[i];
636
+				}
637
+				if (theMesh->textureIndex != NULL)
638
+				{
639
+					newTextureIndex[newIndex-3] = theMesh->textureIndex[first];
640
+					newTextureIndex[newIndex-2] = theMesh->textureIndex[i-1];
641
+					newTextureIndex[newIndex-1] = theMesh->textureIndex[i];
642
+				}
643
+			}
644
+		}
645
+	}
646
+	
647
+	free(theMesh->coordIndex);
648
+	theMesh->coordIndex = newCoords;
649
+	theMesh->coordCount = triangleCount * 3;
650
+	if (theMesh->normalsIndex != NULL)
651
+	{
652
+		free(theMesh->normalsIndex);
653
+		theMesh->normalsIndex = newNormalsIndex;
654
+	}
655
+	if (theMesh->textureIndex != NULL)
656
+	{
657
+		free(theMesh->textureIndex);
658
+		theMesh->textureIndex = newTextureIndex;
659
+	}
660
+} // DecomposeToTriangles
661
+
662
+static void GenerateNormals(Mesh* mesh)
663
+{
664
+	// If model has vertices but no vertexnormals, generate normals
665
+	if (mesh->vertices && !mesh->vertexNormals)
666
+	{
667
+		int face;
668
+		int normalIndex;
669
+
670
+		mesh->vertexNormals = (vec3 *)calloc(sizeof(vec3) * mesh->vertexCount, 1);
671
+		mesh->normalsCount = mesh->vertexCount;
672
+
673
+		mesh->normalsIndex = (int *)calloc(mesh->coordCount, sizeof(GLuint));
674
+		memcpy(mesh->normalsIndex, mesh->coordIndex, sizeof(GLuint) * mesh->coordCount);
675
+
676
+		for (face = 0; face * 3 < mesh->coordCount; face++)
677
+		{
678
+			int i0 = mesh->coordIndex[face * 3 + 0];
679
+			int i1 = mesh->coordIndex[face * 3 + 1];
680
+			int i2 = mesh->coordIndex[face * 3 + 2];
681
+			
682
+			vec3 v0 = VectorSub(mesh->vertices[i1], mesh->vertices[i0]);
683
+			vec3 v1 = VectorSub(mesh->vertices[i2], mesh->vertices[i0]);
684
+			vec3 v2 = VectorSub(mesh->vertices[i2], mesh->vertices[i1]);
685
+
686
+			float sqrLen0 = dot(v0, v0);
687
+			float sqrLen1 = dot(v1, v1);
688
+			float sqrLen2 = dot(v2, v2);
689
+
690
+			float len0 = (sqrLen0 >= 1e-6f) ? sqrt(sqrLen0) : 1e-3f;
691
+			float len1 = (sqrLen1 >= 1e-6f) ? sqrt(sqrLen1) : 1e-3f;
692
+			float len2 = (sqrLen2 >= 1e-6f) ? sqrt(sqrLen2) : 1e-3f;
693
+
694
+			float influence0 = dot(v0, v1) / (len0 * len1);
695
+			float influence1 = -dot(v0, v2) / (len0 * len2);
696
+			float influence2 = dot(v1, v2) / (len1 * len2);
697
+
698
+			float angle0 = (influence0 >= 1.f) ? 0 : 
699
+				(influence0 <= -1.f) ? M_PI : acos(influence0);
700
+			float angle1 = (influence1 >= 1.f) ? 0 : 
701
+				(influence1 <= -1.f) ? M_PI : acos(influence1);
702
+			float angle2 = (influence2 >= 1.f) ? 0 : 
703
+				(influence2 <= -1.f) ? M_PI : acos(influence2);
704
+
705
+			vec3 normal = cross(v0, v1);
706
+			mesh->vertexNormals[i0] = VectorAdd(ScalarMult(normal, angle0), mesh->vertexNormals[i0]);
707
+			mesh->vertexNormals[i1] = VectorAdd(ScalarMult(normal, angle1), mesh->vertexNormals[i1]);
708
+			mesh->vertexNormals[i2] = VectorAdd(ScalarMult(normal, angle2), mesh->vertexNormals[i2]);
709
+		}
710
+
711
+		for (normalIndex = 0; normalIndex < mesh->normalsCount; normalIndex++)
712
+		{
713
+			float length = Norm(mesh->vertexNormals[normalIndex]);
714
+			if (length > 0.01f)
715
+				mesh->vertexNormals[normalIndex] = ScalarMult(mesh->vertexNormals[normalIndex], 1/length);
716
+		}
717
+	}
718
+}
719
+
720
+static Model* GenerateModel(Mesh* mesh)
721
+{
722
+	// Convert from Mesh format (multiple index lists) to Model format
723
+	// (one index list) by generating a new set of vertices/indices
724
+	// and where new vertices have been created whenever necessary
725
+
726
+	typedef struct
727
+	{
728
+		int positionIndex;
729
+		int normalIndex;
730
+		int texCoordIndex;
731
+		int newIndex;
732
+	} IndexTriplet;
733
+
734
+	int hashGap = 6;
735
+
736
+	int indexHashMapSize = (mesh->vertexCount * hashGap + mesh->coordCount);
737
+
738
+	IndexTriplet* indexHashMap = (IndexTriplet *)malloc(sizeof(IndexTriplet)
739
+							* indexHashMapSize);
740
+
741
+	int numNewVertices = 0;
742
+	int index;
743
+
744
+	int maxValue = 0;
745
+		
746
+	Model* model = (Model *)malloc(sizeof(Model));
747
+	memset(model, 0, sizeof(Model));
748
+
749
+	model->indexArray = (GLuint *)malloc(sizeof(GLuint) * mesh->coordCount);
750
+	model->numIndices = mesh->coordCount;
751
+
752
+	memset(indexHashMap, 0xff, sizeof(IndexTriplet) * indexHashMapSize);
753
+
754
+	for (index = 0; index < mesh->coordCount; index++)
755
+	{
756
+		IndexTriplet currentVertex = { -1, -1, -1, -1 };
757
+		int insertPos = 0;
758
+		if (mesh->coordIndex)
759
+			currentVertex.positionIndex = mesh->coordIndex[index];
760
+		if (mesh->normalsIndex)
761
+			currentVertex.normalIndex = mesh->normalsIndex[index];
762
+		if (mesh->textureIndex)
763
+			currentVertex.texCoordIndex = mesh->textureIndex[index];
764
+
765
+		if (maxValue < currentVertex.texCoordIndex)
766
+			maxValue = currentVertex.texCoordIndex;
767
+ 
768
+		if (currentVertex.positionIndex >= 0)
769
+			insertPos = currentVertex.positionIndex * hashGap;
770
+
771
+		while (1)
772
+		{
773
+			if (indexHashMap[insertPos].newIndex == -1)
774
+				{
775
+					currentVertex.newIndex = numNewVertices++;
776
+					indexHashMap[insertPos] = currentVertex;
777
+					break;
778
+				}
779
+			else if (indexHashMap[insertPos].positionIndex
780
+				 == currentVertex.positionIndex
781
+				 && indexHashMap[insertPos].normalIndex
782
+				 == currentVertex.normalIndex
783
+				 && indexHashMap[insertPos].texCoordIndex
784
+				 == currentVertex.texCoordIndex)
785
+				{
786
+					currentVertex.newIndex = indexHashMap[insertPos].newIndex;
787
+					break;
788
+				}
789
+			else
790
+				insertPos++;
791
+		} 
792
+
793
+		model->indexArray[index] = currentVertex.newIndex;
794
+	}
795
+
796
+	if (mesh->vertices)
797
+		model->vertexArray = (vec3 *)malloc(sizeof(vec3) * numNewVertices);
798
+	if (mesh->vertexNormals)
799
+		model->normalArray = (vec3 *)malloc(sizeof(vec3) * numNewVertices);
800
+	if (mesh->textureCoords)
801
+		model->texCoordArray = (vec2 *)malloc(sizeof(vec2) * numNewVertices);
802
+	
803
+	model->numVertices = numNewVertices;
804
+
805
+	for (index = 0; index < indexHashMapSize; index++)
806
+	{
807
+		if (indexHashMap[index].newIndex != -1)
808
+		{
809
+			if (mesh->vertices)
810
+				model->vertexArray[indexHashMap[index].newIndex] = mesh->vertices[indexHashMap[index].positionIndex];
811
+			if (mesh->vertexNormals)
812
+			{
813
+				model->normalArray[indexHashMap[index].newIndex] = mesh->vertexNormals[indexHashMap[index].normalIndex];
814
+			}
815
+			if (mesh->textureCoords)
816
+				model->texCoordArray[indexHashMap[index].newIndex] = mesh->textureCoords[indexHashMap[index].texCoordIndex];
817
+		}
818
+	}
819
+
820
+	free(indexHashMap);
821
+
822
+	// If there is a material set, match materials to parts
823
+	if (gMaterials != NULL)
824
+	if (mesh->materialName != NULL)
825
+		for (int ii = 0; gMaterials[ii] != NULL; ii++)
826
+		{
827
+			Mtl *mtl = gMaterials[ii];
828
+			if (strcmp(mesh->materialName, mtl->newmtl) == 0)
829
+			{
830
+				// Copy mtl to model!
831
+				model->material = (Mtl *)malloc(sizeof(Mtl));
832
+				memcpy(model->material, mtl, sizeof(Mtl));
833
+
834
+				strcpy(model->material->map_Ka, mtl->map_Ka);
835
+				strcpy(model->material->map_Kd, mtl->map_Kd);
836
+				strcpy(model->material->map_Ks, mtl->map_Ks);
837
+				strcpy(model->material->map_Ke, mtl->map_Ke);
838
+				strcpy(model->material->map_Ns, mtl->map_Ns);
839
+				strcpy(model->material->map_d, mtl->map_d);
840
+				strcpy(model->material->map_bump, mtl->map_bump);
841
+			}
842
+		}
843
+
844
+	return model;
845
+}
846
+
847
+Mesh **SplitToMeshes(Mesh *m)
848
+{
849
+	int * mapc = (int *)malloc(m->vertexCount * sizeof(int));
850
+	int * mapt = (int *)malloc(m->texCount * sizeof(int));
851
+	int * mapn = (int *)malloc(m->normalsCount * sizeof(int));
852
+	
853
+	if (m == NULL || m ->vertices == NULL || m->vertexCount == 0)
854
+	{
855
+		printf("Illegal mesh!\n");
856
+		return NULL;
857
+	}
858
+	
859
+	Mesh **mm = (Mesh **)calloc(sizeof(Mesh *), m->groupCount+2);
860
+
861
+	for (int mi = 0; mi < m->groupCount; mi++) // For all sections
862
+	{
863
+		int from = m->coordStarts[mi];
864
+		int to = m->coordStarts[mi+1];
865
+		
866
+		mm[mi] = (Mesh *)calloc(sizeof(Mesh), 1); // allocate struct
867
+		
868
+		// Fill mapc, mapt, mapn with -1 (illegal index)
869
+		for (int ii = 0; ii < m->vertexCount; ii++)
870
+			mapc[ii] = -1;
871
+		for (int ii = 0; ii < m->texCount; ii++)
872
+			mapt[ii] = -1;
873
+		for (int ii = 0; ii < m->normalsCount; ii++)
874
+			mapn[ii] = -1;
875
+		
876
+		// Count number of entries needed
877
+		int intVertexCount = 0;
878
+		int intTexCount = 0;
879
+		int intNormalsCount = 0;
880
+		
881
+		for (int j = from; j < to; j++) // For all index triplets
882
+		{
883
+			int ix = m->coordIndex[j];
884
+			if (ix > -1)
885
+				if (mapc[ix] == -1)
886
+				{
887
+					mapc[ix] = ix;
888
+					intVertexCount++;
889
+				}
890
+			if (m->textureIndex != NULL)
891
+			{
892
+				ix = m->textureIndex[j];
893
+				if (ix > -1)
894
+					if (mapt[ix] == -1)
895
+					{
896
+						mapt[ix] = ix;
897
+						intTexCount++;
898
+					}
899
+			}
900
+			if (m->normalsIndex != NULL)
901
+			{
902
+				ix = m->normalsIndex[j];
903
+				if (ix > -1)
904
+					if (mapn[ix] == -1)
905
+					{
906
+						mapn[ix] = ix;
907
+						intNormalsCount++;
908
+					}
909
+			}
910
+		}
911
+				
912
+		// Allocate buffers
913
+		mm[mi]->coordIndex = (int *)malloc((to - from) * sizeof(int));
914
+		mm[mi]->textureIndex = (int *)malloc((to - from) * sizeof(int));
915
+		mm[mi]->normalsIndex = (int *)malloc((to - from) * sizeof(int));
916
+		if (intVertexCount > 0)
917
+			mm[mi]->vertices = (vec3 *)malloc(intVertexCount * sizeof(vec3));
918
+		if (intTexCount > 0)
919
+			mm[mi]->textureCoords = (vec2 *)malloc(intTexCount * sizeof(vec2));
920
+		if (intNormalsCount > 0)
921
+			mm[mi]->vertexNormals = (vec3 *)malloc(intNormalsCount * sizeof(vec3));
922
+		mm[mi]->vertexCount = intVertexCount;
923
+		mm[mi]->texCount = intTexCount;
924
+		mm[mi]->normalsCount = intNormalsCount;
925
+		
926
+		// Fill mapc, mapt, mapn with -1 (illegal index)
927
+		for (int ii = 0; ii < m->vertexCount; ii++)
928
+			mapc[ii] = -1;
929
+		for (int ii = 0; ii < m->texCount; ii++)
930
+			mapt[ii] = -1;
931
+		for (int ii = 0; ii < m->normalsCount; ii++)
932
+			mapn[ii] = -1;
933
+		
934
+		int mapcCount = 0;
935
+		int maptCount = 0;
936
+		int mapnCount = 0;
937
+		for (int j = from; j < to; j++) // For all index triplets
938
+		{
939
+			int ix = m->coordIndex[j];
940
+			if (ix > -1)
941
+			{
942
+				if (mapc[ix] == -1) // Unmapped
943
+				{
944
+					mapc[ix] = mapcCount++;
945
+					mm[mi]->vertices[mapc[ix]] = m->vertices[ix]; // Copy vertex to mm[i]
946
+				}
947
+				mm[mi]->coordIndex[j-from] = mapc[ix];
948
+			}
949
+			else // Separator
950
+			{
951
+				mm[mi]->coordIndex[j-from] = -1;
952
+			}
953
+
954
+			if (m->textureIndex != NULL)
955
+			if (mm[mi]->textureIndex != NULL)
956
+			{
957
+				ix = m->textureIndex[j];
958
+				if (ix > -1)
959
+				{
960
+					if (mapt[ix] == -1) // Unmapped
961
+					{
962
+						mapt[ix] = maptCount++;
963
+						mm[mi]->textureCoords[mapt[ix]] = m->textureCoords[ix]; // Copy vertex to mm[i]
964
+					}
965
+					mm[mi]->textureIndex[j-from] = mapt[ix];
966
+				}
967
+				else // Separator
968
+				{
969
+					mm[mi]->textureIndex[j-from] = -1;
970
+				}
971
+			}
972
+
973
+			if (m->normalsIndex != NULL)
974
+			if (mm[mi]->normalsIndex != NULL)
975
+			{
976
+				ix = m->normalsIndex[j];
977
+				if (ix > -1)
978
+				{
979
+					if (mapn[ix] == -1) // Unmapped
980
+					{
981
+						mapn[ix] = mapnCount++;
982
+						mm[mi]->vertexNormals[mapn[ix]] = m->vertexNormals[ix]; // Copy vertex to mm[i]
983
+					}
984
+					mm[mi]->normalsIndex[j-from] = mapn[ix];
985
+				}
986
+				else // Separator
987
+				{
988
+					mm[mi]->normalsIndex[j-from] = -1;
989
+				}
990
+			}
991
+		} // for all index triplets
992
+		mm[mi]->coordCount = to - from;
993
+		
994
+		if (gMtlNameList != NULL)
995
+		{
996
+			mm[mi]->materialName = gMtlNameList[mi];
997
+			gMtlNameList[mi] = NULL; // No longer "owned" by the gMtlNameList
998
+		}
999
+	} // for all parts
1000
+	
1001
+	return mm;
1002
+}
1003
+
1004
+
1005
+static void DisposeMesh(Mesh *mesh)
1006
+{
1007
+// Free the mesh!
1008
+	if (mesh != NULL)
1009
+	{
1010
+		if (mesh->vertices != NULL)
1011
+			free(mesh->vertices);
1012
+		if (mesh->vertexNormals != NULL)
1013
+			free(mesh->vertexNormals);
1014
+		if (mesh->textureCoords != NULL)
1015
+			free(mesh->textureCoords);
1016
+		if (mesh->coordIndex != NULL)
1017
+			free(mesh->coordIndex);
1018
+		if (mesh->normalsIndex != NULL)
1019
+			free(mesh->normalsIndex);
1020
+		if (mesh->textureIndex != NULL)
1021
+			free(mesh->textureIndex);
1022
+#if !defined(_WIN32)
1023
+// This is very disturbing, causes heap corruption on Windows. Reason not found.
1024
+		if (mesh->coordStarts != NULL)
1025
+			free(mesh->coordStarts);
1026
+#endif
1027
+		if (mesh->materialName != NULL)
1028
+			free(mesh->materialName);
1029
+
1030
+// Dispose the material name list too
1031
+		if (gMtlNameList != NULL)
1032
+		{
1033
+			for (int i = 0; i < mesh->groupCount; i++)
1034
+				if (gMtlNameList[i] != NULL)
1035
+					free(gMtlNameList[i]);
1036
+			free(gMtlNameList);
1037
+			gMtlNameList = NULL;
1038
+		}
1039
+
1040
+		free(mesh);
1041
+	}
1042
+}
1043
+
1044
+void CenterModel(Model *m)
1045
+{
1046
+	int i;
1047
+	float maxx = -1e10, maxy = -1e10, maxz = -1e10, minx = 1e10, miny = 1e10, minz = 1e10;
1048
+	
1049
+	for (i = 0; i < m->numVertices; i++)
1050
+	{
1051
+		if (m->vertexArray[i].x < minx) minx = m->vertexArray[i].x;
1052
+		if (m->vertexArray[i].x > maxx) maxx = m->vertexArray[i].x;
1053
+		if (m->vertexArray[i].y < miny) miny = m->vertexArray[i].y;
1054
+		if (m->vertexArray[i].y > maxy) maxy = m->vertexArray[i].y;
1055
+		if (m->vertexArray[i].z < minz) minz = m->vertexArray[i].z;
1056
+		if (m->vertexArray[i].z > maxz) maxz = m->vertexArray[i].z;
1057
+	}
1058
+	
1059
+	for (i = 0; i < m->numVertices; i++)
1060
+	{
1061
+		m->vertexArray[i].x -= (maxx + minx)/2.0f;
1062
+		m->vertexArray[i].y -= (maxy + miny)/2.0f;
1063
+		m->vertexArray[i].z -= (maxz + minz)/2.0f;
1064
+	}
1065
+}
1066
+
1067
+void ScaleModel(Model *m, float sx, float sy, float sz)
1068
+{
1069
+	long i;
1070
+	for (i = 0; i < m->numVertices; i++)
1071
+	{
1072
+		m->vertexArray[i].x *= sx;
1073
+		m->vertexArray[i].y *= sy;
1074
+		m->vertexArray[i].z *= sz;
1075
+	}
1076
+}
1077
+
1078
+static void ReportRerror(const char *caller, const char *name)
1079
+{
1080
+	static unsigned int draw_error_counter = 0; 
1081
+   if(draw_error_counter < NUM_DRAWMODEL_ERROR)
1082
+   {
1083
+		    fprintf(stderr, "%s warning: '%s' not found in shader!\n", caller, name);
1084
+		    draw_error_counter++;
1085
+   }
1086
+   else if(draw_error_counter == NUM_DRAWMODEL_ERROR)
1087
+   {
1088
+		    fprintf(stderr, "%s: Number of error bigger than %i. No more vill be printed.\n", caller, NUM_DRAWMODEL_ERROR);
1089
+		    draw_error_counter++;
1090
+   }
1091
+}
1092
+
1093
+// This code makes a lot of calls for rebinding variables just in case,
1094
+// and to get attribute locations. This is clearly not optimal, but the
1095
+// goal is stability.
1096
+
1097
+void DrawModel(Model *m, GLuint program, const char* vertexVariableName, const char* normalVariableName, const char* texCoordVariableName)
1098
+{
1099
+	if (m != NULL)
1100
+	{
1101
+		GLint loc;
1102
+		
1103
+		glBindVertexArray(m->vao);	// Select VAO
1104
+
1105
+		glBindBuffer(GL_ARRAY_BUFFER, m->vb);
1106
+		loc = glGetAttribLocation(program, vertexVariableName);
1107
+		if (loc >= 0)
1108
+		{
1109
+			glVertexAttribPointer(loc, 3, GL_FLOAT, GL_FALSE, 0, 0); 
1110
+			glEnableVertexAttribArray(loc);
1111
+		}
1112
+		else
1113
+			ReportRerror("DrawModel", vertexVariableName);
1114
+		
1115
+		if (normalVariableName!=NULL)
1116
+		{
1117
+			loc = glGetAttribLocation(program, normalVariableName);
1118
+			if (loc >= 0)
1119
+			{
1120
+				glBindBuffer(GL_ARRAY_BUFFER, m->nb);
1121
+				glVertexAttribPointer(loc, 3, GL_FLOAT, GL_FALSE, 0, 0);
1122
+				glEnableVertexAttribArray(loc);
1123
+			}
1124
+			else
1125
+				ReportRerror("DrawModel", normalVariableName);
1126
+		}
1127
+	
1128
+		if ((m->texCoordArray != NULL)&&(texCoordVariableName != NULL))
1129
+		{
1130
+			loc = glGetAttribLocation(program, texCoordVariableName);
1131
+			if (loc >= 0)
1132
+			{
1133
+				glBindBuffer(GL_ARRAY_BUFFER, m->tb);
1134
+				glVertexAttribPointer(loc, 2, GL_FLOAT, GL_FALSE, 0, 0);
1135
+				glEnableVertexAttribArray(loc);
1136
+			}
1137
+			else
1138
+				ReportRerror("DrawModel", texCoordVariableName);
1139
+		}
1140
+
1141
+		glDrawElements(GL_TRIANGLES, m->numIndices, GL_UNSIGNED_INT, 0L);
1142
+	}
1143
+}
1144
+
1145
+void DrawWireframeModel(Model *m, GLuint program, const char* vertexVariableName, const char* normalVariableName, const char* texCoordVariableName)
1146
+{
1147
+	if (m != NULL)
1148
+	{
1149
+		GLint loc;
1150
+		
1151
+		glBindVertexArray(m->vao);	// Select VAO
1152
+
1153
+		glBindBuffer(GL_ARRAY_BUFFER, m->vb);
1154
+		loc = glGetAttribLocation(program, vertexVariableName);
1155
+		if (loc >= 0)
1156
+		{
1157
+			glVertexAttribPointer(loc, 3, GL_FLOAT, GL_FALSE, 0, 0); 
1158
+			glEnableVertexAttribArray(loc);
1159
+		}
1160
+		else
1161
+			ReportRerror("DrawWireframeModel", vertexVariableName);
1162
+		
1163
+		if (normalVariableName!=NULL)
1164
+		{
1165
+			loc = glGetAttribLocation(program, normalVariableName);
1166
+			if (loc >= 0)
1167
+			{
1168
+				glBindBuffer(GL_ARRAY_BUFFER, m->nb);
1169
+				glVertexAttribPointer(loc, 3, GL_FLOAT, GL_FALSE, 0, 0);
1170
+				glEnableVertexAttribArray(loc);
1171
+			}
1172
+			else
1173
+				ReportRerror("DrawWireframeModel", normalVariableName);
1174
+		}
1175
+	
1176
+		if ((m->texCoordArray != NULL)&&(texCoordVariableName != NULL))
1177
+		{
1178
+			loc = glGetAttribLocation(program, texCoordVariableName);
1179
+			if (loc >= 0)
1180
+			{
1181
+				glBindBuffer(GL_ARRAY_BUFFER, m->tb);
1182
+				glVertexAttribPointer(loc, 2, GL_FLOAT, GL_FALSE, 0, 0);
1183
+				glEnableVertexAttribArray(loc);
1184
+			}
1185
+			else
1186
+				ReportRerror("DrawWireframeModel", texCoordVariableName);
1187
+		}
1188
+		glDrawElements(GL_LINE_STRIP, m->numIndices, GL_UNSIGNED_INT, 0L);
1189
+	}
1190
+}
1191
+	
1192
+// Called from LoadModel, LoadModelSet and LoadDataToModel
1193
+// VAO and VBOs must already exist!
1194
+// Useful by its own when the model changes on CPU
1195
+void ReloadModelData(Model *m)
1196
+{
1197
+	glBindVertexArray(m->vao);
1198
+	
1199
+	// VBO for vertex data
1200
+	glBindBuffer(GL_ARRAY_BUFFER, m->vb);
1201
+	glBufferData(GL_ARRAY_BUFFER, m->numVertices*3*sizeof(GLfloat), m->vertexArray, GL_STATIC_DRAW);
1202
+	
1203
+	// VBO for normal data
1204
+	glBindBuffer(GL_ARRAY_BUFFER, m->nb);
1205
+	glBufferData(GL_ARRAY_BUFFER, m->numVertices*3*sizeof(GLfloat), m->normalArray, GL_STATIC_DRAW);
1206
+	
1207
+	// VBO for texture coordinate data NEW for 5b
1208
+	if (m->texCoordArray != NULL)
1209
+	{
1210
+		glBindBuffer(GL_ARRAY_BUFFER, m->tb);
1211
+		glBufferData(GL_ARRAY_BUFFER, m->numVertices*2*sizeof(GLfloat), m->texCoordArray, GL_STATIC_DRAW);
1212
+	}
1213
+	
1214
+	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m->ib);
1215
+	glBufferData(GL_ELEMENT_ARRAY_BUFFER, m->numIndices*sizeof(GLuint), m->indexArray, GL_STATIC_DRAW);
1216
+}
1217
+
1218
+static void GenModelBuffers(Model *m)
1219
+{
1220
+	glGenVertexArrays(1, &m->vao);
1221
+	glGenBuffers(1, &m->vb);
1222
+	glGenBuffers(1, &m->ib);
1223
+	glGenBuffers(1, &m->nb);
1224
+	if (m->texCoordArray != NULL)
1225
+		glGenBuffers(1, &m->tb);
1226
+
1227
+	ReloadModelData(m);
1228
+}
1229
+
1230
+// For simple models
1231
+Model* LoadModel(const char* name)
1232
+{
1233
+	Model* model = NULL;
1234
+	Mesh* mesh = LoadOBJ(name);
1235
+	DecomposeToTriangles(mesh);
1236
+	GenerateNormals(mesh);
1237
+	model = GenerateModel(mesh);
1238
+	DisposeMesh(mesh);
1239
+
1240
+	GenModelBuffers(model);	
1241
+	return model;
1242
+}
1243
+
1244
+// For multiple part models
1245
+Model** LoadModelSet(const char* name)
1246
+{
1247
+	Mesh* mesh = LoadOBJ(name);
1248
+	Mesh **mm = SplitToMeshes(mesh);
1249
+	int i, ii;
1250
+	for (i = 0; mm[i] != NULL; i++) {}
1251
+	Model **md = (Model **)calloc(sizeof(Model *), i+1);
1252
+	for (ii = 0; mm[ii] != NULL; ii++)
1253
+	{
1254
+		DecomposeToTriangles(mm[ii]);
1255
+		GenerateNormals(mm[ii]);
1256
+		md[ii] = GenerateModel(mm[ii]);
1257
+		DisposeMesh(mm[ii]);
1258
+	}
1259
+	free(mm);
1260
+	DisposeMtlList(gMaterials);
1261
+	DisposeMesh(mesh);
1262
+	gMtlNameList = NULL;
1263
+	gMaterials = NULL;
1264
+	
1265
+	for (int i = 0; md[i] != NULL; i++)
1266
+		GenModelBuffers(md[i]);
1267
+
1268
+	return md;
1269
+}
1270
+
1271
+// Loader for inline data to Model (almost same as LoadModelPlus)
1272
+Model* LoadDataToModel(
1273
+			vec3 *vertices,
1274
+			vec3 *normals,
1275
+			vec2 *texCoords,
1276
+			vec3 *colors,
1277
+			GLuint *indices,
1278
+			int numVert,
1279
+			int numInd)
1280
+{
1281
+	Model* m = (Model *)malloc(sizeof(Model));
1282
+	memset(m, 0, sizeof(Model));
1283
+	
1284
+	m->vertexArray = vertices;
1285
+	m->texCoordArray = texCoords;
1286
+	m->normalArray = normals;
1287
+	m->indexArray = indices;
1288
+	m->numVertices = numVert;
1289
+	m->numIndices = numInd;
1290
+	
1291
+	GenModelBuffers(m);
1292
+	
1293
+	return m;
1294
+}
1295
+
1296
+// Cleanup function, not tested!
1297
+void DisposeModel(Model *m)
1298
+{
1299
+	if (m != NULL)
1300
+	{
1301
+		if (m->vertexArray != NULL)
1302
+			free(m->vertexArray);
1303
+		if (m->normalArray != NULL)
1304
+			free(m->normalArray);
1305
+		if (m->texCoordArray != NULL)
1306
+			free(m->texCoordArray);
1307
+		if (m->colorArray != NULL) // obsolete?
1308
+			free(m->colorArray);
1309
+		if (m->indexArray != NULL)
1310
+			free(m->indexArray);
1311
+		
1312
+		// Lazy error checking here since "glDeleteBuffers silently ignores 0's and names that do not correspond to existing buffer objects."
1313
+		glDeleteBuffers(1, &m->vb);
1314
+		glDeleteBuffers(1, &m->ib);
1315
+		glDeleteBuffers(1, &m->nb);
1316
+		glDeleteBuffers(1, &m->tb);
1317
+		glDeleteVertexArrays(1, &m->vao);
1318
+		
1319
+		if (m->material != NULL)
1320
+			free(m->material);
1321
+	}
1322
+	free(m);
1323
+}