aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc Sunet <jeannekamikaze@gmail.com>2012-08-11 11:41:21 +0200
committerMarc Sunet <jeannekamikaze@gmail.com>2012-08-11 11:41:21 +0200
commit08f5c4618dcdbf94bd8451d75f0f376b3726adcf (patch)
tree75e35fd99cfd142eddb810b02955033bf339dda6
parent7404d6f6ca90777cae55bdb352aa85bcc0edf7cc (diff)
OBJ loader rewritten in C
-rw-r--r--Spear.cabal7
-rw-r--r--Spear.lkshs12
-rw-r--r--Spear.lkshw2
-rw-r--r--Spear/Assets/Model/OBJ/Makefile17
-rw-r--r--Spear/Assets/Model/OBJ/OBJ_load.c276
-rw-r--r--Spear/Assets/Model/OBJ/OBJ_load.cc273
-rw-r--r--Spear/Assets/Model/OBJ/cvector.c90
-rw-r--r--Spear/Assets/Model/OBJ/cvector.h36
-rw-r--r--Spear/Assets/Model/OBJ/test.cc47
9 files changed, 424 insertions, 336 deletions
diff --git a/Spear.cabal b/Spear.cabal
index d30cbae..37ab48b 100644
--- a/Spear.cabal
+++ b/Spear.cabal
@@ -42,15 +42,16 @@ library
42 cc-options: -O2 -g -Wno-unused-result 42 cc-options: -O2 -g -Wno-unused-result
43 c-sources: Spear/Assets/Image/Image.c 43 c-sources: Spear/Assets/Image/Image.c
44 Spear/Assets/Image/BMP/BMP_load.c Spear/Assets/Model/Model.c 44 Spear/Assets/Image/BMP/BMP_load.c Spear/Assets/Model/Model.c
45 Spear/Assets/Model/MD2/MD2_load.c 45 Spear/Assets/Model/MD2/MD2_load.c Spear/Assets/Model/OBJ/cvector.c
46 Spear/Assets/Model/OBJ/OBJ_load.cc Spear/Render/RenderModel.c 46 Spear/Assets/Model/OBJ/OBJ_load.c Spear/Render/RenderModel.c
47 Spear/Sys/Timer/ctimer.c 47 Spear/Sys/Timer/ctimer.c
48 extensions: TypeFamilies 48 extensions: TypeFamilies
49 extra-libraries: stdc++ 49 extra-libraries: stdc++
50 includes: Spear/Assets/Image/BMP/BMP_load.h 50 includes: Spear/Assets/Image/BMP/BMP_load.h
51 Spear/Assets/Image/Image.h Spear/Assets/Image/Image_error_code.h 51 Spear/Assets/Image/Image.h Spear/Assets/Image/Image_error_code.h
52 Spear/Assets/Image/sys_types.h Spear/Assets/Model/MD2/MD2_load.h 52 Spear/Assets/Image/sys_types.h Spear/Assets/Model/MD2/MD2_load.h
53 Spear/Assets/Model/OBJ/OBJ_load.h Spear/Assets/Model/Model.h 53 Spear/Assets/Model/OBJ/OBJ_load.h Spear/Assets/Model/OBJ/cvector.h
54 Spear/Assets/Model/Model.h
54 Spear/Assets/Model/Model_error_code.h 55 Spear/Assets/Model/Model_error_code.h
55 Spear/Assets/Model/sys_types.h Spear/Render/RenderModel.h 56 Spear/Assets/Model/sys_types.h Spear/Render/RenderModel.h
56 Timer/Timer.h 57 Timer/Timer.h
diff --git a/Spear.lkshs b/Spear.lkshs
index d69e4f9..c4ef8ee 100644
--- a/Spear.lkshs
+++ b/Spear.lkshs
@@ -1,18 +1,18 @@
1Version of session file format: 1Version of session file format:
2 1 2 1
3Time of storage: 3Time of storage:
4 "Fri Aug 10 15:19:04 CEST 2012" 4 "Fri Aug 10 23:05:26 CEST 2012"
5Layout: VerticalP (TerminalP {paneGroups = fromList [], paneTabs = Just TopP, currentPage = 4, detachedId = Nothing, detachedSize = Nothing}) (HorizontalP (TerminalP {paneGroups = fromList [("Browser",HorizontalP (TerminalP {paneGroups = fromList [], paneTabs = Nothing, currentPage = 0, detachedId = Nothing, detachedSize = Nothing}) (HorizontalP (TerminalP {paneGroups = fromList [], paneTabs = Nothing, currentPage = 0, detachedId = Nothing, detachedSize = Nothing}) (TerminalP {paneGroups = fromList [], paneTabs = Nothing, currentPage = 0, detachedId = Nothing, detachedSize = Nothing}) 255) 201)], paneTabs = Just BottomP, currentPage = 0, detachedId = Nothing, detachedSize = Nothing}) (TerminalP {paneGroups = fromList [], paneTabs = Nothing, currentPage = 0, detachedId = Nothing, detachedSize = Nothing}) 707) 954 5Layout: VerticalP (TerminalP {paneGroups = fromList [], paneTabs = Just TopP, currentPage = 3, detachedId = Nothing, detachedSize = Nothing}) (HorizontalP (TerminalP {paneGroups = fromList [("Browser",HorizontalP (TerminalP {paneGroups = fromList [], paneTabs = Nothing, currentPage = 0, detachedId = Nothing, detachedSize = Nothing}) (HorizontalP (TerminalP {paneGroups = fromList [], paneTabs = Nothing, currentPage = 0, detachedId = Nothing, detachedSize = Nothing}) (TerminalP {paneGroups = fromList [], paneTabs = Nothing, currentPage = 0, detachedId = Nothing, detachedSize = Nothing}) 244) 202)], paneTabs = Just BottomP, currentPage = 0, detachedId = Nothing, detachedSize = Nothing}) (TerminalP {paneGroups = fromList [], paneTabs = Nothing, currentPage = 0, detachedId = Nothing, detachedSize = Nothing}) 710) 954
6Population: [(Just (ErrorsSt ErrorsState),[SplitP RightP,SplitP TopP]),(Just (FilesSt FilesState),[SplitP RightP,SplitP TopP]),(Just (InfoSt (InfoState Nothing)),[SplitP RightP,SplitP TopP,GroupP "Browser",SplitP BottomP,SplitP BottomP]),(Just (BufferSt (BufferState "/home/jeanne/programming/haskell/Spear/Spear/Scene/Loader.hs" 6686)),[SplitP LeftP]),(Just (LogSt LogState),[SplitP RightP,SplitP BottomP]),(Just (BufferSt (BufferState "/home/jeanne/programming/haskell/Spear/Spear/Assets/Model/MD2/MD2_load.c" 13934)),[SplitP LeftP]),(Just (BufferSt (BufferState "/home/jeanne/programming/haskell/Spear/Spear/Assets/Model/Model.c" 433)),[SplitP LeftP]),(Just (BufferSt (BufferState "/home/jeanne/programming/haskell/Spear/Spear/Assets/Model/Model.h" 1424)),[SplitP LeftP]),(Just (BufferSt (BufferState "/home/jeanne/programming/haskell/Spear/Spear/Assets/Model.hsc" 12957)),[SplitP LeftP]),(Just (ModulesSt (ModulesState 328 (PackageScope False,False) (Nothing,Nothing) (ExpanderState {packageExp = ([],[]), packageExpNoBlack = ([],[]), packageDExp = ([],[]), packageDExpNoBlack = ([],[]), workspaceExp = ([],[]), workspaceExpNoBlack = ([[0,2],[0]],[]), workspaceDExp = ([],[]), workspaceDExpNoBlack = ([],[]), systemExp = ([],[]), systemExpNoBlack = ([],[])}))),[SplitP RightP,SplitP TopP,GroupP "Browser",SplitP BottomP,SplitP TopP]),(Just (BufferSt (BufferState "/home/jeanne/programming/haskell/Spear/Spear/Assets/Model/OBJ/OBJ_load.cc" 266)),[SplitP LeftP]),(Just (BufferSt (BufferState "/home/jeanne/programming/haskell/Spear/Spear/Assets/Model/OBJ/OBJ_load.h" 0)),[SplitP LeftP]),(Just (WorkspaceSt WorkspaceState),[SplitP RightP,SplitP TopP,GroupP "Browser",SplitP TopP])] 6Population: [(Just (ErrorsSt ErrorsState),[SplitP RightP,SplitP TopP]),(Just (FilesSt FilesState),[SplitP RightP,SplitP TopP]),(Just (InfoSt (InfoState Nothing)),[SplitP RightP,SplitP TopP,GroupP "Browser",SplitP BottomP,SplitP BottomP]),(Just (LogSt LogState),[SplitP RightP,SplitP BottomP]),(Just (BufferSt (BufferState "/home/jeanne/programming/haskell/Spear/Spear/Assets/Model/Model.c" 433)),[SplitP LeftP]),(Just (BufferSt (BufferState "/home/jeanne/programming/haskell/Spear/Spear/Assets/Model/Model.h" 1424)),[SplitP LeftP]),(Just (BufferSt (BufferState "/home/jeanne/programming/haskell/Spear/Spear/Assets/Model.hsc" 423)),[SplitP LeftP]),(Just (ModulesSt (ModulesState 328 (PackageScope False,False) (Nothing,Nothing) (ExpanderState {packageExp = ([],[]), packageExpNoBlack = ([],[]), packageDExp = ([],[]), packageDExpNoBlack = ([],[]), workspaceExp = ([],[]), workspaceExpNoBlack = ([[0,2],[0]],[]), workspaceDExp = ([],[]), workspaceDExpNoBlack = ([],[]), systemExp = ([],[]), systemExpNoBlack = ([],[])}))),[SplitP RightP,SplitP TopP,GroupP "Browser",SplitP BottomP,SplitP TopP]),(Just (BufferSt (BufferState "/home/jeanne/programming/haskell/Spear/Spear/Assets/Model/OBJ/OBJ_load.c" 3824)),[SplitP LeftP]),(Just (BufferSt (BufferState "/home/jeanne/programming/haskell/Spear/Spear/Assets/Model/OBJ/OBJ_load.h" 0)),[SplitP LeftP]),(Just (WorkspaceSt WorkspaceState),[SplitP RightP,SplitP TopP,GroupP "Browser",SplitP TopP]),(Just (BufferSt (BufferState "/home/jeanne/programming/haskell/Spear/Spear/Assets/Model/OBJ/cvector.c" 575)),[SplitP LeftP]),(Just (BufferSt (BufferState "/home/jeanne/programming/haskell/Spear/Spear/Assets/Model/OBJ/cvector.h" 765)),[SplitP LeftP])]
7Window size: (1841,964) 7Window size: (1841,964)
8Completion size: 8Completion size:
9 (750,400) 9 (750,400)
10Workspace: Just "/home/jeanne/programming/haskell/Spear/Spear.lkshw" 10Workspace: Just "/home/jeanne/programming/haskell/Spear/Spear.lkshw"
11Active pane: Just "Model.hsc" 11Active pane: Just "OBJ_load.c"
12Toolbar visible: 12Toolbar visible:
13 True 13 True
14FindbarState: (False,FindState {entryStr = "asd", entryHist = ["allocaBytes","copyArray","allocaArray","allocaa","putStrLn","assigned","Triangle","transforma","gravity","asdad","rotSpeed","azimuth"], replaceStr = "objects", replaceHist = [], caseSensitive = True, entireWord = False, wrapAround = False, regex = False, lineNr = 1}) 14FindbarState: (False,FindState {entryStr = "asd", entryHist = ["idxs","asd","elemIndexa","elemtIn","splitAt","allocaBytes","copyArray","allocaArray","allocaa","putStrLn","assigned","Triangle"], replaceStr = "objects", replaceHist = [], caseSensitive = True, entireWord = False, wrapAround = False, regex = False, lineNr = 1})
15Recently opened files: 15Recently opened files:
16 ["/home/jeanne/programming/haskell/Spear/Spear/Assets/Image.hsc","/home/jeanne/programming/haskell/Spear/Spear/Render/Model.hsc","/home/jeanne/programming/haskell/Spear/demos/simple-scene/main.hs","/home/jeanne/programming/haskell/Spear/demos/simple-scene/Game/GameObject/Player.hs","/home/jeanne/programming/haskell/Spear/demos/simple-scene/Game/GameState.hs","/home/jeanne/programming/haskell/Spear/demos/simple-scene/Game/GameObject.hs","/home/jeanne/programming/haskell/Spear/demos/simple-scene/Game/GameMessage.hs","/home/jeanne/programming/haskell/Spear/demos/simple-scene/Game/GameObject/Factory.hs","/home/jeanne/programming/haskell/Spear/demos/simple-scene/Game/Animation/Ogro.hs","/home/jeanne/programming/haskell/Spear/demos/simple-scene/Game/GameObject/AnimatedGO.hs","/home/jeanne/programming/haskell/Spear/demos/simple-scene/Game/GameObject/StaticGO.hs","/home/jeanne/programming/haskell/Spear/demos/simple-scene/Game/GameObject/Render.hs"] 16 ["/home/jeanne/programming/haskell/Spear/Spear/Scene/Loader.hs","/home/jeanne/programming/haskell/Spear/Spear/Assets/Model/OBJ/OBJ_load.h","/home/jeanne/programming/haskell/Spear/Spear/Assets/Model/OBJ/OBJ_load.cc","/home/jeanne/programming/haskell/Spear/Spear/Assets/Model/MD2/MD2_load.c","/home/jeanne/programming/haskell/Spear/Spear/Assets/Image.hsc","/home/jeanne/programming/haskell/Spear/Spear/Render/Model.hsc","/home/jeanne/programming/haskell/Spear/demos/simple-scene/main.hs","/home/jeanne/programming/haskell/Spear/demos/simple-scene/Game/GameObject/Player.hs","/home/jeanne/programming/haskell/Spear/demos/simple-scene/Game/GameState.hs","/home/jeanne/programming/haskell/Spear/demos/simple-scene/Game/GameObject.hs","/home/jeanne/programming/haskell/Spear/demos/simple-scene/Game/GameMessage.hs","/home/jeanne/programming/haskell/Spear/demos/simple-scene/Game/GameObject/Factory.hs"]
17Recently opened workspaces: 17Recently opened workspaces:
18 ["/home/jeanne/leksah.lkshw"] \ No newline at end of file 18 ["/home/jeanne/leksah.lkshw"] \ No newline at end of file
diff --git a/Spear.lkshw b/Spear.lkshw
index 143acdc..1cbf39e 100644
--- a/Spear.lkshw
+++ b/Spear.lkshw
@@ -1,7 +1,7 @@
1Version of workspace file format: 1Version of workspace file format:
2 1 2 1
3Time of storage: 3Time of storage:
4 "Fri Aug 10 15:56:20 CEST 2012" 4 "Sat Aug 11 11:39:35 CEST 2012"
5Name of the workspace: 5Name of the workspace:
6 "Spear" 6 "Spear"
7File paths of contained packages: 7File paths of contained packages:
diff --git a/Spear/Assets/Model/OBJ/Makefile b/Spear/Assets/Model/OBJ/Makefile
index 6f9556f..34424f7 100644
--- a/Spear/Assets/Model/OBJ/Makefile
+++ b/Spear/Assets/Model/OBJ/Makefile
@@ -1,10 +1,15 @@
1all: OBJ_load.h OBJ_load.cc test.cc ../Model.c 1test: ../Model.o OBJ_load.o cvector.o test.o
2 g++ -g -c OBJ_load.cc 2 $(CC) Model.o OBJ_load.o cvector.o test.o -o $@ -lm
3 g++ -g -c test.cc 3
4 g++ -g -c ../Model.c -o Model.o 4vector: cvector.o vector-test.o
5 g++ -o test *.o 5 $(CC) cvector.o vector-test.o -o vector
6
7
8%.o: %.c %.h
9 $(CC) -g -c $<
10
6 11
7clean: 12clean:
8 @rm -f test 13 @rm -f test vector
9 @rm -f *.o 14 @rm -f *.o
10 15
diff --git a/Spear/Assets/Model/OBJ/OBJ_load.c b/Spear/Assets/Model/OBJ/OBJ_load.c
new file mode 100644
index 0000000..2474091
--- /dev/null
+++ b/Spear/Assets/Model/OBJ/OBJ_load.c
@@ -0,0 +1,276 @@
1#include "OBJ_load.h"
2#include "cvector.h"
3#include <stdio.h>
4#include <stdlib.h> // free
5#include <string.h> // memcpy
6#include <math.h> // sqrt
7
8
9char lastError [128];
10
11
12static void safe_free (void* ptr)
13{
14 if (ptr)
15 {
16 free (ptr);
17 ptr = 0;
18 }
19}
20
21
22// Cross product.
23// (0,1,0) x (1,0,0) = (0,0,-1).
24static void cross (vec3 a, vec3 b, vec3* c)
25{
26 c->x = a.y * b.z - a.z * b.y;
27 c->y = a.z * b.x - a.x * b.z;
28 c->z = a.x * b.y - a.y * b.x;
29}
30
31
32static void vec3_sub (vec3 a, vec3 b, vec3* out)
33{
34 out->x = a.x - b.x;
35 out->y = a.y - b.y;
36 out->z = a.z - b.z;
37}
38
39
40static void compute_normal (char clockwise, vec3 p1, vec3 p2, vec3 p3, vec3* n)
41{
42 vec3 v1, v2;
43 if (clockwise)
44 {
45 vec3_sub (p3, p2, &v1);
46 vec3_sub (p1, p2, &v2);
47 }
48 else
49 {
50 vec3_sub (p1, p2, &v1);
51 vec3_sub (p3, p2, &v2);
52 }
53 cross (v1, v2, n);
54}
55
56
57static void normalise (vec3* v)
58{
59 float x = v->x;
60 float y = v->y;
61 float z = v->z;
62 float mag = sqrt (x*x + y*y + z*z);
63 mag = mag == 0.0f ? 1.0f : mag;
64 v->x /= mag;
65 v->y /= mag;
66 v->z /= mag;
67}
68
69
70static void vec3_add (vec3 a, vec3* b)
71{
72 b->x += a.x;
73 b->y += a.y;
74 b->z += a.z;
75}
76
77
78static void read_vertex (FILE* file, vec3* vert)
79{
80 fscanf (file, "%f %f", &vert->x, &vert->y);
81 if (fscanf(file, "%f", &vert->z) == 0) vert->z = 0.0f;
82}
83
84
85static void read_normal (FILE* file, vec3* normal)
86{
87 fscanf (file, "%f %f %f", &normal->x, &normal->y, &normal->z);
88}
89
90
91static void read_tex_coord (FILE* file, texCoord* texc)
92{
93 fscanf (file, "%f %f", &texc->s, &texc->t);
94}
95
96
97static void read_face (FILE* file,
98 char clockwise,
99 vector* vertices,
100 vector* normals,
101 vector* triangles)
102{
103 vector idxs;
104 vector texCoords;
105
106 vector_new (&idxs, sizeof(int), 4);
107 vector_new (&texCoords, sizeof(int), 4);
108
109 unsigned int index;
110 unsigned int normal;
111 unsigned int texc;
112
113 fscanf (file, "f");
114
115 while (!feof(file) && fscanf(file, "%d", &index) > 0)
116 {
117 vector_append (&idxs, &index);
118
119 if (fgetc (file) == '/')
120 {
121 fscanf (file, "%d", &texc);
122 vector_append (&texCoords, &texc);
123 }
124 else fseek (file, -1, SEEK_CUR);
125
126 if (fgetc (file) == '/')
127 {
128 fscanf (file, "%d", &normal);
129 }
130 else fseek (file, -1, SEEK_CUR);
131 }
132
133 // Triangulate the face and add its triangles to the triangles vector.
134 triangle tri;
135 tri.vertexIndices[0] = *((int*) vector_ith (&idxs, 0)) - 1;
136 tri.textureIndices[0] = *((int*) vector_ith (&texCoords, 0)) - 1;
137
138 int i;
139 for (i = 1; i < vector_size(&idxs)-1; i++)
140 {
141 tri.vertexIndices[1] = *((int*) vector_ith (&idxs, i)) - 1;
142 tri.textureIndices[1] = *((int*) vector_ith (&texCoords, i)) - 1;
143 tri.vertexIndices[2] = *((int*) vector_ith (&idxs, i+1)) - 1;
144 tri.textureIndices[2] = *((int*) vector_ith (&texCoords, i+1)) - 1;
145 vector_append (triangles, &tri);
146 }
147
148 // Compute face normal and add contribution to each of the face's vertices.
149 unsigned int i0 = tri.vertexIndices[0];
150 unsigned int i1 = tri.vertexIndices[1];
151 unsigned int i2 = tri.vertexIndices[2];
152
153 vec3 n;
154 vec3 v0 = *((vec3*) vector_ith (vertices, i0));
155 vec3 v1 = *((vec3*) vector_ith (vertices, i1));
156 vec3 v2 = *((vec3*) vector_ith (vertices, i2));
157 compute_normal (clockwise, v0, v1, v2, &n);
158
159 for (i = 0; i < vector_size (&idxs); i++)
160 {
161 int j = *((int*) vector_ith (&idxs, i)) - 1;
162 vec3* normal = (vec3*) vector_ith (normals, j);
163 vec3_add (n, normal);
164 }
165
166 vector_free (&idxs);
167 vector_free (&texCoords);
168}
169
170
171Model_error_code OBJ_load (const char* filename, char clockwise, char left_handed, Model* model)
172{
173 vec3* norms = 0;
174 vec3* verts = 0;
175 texCoord* texcs = 0;
176 triangle* tris = 0;
177
178 FILE* file = fopen (filename, "r");
179 if (file == NULL) return Model_File_Not_Found;
180
181 vec3 vert;
182 vec3 normal;
183 texCoord texc;
184
185 vector vertices;
186 vector normals;
187 vector texCoords;
188 vector triangles;
189
190 int result = vector_new (&vertices, sizeof(vec3), 0)
191 | vector_new (&normals, sizeof(vec3), 0)
192 | vector_new (&texCoords, sizeof(texCoord), 0)
193 | vector_new (&triangles, sizeof(triangle), 0);
194
195 if (result != 0)
196 {
197 safe_free (vertices.data);
198 safe_free (normals.data);
199 safe_free (texCoords.data);
200 safe_free (triangles.data);
201 return Model_Memory_Allocation_Error;
202 }
203
204 while (!feof(file))
205 {
206 switch (fgetc(file))
207 {
208 case 'v':
209 switch (fgetc(file))
210 {
211 case 't':
212 read_tex_coord (file, &texc);
213 vector_append (&texCoords, &texc);
214 break;
215
216 case 'n':
217 read_normal (file, &normal);
218 vector_append (&normals, &normal);
219 break;
220
221 default:
222 read_vertex (file, &vert);
223 vector_append (&vertices, &vert);
224 break;
225 }
226 break;
227
228 case 'f':
229 // Initialise the normals vector if it is empty.
230 if (vector_size(&normals) == 0)
231 {
232 vec3 zero;
233 zero.x = 0.0f; zero.y = 0.0f; zero.z = 0.0f;
234 vector_new (&normals, sizeof(vec3), vector_size(&vertices));
235 vector_initialise (&normals, &zero);
236 }
237 read_face (file, clockwise, &vertices, &normals, &triangles);
238 break;
239
240 case '#':
241 {
242 int x = 17;
243 while (x != '\n' && x != EOF) x = fgetc(file);
244 break;
245 }
246
247 default: break;
248 }
249 }
250
251 fclose (file);
252
253 unsigned numVertices = vector_size (&vertices);
254
255 // Normalise normals.
256 unsigned i;
257 for (i = 0; i < numVertices; ++i)
258 {
259 normalise (vector_ith (&normals, i));
260 }
261
262 model->vertices = (vec3*) vertices.data;
263 model->normals = (vec3*) normals.data;
264 model->texCoords = (texCoord*) texCoords.data;
265 model->triangles = (triangle*) triangles.data;
266 model->skins = 0;
267 model->animations = 0;
268 model->numFrames = 1;
269 model->numVertices = numVertices;
270 model->numTriangles = vector_size (&triangles);
271 model->numTexCoords = vector_size (&texCoords);
272 model->numSkins = 0;
273 model->numAnimations = 0;
274
275 return Model_Success;
276}
diff --git a/Spear/Assets/Model/OBJ/OBJ_load.cc b/Spear/Assets/Model/OBJ/OBJ_load.cc
deleted file mode 100644
index bf409b1..0000000
--- a/Spear/Assets/Model/OBJ/OBJ_load.cc
+++ /dev/null
@@ -1,273 +0,0 @@
1#include "OBJ_load.h"
2#include <cstdio>
3#include <cstdlib> // free
4#include <cstring> // memcpy
5#include <cmath> // sqrt
6#include <vector>
7
8
9char lastError [128];
10
11
12static void safe_free (void* ptr)
13{
14 if (ptr)
15 {
16 free (ptr);
17 ptr = 0;
18 }
19}
20
21
22// Cross product.
23// (0,1,0) x (1,0,0) = (0,0,-1).
24static void cross (const vec3& a, const vec3& b, vec3& c)
25{
26 c.x = a.y * b.z - a.z * b.y;
27 c.y = a.z * b.x - a.x * b.z;
28 c.z = a.x * b.y - a.y * b.x;
29}
30
31
32static void vec3_sub (const vec3& a, const vec3& b, vec3& out)
33{
34 out.x = a.x - b.x;
35 out.y = a.y - b.y;
36 out.z = a.z - b.z;
37}
38
39
40static void compute_normal (char clockwise, const vec3& p1, const vec3& p2, const vec3& p3, vec3& n)
41{
42 vec3 v1, v2;
43 if (clockwise)
44 {
45 vec3_sub (p3, p2, v1);
46 vec3_sub (p1, p2, v2);
47 }
48 else
49 {
50 vec3_sub (p1, p2, v1);
51 vec3_sub (p3, p2, v2);
52 }
53 cross (v1, v2, n);
54}
55
56
57static void normalise (vec3& v)
58{
59 float x = v.x;
60 float y = v.y;
61 float z = v.z;
62 float mag = sqrt (x*x + y*y + z*z);
63 mag = mag == 0.0f ? 1.0f : mag;
64 v.x /= mag;
65 v.y /= mag;
66 v.z /= mag;
67}
68
69
70static void vec3_add (const vec3& a, vec3& b)
71{
72 b.x += a.x;
73 b.y += a.y;
74 b.z += a.z;
75}
76
77
78static void read_vertex (FILE* file, vec3& vert)
79{
80 fscanf (file, "%f %f", &vert.x, &vert.y);
81 if (fscanf(file, "%f", &vert.z) == 0) vert.z = 0.0f;
82}
83
84
85static void read_normal (FILE* file, vec3& normal)
86{
87 fscanf (file, "%f %f %f", &normal.x, &normal.y, &normal.z);
88}
89
90
91static void read_tex_coord (FILE* file, texCoord& texc)
92{
93 fscanf (file, "%f %f", &texc.s, &texc.t);
94}
95
96
97static void read_face (FILE* file, char clockwise,
98 const std::vector<vec3>& vertices,
99 std::vector<vec3>& normals,
100 std::vector<triangle>& triangles)
101{
102 std::vector<unsigned int> idxs;
103 std::vector<unsigned int> texCoords;
104
105 unsigned int index;
106 unsigned int normal;
107 unsigned int texc;
108
109 fscanf (file, "f");
110
111 while (!feof(file) && fscanf(file, "%d", &index) > 0)
112 {
113 idxs.push_back(index);
114
115 if (fgetc (file) == '/')
116 {
117 fscanf (file, "%d", &texc);
118 texCoords.push_back(texc);
119 }
120 else fseek (file, -1, SEEK_CUR);
121
122 if (fgetc (file) == '/')
123 {
124 fscanf (file, "%d", &normal);
125 }
126 else fseek (file, -1, SEEK_CUR);
127 }
128
129 // Triangulate the face and add its triangles to the triangles vector.
130 triangle tri;
131 tri.vertexIndices[0] = idxs[0] - 1;
132 tri.textureIndices[0] = texCoords[0] - 1;
133
134 for (int i = 1; i < idxs.size()-1; i++)
135 {
136 tri.vertexIndices[1] = idxs[i] - 1;
137 tri.textureIndices[1] = texCoords[i] - 1;
138 tri.vertexIndices[2] = idxs[i+1] - 1;
139 tri.textureIndices[2] = texCoords[i+1] - 1;
140 triangles.push_back(tri);
141 }
142
143 // Compute face normal and add contribution to each of the face's vertices.
144 unsigned int i0 = tri.vertexIndices[0];
145 unsigned int i1 = tri.vertexIndices[1];
146 unsigned int i2 = tri.vertexIndices[2];
147
148 vec3 n;
149 compute_normal (clockwise, vertices[i0], vertices[i1], vertices[i2], n);
150
151 for (int i = 0; i < idxs.size(); i++)
152 {
153 vec3_add (n, normals[idxs[i]-1]);
154 }
155}
156
157
158Model_error_code OBJ_load (const char* filename, char clockwise, char left_handed, Model* model)
159{
160 vec3* norms = 0;
161 vec3* verts = 0;
162 texCoord* texcs = 0;
163 triangle* tris = 0;
164 FILE* file = 0;
165
166 try
167 {
168 file = fopen (filename, "r");
169
170 vec3 vert;
171 vec3 normal;
172 texCoord texc;
173
174 std::vector<vec3> vertices;
175 std::vector<vec3> normals;
176 std::vector<texCoord> texCoords;
177 std::vector<triangle> triangles;
178
179 while (!feof(file))
180 {
181 switch (fgetc(file))
182 {
183 case 'v':
184 switch (fgetc(file))
185 {
186 case 't':
187 read_tex_coord (file, texc);
188 texCoords.push_back(texc);
189 break;
190
191 case 'n':
192 read_normal (file, normal);
193 break;
194
195 default:
196 read_vertex (file, vert);
197 vertices.push_back(vert);
198 break;
199 }
200 break;
201
202 case 'f':
203 // If the normals vector has no size, initialise it.
204 if (normals.size() == 0)
205 {
206 vec3 zero;
207 zero.x = 0.0f; zero.y = 0.0f; zero.z = 0.0f;
208 normals = std::vector<vec3>(vertices.size(), zero);
209 }
210 read_face (file, clockwise, vertices, normals, triangles);
211 break;
212
213 case '#':
214 {
215 int x = 17;
216 while (x != '\n' && x != EOF) x = fgetc(file);
217 break;
218 }
219
220 default: break;
221 }
222 }
223
224 fclose (file);
225
226 unsigned int numVertices = vertices.size();
227 unsigned int numTexCoords = texCoords.size();
228 unsigned int numTriangles = triangles.size();
229
230 verts = new vec3 [numVertices];
231 norms = new vec3 [numVertices];
232 texcs = new texCoord [numTexCoords];
233 tris = new triangle [numTriangles];
234
235 memcpy (verts, &vertices[0], numVertices * sizeof(vec3));
236 memcpy (norms, &normals[0], numVertices * sizeof(vec3));
237 memcpy (texcs, &texCoords[0], numTexCoords * sizeof(texCoord));
238 memcpy (tris, &triangles[0], numTriangles * sizeof(triangle));
239
240 // Copy normals if the model file specified them.
241
242
243
244 // Otherwise normalise the normals that have been previously computed.
245
246 for (size_t i = 0; i < numVertices; ++i)
247 {
248 normalise(norms[i]);
249 }
250
251 model->vertices = verts;
252 model->normals = norms;
253 model->texCoords = texcs;
254 model->triangles = tris;
255 model->skins = 0;
256 model->animations = 0;
257 model->numFrames = 1;
258 model->numVertices = numVertices;
259 model->numTriangles = numTriangles;
260 model->numTexCoords = numTexCoords;
261 model->numSkins = 0;
262 model->numAnimations = 0;
263
264 return Model_Success;
265 }
266 catch (std::bad_alloc)
267 {
268 safe_free (verts);
269 safe_free (texcs);
270 safe_free (tris);
271 return Model_Memory_Allocation_Error;
272 }
273}
diff --git a/Spear/Assets/Model/OBJ/cvector.c b/Spear/Assets/Model/OBJ/cvector.c
new file mode 100644
index 0000000..4e90204
--- /dev/null
+++ b/Spear/Assets/Model/OBJ/cvector.c
@@ -0,0 +1,90 @@
1#include "cvector.h"
2#include <stdlib.h> // malloc, realloc, free
3#include <string.h> // memcpy
4
5
6int max (int a, int b)
7{
8 if (a > b) return a;
9 return b;
10}
11
12
13int vector_new (vector* v, int elem_size, int num_elems)
14{
15 int n = num_elems * elem_size;
16
17 char* data = 0;
18 if (num_elems > 0)
19 {
20 data = (char*) malloc (n);
21 if (data == NULL) return 1;
22 }
23
24 v->data = data;
25 v->next = data;
26 v->chunk_size = n;
27 v->elem_size = elem_size;
28
29 return 0;
30}
31
32
33void vector_free (vector* v)
34{
35 if (v->data != 0) free (v->data);
36}
37
38
39void vector_initialise (vector* v, void* value)
40{
41 char* ptr = v->data;
42 int esize = v->elem_size;
43 int n = vector_size (v);
44
45 int i;
46 for (i = 0; i < n; ++i)
47 {
48 memcpy (ptr, value, esize);
49 ptr += esize;
50 }
51}
52
53
54int vector_append (vector* v, void* elem)
55{
56 // Realloc a bigger chunk when the vector runs out of space.
57 if (v->next == v->data + v->chunk_size)
58 {
59 int old_chunk_size = v->chunk_size;
60 int n = max (v->elem_size, 2 * old_chunk_size);
61
62 char* data = (char*) realloc (v->data, n);
63 if (data == NULL) return 1;
64
65 v->data = data;
66 v->next = data + old_chunk_size;
67 v->chunk_size = n;
68 }
69
70 memcpy ((void*)v->next, elem, v->elem_size);
71 v->next += v->elem_size;
72}
73
74
75void* vector_ith (vector* v, int i)
76{
77 return (void*) (v->data + i*v->elem_size);
78}
79
80
81int vector_size (vector* v)
82{
83 return (v->next - v->data) / v->elem_size;
84}
85
86
87int vector_capacity (vector* v)
88{
89 return v->chunk_size / v->elem_size;
90}
diff --git a/Spear/Assets/Model/OBJ/cvector.h b/Spear/Assets/Model/OBJ/cvector.h
new file mode 100644
index 0000000..1d16c46
--- /dev/null
+++ b/Spear/Assets/Model/OBJ/cvector.h
@@ -0,0 +1,36 @@
1#ifndef _C_SPEAR_VECTOR_H
2#define _C_SPEAR_VECTOR_H
3
4typedef struct
5{
6 char* data;
7 char* next;
8 int chunk_size;
9 int elem_size;
10}
11vector;
12
13/// Construct a new vector.
14/// Returns non-zero on error.
15int vector_new (vector* v, int elem_size, int num_elems);
16
17/// Free the vector.
18void vector_free (vector* v);
19
20/// Initialise every position to the given value.
21void vector_initialise (vector* v, void* value);
22
23/// Append an element.
24/// Returns non-zero on error.
25int vector_append (vector* v, void* elem);
26
27/// Access the ith element.
28void* vector_ith (vector* v, int i);
29
30/// Return the number of elements in the vector.
31int vector_size (vector* v);
32
33/// Return the vector's capacity.
34int vector_capacity (vector* v);
35
36#endif // _C_SPEAR_VECTOR_H
diff --git a/Spear/Assets/Model/OBJ/test.cc b/Spear/Assets/Model/OBJ/test.cc
deleted file mode 100644
index 31e0e39..0000000
--- a/Spear/Assets/Model/OBJ/test.cc
+++ /dev/null
@@ -1,47 +0,0 @@
1#include "OBJ_load.h"
2#include <cstdio>
3
4
5int main (void)
6{
7 Model model;
8 OBJ_load ("/home/jeanne/assets/box.obj", 1, 1, &model);
9
10 printf("Vertices:\n");
11
12 for (size_t i = 0; i < model.numVertices; ++i)
13 {
14 vec3 v = model.vertices[i];
15 printf ("%f, %f, %f\n", v.x, v.y, v.z);
16 }
17
18 printf("\nNormals:\n");
19
20 for (size_t i = 0; i < model.numVertices; ++i)
21 {
22 vec3 n = model.normals[i];
23 printf ("%f, %f, %f\n", n.x, n.y, n.z);
24 }
25
26 printf("\nTex coords:\n");
27
28 for (size_t i = 0; i < model.numTexCoords; ++i)
29 {
30 texCoord tex = model.texCoords[i];
31 printf("%f, %f\n", tex.s, tex.t);
32 }
33
34 printf("\nTriangles:\n");
35
36 for (size_t i = 0; i < model.numTriangles; ++i)
37 {
38 triangle t = model.triangles[i];
39 printf ("%d, %d, %d - %d, %d, %d\n",
40 t.vertexIndices[0]+1, t.vertexIndices[1]+1, t.vertexIndices[2]+1,
41 t.textureIndices[0]+1, t.textureIndices[1]+1, t.textureIndices[2]+1);
42 }
43
44 model_free (&model);
45
46 return 0;
47}