| 1 | /* |
| 2 | Copyright (c) 2012, Broadcom Europe Ltd |
| 3 | All rights reserved. |
| 4 | |
| 5 | Redistribution and use in source and binary forms, with or without |
| 6 | modification, are permitted provided that the following conditions are met: |
| 7 | * Redistributions of source code must retain the above copyright |
| 8 | notice, this list of conditions and the following disclaimer. |
| 9 | * Redistributions in binary form must reproduce the above copyright |
| 10 | notice, this list of conditions and the following disclaimer in the |
| 11 | documentation and/or other materials provided with the distribution. |
| 12 | * Neither the name of the copyright holder nor the |
| 13 | names of its contributors may be used to endorse or promote products |
| 14 | derived from this software without specific prior written permission. |
| 15 | |
| 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
| 17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY |
| 20 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| 21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| 22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| 23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 26 | */ |
| 27 | |
| 28 | #include <math.h> |
| 29 | #include <stdio.h> |
| 30 | #include <stdint.h> |
| 31 | |
| 32 | #include "GLES/gl.h" |
| 33 | #include <GLES/glext.h> |
| 34 | #include "EGL/egl.h" |
| 35 | #include "EGL/eglext.h" |
| 36 | #include "models.h" |
| 37 | |
| 38 | #define VMCS_RESOURCE(a,b) (b) |
| 39 | |
| 40 | /****************************************************************************** |
| 41 | Private typedefs, macros and constants |
| 42 | ******************************************************************************/ |
| 43 | |
| 44 | enum {VBO_VERTEX, VBO_NORMAL, VBO_TEXTURE, VBO_MAX}; |
| 45 | #define MAX_MATERIALS 4 |
| 46 | #define MAX_MATERIAL_NAME 32 |
| 47 | |
| 48 | typedef struct wavefront_material_s { |
| 49 | GLuint vbo[VBO_MAX]; |
| 50 | int numverts; |
| 51 | char name[MAX_MATERIAL_NAME]; |
| 52 | GLuint texture; |
| 53 | } WAVEFRONT_MATERIAL_T; |
| 54 | |
| 55 | typedef struct wavefront_model_s { |
| 56 | WAVEFRONT_MATERIAL_T material[MAX_MATERIALS]; |
| 57 | int num_materials; |
| 58 | GLuint texture; |
| 59 | } WAVEFRONT_MODEL_T; |
| 60 | |
| 61 | |
| 62 | /****************************************************************************** |
| 63 | Static Data |
| 64 | ******************************************************************************/ |
| 65 | |
| 66 | /****************************************************************************** |
| 67 | Static Function Declarations |
| 68 | ******************************************************************************/ |
| 69 | |
| 70 | /****************************************************************************** |
| 71 | Static Function Definitions |
| 72 | ******************************************************************************/ |
| 73 | |
| 74 | static void create_vbo(GLenum type, GLuint *vbo, int size, void *data) |
| 75 | { |
| 76 | glGenBuffers(1, vbo); |
| 77 | vc_assert(*vbo); |
| 78 | glBindBuffer(type, *vbo); |
| 79 | glBufferData(type, size, data, GL_STATIC_DRAW); |
| 80 | glBindBuffer(type, 0); |
| 81 | } |
| 82 | |
| 83 | |
| 84 | static void destroy_vbo(GLuint *vbo) |
| 85 | { |
| 86 | glDeleteBuffers(1, vbo); |
| 87 | *vbo = 0; |
| 88 | } |
| 89 | |
| 90 | #define MAX_VERTICES 100000 |
| 91 | static void *allocbuffer(int size) |
| 92 | { |
| 93 | return malloc(size); |
| 94 | } |
| 95 | |
| 96 | static void freebuffer(void *p) |
| 97 | { |
| 98 | free (p); |
| 99 | } |
| 100 | |
| 101 | static void centre_and_rescale(float *verts, int numvertices) |
| 102 | { |
| 103 | float cx=0.0f, cy=0.0f, cz=0.0f, scale=0.0f; |
| 104 | float minx=0.0f, miny=0.0f, minz=0.0f; |
| 105 | float maxx=0.0f, maxy=0.0f, maxz=0.0f; |
| 106 | int i; |
| 107 | float *v = verts; |
| 108 | minx = maxx = verts[0]; |
| 109 | miny = maxy = verts[1]; |
| 110 | minz = maxz = verts[2]; |
| 111 | for (i=0; i<numvertices; i++) { |
| 112 | float x = *v++; |
| 113 | float y = *v++; |
| 114 | float z = *v++; |
| 115 | minx = vcos_min(minx, x); |
| 116 | miny = vcos_min(miny, y); |
| 117 | minz = vcos_min(minz, z); |
| 118 | maxx = vcos_max(maxx, x); |
| 119 | maxy = vcos_max(maxy, y); |
| 120 | maxz = vcos_max(maxz, z); |
| 121 | cx += x; |
| 122 | cy += y; |
| 123 | cz += z; |
| 124 | } |
| 125 | cx /= (float)numvertices; |
| 126 | cy /= (float)numvertices; |
| 127 | cz /= (float)numvertices; |
| 128 | scale = 3.0f / (maxx-minx + maxy-miny + maxz-minz); |
| 129 | v = verts; |
| 130 | for (i=0; i<numvertices; i++) { |
| 131 | *v = (*v-cx) * scale; v++; |
| 132 | *v = (*v-cy) * scale; v++; |
| 133 | *v = (*v-cz) * scale; v++; |
| 134 | } |
| 135 | } |
| 136 | |
| 137 | static void renormalise(float *verts, int numvertices) |
| 138 | { |
| 139 | int i; |
| 140 | float *v = verts; |
| 141 | for (i=0;i<numvertices; i++) { |
| 142 | float x = v[0]; |
| 143 | float y = v[1]; |
| 144 | float z = v[2]; |
| 145 | float scale = 1.0f/sqrtf(x*x + y*y + z*z); |
| 146 | *v++ = x * scale; |
| 147 | *v++ = y * scale; |
| 148 | *v++ = z * scale; |
| 149 | } |
| 150 | } |
| 151 | |
| 152 | static void deindex(float *dst, const float *src, const unsigned short *indexes, GLsizei size, GLsizei count) |
| 153 | { |
| 154 | int i; |
| 155 | for (i=0; i<count; i++) { |
| 156 | int ind = size * (indexes[0]-1); |
| 157 | *dst++ = src[ind + 0]; |
| 158 | *dst++ = src[ind + 1]; |
| 159 | // todo: optimise - move out of loop |
| 160 | if (size >= 3) *dst++ = src[ind + 2]; |
| 161 | indexes += 3; |
| 162 | } |
| 163 | } |
| 164 | |
| 165 | int draw_wavefront(MODEL_T m, GLuint texture) |
| 166 | { |
| 167 | int i; |
| 168 | WAVEFRONT_MODEL_T *model = (WAVEFRONT_MODEL_T *)m; |
| 169 | |
| 170 | for (i=0; i<model->num_materials; i++) { |
| 171 | WAVEFRONT_MATERIAL_T *mat = model->material + i; |
| 172 | if (mat->texture == -1) continue; |
| 173 | |
| 174 | if (mat->texture) |
| 175 | glBindTexture(GL_TEXTURE_2D, mat->texture); |
| 176 | else |
| 177 | glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture); |
| 178 | |
| 179 | if (mat->vbo[VBO_VERTEX]) { |
| 180 | glBindBuffer(GL_ARRAY_BUFFER, mat->vbo[VBO_VERTEX]); |
| 181 | glVertexPointer(3, GL_FLOAT, 0, NULL); |
| 182 | } |
| 183 | if (mat->vbo[VBO_NORMAL]) { |
| 184 | glEnableClientState(GL_NORMAL_ARRAY); |
| 185 | glBindBuffer(GL_ARRAY_BUFFER, mat->vbo[VBO_NORMAL]); |
| 186 | glNormalPointer(GL_FLOAT, 0, NULL); |
| 187 | } else { |
| 188 | glDisableClientState(GL_NORMAL_ARRAY); |
| 189 | } |
| 190 | if (mat->vbo[VBO_TEXTURE]) { |
| 191 | glEnableClientState(GL_TEXTURE_COORD_ARRAY); |
| 192 | glBindBuffer(GL_ARRAY_BUFFER, mat->vbo[VBO_TEXTURE]); |
| 193 | glTexCoordPointer(2, GL_FLOAT, 0, NULL); |
| 194 | } else { |
| 195 | glDisableClientState(GL_TEXTURE_COORD_ARRAY); |
| 196 | } |
| 197 | glDrawArrays(GL_TRIANGLES, 0, mat->numverts); |
| 198 | } |
| 199 | glBindBuffer(GL_ARRAY_BUFFER, 0); |
| 200 | return 0; |
| 201 | } |
| 202 | |
| 203 | struct wavefront_model_loading_s { |
| 204 | unsigned short material_index[MAX_MATERIALS]; |
| 205 | int num_materials; |
| 206 | int numv, numt, numn, numf; |
| 207 | unsigned int data[0]; |
| 208 | }; |
| 209 | |
| 210 | static int load_wavefront_obj(const char *modelname, WAVEFRONT_MODEL_T *model, struct wavefront_model_loading_s *m) |
| 211 | { |
| 212 | char line[256+1]; |
| 213 | unsigned short pp[54+1]; |
| 214 | FILE *fp; |
| 215 | int i, valid; |
| 216 | float *qv = (float *)m->data; |
| 217 | float *qt = (float *)m->data + 3 * MAX_VERTICES; |
| 218 | float *qn = (float *)m->data + (3+2) * MAX_VERTICES; |
| 219 | unsigned short *qf = (unsigned short *)((float *)m->data + (3+2+3) * MAX_VERTICES); |
| 220 | float *pv = qv, *pt = qt, *pn = qn; |
| 221 | unsigned short *pf = qf; |
| 222 | fp = fopen(modelname, "r" ); |
| 223 | if (!fp) return -1; |
| 224 | |
| 225 | m->num_materials = 0; |
| 226 | m->material_index[0] = 0; |
| 227 | |
| 228 | valid = fread(line, 1, sizeof(line)-1, fp); |
| 229 | |
| 230 | while (valid > 0) { |
| 231 | char *s, *end = line; |
| 232 | |
| 233 | while((end-line < valid) && *end != '\n' && *end != '\r') |
| 234 | end++; |
| 235 | *end++ = 0; |
| 236 | |
| 237 | if((end-line < valid) && *end != '\n' && *end != '\r') |
| 238 | *end++ = 0; |
| 239 | |
| 240 | s = line; |
| 241 | |
| 242 | if (s[strlen(s)-1] == 10) s[strlen(s)-1]=0; |
| 243 | switch (s[0]) { |
| 244 | case '#': break; // comment |
| 245 | case '\r': case '\n': case '\0': break; // blank line |
| 246 | case 'm': vc_assert(strncmp(s, "mtllib" , sizeof "mtllib" -1)==0); break; |
| 247 | case 'o': break; |
| 248 | case 'u': |
| 249 | if (sscanf(s, "usemtl %s" , /*MAX_MATERIAL_NAME-1, */model->material[m->num_materials].name) == 1) { |
| 250 | if (m->num_materials < MAX_MATERIALS) { |
| 251 | if (m->num_materials > 0 && ((pf-qf)/3 == m->material_index[m->num_materials-1] || strcmp(model->material[m->num_materials-1].name, model->material[m->num_materials].name)==0)) { |
| 252 | strcpy(model->material[m->num_materials-1].name, model->material[m->num_materials].name); |
| 253 | m->num_materials--; |
| 254 | } else |
| 255 | m->material_index[m->num_materials] = (pf-qf)/3; |
| 256 | m->num_materials++; |
| 257 | } |
| 258 | } else { printf("%s" , s); vc_assert(0); } |
| 259 | break; |
| 260 | case 'g': vc_assert(strncmp(s, "g " , sizeof "g " -1)==0); break; |
| 261 | case 's': vc_assert(strncmp(s, "s " , sizeof "s " -1)==0); break; |
| 262 | case 'v': case 'f': |
| 263 | if (sscanf(s, "v %f %f %f" , pv+0, pv+1, pv+2) == 3) { |
| 264 | pv += 3; |
| 265 | } else if (sscanf(s, "vt %f %f" , pt+0, pt+1) == 2) { |
| 266 | pt += 2; |
| 267 | } else if (sscanf(s, "vn %f %f %f" , pn+0, pn+1, pn+2) == 3) { |
| 268 | pn += 3; |
| 269 | } else if (i = sscanf(s, "f" " %hu//%hu %hu//%hu %hu//%hu %hu//%hu %hu//%hu %hu//%hu" |
| 270 | " %hu//%hu %hu//%hu %hu//%hu %hu//%hu %hu//%hu %hu//%hu" |
| 271 | " %hu//%hu %hu//%hu %hu//%hu %hu//%hu %hu//%hu %hu//%hu %hu" , |
| 272 | pp+ 0, pp+ 1, pp+ 2, pp+ 3, pp+ 4, pp+ 5, pp+ 6, pp+ 7, pp+ 8, pp+ 9, pp+10, pp+11, |
| 273 | pp+12, pp+13, pp+14, pp+15, pp+16, pp+17, pp+18, pp+19, pp+20, pp+21, pp+22, pp+23, |
| 274 | pp+24, pp+25, pp+26, pp+27, pp+28, pp+29, pp+30, pp+32, pp+32, pp+33, pp+34, pp+35, pp+36), i >= 6) { |
| 275 | int poly = i/2; |
| 276 | //vc_assert(i < countof(pp)); // may need to increment poly count and pp array |
| 277 | for (i=1; i<poly-1; i++) { |
| 278 | *pf++ = pp[0]; *pf++ = 0; *pf++ = pp[1]; |
| 279 | *pf++ = pp[2*i+0]; *pf++ = 0; *pf++ = pp[2*i+1]; |
| 280 | *pf++ = pp[2*(i+1)+0]; *pf++ = 0; *pf++ = pp[2*(i+1)+1]; |
| 281 | } |
| 282 | } else if (i = sscanf(s, "f" " %hu/%hu %hu/%hu %hu/%hu %hu/%hu %hu/%hu %hu/%hu" |
| 283 | " %hu/%hu %hu/%hu %hu/%hu %hu/%hu %hu/%hu %hu/%hu" |
| 284 | " %hu/%hu %hu/%hu %hu/%hu %hu/%hu %hu/%hu %hu/%hu %hu" , |
| 285 | pp+ 0, pp+ 1, pp+ 2, pp+ 3, pp+ 4, pp+ 5, pp+ 6, pp+ 7, pp+ 8, pp+ 9, pp+10, pp+11, |
| 286 | pp+12, pp+13, pp+14, pp+15, pp+16, pp+17, pp+18, pp+19, pp+20, pp+21, pp+22, pp+23, |
| 287 | pp+24, pp+25, pp+26, pp+27, pp+28, pp+29, pp+30, pp+32, pp+32, pp+33, pp+34, pp+35, pp+36), i >= 6) { |
| 288 | int poly = i/2; |
| 289 | //vc_assert(i < countof(pp); // may need to increment poly count and pp array |
| 290 | for (i=1; i<poly-1; i++) { |
| 291 | *pf++ = pp[0]; *pf++ = pp[1]; *pf++ = 0; |
| 292 | *pf++ = pp[2*i+0]; *pf++ = pp[2*i+1]; *pf++ = 0; |
| 293 | *pf++ = pp[2*(i+1)+0]; *pf++ = pp[2*(i+1)+1]; *pf++ = 0; |
| 294 | } |
| 295 | } else if (i = sscanf(s, "f" " %hu/%hu/%hu %hu/%hu/%hu %hu/%hu/%hu %hu/%hu/%hu %hu/%hu/%hu %hu/%hu/%hu" |
| 296 | " %hu/%hu/%hu %hu/%hu/%hu %hu/%hu/%hu %hu/%hu/%hu %hu/%hu/%hu %hu/%hu/%hu" |
| 297 | " %hu/%hu/%hu %hu/%hu/%hu %hu/%hu/%hu %hu/%hu/%hu %hu/%hu/%hu %hu/%hu/%hu %hu" , |
| 298 | pp+ 0, pp+ 1, pp+ 2, pp+ 3, pp+ 4, pp+ 5, pp+ 6, pp+ 7, pp+ 8, pp+ 9, pp+10, pp+11, pp+12, pp+13, pp+14, pp+15, pp+16, pp+17, |
| 299 | pp+18, pp+19, pp+20, pp+21, pp+22, pp+23, pp+24, pp+25, pp+26, pp+27, pp+28, pp+29, pp+30, pp+32, pp+32, pp+33, pp+34, pp+35, |
| 300 | pp+36, pp+37, pp+38, pp+39, pp+40, pp+41, pp+42, pp+43, pp+44, pp+45, pp+46, pp+47, pp+48, pp+49, pp+50, pp+51, pp+52, pp+53, pp+54), i >= 9) { |
| 301 | int poly = i/3; |
| 302 | //vc_assert(i < countof(pp); // may need to increment poly count and pp array |
| 303 | for (i=1; i<poly-1; i++) { |
| 304 | *pf++ = pp[0]; *pf++ = pp[1]; *pf++ = pp[2]; |
| 305 | *pf++ = pp[3*i+0]; *pf++ = pp[3*i+1]; *pf++ = pp[3*i+2]; |
| 306 | *pf++ = pp[3*(i+1)+0]; *pf++ = pp[3*(i+1)+1]; *pf++ = pp[3*(i+1)+2]; |
| 307 | } |
| 308 | } else { printf("%s" , s); vc_assert(0); } |
| 309 | break; |
| 310 | default: |
| 311 | printf("%02x %02x %s" , s[0], s[1], s); vc_assert(0); break; |
| 312 | } |
| 313 | |
| 314 | // shift down read characters and read some more into the end |
| 315 | // if we didn't find a newline, then end is one off the end of our |
| 316 | // line, so end-line will be valid+1 |
| 317 | i = end-line > valid ? valid : end-line; |
| 318 | memmove(line, end, valid - i); |
| 319 | valid -= i; |
| 320 | valid += fread(line+valid, 1, sizeof(line)-1-valid, fp); |
| 321 | } |
| 322 | fclose(fp); |
| 323 | |
| 324 | if (m->num_materials==0) m->material_index[m->num_materials++] = 0; |
| 325 | |
| 326 | centre_and_rescale(qv, (pv-qv)/3); |
| 327 | renormalise(qn, (pn-qn)/3); |
| 328 | //centre_and_rescale2(qt, (pt-qt)/2); |
| 329 | |
| 330 | m->numv = pv-qv; |
| 331 | m->numt = pt-qt; |
| 332 | m->numn = pn-qn; |
| 333 | m->numf = pf-qf; |
| 334 | |
| 335 | // compress array |
| 336 | //memcpy((float *)m->data, (float *)m->data, m->numv * sizeof *qv); - nop |
| 337 | memcpy((float *)m->data + m->numv, (float *)m->data + 3 * MAX_VERTICES, m->numt * sizeof *qt); |
| 338 | memcpy((float *)m->data + m->numv + m->numt,(float *) m->data + (3 + 2) * MAX_VERTICES, m->numn * sizeof *qn); |
| 339 | memcpy((float *)m->data + m->numv + m->numt + m->numn, (float *)m->data + (3 + 2 + 3) * MAX_VERTICES, m->numf * sizeof *qf); |
| 340 | |
| 341 | return 0; |
| 342 | } |
| 343 | |
| 344 | static int load_wavefront_dat(const char *modelname, WAVEFRONT_MODEL_T *model, struct wavefront_model_loading_s *m) |
| 345 | { |
| 346 | FILE *fp; |
| 347 | int s; |
| 348 | const int size = sizeof *m + |
| 349 | sizeof(float)*(3+2+3)*MAX_VERTICES + // 3 vertices + 2 textures + 3 normals |
| 350 | sizeof(unsigned short)*3*MAX_VERTICES; //each face has 9 vertices |
| 351 | |
| 352 | fp = fopen(modelname, "r" ); |
| 353 | if (!fp) return -1; |
| 354 | s = fread(m, 1, size, fp); |
| 355 | if (s < 0) return -1; |
| 356 | fclose(fp); |
| 357 | return 0; |
| 358 | } |
| 359 | |
| 360 | MODEL_T load_wavefront(const char *modelname, const char *texturename) |
| 361 | { |
| 362 | WAVEFRONT_MODEL_T *model; |
| 363 | float *temp, *qv, *qt, *qn; |
| 364 | unsigned short *qf; |
| 365 | int i; |
| 366 | int numverts = 0, offset = 0; |
| 367 | struct wavefront_model_loading_s *m; |
| 368 | int s=-1; |
| 369 | char modelname_obj[128]; |
| 370 | model = malloc(sizeof *model); |
| 371 | if (!model || !modelname) return NULL; |
| 372 | memset (model, 0, sizeof *model); |
| 373 | model->texture = 0; //load_texture(texturename); |
| 374 | m = allocbuffer(sizeof *m + |
| 375 | sizeof(float)*(3+2+3)*MAX_VERTICES + // 3 vertices + 2 textures + 3 normals |
| 376 | sizeof(unsigned short)*3*MAX_VERTICES); //each face has 9 vertices |
| 377 | if (!m) return 0; |
| 378 | |
| 379 | if (strlen(modelname) + 5 <= sizeof modelname_obj) { |
| 380 | strcpy(modelname_obj, modelname); |
| 381 | strcat(modelname_obj, ".dat" ); |
| 382 | s = load_wavefront_dat(modelname_obj, model, m); |
| 383 | } |
| 384 | if (s==0) {} |
| 385 | else if (strncmp(modelname + strlen(modelname) - 4, ".obj" , 4) == 0) { |
| 386 | #ifdef DUMP_OBJ_DAT |
| 387 | int size; |
| 388 | FILE *fp; |
| 389 | #endif |
| 390 | s = load_wavefront_obj(modelname, model, m); |
| 391 | #ifdef DUMP_OBJ_DAT |
| 392 | strcpy(modelname_obj, modelname); |
| 393 | strcat(modelname_obj, ".dat" ); |
| 394 | size = sizeof *m + |
| 395 | sizeof(float)*(3*m->numv+2*m->numt+3*m->numn) + // 3 vertices + 2 textures + 3 normals |
| 396 | sizeof(unsigned short)*3*m->numf; //each face has 9 vertices |
| 397 | fp = host_file_open(modelname_obj, "w" ); |
| 398 | fwrite(m, 1, size, fp); |
| 399 | fclose(fp); |
| 400 | #endif |
| 401 | } else if (strncmp(modelname + strlen(modelname) - 4, ".dat" , 4) == 0) { |
| 402 | s = load_wavefront_dat(modelname, model, m); |
| 403 | } |
| 404 | if (s != 0) return 0; |
| 405 | |
| 406 | qv = (float *)(m->data); |
| 407 | qt = (float *)(m->data + m->numv); |
| 408 | qn = (float *)(m->data + m->numv + m->numt); |
| 409 | qf = (unsigned short *)(m->data + m->numv + m->numt + m->numn); |
| 410 | |
| 411 | numverts = m->numf/3; |
| 412 | vc_assert(numverts <= MAX_VERTICES); |
| 413 | |
| 414 | temp = allocbuffer(3*numverts*sizeof *temp); |
| 415 | for (i=0; i<m->num_materials; i++) { |
| 416 | WAVEFRONT_MATERIAL_T *mat = model->material + i; |
| 417 | mat->numverts = i < m->num_materials-1 ? m->material_index[i+1]-m->material_index[i] : numverts - m->material_index[i]; |
| 418 | // vertex, texture, normal |
| 419 | deindex(temp, qv, qf+3*offset+0, 3, mat->numverts); |
| 420 | create_vbo(GL_ARRAY_BUFFER, mat->vbo+VBO_VERTEX, 3 * mat->numverts * sizeof *qv, temp); // 3 |
| 421 | |
| 422 | deindex(temp, qt, qf+3*offset+1, 2, mat->numverts); |
| 423 | create_vbo(GL_ARRAY_BUFFER, mat->vbo+VBO_TEXTURE, 2 * mat->numverts * sizeof *qt, temp); // 2 |
| 424 | |
| 425 | deindex(temp, qn, qf+3*offset+2, 3, mat->numverts); |
| 426 | create_vbo(GL_ARRAY_BUFFER, mat->vbo+VBO_NORMAL, 3 * mat->numverts * sizeof *qn, temp); // 3 |
| 427 | offset += mat->numverts; |
| 428 | mat->texture = model->texture; |
| 429 | } |
| 430 | model->num_materials = m->num_materials; |
| 431 | vc_assert(offset == numverts); |
| 432 | freebuffer(temp); |
| 433 | freebuffer(m); |
| 434 | return (MODEL_T)model; |
| 435 | } |
| 436 | |
| 437 | void unload_wavefront(MODEL_T m) |
| 438 | { |
| 439 | WAVEFRONT_MODEL_T *model = (WAVEFRONT_MODEL_T *)m; |
| 440 | int i; |
| 441 | for (i=0; i<model->num_materials; i++) { |
| 442 | WAVEFRONT_MATERIAL_T *mat = model->material + i; |
| 443 | if (mat->vbo[VBO_VERTEX]) |
| 444 | destroy_vbo(mat->vbo+VBO_VERTEX); |
| 445 | if (mat->vbo[VBO_TEXTURE]) |
| 446 | destroy_vbo(mat->vbo+VBO_TEXTURE); |
| 447 | if (mat->vbo[VBO_NORMAL]) |
| 448 | destroy_vbo(mat->vbo+VBO_NORMAL); |
| 449 | } |
| 450 | } |
| 451 | |
| 452 | // create a cube model that looks like a wavefront model, |
| 453 | MODEL_T cube_wavefront(void) |
| 454 | { |
| 455 | static const float qv[] = { |
| 456 | -0.5f, -0.5f, 0.5f, |
| 457 | -0.5f, -0.5f, -0.5f, |
| 458 | 0.5f, -0.5f, -0.5f, |
| 459 | 0.5f, -0.5f, 0.5f, |
| 460 | -0.5f, 0.5f, 0.5f, |
| 461 | 0.5f, 0.5f, 0.5f, |
| 462 | 0.5f, 0.5f, -0.5f, |
| 463 | -0.5f, 0.5f, -0.5f, |
| 464 | }; |
| 465 | |
| 466 | static const float qn[] = { |
| 467 | 0.0f, -1.0f, -0.0f, |
| 468 | 0.0f, 1.0f, -0.0f, |
| 469 | 0.0f, 0.0f, 1.0f, |
| 470 | 1.0f, 0.0f, -0.0f, |
| 471 | 0.0f, 0.0f, -1.0f, |
| 472 | -1.0f, 0.0f, -0.0f, |
| 473 | }; |
| 474 | |
| 475 | static const float qt[] = { |
| 476 | 1.0f, 0.0f, |
| 477 | 1.0f, 1.0f, |
| 478 | 0.0f, 1.0f, |
| 479 | 0.0f, 0.0f, |
| 480 | }; |
| 481 | |
| 482 | static const unsigned short qf[] = { |
| 483 | 1,1,1, 2,2,1, 3,3,1, |
| 484 | 3,3,1, 4,4,1, 1,1,1, |
| 485 | 5,4,2, 6,1,2, 7,2,2, |
| 486 | 7,2,2, 8,3,2, 5,4,2, |
| 487 | 1,4,3, 4,1,3, 6,2,3, |
| 488 | 6,2,3, 5,3,3, 1,4,3, |
| 489 | 4,4,4, 3,1,4, 7,2,4, |
| 490 | 7,2,4, 6,3,4, 4,4,4, |
| 491 | 3,4,5, 2,1,5, 8,2,5, |
| 492 | 8,2,5, 7,3,5, 3,4,5, |
| 493 | 2,4,6, 1,1,6, 5,2,6, |
| 494 | 5,2,6, 8,3,6, 2,4,6, |
| 495 | }; |
| 496 | WAVEFRONT_MODEL_T *model = malloc(sizeof *model); |
| 497 | if (model) { |
| 498 | WAVEFRONT_MATERIAL_T *mat = model->material; |
| 499 | float *temp; |
| 500 | const int offset = 0; |
| 501 | memset(model, 0, sizeof *model); |
| 502 | |
| 503 | temp = allocbuffer(3*MAX_VERTICES*sizeof *temp); |
| 504 | mat->numverts = countof(qf)/3; |
| 505 | // vertex, texture, normal |
| 506 | deindex(temp, qv, qf+3*offset+0, 3, mat->numverts); |
| 507 | create_vbo(GL_ARRAY_BUFFER, mat->vbo+VBO_VERTEX, 3 * mat->numverts * sizeof *qv, temp); // 3 |
| 508 | |
| 509 | deindex(temp, qt, qf+3*offset+1, 2, mat->numverts); |
| 510 | create_vbo(GL_ARRAY_BUFFER, mat->vbo+VBO_TEXTURE, 2 * mat->numverts * sizeof *qt, temp); // 2 |
| 511 | |
| 512 | deindex(temp, qn, qf+3*offset+2, 3, mat->numverts); |
| 513 | create_vbo(GL_ARRAY_BUFFER, mat->vbo+VBO_NORMAL, 3 * mat->numverts * sizeof *qn, temp); // 3 |
| 514 | |
| 515 | freebuffer(temp); |
| 516 | model->num_materials = 1; |
| 517 | } |
| 518 | return (MODEL_T)model; |
| 519 | } |
| 520 | |
| 521 | |
| 522 | |