Browse code

Standardize OpenGL-related #includes and #defines

We use glXGetProcAddress to load glXCreateContextAttribsARB ourselves,
so GLX_GLXEXT_PROTOTYPES is not needed.

Robert Cranston authored on 27/02/2024 02:27:47
Showing 1 changed files
... ...
@@ -1,12 +1,13 @@
1 1
 #ifndef loadobj_h
2 2
 #define loadobj_h
3 3
 
4
-#ifdef __APPLE__
4
+#if defined(__APPLE__)
5
+	#define GL_SILENCE_DEPRECATION
5 6
 	#include <OpenGL/gl3.h>
7
+#elif defined(_WIN32)
8
+	#include "glew.h"
6 9
 #else
7
-	#if defined(_WIN32)
8
-		#include "glew.h"
9
-	#endif
10
+	#define GL_GLEXT_PROTOTYPES
10 11
 	#include <GL/gl.h>
11 12
 #endif
12 13
 
Browse code

Remove executable bit on files

find . -type f -exec chmod -x {} +

Robert Cranston authored on 27/02/2024 02:27:27
Showing 1 changed files
1 1
old mode 100755
2 2
new mode 100644
Browse code

Add cpp-v5

Ingemar Ragnemalm authored on 21/02/2024 20:24:32 • Robert Cranston committed on 21/02/2024 20:24:32
Showing 1 changed files
... ...
@@ -84,8 +84,12 @@ void DisposeModel(Model *m);
84 84
 //}
85 85
 ///#endif
86 86
 
87
+#endif
88
+
87 89
 // --------------- Implementation part ----------------
88 90
 
91
+#ifdef MAIN
92
+
89 93
 #ifndef LOL_IMPLEMENTATION
90 94
 #define LOL_IMPLEMENTATION
91 95
 
Browse code

Add cpp-v4

Ingemar Ragnemalm authored on 21/02/2024 20:24:31 • Robert Cranston committed on 21/02/2024 20:24:31
Showing 1 changed files
... ...
@@ -86,7 +86,7 @@ void DisposeModel(Model *m);
86 86
 
87 87
 // --------------- Implementation part ----------------
88 88
 
89
-#ifdef LOL_IMPLEMENTATION
89
+#ifndef LOL_IMPLEMENTATION
90 90
 #define LOL_IMPLEMENTATION
91 91
 
92 92
 // Little OBJ loader
Browse code

Add cpp-v3

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