diff options
| -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 | } | ||
