loadobj.cc (4018B)
1 /* Copyright 2013 Brian Swetland <swetland@frotz.net> 2 * 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #include <stdio.h> 17 #include <stdlib.h> 18 #include <string.h> 19 20 #include <vector> 21 using std::vector; 22 23 #include "util.h" 24 #include "io.h" 25 26 struct v3 { 27 float x; 28 float y; 29 float z; 30 }; 31 32 struct v2 { 33 float u; 34 float v; 35 }; 36 37 struct i3 { 38 unsigned v; 39 unsigned vt; 40 unsigned vn; 41 }; 42 43 struct obj { 44 vector<v3> vertices; 45 vector<v3> normals; 46 vector<v2> texcoords; 47 vector<i3> triangles; 48 }; 49 50 struct obj *load_obj(const char *fn) { 51 char buf[128]; 52 FILE *fp; 53 struct obj *o = 0; 54 55 if (!(fp = io_fopen_asset(fn, "model"))) 56 goto exit; 57 58 o = new(obj); 59 if (!o) 60 goto close_and_exit; 61 62 while (fgets(buf, sizeof(buf), fp) != 0) { 63 if (!strncmp(buf, "v ", 2)) { 64 v3 t; 65 sscanf(buf + 2, "%f %f %f", &t.x, &t.y, &t.z); 66 o->vertices.push_back(t); 67 } else if (!strncmp(buf, "vn ", 3)) { 68 v3 t; 69 sscanf(buf + 3, "%f %f %f", &t.x, &t.y, &t.z); 70 o->normals.push_back(t); 71 } else if (!strncmp(buf, "vt ", 3)) { 72 v2 t; 73 sscanf(buf + 3, "%f %f", &t.u, &t.v); 74 75 /* TODO: make parameter -- inverting V for DX... */ 76 t.v = 1.0 - t.v; 77 78 o->texcoords.push_back(t); 79 } else if (!strncmp(buf, "f ", 2)) { 80 i3 t; 81 char *tmp = buf + 2; 82 /* XXX: handle non-triangles */ 83 while (sscanf(tmp, "%d/%d/%d", &t.v, &t.vt, &t.vn) == 3) { 84 t.v--; 85 t.vt--; 86 t.vn--; 87 o->triangles.push_back(t); 88 tmp = strstr(tmp, " "); 89 if (!tmp) break; 90 tmp++; 91 } 92 } else { 93 // fprintf(stderr,"ignoring: %s", buf); 94 } 95 } 96 97 close_and_exit: 98 fclose(fp); 99 exit: 100 return o; 101 } 102 103 static struct model *obj_to_model(struct obj *o) { 104 int i, j, n; 105 struct model *m; 106 int count = o->triangles.size(); 107 108 if(!(m = (model*) malloc(sizeof(struct model)))) 109 return 0; 110 memset(m, 0, sizeof(struct model)); 111 112 if (!(m->vdata = (float*) malloc(sizeof(float) * 8 * count))) { 113 free(m); 114 return 0; 115 } 116 if (!(m->idx = (unsigned short *) malloc(sizeof(short) * count))) { 117 free(m->vdata); 118 free(m); 119 return 0; 120 } 121 122 for (n = 0, i = 0; i < count; i++) { 123 i3 &tri = o->triangles[i]; 124 float data[8]; 125 v3 &vrt = o->vertices[tri.v]; 126 v3 &nrm = o->normals[tri.vn]; 127 v2 &txc = o->texcoords[tri.vt]; 128 data[0] = vrt.x; 129 data[1] = vrt.y; 130 data[2] = vrt.z; 131 data[3] = nrm.x; 132 data[4] = nrm.y; 133 data[5] = nrm.z; 134 data[6] = txc.u; 135 data[7] = txc.v; 136 for (j = 0; j < n; j++) 137 if (!memcmp(data, &m->vdata[8 * j], sizeof(float) * 8)) 138 goto found_it; 139 memcpy(&m->vdata[8 * j], data, sizeof(float) * 8); 140 n++; 141 found_it: 142 m->idx[i] = j; 143 } 144 145 m->vcount = n; 146 m->icount = count; 147 148 return m; 149 } 150 151 #if 0 152 void model_dump(struct model *m, FILE *fp) { 153 int i; 154 fprintf(fp, "struct model M = {\n"); 155 fprintf(fp, " .vdata = {\n"); 156 for (i = 0; i < m->vcount; i++) 157 fprintf(fp, " %f, %f, %f,\n %f, %f, %f, %f, %f,\n", 158 m->vdata[i*8+0], m->vdata[i*8+1], 159 m->vdata[i*8+2], m->vdata[i*8+3], 160 m->vdata[i*8+4], m->vdata[i*8+5], 161 m->vdata[i*8+6], m->vdata[i*8+7]); 162 fprintf(fp, " },\n .idx[] = {\n"); 163 for (i = 0; i < m->icount; i += 3) 164 fprintf(fp, " %d, %d, %d,\n", 165 m->idx[i+0], m->idx[i+1], m->idx[i+2]); 166 fprintf(fp, " },\n .vcount = %d,\n .icount = %d,\n};\n", 167 m->vcount, m->icount); 168 } 169 #endif 170 171 struct model *load_wavefront_obj(const char *fn) { 172 struct obj *o; 173 struct model *m; 174 o = load_obj(fn); 175 if (!o) { 176 error("Failed to load Model '%s'", fn); 177 return 0; 178 } 179 m = obj_to_model(o); 180 delete o; 181 return m; 182 } 183 184 void delete_wavefront_obj(struct model *m) { 185 free(m->vdata); 186 free(m->idx); 187 free(m); 188 }