diff options
author | Marc Sunet <jeannekamikaze@gmail.com> | 2012-08-11 11:41:21 +0200 |
---|---|---|
committer | Marc Sunet <jeannekamikaze@gmail.com> | 2012-08-11 11:41:21 +0200 |
commit | 08f5c4618dcdbf94bd8451d75f0f376b3726adcf (patch) | |
tree | 75e35fd99cfd142eddb810b02955033bf339dda6 | |
parent | 7404d6f6ca90777cae55bdb352aa85bcc0edf7cc (diff) |
OBJ loader rewritten in C
-rw-r--r-- | Spear.cabal | 7 | ||||
-rw-r--r-- | Spear.lkshs | 12 | ||||
-rw-r--r-- | Spear.lkshw | 2 | ||||
-rw-r--r-- | Spear/Assets/Model/OBJ/Makefile | 17 | ||||
-rw-r--r-- | Spear/Assets/Model/OBJ/OBJ_load.c | 276 | ||||
-rw-r--r-- | Spear/Assets/Model/OBJ/OBJ_load.cc | 273 | ||||
-rw-r--r-- | Spear/Assets/Model/OBJ/cvector.c | 90 | ||||
-rw-r--r-- | Spear/Assets/Model/OBJ/cvector.h | 36 | ||||
-rw-r--r-- | Spear/Assets/Model/OBJ/test.cc | 47 |
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 @@ | |||
1 | Version of session file format: | 1 | Version of session file format: |
2 | 1 | 2 | 1 |
3 | Time of storage: | 3 | Time of storage: |
4 | "Fri Aug 10 15:19:04 CEST 2012" | 4 | "Fri Aug 10 23:05:26 CEST 2012" |
5 | Layout: 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 | 5 | Layout: 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 |
6 | Population: [(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])] | 6 | Population: [(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])] |
7 | Window size: (1841,964) | 7 | Window size: (1841,964) |
8 | Completion size: | 8 | Completion size: |
9 | (750,400) | 9 | (750,400) |
10 | Workspace: Just "/home/jeanne/programming/haskell/Spear/Spear.lkshw" | 10 | Workspace: Just "/home/jeanne/programming/haskell/Spear/Spear.lkshw" |
11 | Active pane: Just "Model.hsc" | 11 | Active pane: Just "OBJ_load.c" |
12 | Toolbar visible: | 12 | Toolbar visible: |
13 | True | 13 | True |
14 | FindbarState: (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}) | 14 | FindbarState: (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}) |
15 | Recently opened files: | 15 | Recently 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"] |
17 | Recently opened workspaces: | 17 | Recently 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 @@ | |||
1 | Version of workspace file format: | 1 | Version of workspace file format: |
2 | 1 | 2 | 1 |
3 | Time of storage: | 3 | Time of storage: |
4 | "Fri Aug 10 15:56:20 CEST 2012" | 4 | "Sat Aug 11 11:39:35 CEST 2012" |
5 | Name of the workspace: | 5 | Name of the workspace: |
6 | "Spear" | 6 | "Spear" |
7 | File paths of contained packages: | 7 | File 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 @@ | |||
1 | all: OBJ_load.h OBJ_load.cc test.cc ../Model.c | 1 | test: ../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 | 4 | vector: 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 | ||
7 | clean: | 12 | clean: |
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 | |||
9 | char lastError [128]; | ||
10 | |||
11 | |||
12 | static 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). | ||
24 | static 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 | |||
32 | static 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 | |||
40 | static 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 | |||
57 | static 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 | |||
70 | static 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 | |||
78 | static 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 | |||
85 | static void read_normal (FILE* file, vec3* normal) | ||
86 | { | ||
87 | fscanf (file, "%f %f %f", &normal->x, &normal->y, &normal->z); | ||
88 | } | ||
89 | |||
90 | |||
91 | static void read_tex_coord (FILE* file, texCoord* texc) | ||
92 | { | ||
93 | fscanf (file, "%f %f", &texc->s, &texc->t); | ||
94 | } | ||
95 | |||
96 | |||
97 | static 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 | |||
171 | Model_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 | |||
9 | char lastError [128]; | ||
10 | |||
11 | |||
12 | static 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). | ||
24 | static 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 | |||
32 | static 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 | |||
40 | static 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 | |||
57 | static 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 | |||
70 | static 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 | |||
78 | static 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 | |||
85 | static void read_normal (FILE* file, vec3& normal) | ||
86 | { | ||
87 | fscanf (file, "%f %f %f", &normal.x, &normal.y, &normal.z); | ||
88 | } | ||
89 | |||
90 | |||
91 | static void read_tex_coord (FILE* file, texCoord& texc) | ||
92 | { | ||
93 | fscanf (file, "%f %f", &texc.s, &texc.t); | ||
94 | } | ||
95 | |||
96 | |||
97 | static 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 | |||
158 | Model_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 | |||
6 | int max (int a, int b) | ||
7 | { | ||
8 | if (a > b) return a; | ||
9 | return b; | ||
10 | } | ||
11 | |||
12 | |||
13 | int 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 | |||
33 | void vector_free (vector* v) | ||
34 | { | ||
35 | if (v->data != 0) free (v->data); | ||
36 | } | ||
37 | |||
38 | |||
39 | void 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 | |||
54 | int 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 | |||
75 | void* vector_ith (vector* v, int i) | ||
76 | { | ||
77 | return (void*) (v->data + i*v->elem_size); | ||
78 | } | ||
79 | |||
80 | |||
81 | int vector_size (vector* v) | ||
82 | { | ||
83 | return (v->next - v->data) / v->elem_size; | ||
84 | } | ||
85 | |||
86 | |||
87 | int 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 | |||
4 | typedef struct | ||
5 | { | ||
6 | char* data; | ||
7 | char* next; | ||
8 | int chunk_size; | ||
9 | int elem_size; | ||
10 | } | ||
11 | vector; | ||
12 | |||
13 | /// Construct a new vector. | ||
14 | /// Returns non-zero on error. | ||
15 | int vector_new (vector* v, int elem_size, int num_elems); | ||
16 | |||
17 | /// Free the vector. | ||
18 | void vector_free (vector* v); | ||
19 | |||
20 | /// Initialise every position to the given value. | ||
21 | void vector_initialise (vector* v, void* value); | ||
22 | |||
23 | /// Append an element. | ||
24 | /// Returns non-zero on error. | ||
25 | int vector_append (vector* v, void* elem); | ||
26 | |||
27 | /// Access the ith element. | ||
28 | void* vector_ith (vector* v, int i); | ||
29 | |||
30 | /// Return the number of elements in the vector. | ||
31 | int vector_size (vector* v); | ||
32 | |||
33 | /// Return the vector's capacity. | ||
34 | int 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 | |||
5 | int 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 | } | ||