m3d.h (305622B)
1 /* 2 * m3d.h 3 * https://gitlab.com/bztsrc/model3d 4 * 5 * Copyright (C) 2020 bzt (bztsrc@gitlab) 6 * 7 * Permission is hereby granted, free of charge, to any person 8 * obtaining a copy of this software and associated documentation 9 * files (the "Software"), to deal in the Software without 10 * restriction, including without limitation the rights to use, copy, 11 * modify, merge, publish, distribute, sublicense, and/or sell copies 12 * of the Software, and to permit persons to whom the Software is 13 * furnished to do so, subject to the following conditions: 14 * 15 * The above copyright notice and this permission notice shall be 16 * included in all copies or substantial portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 22 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 * DEALINGS IN THE SOFTWARE. 26 * 27 * @brief ANSI C89 / C++11 single header importer / exporter SDK for the Model 3D (.M3D) format 28 * https://gitlab.com/bztsrc/model3d 29 * 30 * PNG decompressor included from (with minor modifications to make it C89 valid): 31 * stb_image - v2.13 - public domain image loader - http://nothings.org/stb_image.h 32 * 33 * @version: 1.0.0 34 */ 35 36 #ifndef _M3D_H_ 37 #define _M3D_H_ 38 39 #ifdef __cplusplus 40 extern "C" { 41 #endif 42 43 #include <stdint.h> 44 45 /*** configuration ***/ 46 #ifndef M3D_MALLOC 47 # define M3D_MALLOC(sz) malloc(sz) 48 #endif 49 #ifndef M3D_REALLOC 50 # define M3D_REALLOC(p,nsz) realloc(p,nsz) 51 #endif 52 #ifndef M3D_FREE 53 # define M3D_FREE(p) free(p) 54 #endif 55 #ifndef M3D_LOG 56 # define M3D_LOG(x) 57 #endif 58 #ifndef M3D_APIVERSION 59 #define M3D_APIVERSION 0x0100 60 #ifndef M3D_DOUBLE 61 typedef float M3D_FLOAT; 62 #ifndef M3D_EPSILON 63 /* carefully choosen for IEEE 754 don't change */ 64 #define M3D_EPSILON ((M3D_FLOAT)1e-7) 65 #endif 66 #else 67 typedef double M3D_FLOAT; 68 #ifndef M3D_EPSILON 69 #define M3D_EPSILON ((M3D_FLOAT)1e-14) 70 #endif 71 #endif 72 #if !defined(M3D_SMALLINDEX) 73 typedef uint32_t M3D_INDEX; 74 typedef uint16_t M3D_VOXEL; 75 #define M3D_UNDEF 0xffffffff 76 #define M3D_INDEXMAX 0xfffffffe 77 #define M3D_VOXUNDEF 0xffff 78 #define M3D_VOXCLEAR 0xfffe 79 #else 80 typedef uint16_t M3D_INDEX; 81 typedef uint8_t M3D_VOXEL; 82 #define M3D_UNDEF 0xffff 83 #define M3D_INDEXMAX 0xfffe 84 #define M3D_VOXUNDEF 0xff 85 #define M3D_VOXCLEAR 0xfe 86 #endif 87 #define M3D_NOTDEFINED 0xffffffff 88 #ifndef M3D_NUMBONE 89 #define M3D_NUMBONE 4 90 #endif 91 #ifndef M3D_BONEMAXLEVEL 92 #define M3D_BONEMAXLEVEL 64 93 #endif 94 #ifndef _MSC_VER 95 #ifndef _inline 96 #define _inline __inline__ 97 #endif 98 #define _pack __attribute__((packed)) 99 #define _unused __attribute__((unused)) 100 #else 101 #define _inline 102 #define _pack 103 #define _unused __pragma(warning(suppress:4100)) 104 #endif 105 #ifndef __cplusplus 106 #define _register register 107 #else 108 #define _register 109 #endif 110 111 /*** File format structures ***/ 112 113 /** 114 * M3D file format structure 115 * 3DMO m3dchunk_t file header chunk, may followed by compressed data 116 * PRVW preview chunk (optional) 117 * HEAD m3dhdr_t model header chunk 118 * n x m3dchunk_t more chunks follow 119 * CMAP color map chunk (optional) 120 * TMAP texture map chunk (optional) 121 * VRTS vertex data chunk (optional if it's a material library) 122 * BONE bind-pose skeleton, bone hierarchy chunk (optional) 123 * n x m3db_t contains propably more, but at least one bone 124 * n x m3ds_t skin group records 125 * MTRL* material chunk(s), can be more (optional) 126 * n x m3dp_t each material contains propapbly more, but at least one property 127 * the properties are configurable with a static array, see m3d_propertytypes 128 * n x m3dchunk_t at least one, but maybe more face chunks 129 * PROC* procedural face, or 130 * MESH* triangle mesh (vertex index list) or 131 * VOXT, VOXD* voxel image (converted to mesh) or 132 * SHPE* mathematical shapes like parameterized surfaces 133 * LBLS* annotation label chunks, can be more (optional) 134 * ACTN* action chunk(s), animation-pose skeletons, can be more (optional) 135 * n x m3dfr_t each action contains probably more, but at least one frame 136 * n x m3dtr_t each frame contains probably more, but at least one transformation 137 * ASET* inlined asset chunk(s), can be more (optional) 138 * OMD3 end chunk 139 * 140 * Typical chunks for a game engine: 3DMO, HEAD, CMAP, TMAP, VRTS, BONE, MTRL, MESH, ACTN, OMD3 141 * Typical chunks for distibution: 3DMO, PRVW, HEAD, CMAP, TMAP, VRTS, BONE, MTRL, MESH, ACTN, ASET, OMD3 142 * Typical chunks for voxel image: 3DMO, HEAD, CMAP, MTRL, VOXT, VOXD, VOXD, VOXD, OMD3 143 * Typical chunks for CAD software: 3DMO, PRVW, HEAD, CMAP, TMAP, VRTS, MTRL, SHPE, LBLS, OMD3 144 */ 145 #ifdef _MSC_VER 146 #pragma pack(push) 147 #pragma pack(1) 148 #endif 149 150 typedef struct { 151 char magic[4]; 152 uint32_t length; 153 float scale; /* deliberately not M3D_FLOAT */ 154 uint32_t types; 155 } _pack m3dhdr_t; 156 157 typedef struct { 158 char magic[4]; 159 uint32_t length; 160 } _pack m3dchunk_t; 161 162 #ifdef _MSC_VER 163 #pragma pack(pop) 164 #endif 165 166 /*** in-memory model structure ***/ 167 168 /* textmap entry */ 169 typedef struct { 170 M3D_FLOAT u; 171 M3D_FLOAT v; 172 } m3dti_t; 173 #define m3d_textureindex_t m3dti_t 174 175 /* texture */ 176 typedef struct { 177 char *name; /* texture name */ 178 uint8_t *d; /* pixels data */ 179 uint16_t w; /* width */ 180 uint16_t h; /* height */ 181 uint8_t f; /* format, 1 = grayscale, 2 = grayscale+alpha, 3 = rgb, 4 = rgba */ 182 } m3dtx_t; 183 #define m3d_texturedata_t m3dtx_t 184 185 typedef struct { 186 M3D_INDEX vertexid; 187 M3D_FLOAT weight; 188 } m3dw_t; 189 #define m3d_weight_t m3dw_t 190 191 /* bone entry */ 192 typedef struct { 193 M3D_INDEX parent; /* parent bone index */ 194 char *name; /* name for this bone */ 195 M3D_INDEX pos; /* vertex index position */ 196 M3D_INDEX ori; /* vertex index orientation (quaternion) */ 197 M3D_INDEX numweight; /* number of controlled vertices */ 198 m3dw_t *weight; /* weights for those vertices */ 199 M3D_FLOAT mat4[16]; /* transformation matrix */ 200 } m3db_t; 201 #define m3d_bone_t m3db_t 202 203 /* skin: bone per vertex entry */ 204 typedef struct { 205 M3D_INDEX boneid[M3D_NUMBONE]; 206 M3D_FLOAT weight[M3D_NUMBONE]; 207 } m3ds_t; 208 #define m3d_skin_t m3ds_t 209 210 /* vertex entry */ 211 typedef struct { 212 M3D_FLOAT x; /* 3D coordinates and weight */ 213 M3D_FLOAT y; 214 M3D_FLOAT z; 215 M3D_FLOAT w; 216 uint32_t color; /* default vertex color */ 217 M3D_INDEX skinid; /* skin index */ 218 #ifdef M3D_VERTEXTYPE 219 uint8_t type; 220 #endif 221 } m3dv_t; 222 #define m3d_vertex_t m3dv_t 223 224 /* material property formats */ 225 enum { 226 m3dpf_color, 227 m3dpf_uint8, 228 m3dpf_uint16, 229 m3dpf_uint32, 230 m3dpf_float, 231 m3dpf_map 232 }; 233 typedef struct { 234 uint8_t format; 235 uint8_t id; 236 #ifdef M3D_ASCII 237 #define M3D_PROPERTYDEF(f,i,n) { (f), (i), (char*)(n) } 238 char *key; 239 #else 240 #define M3D_PROPERTYDEF(f,i,n) { (f), (i) } 241 #endif 242 } m3dpd_t; 243 244 /* material property types */ 245 /* You shouldn't change the first 8 display and first 4 physical property. Assign the rest as you like. */ 246 enum { 247 m3dp_Kd = 0, /* scalar display properties */ 248 m3dp_Ka, 249 m3dp_Ks, 250 m3dp_Ns, 251 m3dp_Ke, 252 m3dp_Tf, 253 m3dp_Km, 254 m3dp_d, 255 m3dp_il, 256 257 m3dp_Pr = 64, /* scalar physical properties */ 258 m3dp_Pm, 259 m3dp_Ps, 260 m3dp_Ni, 261 m3dp_Nt, 262 263 m3dp_map_Kd = 128, /* textured display map properties */ 264 m3dp_map_Ka, 265 m3dp_map_Ks, 266 m3dp_map_Ns, 267 m3dp_map_Ke, 268 m3dp_map_Tf, 269 m3dp_map_Km, /* bump map */ 270 m3dp_map_D, 271 m3dp_map_N, /* normal map */ 272 273 m3dp_map_Pr = 192, /* textured physical map properties */ 274 m3dp_map_Pm, 275 m3dp_map_Ps, 276 m3dp_map_Ni, 277 m3dp_map_Nt 278 }; 279 enum { /* aliases */ 280 m3dp_bump = m3dp_map_Km, 281 m3dp_map_il = m3dp_map_N, 282 m3dp_refl = m3dp_map_Pm 283 }; 284 285 /* material property */ 286 typedef struct { 287 uint8_t type; /* property type, see "m3dp_*" enumeration */ 288 union { 289 uint32_t color; /* if value is a color, m3dpf_color */ 290 uint32_t num; /* if value is a number, m3dpf_uint8, m3pf_uint16, m3dpf_uint32 */ 291 float fnum; /* if value is a floating point number, m3dpf_float */ 292 M3D_INDEX textureid; /* if value is a texture, m3dpf_map */ 293 } value; 294 } m3dp_t; 295 #define m3d_property_t m3dp_t 296 297 /* material entry */ 298 typedef struct { 299 char *name; /* name of the material */ 300 uint8_t numprop; /* number of properties */ 301 m3dp_t *prop; /* properties array */ 302 } m3dm_t; 303 #define m3d_material_t m3dm_t 304 305 /* face entry */ 306 typedef struct { 307 M3D_INDEX materialid; /* material index */ 308 M3D_INDEX vertex[3]; /* 3D points of the triangle in CCW order */ 309 M3D_INDEX normal[3]; /* normal vectors */ 310 M3D_INDEX texcoord[3]; /* UV coordinates */ 311 #ifdef M3D_VERTEXMAX 312 M3D_INDEX paramid; /* parameter index */ 313 M3D_INDEX vertmax[3]; /* maximum 3D points of the triangle in CCW order */ 314 #endif 315 } m3df_t; 316 #define m3d_face_t m3df_t 317 318 typedef struct { 319 uint16_t count; 320 char *name; 321 } m3dvi_t; 322 #define m3d_voxelitem_t m3dvi_t 323 #define m3d_parameter_t m3dvi_t 324 325 /* voxel types (voxel palette) */ 326 typedef struct { 327 char *name; /* technical name of the voxel */ 328 uint8_t rotation; /* rotation info */ 329 uint16_t voxshape; /* voxel shape */ 330 M3D_INDEX materialid; /* material index */ 331 uint32_t color; /* default voxel color */ 332 M3D_INDEX skinid; /* skin index */ 333 uint8_t numitem; /* number of sub-voxels */ 334 m3dvi_t *item; /* list of sub-voxels */ 335 } m3dvt_t; 336 #define m3d_voxeltype_t m3dvt_t 337 338 /* voxel data blocks */ 339 typedef struct { 340 char *name; /* name of the block */ 341 int32_t x, y, z; /* position */ 342 uint32_t w, h, d; /* dimension */ 343 uint8_t uncertain; /* probability */ 344 uint8_t groupid; /* block group id */ 345 M3D_VOXEL *data; /* voxel data, indices to voxel type */ 346 } m3dvx_t; 347 #define m3d_voxel_t m3dvx_t 348 349 /* shape command types. must match the row in m3d_commandtypes */ 350 enum { 351 /* special commands */ 352 m3dc_use = 0, /* use material */ 353 m3dc_inc, /* include another shape */ 354 m3dc_mesh, /* include part of polygon mesh */ 355 /* approximations */ 356 m3dc_div, /* subdivision by constant resolution for both u, v */ 357 m3dc_sub, /* subdivision by constant, different for u and v */ 358 m3dc_len, /* spacial subdivision by maxlength */ 359 m3dc_dist, /* subdivision by maxdistance and maxangle */ 360 /* modifiers */ 361 m3dc_degu, /* degree for both u, v */ 362 m3dc_deg, /* separate degree for u and v */ 363 m3dc_rangeu, /* range for u */ 364 m3dc_range, /* range for u and v */ 365 m3dc_paru, /* u parameters (knots) */ 366 m3dc_parv, /* v parameters */ 367 m3dc_trim, /* outer trimming curve */ 368 m3dc_hole, /* inner trimming curve */ 369 m3dc_scrv, /* spacial curve */ 370 m3dc_sp, /* special points */ 371 /* helper curves */ 372 m3dc_bez1, /* Bezier 1D */ 373 m3dc_bsp1, /* B-spline 1D */ 374 m3dc_bez2, /* bezier 2D */ 375 m3dc_bsp2, /* B-spline 2D */ 376 /* surfaces */ 377 m3dc_bezun, /* Bezier 3D with control, UV, normal */ 378 m3dc_bezu, /* with control and UV */ 379 m3dc_bezn, /* with control and normal */ 380 m3dc_bez, /* control points only */ 381 m3dc_nurbsun, /* B-spline 3D */ 382 m3dc_nurbsu, 383 m3dc_nurbsn, 384 m3dc_nurbs, 385 m3dc_conn, /* connect surfaces */ 386 /* geometrical */ 387 m3dc_line, 388 m3dc_polygon, 389 m3dc_circle, 390 m3dc_cylinder, 391 m3dc_shpere, 392 m3dc_torus, 393 m3dc_cone, 394 m3dc_cube 395 }; 396 397 /* shape command argument types */ 398 enum { 399 m3dcp_mi_t = 1, /* material index */ 400 m3dcp_hi_t, /* shape index */ 401 m3dcp_fi_t, /* face index */ 402 m3dcp_ti_t, /* texture map index */ 403 m3dcp_vi_t, /* vertex index */ 404 m3dcp_qi_t, /* vertex index for quaternions */ 405 m3dcp_vc_t, /* coordinate or radius, float scalar */ 406 m3dcp_i1_t, /* int8 scalar */ 407 m3dcp_i2_t, /* int16 scalar */ 408 m3dcp_i4_t, /* int32 scalar */ 409 m3dcp_va_t /* variadic arguments */ 410 }; 411 412 #define M3D_CMDMAXARG 8 /* if you increase this, add more arguments to the macro below */ 413 typedef struct { 414 #ifdef M3D_ASCII 415 #define M3D_CMDDEF(t,n,p,a,b,c,d,e,f,g,h) { (char*)(n), (p), { (a), (b), (c), (d), (e), (f), (g), (h) } } 416 char *key; 417 #else 418 #define M3D_CMDDEF(t,n,p,a,b,c,d,e,f,g,h) { (p), { (a), (b), (c), (d), (e), (f), (g), (h) } } 419 #endif 420 uint8_t p; 421 uint8_t a[M3D_CMDMAXARG]; 422 } m3dcd_t; 423 424 /* shape command */ 425 typedef struct { 426 uint16_t type; /* shape type */ 427 uint32_t *arg; /* arguments array */ 428 } m3dc_t; 429 #define m3d_shapecommand_t m3dc_t 430 431 /* shape entry */ 432 typedef struct { 433 char *name; /* name of the mathematical shape */ 434 M3D_INDEX group; /* group this shape belongs to or -1 */ 435 uint32_t numcmd; /* number of commands */ 436 m3dc_t *cmd; /* commands array */ 437 } m3dh_t; 438 #define m3d_shape_t m3dh_t 439 440 /* label entry */ 441 typedef struct { 442 char *name; /* name of the annotation layer or NULL */ 443 char *lang; /* language code or NULL */ 444 char *text; /* the label text */ 445 uint32_t color; /* color */ 446 M3D_INDEX vertexid; /* the vertex the label refers to */ 447 } m3dl_t; 448 #define m3d_label_t m3dl_t 449 450 /* frame transformations / working copy skeleton entry */ 451 typedef struct { 452 M3D_INDEX boneid; /* selects a node in bone hierarchy */ 453 M3D_INDEX pos; /* vertex index new position */ 454 M3D_INDEX ori; /* vertex index new orientation (quaternion) */ 455 } m3dtr_t; 456 #define m3d_transform_t m3dtr_t 457 458 /* animation frame entry */ 459 typedef struct { 460 uint32_t msec; /* frame's position on the timeline, timestamp */ 461 M3D_INDEX numtransform; /* number of transformations in this frame */ 462 m3dtr_t *transform; /* transformations */ 463 } m3dfr_t; 464 #define m3d_frame_t m3dfr_t 465 466 /* model action entry */ 467 typedef struct { 468 char *name; /* name of the action */ 469 uint32_t durationmsec; /* duration in millisec (1/1000 sec) */ 470 M3D_INDEX numframe; /* number of frames in this animation */ 471 m3dfr_t *frame; /* frames array */ 472 } m3da_t; 473 #define m3d_action_t m3da_t 474 475 /* inlined asset */ 476 typedef struct { 477 char *name; /* asset name (same pointer as in texture[].name) */ 478 uint8_t *data; /* compressed asset data */ 479 uint32_t length; /* compressed data length */ 480 } m3di_t; 481 #define m3d_inlinedasset_t m3di_t 482 483 /*** in-memory model structure ***/ 484 #define M3D_FLG_FREERAW (1<<0) 485 #define M3D_FLG_FREESTR (1<<1) 486 #define M3D_FLG_MTLLIB (1<<2) 487 #define M3D_FLG_GENNORM (1<<3) 488 489 typedef struct { 490 m3dhdr_t *raw; /* pointer to raw data */ 491 char flags; /* internal flags */ 492 signed char errcode; /* returned error code */ 493 char vc_s, vi_s, si_s, ci_s, ti_s, bi_s, nb_s, sk_s, fc_s, hi_s, fi_s, vd_s, vp_s; /* decoded sizes for types */ 494 char *name; /* name of the model, like "Utah teapot" */ 495 char *license; /* usage condition or license, like "MIT", "LGPL" or "BSD-3clause" */ 496 char *author; /* nickname, email, homepage or github URL etc. */ 497 char *desc; /* comments, descriptions. May contain '\n' newline character */ 498 M3D_FLOAT scale; /* the model's bounding cube's size in SI meters */ 499 M3D_INDEX numcmap; 500 uint32_t *cmap; /* color map */ 501 M3D_INDEX numtmap; 502 m3dti_t *tmap; /* texture map indices */ 503 M3D_INDEX numtexture; 504 m3dtx_t *texture; /* uncompressed textures */ 505 M3D_INDEX numbone; 506 m3db_t *bone; /* bone hierarchy */ 507 M3D_INDEX numvertex; 508 m3dv_t *vertex; /* vertex data */ 509 M3D_INDEX numskin; 510 m3ds_t *skin; /* skin data */ 511 M3D_INDEX nummaterial; 512 m3dm_t *material; /* material list */ 513 #ifdef M3D_VERTEXMAX 514 M3D_INDEX numparam; 515 m3dvi_t *param; /* parameters and their values list */ 516 #endif 517 M3D_INDEX numface; 518 m3df_t *face; /* model face, polygon (triangle) mesh */ 519 M3D_INDEX numvoxtype; 520 m3dvt_t *voxtype; /* model face, voxel types */ 521 M3D_INDEX numvoxel; 522 m3dvx_t *voxel; /* model face, cubes compressed into voxels */ 523 M3D_INDEX numshape; 524 m3dh_t *shape; /* model face, shape commands */ 525 M3D_INDEX numlabel; 526 m3dl_t *label; /* annotation labels */ 527 M3D_INDEX numaction; 528 m3da_t *action; /* action animations */ 529 M3D_INDEX numinlined; 530 m3di_t *inlined; /* inlined assets */ 531 M3D_INDEX numextra; 532 m3dchunk_t **extra; /* unknown chunks, application / engine specific data probably */ 533 m3di_t preview; /* preview chunk */ 534 } m3d_t; 535 536 /*** export parameters ***/ 537 #define M3D_EXP_INT8 0 538 #define M3D_EXP_INT16 1 539 #define M3D_EXP_FLOAT 2 540 #define M3D_EXP_DOUBLE 3 541 542 #define M3D_EXP_NOCMAP (1<<0) 543 #define M3D_EXP_NOMATERIAL (1<<1) 544 #define M3D_EXP_NOFACE (1<<2) 545 #define M3D_EXP_NONORMAL (1<<3) 546 #define M3D_EXP_NOTXTCRD (1<<4) 547 #define M3D_EXP_FLIPTXTCRD (1<<5) 548 #define M3D_EXP_NORECALC (1<<6) 549 #define M3D_EXP_IDOSUCK (1<<7) 550 #define M3D_EXP_NOBONE (1<<8) 551 #define M3D_EXP_NOACTION (1<<9) 552 #define M3D_EXP_INLINE (1<<10) 553 #define M3D_EXP_EXTRA (1<<11) 554 #define M3D_EXP_NOZLIB (1<<14) 555 #define M3D_EXP_ASCII (1<<15) 556 #define M3D_EXP_NOVRTMAX (1<<16) 557 558 /*** error codes ***/ 559 #define M3D_SUCCESS 0 560 #define M3D_ERR_ALLOC -1 561 #define M3D_ERR_BADFILE -2 562 #define M3D_ERR_UNIMPL -65 563 #define M3D_ERR_UNKPROP -66 564 #define M3D_ERR_UNKMESH -67 565 #define M3D_ERR_UNKIMG -68 566 #define M3D_ERR_UNKFRAME -69 567 #define M3D_ERR_UNKCMD -70 568 #define M3D_ERR_UNKVOX -71 569 #define M3D_ERR_TRUNC -72 570 #define M3D_ERR_CMAP -73 571 #define M3D_ERR_TMAP -74 572 #define M3D_ERR_VRTS -75 573 #define M3D_ERR_BONE -76 574 #define M3D_ERR_MTRL -77 575 #define M3D_ERR_SHPE -78 576 #define M3D_ERR_VOXT -79 577 578 #define M3D_ERR_ISFATAL(x) ((x) < 0 && (x) > -65) 579 580 /* callbacks */ 581 typedef unsigned char *(*m3dread_t)(char *filename, unsigned int *size); /* read file contents into buffer */ 582 typedef void (*m3dfree_t)(void *buffer); /* free file contents buffer */ 583 typedef int (*m3dtxsc_t)(const char *name, const void *script, uint32_t len, m3dtx_t *output); /* interpret texture script */ 584 typedef int (*m3dprsc_t)(const char *name, const void *script, uint32_t len, m3d_t *model); /* interpret surface script */ 585 #endif /* ifndef M3D_APIVERSION */ 586 587 /*** C prototypes ***/ 588 /* import / export */ 589 m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d_t *mtllib); 590 unsigned char *m3d_save(m3d_t *model, int quality, int flags, unsigned int *size); 591 void m3d_free(m3d_t *model); 592 /* generate animation pose skeleton */ 593 m3dtr_t *m3d_frame(m3d_t *model, M3D_INDEX actionid, M3D_INDEX frameid, m3dtr_t *skeleton); 594 m3db_t *m3d_pose(m3d_t *model, M3D_INDEX actionid, uint32_t msec); 595 596 /* private prototypes used by both importer and exporter */ 597 char *_m3d_safestr(char *in, int morelines); 598 599 /*** C implementation ***/ 600 #ifdef M3D_IMPLEMENTATION 601 #if !defined(M3D_NOIMPORTER) || defined(M3D_EXPORTER) 602 /* material property definitions */ 603 static m3dpd_t m3d_propertytypes[] = { 604 M3D_PROPERTYDEF(m3dpf_color, m3dp_Kd, "Kd"), /* diffuse color */ 605 M3D_PROPERTYDEF(m3dpf_color, m3dp_Ka, "Ka"), /* ambient color */ 606 M3D_PROPERTYDEF(m3dpf_color, m3dp_Ks, "Ks"), /* specular color */ 607 M3D_PROPERTYDEF(m3dpf_float, m3dp_Ns, "Ns"), /* specular exponent */ 608 M3D_PROPERTYDEF(m3dpf_color, m3dp_Ke, "Ke"), /* emissive (emitting light of this color) */ 609 M3D_PROPERTYDEF(m3dpf_color, m3dp_Tf, "Tf"), /* transmission color */ 610 M3D_PROPERTYDEF(m3dpf_float, m3dp_Km, "Km"), /* bump strength */ 611 M3D_PROPERTYDEF(m3dpf_float, m3dp_d, "d"), /* dissolve (transparency) */ 612 M3D_PROPERTYDEF(m3dpf_uint8, m3dp_il, "il"), /* illumination model (informational, ignored by PBR-shaders) */ 613 614 M3D_PROPERTYDEF(m3dpf_float, m3dp_Pr, "Pr"), /* roughness */ 615 M3D_PROPERTYDEF(m3dpf_float, m3dp_Pm, "Pm"), /* metallic, also reflection */ 616 M3D_PROPERTYDEF(m3dpf_float, m3dp_Ps, "Ps"), /* sheen */ 617 M3D_PROPERTYDEF(m3dpf_float, m3dp_Ni, "Ni"), /* index of refraction (optical density) */ 618 M3D_PROPERTYDEF(m3dpf_float, m3dp_Nt, "Nt"), /* thickness of face in millimeter, for printing */ 619 620 /* aliases, note that "map_*" aliases are handled automatically */ 621 M3D_PROPERTYDEF(m3dpf_map, m3dp_map_Km, "bump"), 622 M3D_PROPERTYDEF(m3dpf_map, m3dp_map_N, "map_N"),/* as normal map has no scalar version, it's counterpart is 'il' */ 623 M3D_PROPERTYDEF(m3dpf_map, m3dp_map_Pm, "refl") 624 }; 625 /* shape command definitions. if more commands start with the same string, the longer must come first */ 626 static m3dcd_t m3d_commandtypes[] = { 627 /* technical */ 628 M3D_CMDDEF(m3dc_use, "use", 1, m3dcp_mi_t, 0, 0, 0, 0, 0, 0, 0), 629 M3D_CMDDEF(m3dc_inc, "inc", 3, m3dcp_hi_t, m3dcp_vi_t, m3dcp_qi_t, m3dcp_vi_t, 0, 0, 0, 0), 630 M3D_CMDDEF(m3dc_mesh, "mesh", 1, m3dcp_fi_t, m3dcp_fi_t, m3dcp_vi_t, m3dcp_qi_t, m3dcp_vi_t, 0, 0, 0), 631 /* approximations */ 632 M3D_CMDDEF(m3dc_div, "div", 1, m3dcp_vc_t, 0, 0, 0, 0, 0, 0, 0), 633 M3D_CMDDEF(m3dc_sub, "sub", 2, m3dcp_vc_t, m3dcp_vc_t, 0, 0, 0, 0, 0, 0), 634 M3D_CMDDEF(m3dc_len, "len", 1, m3dcp_vc_t, 0, 0, 0, 0, 0, 0, 0), 635 M3D_CMDDEF(m3dc_dist, "dist", 2, m3dcp_vc_t, m3dcp_vc_t, 0, 0, 0, 0, 0, 0), 636 /* modifiers */ 637 M3D_CMDDEF(m3dc_degu, "degu", 1, m3dcp_i1_t, 0, 0, 0, 0, 0, 0, 0), 638 M3D_CMDDEF(m3dc_deg, "deg", 2, m3dcp_i1_t, m3dcp_i1_t, 0, 0, 0, 0, 0, 0), 639 M3D_CMDDEF(m3dc_rangeu, "rangeu", 1, m3dcp_ti_t, 0, 0, 0, 0, 0, 0, 0), 640 M3D_CMDDEF(m3dc_range, "range", 2, m3dcp_ti_t, m3dcp_ti_t, 0, 0, 0, 0, 0, 0), 641 M3D_CMDDEF(m3dc_paru, "paru", 2, m3dcp_va_t, m3dcp_vc_t, 0, 0, 0, 0, 0, 0), 642 M3D_CMDDEF(m3dc_parv, "parv", 2, m3dcp_va_t, m3dcp_vc_t, 0, 0, 0, 0, 0, 0), 643 M3D_CMDDEF(m3dc_trim, "trim", 3, m3dcp_va_t, m3dcp_ti_t, m3dcp_i2_t, 0, 0, 0, 0, 0), 644 M3D_CMDDEF(m3dc_hole, "hole", 3, m3dcp_va_t, m3dcp_ti_t, m3dcp_i2_t, 0, 0, 0, 0, 0), 645 M3D_CMDDEF(m3dc_scrv, "scrv", 3, m3dcp_va_t, m3dcp_ti_t, m3dcp_i2_t, 0, 0, 0, 0, 0), 646 M3D_CMDDEF(m3dc_sp, "sp", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0), 647 /* helper curves */ 648 M3D_CMDDEF(m3dc_bez1, "bez1", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0), 649 M3D_CMDDEF(m3dc_bsp1, "bsp1", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0), 650 M3D_CMDDEF(m3dc_bez2, "bez2", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0), 651 M3D_CMDDEF(m3dc_bsp2, "bsp2", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0), 652 /* surfaces */ 653 M3D_CMDDEF(m3dc_bezun, "bezun", 4, m3dcp_va_t, m3dcp_vi_t, m3dcp_ti_t, m3dcp_vi_t, 0, 0, 0, 0), 654 M3D_CMDDEF(m3dc_bezu, "bezu", 3, m3dcp_va_t, m3dcp_vi_t, m3dcp_ti_t, 0, 0, 0, 0, 0), 655 M3D_CMDDEF(m3dc_bezn, "bezn", 3, m3dcp_va_t, m3dcp_vi_t, m3dcp_vi_t, 0, 0, 0, 0, 0), 656 M3D_CMDDEF(m3dc_bez, "bez", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0), 657 M3D_CMDDEF(m3dc_nurbsun, "nurbsun", 4, m3dcp_va_t, m3dcp_vi_t, m3dcp_ti_t, m3dcp_vi_t, 0, 0, 0, 0), 658 M3D_CMDDEF(m3dc_nurbsu, "nurbsu", 3, m3dcp_va_t, m3dcp_vi_t, m3dcp_ti_t, 0, 0, 0, 0, 0), 659 M3D_CMDDEF(m3dc_nurbsn, "nurbsn", 3, m3dcp_va_t, m3dcp_vi_t, m3dcp_vi_t, 0, 0, 0, 0, 0), 660 M3D_CMDDEF(m3dc_nurbs, "nurbs", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0), 661 M3D_CMDDEF(m3dc_conn, "conn", 6, m3dcp_i2_t, m3dcp_ti_t, m3dcp_i2_t, m3dcp_i2_t, m3dcp_ti_t, m3dcp_i2_t, 0, 0), 662 /* geometrical */ 663 M3D_CMDDEF(m3dc_line, "line", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0), 664 M3D_CMDDEF(m3dc_polygon, "polygon", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0), 665 M3D_CMDDEF(m3dc_circle, "circle", 3, m3dcp_vi_t, m3dcp_qi_t, m3dcp_vc_t, 0, 0, 0, 0, 0), 666 M3D_CMDDEF(m3dc_cylinder,"cylinder",6, m3dcp_vi_t, m3dcp_qi_t, m3dcp_vc_t, m3dcp_vi_t, m3dcp_qi_t, m3dcp_vc_t, 0, 0), 667 M3D_CMDDEF(m3dc_shpere, "shpere", 2, m3dcp_vi_t, m3dcp_vc_t, 0, 0, 0, 0, 0, 0), 668 M3D_CMDDEF(m3dc_torus, "torus", 4, m3dcp_vi_t, m3dcp_qi_t, m3dcp_vc_t, m3dcp_vc_t, 0, 0, 0, 0), 669 M3D_CMDDEF(m3dc_cone, "cone", 3, m3dcp_vi_t, m3dcp_vi_t, m3dcp_vi_t, 0, 0, 0, 0, 0), 670 M3D_CMDDEF(m3dc_cube, "cube", 3, m3dcp_vi_t, m3dcp_vi_t, m3dcp_vi_t, 0, 0, 0, 0, 0) 671 }; 672 #endif 673 674 #include <stdlib.h> 675 #include <string.h> 676 677 #if !defined(M3D_NOIMPORTER) && !defined(STBI_INCLUDE_STB_IMAGE_H) 678 /* PNG decompressor from 679 680 stb_image - v2.23 - public domain image loader - http://nothings.org/stb_image.h 681 */ 682 static const char *_m3dstbi__g_failure_reason; 683 684 enum 685 { 686 STBI_default = 0, 687 688 STBI_grey = 1, 689 STBI_grey_alpha = 2, 690 STBI_rgb = 3, 691 STBI_rgb_alpha = 4 692 }; 693 694 enum 695 { 696 STBI__SCAN_load=0, 697 STBI__SCAN_type, 698 STBI__SCAN_header 699 }; 700 701 typedef unsigned short _m3dstbi_us; 702 703 typedef uint16_t _m3dstbi__uint16; 704 typedef int16_t _m3dstbi__int16; 705 typedef uint32_t _m3dstbi__uint32; 706 typedef int32_t _m3dstbi__int32; 707 708 typedef struct 709 { 710 _m3dstbi__uint32 img_x, img_y; 711 int img_n, img_out_n; 712 713 void *io_user_data; 714 715 int read_from_callbacks; 716 int buflen; 717 unsigned char buffer_start[128]; 718 719 unsigned char *img_buffer, *img_buffer_end; 720 unsigned char *img_buffer_original, *img_buffer_original_end; 721 } _m3dstbi__context; 722 723 typedef struct 724 { 725 int bits_per_channel; 726 int num_channels; 727 int channel_order; 728 } _m3dstbi__result_info; 729 730 #define STBI_ASSERT(v) 731 #define STBI_NOTUSED(v) (void)sizeof(v) 732 #define STBI__BYTECAST(x) ((unsigned char) ((x) & 255)) 733 #define STBI_MALLOC(sz) M3D_MALLOC(sz) 734 #define STBI_REALLOC(p,newsz) M3D_REALLOC(p,newsz) 735 #define STBI_FREE(p) M3D_FREE(p) 736 #define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz) 737 738 _inline static unsigned char _m3dstbi__get8(_m3dstbi__context *s) 739 { 740 if (s->img_buffer < s->img_buffer_end) 741 return *s->img_buffer++; 742 return 0; 743 } 744 745 _inline static int _m3dstbi__at_eof(_m3dstbi__context *s) 746 { 747 return s->img_buffer >= s->img_buffer_end; 748 } 749 750 static void _m3dstbi__skip(_m3dstbi__context *s, int n) 751 { 752 if (n < 0) { 753 s->img_buffer = s->img_buffer_end; 754 return; 755 } 756 s->img_buffer += n; 757 } 758 759 static int _m3dstbi__getn(_m3dstbi__context *s, unsigned char *buffer, int n) 760 { 761 if (s->img_buffer+n <= s->img_buffer_end) { 762 memcpy(buffer, s->img_buffer, n); 763 s->img_buffer += n; 764 return 1; 765 } else 766 return 0; 767 } 768 769 static int _m3dstbi__get16be(_m3dstbi__context *s) 770 { 771 int z = _m3dstbi__get8(s); 772 return (z << 8) + _m3dstbi__get8(s); 773 } 774 775 static _m3dstbi__uint32 _m3dstbi__get32be(_m3dstbi__context *s) 776 { 777 _m3dstbi__uint32 z = _m3dstbi__get16be(s); 778 return (z << 16) + _m3dstbi__get16be(s); 779 } 780 781 #define _m3dstbi__err(x,y) _m3dstbi__errstr(y) 782 static int _m3dstbi__errstr(const char *str) 783 { 784 _m3dstbi__g_failure_reason = str; 785 return 0; 786 } 787 788 _inline static void *_m3dstbi__malloc(size_t size) 789 { 790 return STBI_MALLOC(size); 791 } 792 793 static int _m3dstbi__addsizes_valid(int a, int b) 794 { 795 if (b < 0) return 0; 796 return a <= 2147483647 - b; 797 } 798 799 static int _m3dstbi__mul2sizes_valid(int a, int b) 800 { 801 if (a < 0 || b < 0) return 0; 802 if (b == 0) return 1; 803 return a <= 2147483647/b; 804 } 805 806 static int _m3dstbi__mad2sizes_valid(int a, int b, int add) 807 { 808 return _m3dstbi__mul2sizes_valid(a, b) && _m3dstbi__addsizes_valid(a*b, add); 809 } 810 811 static int _m3dstbi__mad3sizes_valid(int a, int b, int c, int add) 812 { 813 return _m3dstbi__mul2sizes_valid(a, b) && _m3dstbi__mul2sizes_valid(a*b, c) && 814 _m3dstbi__addsizes_valid(a*b*c, add); 815 } 816 817 static void *_m3dstbi__malloc_mad2(int a, int b, int add) 818 { 819 if (!_m3dstbi__mad2sizes_valid(a, b, add)) return NULL; 820 return _m3dstbi__malloc(a*b + add); 821 } 822 823 static void *_m3dstbi__malloc_mad3(int a, int b, int c, int add) 824 { 825 if (!_m3dstbi__mad3sizes_valid(a, b, c, add)) return NULL; 826 return _m3dstbi__malloc(a*b*c + add); 827 } 828 829 static unsigned char _m3dstbi__compute_y(int r, int g, int b) 830 { 831 return (unsigned char) (((r*77) + (g*150) + (29*b)) >> 8); 832 } 833 834 static unsigned char *_m3dstbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) 835 { 836 int i,j; 837 unsigned char *good; 838 839 if (req_comp == img_n) return data; 840 STBI_ASSERT(req_comp >= 1 && req_comp <= 4); 841 842 good = (unsigned char *) _m3dstbi__malloc_mad3(req_comp, x, y, 0); 843 if (good == NULL) { 844 STBI_FREE(data); 845 _m3dstbi__err("outofmem", "Out of memory"); 846 return NULL; 847 } 848 849 for (j=0; j < (int) y; ++j) { 850 unsigned char *src = data + j * x * img_n ; 851 unsigned char *dest = good + j * x * req_comp; 852 853 #define STBI__COMBO(a,b) ((a)*8+(b)) 854 #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) 855 switch (STBI__COMBO(img_n, req_comp)) { 856 STBI__CASE(1,2) { dest[0]=src[0], dest[1]=255; } break; 857 STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; 858 STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=255; } break; 859 STBI__CASE(2,1) { dest[0]=src[0]; } break; 860 STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; 861 STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; } break; 862 STBI__CASE(3,4) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=255; } break; 863 STBI__CASE(3,1) { dest[0]=_m3dstbi__compute_y(src[0],src[1],src[2]); } break; 864 STBI__CASE(3,2) { dest[0]=_m3dstbi__compute_y(src[0],src[1],src[2]), dest[1] = 255; } break; 865 STBI__CASE(4,1) { dest[0]=_m3dstbi__compute_y(src[0],src[1],src[2]); } break; 866 STBI__CASE(4,2) { dest[0]=_m3dstbi__compute_y(src[0],src[1],src[2]), dest[1] = src[3]; } break; 867 STBI__CASE(4,3) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; } break; 868 default: STBI_ASSERT(0); 869 } 870 #undef STBI__CASE 871 } 872 873 STBI_FREE(data); 874 return good; 875 } 876 877 static _m3dstbi__uint16 _m3dstbi__compute_y_16(int r, int g, int b) 878 { 879 return (_m3dstbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8); 880 } 881 882 static _m3dstbi__uint16 *_m3dstbi__convert_format16(_m3dstbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y) 883 { 884 int i,j; 885 _m3dstbi__uint16 *good; 886 887 if (req_comp == img_n) return data; 888 STBI_ASSERT(req_comp >= 1 && req_comp <= 4); 889 890 good = (_m3dstbi__uint16 *) _m3dstbi__malloc(req_comp * x * y * 2); 891 if (good == NULL) { 892 STBI_FREE(data); 893 _m3dstbi__err("outofmem", "Out of memory"); 894 return NULL; 895 } 896 897 for (j=0; j < (int) y; ++j) { 898 _m3dstbi__uint16 *src = data + j * x * img_n ; 899 _m3dstbi__uint16 *dest = good + j * x * req_comp; 900 901 #define STBI__COMBO(a,b) ((a)*8+(b)) 902 #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) 903 switch (STBI__COMBO(img_n, req_comp)) { 904 STBI__CASE(1,2) { dest[0]=src[0], dest[1]=0xffff; } break; 905 STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; 906 STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=0xffff; } break; 907 STBI__CASE(2,1) { dest[0]=src[0]; } break; 908 STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; 909 STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; } break; 910 STBI__CASE(3,4) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=0xffff; } break; 911 STBI__CASE(3,1) { dest[0]=_m3dstbi__compute_y_16(src[0],src[1],src[2]); } break; 912 STBI__CASE(3,2) { dest[0]=_m3dstbi__compute_y_16(src[0],src[1],src[2]), dest[1] = 0xffff; } break; 913 STBI__CASE(4,1) { dest[0]=_m3dstbi__compute_y_16(src[0],src[1],src[2]); } break; 914 STBI__CASE(4,2) { dest[0]=_m3dstbi__compute_y_16(src[0],src[1],src[2]), dest[1] = src[3]; } break; 915 STBI__CASE(4,3) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; } break; 916 default: STBI_ASSERT(0); 917 } 918 #undef STBI__CASE 919 } 920 921 STBI_FREE(data); 922 return good; 923 } 924 925 #define STBI__ZFAST_BITS 9 926 #define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) 927 928 typedef struct 929 { 930 _m3dstbi__uint16 fast[1 << STBI__ZFAST_BITS]; 931 _m3dstbi__uint16 firstcode[16]; 932 int maxcode[17]; 933 _m3dstbi__uint16 firstsymbol[16]; 934 unsigned char size[288]; 935 _m3dstbi__uint16 value[288]; 936 } _m3dstbi__zhuffman; 937 938 _inline static int _m3dstbi__bitreverse16(int n) 939 { 940 n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); 941 n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); 942 n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); 943 n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); 944 return n; 945 } 946 947 _inline static int _m3dstbi__bit_reverse(int v, int bits) 948 { 949 STBI_ASSERT(bits <= 16); 950 return _m3dstbi__bitreverse16(v) >> (16-bits); 951 } 952 953 static int _m3dstbi__zbuild_huffman(_m3dstbi__zhuffman *z, unsigned char *sizelist, int num) 954 { 955 int i,k=0; 956 int code, next_code[16], sizes[17]; 957 958 memset(sizes, 0, sizeof(sizes)); 959 memset(z->fast, 0, sizeof(z->fast)); 960 for (i=0; i < num; ++i) 961 ++sizes[sizelist[i]]; 962 sizes[0] = 0; 963 for (i=1; i < 16; ++i) 964 if (sizes[i] > (1 << i)) 965 return _m3dstbi__err("bad sizes", "Corrupt PNG"); 966 code = 0; 967 for (i=1; i < 16; ++i) { 968 next_code[i] = code; 969 z->firstcode[i] = (_m3dstbi__uint16) code; 970 z->firstsymbol[i] = (_m3dstbi__uint16) k; 971 code = (code + sizes[i]); 972 if (sizes[i]) 973 if (code-1 >= (1 << i)) return _m3dstbi__err("bad codelengths","Corrupt PNG"); 974 z->maxcode[i] = code << (16-i); 975 code <<= 1; 976 k += sizes[i]; 977 } 978 z->maxcode[16] = 0x10000; 979 for (i=0; i < num; ++i) { 980 int s = sizelist[i]; 981 if (s) { 982 int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; 983 _m3dstbi__uint16 fastv = (_m3dstbi__uint16) ((s << 9) | i); 984 z->size [c] = (unsigned char ) s; 985 z->value[c] = (_m3dstbi__uint16) i; 986 if (s <= STBI__ZFAST_BITS) { 987 int j = _m3dstbi__bit_reverse(next_code[s],s); 988 while (j < (1 << STBI__ZFAST_BITS)) { 989 z->fast[j] = fastv; 990 j += (1 << s); 991 } 992 } 993 ++next_code[s]; 994 } 995 } 996 return 1; 997 } 998 999 typedef struct 1000 { 1001 unsigned char *zbuffer, *zbuffer_end; 1002 int num_bits; 1003 _m3dstbi__uint32 code_buffer; 1004 1005 char *zout; 1006 char *zout_start; 1007 char *zout_end; 1008 int z_expandable; 1009 1010 _m3dstbi__zhuffman z_length, z_distance; 1011 } _m3dstbi__zbuf; 1012 1013 _inline static unsigned char _m3dstbi__zget8(_m3dstbi__zbuf *z) 1014 { 1015 if (z->zbuffer >= z->zbuffer_end) return 0; 1016 return *z->zbuffer++; 1017 } 1018 1019 static void _m3dstbi__fill_bits(_m3dstbi__zbuf *z) 1020 { 1021 do { 1022 STBI_ASSERT(z->code_buffer < (1U << z->num_bits)); 1023 z->code_buffer |= (unsigned int) _m3dstbi__zget8(z) << z->num_bits; 1024 z->num_bits += 8; 1025 } while (z->num_bits <= 24); 1026 } 1027 1028 _inline static unsigned int _m3dstbi__zreceive(_m3dstbi__zbuf *z, int n) 1029 { 1030 unsigned int k; 1031 if (z->num_bits < n) _m3dstbi__fill_bits(z); 1032 k = z->code_buffer & ((1 << n) - 1); 1033 z->code_buffer >>= n; 1034 z->num_bits -= n; 1035 return k; 1036 } 1037 1038 static int _m3dstbi__zhuffman_decode_slowpath(_m3dstbi__zbuf *a, _m3dstbi__zhuffman *z) 1039 { 1040 int b,s,k; 1041 k = _m3dstbi__bit_reverse(a->code_buffer, 16); 1042 for (s=STBI__ZFAST_BITS+1; ; ++s) 1043 if (k < z->maxcode[s]) 1044 break; 1045 if (s == 16) return -1; 1046 b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; 1047 STBI_ASSERT(z->size[b] == s); 1048 a->code_buffer >>= s; 1049 a->num_bits -= s; 1050 return z->value[b]; 1051 } 1052 1053 _inline static int _m3dstbi__zhuffman_decode(_m3dstbi__zbuf *a, _m3dstbi__zhuffman *z) 1054 { 1055 int b,s; 1056 if (a->num_bits < 16) _m3dstbi__fill_bits(a); 1057 b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; 1058 if (b) { 1059 s = b >> 9; 1060 a->code_buffer >>= s; 1061 a->num_bits -= s; 1062 return b & 511; 1063 } 1064 return _m3dstbi__zhuffman_decode_slowpath(a, z); 1065 } 1066 1067 static int _m3dstbi__zexpand(_m3dstbi__zbuf *z, char *zout, int n) 1068 { 1069 char *q; 1070 int cur, limit, old_limit; 1071 z->zout = zout; 1072 if (!z->z_expandable) return _m3dstbi__err("output buffer limit","Corrupt PNG"); 1073 cur = (int) (z->zout - z->zout_start); 1074 limit = old_limit = (int) (z->zout_end - z->zout_start); 1075 while (cur + n > limit) 1076 limit *= 2; 1077 q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit); 1078 STBI_NOTUSED(old_limit); 1079 if (q == NULL) return _m3dstbi__err("outofmem", "Out of memory"); 1080 z->zout_start = q; 1081 z->zout = q + cur; 1082 z->zout_end = q + limit; 1083 return 1; 1084 } 1085 1086 static int _m3dstbi__zlength_base[31] = { 1087 3,4,5,6,7,8,9,10,11,13, 1088 15,17,19,23,27,31,35,43,51,59, 1089 67,83,99,115,131,163,195,227,258,0,0 }; 1090 1091 static int _m3dstbi__zlength_extra[31]= 1092 { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; 1093 1094 static int _m3dstbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, 1095 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; 1096 1097 static int _m3dstbi__zdist_extra[32] = 1098 { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; 1099 1100 static int _m3dstbi__parse_huffman_block(_m3dstbi__zbuf *a) 1101 { 1102 char *zout = a->zout; 1103 for(;;) { 1104 int z = _m3dstbi__zhuffman_decode(a, &a->z_length); 1105 if (z < 256) { 1106 if (z < 0) return _m3dstbi__err("bad huffman code","Corrupt PNG"); 1107 if (zout >= a->zout_end) { 1108 if (!_m3dstbi__zexpand(a, zout, 1)) return 0; 1109 zout = a->zout; 1110 } 1111 *zout++ = (char) z; 1112 } else { 1113 unsigned char *p; 1114 int len,dist; 1115 if (z == 256) { 1116 a->zout = zout; 1117 return 1; 1118 } 1119 z -= 257; 1120 len = _m3dstbi__zlength_base[z]; 1121 if (_m3dstbi__zlength_extra[z]) len += _m3dstbi__zreceive(a, _m3dstbi__zlength_extra[z]); 1122 z = _m3dstbi__zhuffman_decode(a, &a->z_distance); 1123 if (z < 0) return _m3dstbi__err("bad huffman code","Corrupt PNG"); 1124 dist = _m3dstbi__zdist_base[z]; 1125 if (_m3dstbi__zdist_extra[z]) dist += _m3dstbi__zreceive(a, _m3dstbi__zdist_extra[z]); 1126 if (zout - a->zout_start < dist) return _m3dstbi__err("bad dist","Corrupt PNG"); 1127 if (zout + len > a->zout_end) { 1128 if (!_m3dstbi__zexpand(a, zout, len)) return 0; 1129 zout = a->zout; 1130 } 1131 p = (unsigned char *) (zout - dist); 1132 if (dist == 1) { 1133 unsigned char v = *p; 1134 if (len) { do *zout++ = v; while (--len); } 1135 } else { 1136 if (len) { do *zout++ = *p++; while (--len); } 1137 } 1138 } 1139 } 1140 } 1141 1142 static int _m3dstbi__compute_huffman_codes(_m3dstbi__zbuf *a) 1143 { 1144 static unsigned char length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; 1145 _m3dstbi__zhuffman z_codelength; 1146 unsigned char lencodes[286+32+137]; 1147 unsigned char codelength_sizes[19]; 1148 int i,n; 1149 1150 int hlit = _m3dstbi__zreceive(a,5) + 257; 1151 int hdist = _m3dstbi__zreceive(a,5) + 1; 1152 int hclen = _m3dstbi__zreceive(a,4) + 4; 1153 int ntot = hlit + hdist; 1154 1155 memset(codelength_sizes, 0, sizeof(codelength_sizes)); 1156 for (i=0; i < hclen; ++i) { 1157 int s = _m3dstbi__zreceive(a,3); 1158 codelength_sizes[length_dezigzag[i]] = (unsigned char) s; 1159 } 1160 if (!_m3dstbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; 1161 1162 n = 0; 1163 while (n < ntot) { 1164 int c = _m3dstbi__zhuffman_decode(a, &z_codelength); 1165 if (c < 0 || c >= 19) return _m3dstbi__err("bad codelengths", "Corrupt PNG"); 1166 if (c < 16) 1167 lencodes[n++] = (unsigned char) c; 1168 else { 1169 unsigned char fill = 0; 1170 if (c == 16) { 1171 c = _m3dstbi__zreceive(a,2)+3; 1172 if (n == 0) return _m3dstbi__err("bad codelengths", "Corrupt PNG"); 1173 fill = lencodes[n-1]; 1174 } else if (c == 17) 1175 c = _m3dstbi__zreceive(a,3)+3; 1176 else { 1177 STBI_ASSERT(c == 18); 1178 c = _m3dstbi__zreceive(a,7)+11; 1179 } 1180 if (ntot - n < c) return _m3dstbi__err("bad codelengths", "Corrupt PNG"); 1181 memset(lencodes+n, fill, c); 1182 n += c; 1183 } 1184 } 1185 if (n != ntot) return _m3dstbi__err("bad codelengths","Corrupt PNG"); 1186 if (!_m3dstbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; 1187 if (!_m3dstbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; 1188 return 1; 1189 } 1190 1191 _inline static int _m3dstbi__parse_uncompressed_block(_m3dstbi__zbuf *a) 1192 { 1193 unsigned char header[4]; 1194 int len,nlen,k; 1195 if (a->num_bits & 7) 1196 _m3dstbi__zreceive(a, a->num_bits & 7); 1197 k = 0; 1198 while (a->num_bits > 0) { 1199 header[k++] = (unsigned char) (a->code_buffer & 255); 1200 a->code_buffer >>= 8; 1201 a->num_bits -= 8; 1202 } 1203 STBI_ASSERT(a->num_bits == 0); 1204 while (k < 4) 1205 header[k++] = _m3dstbi__zget8(a); 1206 len = header[1] * 256 + header[0]; 1207 nlen = header[3] * 256 + header[2]; 1208 if (nlen != (len ^ 0xffff)) return _m3dstbi__err("zlib corrupt","Corrupt PNG"); 1209 if (a->zbuffer + len > a->zbuffer_end) return _m3dstbi__err("read past buffer","Corrupt PNG"); 1210 if (a->zout + len > a->zout_end) 1211 if (!_m3dstbi__zexpand(a, a->zout, len)) return 0; 1212 memcpy(a->zout, a->zbuffer, len); 1213 a->zbuffer += len; 1214 a->zout += len; 1215 return 1; 1216 } 1217 1218 static int _m3dstbi__parse_zlib_header(_m3dstbi__zbuf *a) 1219 { 1220 int cmf = _m3dstbi__zget8(a); 1221 int cm = cmf & 15; 1222 /* int cinfo = cmf >> 4; */ 1223 int flg = _m3dstbi__zget8(a); 1224 if ((cmf*256+flg) % 31 != 0) return _m3dstbi__err("bad zlib header","Corrupt PNG"); 1225 if (flg & 32) return _m3dstbi__err("no preset dict","Corrupt PNG"); 1226 if (cm != 8) return _m3dstbi__err("bad compression","Corrupt PNG"); 1227 return 1; 1228 } 1229 1230 static unsigned char _m3dstbi__zdefault_length[288], _m3dstbi__zdefault_distance[32]; 1231 static void _m3dstbi__init_zdefaults(void) 1232 { 1233 int i; 1234 for (i=0; i <= 143; ++i) _m3dstbi__zdefault_length[i] = 8; 1235 for ( ; i <= 255; ++i) _m3dstbi__zdefault_length[i] = 9; 1236 for ( ; i <= 279; ++i) _m3dstbi__zdefault_length[i] = 7; 1237 for ( ; i <= 287; ++i) _m3dstbi__zdefault_length[i] = 8; 1238 1239 for (i=0; i <= 31; ++i) _m3dstbi__zdefault_distance[i] = 5; 1240 } 1241 1242 static int _m3dstbi__parse_zlib(_m3dstbi__zbuf *a, int parse_header) 1243 { 1244 int final, type; 1245 if (parse_header) 1246 if (!_m3dstbi__parse_zlib_header(a)) return 0; 1247 a->num_bits = 0; 1248 a->code_buffer = 0; 1249 do { 1250 final = _m3dstbi__zreceive(a,1); 1251 type = _m3dstbi__zreceive(a,2); 1252 if (type == 0) { 1253 if (!_m3dstbi__parse_uncompressed_block(a)) return 0; 1254 } else if (type == 3) { 1255 return 0; 1256 } else { 1257 if (type == 1) { 1258 if (!_m3dstbi__zbuild_huffman(&a->z_length , _m3dstbi__zdefault_length , 288)) return 0; 1259 if (!_m3dstbi__zbuild_huffman(&a->z_distance, _m3dstbi__zdefault_distance, 32)) return 0; 1260 } else { 1261 if (!_m3dstbi__compute_huffman_codes(a)) return 0; 1262 } 1263 if (!_m3dstbi__parse_huffman_block(a)) return 0; 1264 } 1265 } while (!final); 1266 return 1; 1267 } 1268 1269 static int _m3dstbi__do_zlib(_m3dstbi__zbuf *a, char *obuf, int olen, int exp, int parse_header) 1270 { 1271 a->zout_start = obuf; 1272 a->zout = obuf; 1273 a->zout_end = obuf + olen; 1274 a->z_expandable = exp; 1275 _m3dstbi__init_zdefaults(); 1276 return _m3dstbi__parse_zlib(a, parse_header); 1277 } 1278 1279 char *_m3dstbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header) 1280 { 1281 _m3dstbi__zbuf a; 1282 char *p = (char *) _m3dstbi__malloc(initial_size); 1283 if (p == NULL) return NULL; 1284 a.zbuffer = (unsigned char *) buffer; 1285 a.zbuffer_end = (unsigned char *) buffer + len; 1286 if (_m3dstbi__do_zlib(&a, p, initial_size, 1, parse_header)) { 1287 if (outlen) *outlen = (int) (a.zout - a.zout_start); 1288 return a.zout_start; 1289 } else { 1290 STBI_FREE(a.zout_start); 1291 return NULL; 1292 } 1293 } 1294 1295 typedef struct 1296 { 1297 _m3dstbi__uint32 length; 1298 _m3dstbi__uint32 type; 1299 } _m3dstbi__pngchunk; 1300 1301 static _m3dstbi__pngchunk _m3dstbi__get_chunk_header(_m3dstbi__context *s) 1302 { 1303 _m3dstbi__pngchunk c; 1304 c.length = _m3dstbi__get32be(s); 1305 c.type = _m3dstbi__get32be(s); 1306 return c; 1307 } 1308 1309 _inline static int _m3dstbi__check_png_header(_m3dstbi__context *s) 1310 { 1311 static unsigned char png_sig[8] = { 137,80,78,71,13,10,26,10 }; 1312 int i; 1313 for (i=0; i < 8; ++i) 1314 if (_m3dstbi__get8(s) != png_sig[i]) return _m3dstbi__err("bad png sig","Not a PNG"); 1315 return 1; 1316 } 1317 1318 typedef struct 1319 { 1320 _m3dstbi__context *s; 1321 unsigned char *idata, *expanded, *out; 1322 int depth; 1323 } _m3dstbi__png; 1324 1325 1326 enum { 1327 STBI__F_none=0, 1328 STBI__F_sub=1, 1329 STBI__F_up=2, 1330 STBI__F_avg=3, 1331 STBI__F_paeth=4, 1332 STBI__F_avg_first, 1333 STBI__F_paeth_first 1334 }; 1335 1336 static unsigned char first_row_filter[5] = 1337 { 1338 STBI__F_none, 1339 STBI__F_sub, 1340 STBI__F_none, 1341 STBI__F_avg_first, 1342 STBI__F_paeth_first 1343 }; 1344 1345 static int _m3dstbi__paeth(int a, int b, int c) 1346 { 1347 int p = a + b - c; 1348 int pa = abs(p-a); 1349 int pb = abs(p-b); 1350 int pc = abs(p-c); 1351 if (pa <= pb && pa <= pc) return a; 1352 if (pb <= pc) return b; 1353 return c; 1354 } 1355 1356 static unsigned char _m3dstbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; 1357 1358 static int _m3dstbi__create_png_image_raw(_m3dstbi__png *a, unsigned char *raw, _m3dstbi__uint32 raw_len, int out_n, _m3dstbi__uint32 x, _m3dstbi__uint32 y, int depth, int color) 1359 { 1360 int bytes = (depth == 16? 2 : 1); 1361 _m3dstbi__context *s = a->s; 1362 _m3dstbi__uint32 i,j,stride = x*out_n*bytes; 1363 _m3dstbi__uint32 img_len, img_width_bytes; 1364 int k; 1365 int img_n = s->img_n; 1366 1367 int output_bytes = out_n*bytes; 1368 int filter_bytes = img_n*bytes; 1369 int width = x; 1370 1371 STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1); 1372 a->out = (unsigned char *) _m3dstbi__malloc_mad3(x, y, output_bytes, 0); 1373 if (!a->out) return _m3dstbi__err("outofmem", "Out of memory"); 1374 1375 if (!_m3dstbi__mad3sizes_valid(img_n, x, depth, 7)) return _m3dstbi__err("too large", "Corrupt PNG"); 1376 img_width_bytes = (((img_n * x * depth) + 7) >> 3); 1377 img_len = (img_width_bytes + 1) * y; 1378 if (s->img_x == x && s->img_y == y) { 1379 if (raw_len != img_len) return _m3dstbi__err("not enough pixels","Corrupt PNG"); 1380 } else { 1381 if (raw_len < img_len) return _m3dstbi__err("not enough pixels","Corrupt PNG"); 1382 } 1383 1384 for (j=0; j < y; ++j) { 1385 unsigned char *cur = a->out + stride*j; 1386 unsigned char *prior = cur - stride; 1387 int filter = *raw++; 1388 1389 if (filter > 4) 1390 return _m3dstbi__err("invalid filter","Corrupt PNG"); 1391 1392 if (depth < 8) { 1393 STBI_ASSERT(img_width_bytes <= x); 1394 cur += x*out_n - img_width_bytes; 1395 filter_bytes = 1; 1396 width = img_width_bytes; 1397 } 1398 prior = cur - stride; 1399 1400 if (j == 0) filter = first_row_filter[filter]; 1401 1402 for (k=0; k < filter_bytes; ++k) { 1403 switch (filter) { 1404 case STBI__F_none : cur[k] = raw[k]; break; 1405 case STBI__F_sub : cur[k] = raw[k]; break; 1406 case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; 1407 case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break; 1408 case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + _m3dstbi__paeth(0,prior[k],0)); break; 1409 case STBI__F_avg_first : cur[k] = raw[k]; break; 1410 case STBI__F_paeth_first: cur[k] = raw[k]; break; 1411 } 1412 } 1413 1414 if (depth == 8) { 1415 if (img_n != out_n) 1416 cur[img_n] = 255; 1417 raw += img_n; 1418 cur += out_n; 1419 prior += out_n; 1420 } else if (depth == 16) { 1421 if (img_n != out_n) { 1422 cur[filter_bytes] = 255; 1423 cur[filter_bytes+1] = 255; 1424 } 1425 raw += filter_bytes; 1426 cur += output_bytes; 1427 prior += output_bytes; 1428 } else { 1429 raw += 1; 1430 cur += 1; 1431 prior += 1; 1432 } 1433 1434 if (depth < 8 || img_n == out_n) { 1435 int nk = (width - 1)*filter_bytes; 1436 #define STBI__CASE(f) \ 1437 case f: \ 1438 for (k=0; k < nk; ++k) 1439 switch (filter) { 1440 case STBI__F_none: memcpy(cur, raw, nk); break; 1441 STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break; 1442 STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; 1443 STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break; 1444 STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + _m3dstbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break; 1445 STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break; 1446 STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + _m3dstbi__paeth(cur[k-filter_bytes],0,0)); } break; 1447 } 1448 #undef STBI__CASE 1449 raw += nk; 1450 } else { 1451 STBI_ASSERT(img_n+1 == out_n); 1452 #define STBI__CASE(f) \ 1453 case f: \ 1454 for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \ 1455 for (k=0; k < filter_bytes; ++k) 1456 switch (filter) { 1457 STBI__CASE(STBI__F_none) { cur[k] = raw[k]; } break; 1458 STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break; 1459 STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; 1460 STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break; 1461 STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + _m3dstbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break; 1462 STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break; 1463 STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + _m3dstbi__paeth(cur[k- output_bytes],0,0)); } break; 1464 } 1465 #undef STBI__CASE 1466 1467 if (depth == 16) { 1468 cur = a->out + stride*j; 1469 for (i=0; i < x; ++i,cur+=output_bytes) { 1470 cur[filter_bytes+1] = 255; 1471 } 1472 } 1473 } 1474 } 1475 1476 if (depth < 8) { 1477 for (j=0; j < y; ++j) { 1478 unsigned char *cur = a->out + stride*j; 1479 unsigned char *in = a->out + stride*j + x*out_n - img_width_bytes; 1480 unsigned char scale = (color == 0) ? _m3dstbi__depth_scale_table[depth] : 1; 1481 1482 if (depth == 4) { 1483 for (k=x*img_n; k >= 2; k-=2, ++in) { 1484 *cur++ = scale * ((*in >> 4) ); 1485 *cur++ = scale * ((*in ) & 0x0f); 1486 } 1487 if (k > 0) *cur++ = scale * ((*in >> 4) ); 1488 } else if (depth == 2) { 1489 for (k=x*img_n; k >= 4; k-=4, ++in) { 1490 *cur++ = scale * ((*in >> 6) ); 1491 *cur++ = scale * ((*in >> 4) & 0x03); 1492 *cur++ = scale * ((*in >> 2) & 0x03); 1493 *cur++ = scale * ((*in ) & 0x03); 1494 } 1495 if (k > 0) *cur++ = scale * ((*in >> 6) ); 1496 if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03); 1497 if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03); 1498 } else if (depth == 1) { 1499 for (k=x*img_n; k >= 8; k-=8, ++in) { 1500 *cur++ = scale * ((*in >> 7) ); 1501 *cur++ = scale * ((*in >> 6) & 0x01); 1502 *cur++ = scale * ((*in >> 5) & 0x01); 1503 *cur++ = scale * ((*in >> 4) & 0x01); 1504 *cur++ = scale * ((*in >> 3) & 0x01); 1505 *cur++ = scale * ((*in >> 2) & 0x01); 1506 *cur++ = scale * ((*in >> 1) & 0x01); 1507 *cur++ = scale * ((*in ) & 0x01); 1508 } 1509 if (k > 0) *cur++ = scale * ((*in >> 7) ); 1510 if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01); 1511 if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01); 1512 if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01); 1513 if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01); 1514 if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01); 1515 if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01); 1516 } 1517 if (img_n != out_n) { 1518 int q; 1519 cur = a->out + stride*j; 1520 if (img_n == 1) { 1521 for (q=x-1; q >= 0; --q) { 1522 cur[q*2+1] = 255; 1523 cur[q*2+0] = cur[q]; 1524 } 1525 } else { 1526 STBI_ASSERT(img_n == 3); 1527 for (q=x-1; q >= 0; --q) { 1528 cur[q*4+3] = 255; 1529 cur[q*4+2] = cur[q*3+2]; 1530 cur[q*4+1] = cur[q*3+1]; 1531 cur[q*4+0] = cur[q*3+0]; 1532 } 1533 } 1534 } 1535 } 1536 } else if (depth == 16) { 1537 unsigned char *cur = a->out; 1538 _m3dstbi__uint16 *cur16 = (_m3dstbi__uint16*)cur; 1539 1540 for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) { 1541 *cur16 = (cur[0] << 8) | cur[1]; 1542 } 1543 } 1544 1545 return 1; 1546 } 1547 1548 static int _m3dstbi__create_png_image(_m3dstbi__png *a, unsigned char *image_data, _m3dstbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced) 1549 { 1550 int bytes = (depth == 16 ? 2 : 1); 1551 int out_bytes = out_n * bytes; 1552 unsigned char *final; 1553 int p; 1554 if (!interlaced) 1555 return _m3dstbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); 1556 1557 final = (unsigned char *) _m3dstbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); 1558 for (p=0; p < 7; ++p) { 1559 int xorig[] = { 0,4,0,2,0,1,0 }; 1560 int yorig[] = { 0,0,4,0,2,0,1 }; 1561 int xspc[] = { 8,8,4,4,2,2,1 }; 1562 int yspc[] = { 8,8,8,4,4,2,2 }; 1563 int i,j,x,y; 1564 x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p]; 1565 y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p]; 1566 if (x && y) { 1567 _m3dstbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; 1568 if (!_m3dstbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) { 1569 STBI_FREE(final); 1570 return 0; 1571 } 1572 for (j=0; j < y; ++j) { 1573 for (i=0; i < x; ++i) { 1574 int out_y = j*yspc[p]+yorig[p]; 1575 int out_x = i*xspc[p]+xorig[p]; 1576 memcpy(final + out_y*a->s->img_x*out_bytes + out_x*out_bytes, 1577 a->out + (j*x+i)*out_bytes, out_bytes); 1578 } 1579 } 1580 STBI_FREE(a->out); 1581 image_data += img_len; 1582 image_data_len -= img_len; 1583 } 1584 } 1585 a->out = final; 1586 1587 return 1; 1588 } 1589 1590 static int _m3dstbi__compute_transparency(_m3dstbi__png *z, unsigned char tc[3], int out_n) 1591 { 1592 _m3dstbi__context *s = z->s; 1593 _m3dstbi__uint32 i, pixel_count = s->img_x * s->img_y; 1594 unsigned char *p = z->out; 1595 1596 STBI_ASSERT(out_n == 2 || out_n == 4); 1597 1598 if (out_n == 2) { 1599 for (i=0; i < pixel_count; ++i) { 1600 p[1] = (p[0] == tc[0] ? 0 : 255); 1601 p += 2; 1602 } 1603 } else { 1604 for (i=0; i < pixel_count; ++i) { 1605 if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) 1606 p[3] = 0; 1607 p += 4; 1608 } 1609 } 1610 return 1; 1611 } 1612 1613 static int _m3dstbi__compute_transparency16(_m3dstbi__png *z, _m3dstbi__uint16 tc[3], int out_n) 1614 { 1615 _m3dstbi__context *s = z->s; 1616 _m3dstbi__uint32 i, pixel_count = s->img_x * s->img_y; 1617 _m3dstbi__uint16 *p = (_m3dstbi__uint16*) z->out; 1618 1619 STBI_ASSERT(out_n == 2 || out_n == 4); 1620 1621 if (out_n == 2) { 1622 for (i = 0; i < pixel_count; ++i) { 1623 p[1] = (p[0] == tc[0] ? 0 : 65535); 1624 p += 2; 1625 } 1626 } else { 1627 for (i = 0; i < pixel_count; ++i) { 1628 if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) 1629 p[3] = 0; 1630 p += 4; 1631 } 1632 } 1633 return 1; 1634 } 1635 1636 static int _m3dstbi__expand_png_palette(_m3dstbi__png *a, unsigned char *palette, int len, int pal_img_n) 1637 { 1638 _m3dstbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; 1639 unsigned char *p, *temp_out, *orig = a->out; 1640 1641 p = (unsigned char *) _m3dstbi__malloc_mad2(pixel_count, pal_img_n, 0); 1642 if (p == NULL) return _m3dstbi__err("outofmem", "Out of memory"); 1643 1644 temp_out = p; 1645 1646 if (pal_img_n == 3) { 1647 for (i=0; i < pixel_count; ++i) { 1648 int n = orig[i]*4; 1649 p[0] = palette[n ]; 1650 p[1] = palette[n+1]; 1651 p[2] = palette[n+2]; 1652 p += 3; 1653 } 1654 } else { 1655 for (i=0; i < pixel_count; ++i) { 1656 int n = orig[i]*4; 1657 p[0] = palette[n ]; 1658 p[1] = palette[n+1]; 1659 p[2] = palette[n+2]; 1660 p[3] = palette[n+3]; 1661 p += 4; 1662 } 1663 } 1664 STBI_FREE(a->out); 1665 a->out = temp_out; 1666 1667 STBI_NOTUSED(len); 1668 1669 return 1; 1670 } 1671 1672 #define STBI__PNG_TYPE(a,b,c,d) (((unsigned) (a) << 24) + ((unsigned) (b) << 16) + ((unsigned) (c) << 8) + (unsigned) (d)) 1673 1674 static int _m3dstbi__parse_png_file(_m3dstbi__png *z, int scan, int req_comp) 1675 { 1676 unsigned char palette[1024], pal_img_n=0; 1677 unsigned char has_trans=0, tc[3]; 1678 _m3dstbi__uint16 tc16[3]; 1679 _m3dstbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; 1680 int first=1,k,interlace=0, color=0; 1681 _m3dstbi__context *s = z->s; 1682 1683 z->expanded = NULL; 1684 z->idata = NULL; 1685 z->out = NULL; 1686 1687 if (!_m3dstbi__check_png_header(s)) return 0; 1688 1689 if (scan == STBI__SCAN_type) return 1; 1690 1691 for (;;) { 1692 _m3dstbi__pngchunk c = _m3dstbi__get_chunk_header(s); 1693 switch (c.type) { 1694 case STBI__PNG_TYPE('C','g','B','I'): 1695 _m3dstbi__skip(s, c.length); 1696 break; 1697 case STBI__PNG_TYPE('I','H','D','R'): { 1698 int comp,filter; 1699 if (!first) return _m3dstbi__err("multiple IHDR","Corrupt PNG"); 1700 first = 0; 1701 if (c.length != 13) return _m3dstbi__err("bad IHDR len","Corrupt PNG"); 1702 s->img_x = _m3dstbi__get32be(s); if (s->img_x > (1 << 24)) return _m3dstbi__err("too large","Very large image (corrupt?)"); 1703 s->img_y = _m3dstbi__get32be(s); if (s->img_y > (1 << 24)) return _m3dstbi__err("too large","Very large image (corrupt?)"); 1704 z->depth = _m3dstbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return _m3dstbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only"); 1705 color = _m3dstbi__get8(s); if (color > 6) return _m3dstbi__err("bad ctype","Corrupt PNG"); 1706 if (color == 3 && z->depth == 16) return _m3dstbi__err("bad ctype","Corrupt PNG"); 1707 if (color == 3) pal_img_n = 3; else if (color & 1) return _m3dstbi__err("bad ctype","Corrupt PNG"); 1708 comp = _m3dstbi__get8(s); if (comp) return _m3dstbi__err("bad comp method","Corrupt PNG"); 1709 filter= _m3dstbi__get8(s); if (filter) return _m3dstbi__err("bad filter method","Corrupt PNG"); 1710 interlace = _m3dstbi__get8(s); if (interlace>1) return _m3dstbi__err("bad interlace method","Corrupt PNG"); 1711 if (!s->img_x || !s->img_y) return _m3dstbi__err("0-pixel image","Corrupt PNG"); 1712 if (!pal_img_n) { 1713 s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); 1714 if ((1 << 30) / s->img_x / s->img_n < s->img_y) return _m3dstbi__err("too large", "Image too large to decode"); 1715 if (scan == STBI__SCAN_header) return 1; 1716 } else { 1717 s->img_n = 1; 1718 if ((1 << 30) / s->img_x / 4 < s->img_y) return _m3dstbi__err("too large","Corrupt PNG"); 1719 } 1720 break; 1721 } 1722 1723 case STBI__PNG_TYPE('P','L','T','E'): { 1724 if (first) return _m3dstbi__err("first not IHDR", "Corrupt PNG"); 1725 if (c.length > 256*3) return _m3dstbi__err("invalid PLTE","Corrupt PNG"); 1726 pal_len = c.length / 3; 1727 if (pal_len * 3 != c.length) return _m3dstbi__err("invalid PLTE","Corrupt PNG"); 1728 for (i=0; i < pal_len; ++i) { 1729 palette[i*4+0] = _m3dstbi__get8(s); 1730 palette[i*4+1] = _m3dstbi__get8(s); 1731 palette[i*4+2] = _m3dstbi__get8(s); 1732 palette[i*4+3] = 255; 1733 } 1734 break; 1735 } 1736 1737 case STBI__PNG_TYPE('t','R','N','S'): { 1738 if (first) return _m3dstbi__err("first not IHDR", "Corrupt PNG"); 1739 if (z->idata) return _m3dstbi__err("tRNS after IDAT","Corrupt PNG"); 1740 if (pal_img_n) { 1741 if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; } 1742 if (pal_len == 0) return _m3dstbi__err("tRNS before PLTE","Corrupt PNG"); 1743 if (c.length > pal_len) return _m3dstbi__err("bad tRNS len","Corrupt PNG"); 1744 pal_img_n = 4; 1745 for (i=0; i < c.length; ++i) 1746 palette[i*4+3] = _m3dstbi__get8(s); 1747 } else { 1748 if (!(s->img_n & 1)) return _m3dstbi__err("tRNS with alpha","Corrupt PNG"); 1749 if (c.length != (_m3dstbi__uint32) s->img_n*2) return _m3dstbi__err("bad tRNS len","Corrupt PNG"); 1750 has_trans = 1; 1751 if (z->depth == 16) { 1752 for (k = 0; k < s->img_n; ++k) tc16[k] = (_m3dstbi__uint16)_m3dstbi__get16be(s); 1753 } else { 1754 for (k = 0; k < s->img_n; ++k) tc[k] = (unsigned char)(_m3dstbi__get16be(s) & 255) * _m3dstbi__depth_scale_table[z->depth]; 1755 } 1756 } 1757 break; 1758 } 1759 1760 case STBI__PNG_TYPE('I','D','A','T'): { 1761 if (first) return _m3dstbi__err("first not IHDR", "Corrupt PNG"); 1762 if (pal_img_n && !pal_len) return _m3dstbi__err("no PLTE","Corrupt PNG"); 1763 if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; } 1764 if ((int)(ioff + c.length) < (int)ioff) return 0; 1765 if (ioff + c.length > idata_limit) { 1766 _m3dstbi__uint32 idata_limit_old = idata_limit; 1767 unsigned char *p; 1768 if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; 1769 while (ioff + c.length > idata_limit) 1770 idata_limit *= 2; 1771 STBI_NOTUSED(idata_limit_old); 1772 p = (unsigned char *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return _m3dstbi__err("outofmem", "Out of memory"); 1773 z->idata = p; 1774 } 1775 if (!_m3dstbi__getn(s, z->idata+ioff,c.length)) return _m3dstbi__err("outofdata","Corrupt PNG"); 1776 ioff += c.length; 1777 break; 1778 } 1779 1780 case STBI__PNG_TYPE('I','E','N','D'): { 1781 _m3dstbi__uint32 raw_len, bpl; 1782 if (first) return _m3dstbi__err("first not IHDR", "Corrupt PNG"); 1783 if (scan != STBI__SCAN_load) return 1; 1784 if (z->idata == NULL) return _m3dstbi__err("no IDAT","Corrupt PNG"); 1785 bpl = (s->img_x * z->depth + 7) / 8; 1786 raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */; 1787 z->expanded = (unsigned char *) _m3dstbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, 1); 1788 if (z->expanded == NULL) return 0; 1789 STBI_FREE(z->idata); z->idata = NULL; 1790 if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans) 1791 s->img_out_n = s->img_n+1; 1792 else 1793 s->img_out_n = s->img_n; 1794 if (!_m3dstbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0; 1795 if (has_trans) { 1796 if (z->depth == 16) { 1797 if (!_m3dstbi__compute_transparency16(z, tc16, s->img_out_n)) return 0; 1798 } else { 1799 if (!_m3dstbi__compute_transparency(z, tc, s->img_out_n)) return 0; 1800 } 1801 } 1802 if (pal_img_n) { 1803 s->img_n = pal_img_n; 1804 s->img_out_n = pal_img_n; 1805 if (req_comp >= 3) s->img_out_n = req_comp; 1806 if (!_m3dstbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) 1807 return 0; 1808 } else if (has_trans) { 1809 ++s->img_n; 1810 } 1811 STBI_FREE(z->expanded); z->expanded = NULL; 1812 return 1; 1813 } 1814 1815 default: 1816 if (first) return _m3dstbi__err("first not IHDR", "Corrupt PNG"); 1817 if ((c.type & (1 << 29)) == 0) { 1818 return _m3dstbi__err("invalid_chunk", "PNG not supported: unknown PNG chunk type"); 1819 } 1820 _m3dstbi__skip(s, c.length); 1821 break; 1822 } 1823 _m3dstbi__get32be(s); 1824 } 1825 } 1826 1827 static void *_m3dstbi__do_png(_m3dstbi__png *p, int *x, int *y, int *n, int req_comp, _m3dstbi__result_info *ri) 1828 { 1829 void *result=NULL; 1830 if (req_comp < 0 || req_comp > 4) { _m3dstbi__err("bad req_comp", "Internal error"); return NULL; } 1831 if (_m3dstbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { 1832 if (p->depth < 8) 1833 ri->bits_per_channel = 8; 1834 else 1835 ri->bits_per_channel = p->depth; 1836 result = p->out; 1837 p->out = NULL; 1838 if (req_comp && req_comp != p->s->img_out_n) { 1839 if (ri->bits_per_channel == 8) 1840 result = _m3dstbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); 1841 else 1842 result = _m3dstbi__convert_format16((_m3dstbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); 1843 p->s->img_out_n = req_comp; 1844 if (result == NULL) return result; 1845 } 1846 *x = p->s->img_x; 1847 *y = p->s->img_y; 1848 if (n) *n = p->s->img_n; 1849 } 1850 STBI_FREE(p->out); p->out = NULL; 1851 STBI_FREE(p->expanded); p->expanded = NULL; 1852 STBI_FREE(p->idata); p->idata = NULL; 1853 1854 return result; 1855 } 1856 1857 static void *_m3dstbi__png_load(_m3dstbi__context *s, int *x, int *y, int *comp, int req_comp, _m3dstbi__result_info *ri) 1858 { 1859 _m3dstbi__png p; 1860 p.s = s; 1861 return _m3dstbi__do_png(&p, x,y,comp,req_comp, ri); 1862 } 1863 #define stbi__context _m3dstbi__context 1864 #define stbi__result_info _m3dstbi__result_info 1865 #define stbi__png_load _m3dstbi__png_load 1866 #define stbi_zlib_decode_malloc_guesssize_headerflag _m3dstbi_zlib_decode_malloc_guesssize_headerflag 1867 #endif 1868 #if !defined(M3D_NOIMPORTER) && defined(STBI_INCLUDE_STB_IMAGE_H) && !defined(STB_IMAGE_IMPLEMENTATION) 1869 #error "stb_image.h included without STB_IMAGE_IMPLEMENTATION. Sorry, we need some stuff defined inside the ifguard for proper integration" 1870 #endif 1871 1872 #if defined(M3D_EXPORTER) && !defined(INCLUDE_STB_IMAGE_WRITE_H) 1873 /* zlib_compressor from 1874 1875 stb_image_write - v1.13 - public domain - http://nothings.org/stb/stb_image_write.h 1876 */ 1877 typedef unsigned char _m3dstbiw__uc; 1878 typedef unsigned short _m3dstbiw__us; 1879 1880 typedef uint16_t _m3dstbiw__uint16; 1881 typedef int16_t _m3dstbiw__int16; 1882 typedef uint32_t _m3dstbiw__uint32; 1883 typedef int32_t _m3dstbiw__int32; 1884 1885 #define STBIW_MALLOC(s) M3D_MALLOC(s) 1886 #define STBIW_REALLOC(p,ns) M3D_REALLOC(p,ns) 1887 #define STBIW_REALLOC_SIZED(p,oldsz,newsz) STBIW_REALLOC(p,newsz) 1888 #define STBIW_FREE M3D_FREE 1889 #define STBIW_MEMMOVE memmove 1890 #define STBIW_UCHAR (uint8_t) 1891 #define STBIW_ASSERT(x) 1892 #define _m3dstbiw___sbraw(a) ((int *) (a) - 2) 1893 #define _m3dstbiw___sbm(a) _m3dstbiw___sbraw(a)[0] 1894 #define _m3dstbiw___sbn(a) _m3dstbiw___sbraw(a)[1] 1895 1896 #define _m3dstbiw___sbneedgrow(a,n) ((a)==0 || _m3dstbiw___sbn(a)+n >= _m3dstbiw___sbm(a)) 1897 #define _m3dstbiw___sbmaybegrow(a,n) (_m3dstbiw___sbneedgrow(a,(n)) ? _m3dstbiw___sbgrow(a,n) : 0) 1898 #define _m3dstbiw___sbgrow(a,n) _m3dstbiw___sbgrowf((void **) &(a), (n), sizeof(*(a))) 1899 1900 #define _m3dstbiw___sbpush(a, v) (_m3dstbiw___sbmaybegrow(a,1), (a)[_m3dstbiw___sbn(a)++] = (v)) 1901 #define _m3dstbiw___sbcount(a) ((a) ? _m3dstbiw___sbn(a) : 0) 1902 #define _m3dstbiw___sbfree(a) ((a) ? STBIW_FREE(_m3dstbiw___sbraw(a)),0 : 0) 1903 1904 static void *_m3dstbiw___sbgrowf(void **arr, int increment, int itemsize) 1905 { 1906 int m = *arr ? 2*_m3dstbiw___sbm(*arr)+increment : increment+1; 1907 void *p = STBIW_REALLOC_SIZED(*arr ? _m3dstbiw___sbraw(*arr) : 0, *arr ? (_m3dstbiw___sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2); 1908 STBIW_ASSERT(p); 1909 if (p) { 1910 if (!*arr) ((int *) p)[1] = 0; 1911 *arr = (void *) ((int *) p + 2); 1912 _m3dstbiw___sbm(*arr) = m; 1913 } 1914 return *arr; 1915 } 1916 1917 static unsigned char *_m3dstbiw___zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount) 1918 { 1919 while (*bitcount >= 8) { 1920 _m3dstbiw___sbpush(data, STBIW_UCHAR(*bitbuffer)); 1921 *bitbuffer >>= 8; 1922 *bitcount -= 8; 1923 } 1924 return data; 1925 } 1926 1927 static int _m3dstbiw___zlib_bitrev(int code, int codebits) 1928 { 1929 int res=0; 1930 while (codebits--) { 1931 res = (res << 1) | (code & 1); 1932 code >>= 1; 1933 } 1934 return res; 1935 } 1936 1937 static unsigned int _m3dstbiw___zlib_countm(unsigned char *a, unsigned char *b, int limit) 1938 { 1939 int i; 1940 for (i=0; i < limit && i < 258; ++i) 1941 if (a[i] != b[i]) break; 1942 return i; 1943 } 1944 1945 static unsigned int _m3dstbiw___zhash(unsigned char *data) 1946 { 1947 _m3dstbiw__uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16); 1948 hash ^= hash << 3; 1949 hash += hash >> 5; 1950 hash ^= hash << 4; 1951 hash += hash >> 17; 1952 hash ^= hash << 25; 1953 hash += hash >> 6; 1954 return hash; 1955 } 1956 1957 #define _m3dstbiw___zlib_flush() (out = _m3dstbiw___zlib_flushf(out, &bitbuf, &bitcount)) 1958 #define _m3dstbiw___zlib_add(code,codebits) \ 1959 (bitbuf |= (code) << bitcount, bitcount += (codebits), _m3dstbiw___zlib_flush()) 1960 #define _m3dstbiw___zlib_huffa(b,c) _m3dstbiw___zlib_add(_m3dstbiw___zlib_bitrev(b,c),c) 1961 #define _m3dstbiw___zlib_huff1(n) _m3dstbiw___zlib_huffa(0x30 + (n), 8) 1962 #define _m3dstbiw___zlib_huff2(n) _m3dstbiw___zlib_huffa(0x190 + (n)-144, 9) 1963 #define _m3dstbiw___zlib_huff3(n) _m3dstbiw___zlib_huffa(0 + (n)-256,7) 1964 #define _m3dstbiw___zlib_huff4(n) _m3dstbiw___zlib_huffa(0xc0 + (n)-280,8) 1965 #define _m3dstbiw___zlib_huff(n) ((n) <= 143 ? _m3dstbiw___zlib_huff1(n) : (n) <= 255 ? _m3dstbiw___zlib_huff2(n) : (n) <= 279 ? _m3dstbiw___zlib_huff3(n) : _m3dstbiw___zlib_huff4(n)) 1966 #define _m3dstbiw___zlib_huffb(n) ((n) <= 143 ? _m3dstbiw___zlib_huff1(n) : _m3dstbiw___zlib_huff2(n)) 1967 1968 #define _m3dstbiw___ZHASH 16384 1969 1970 unsigned char * _m3dstbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) 1971 { 1972 static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 }; 1973 static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 }; 1974 static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 }; 1975 static unsigned char disteb[] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 }; 1976 unsigned int bitbuf=0; 1977 int i,j, bitcount=0; 1978 unsigned char *out = NULL; 1979 unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(_m3dstbiw___ZHASH * sizeof(char**)); 1980 if (hash_table == NULL) 1981 return NULL; 1982 if (quality < 5) quality = 5; 1983 1984 _m3dstbiw___sbpush(out, 0x78); 1985 _m3dstbiw___sbpush(out, 0x5e); 1986 _m3dstbiw___zlib_add(1,1); 1987 _m3dstbiw___zlib_add(1,2); 1988 1989 for (i=0; i < _m3dstbiw___ZHASH; ++i) 1990 hash_table[i] = NULL; 1991 1992 i=0; 1993 while (i < data_len-3) { 1994 int h = _m3dstbiw___zhash(data+i)&(_m3dstbiw___ZHASH-1), best=3; 1995 unsigned char *bestloc = 0; 1996 unsigned char **hlist = hash_table[h]; 1997 int n = _m3dstbiw___sbcount(hlist); 1998 for (j=0; j < n; ++j) { 1999 if (hlist[j]-data > i-32768) { 2000 int d = _m3dstbiw___zlib_countm(hlist[j], data+i, data_len-i); 2001 if (d >= best) best=d,bestloc=hlist[j]; 2002 } 2003 } 2004 if (hash_table[h] && _m3dstbiw___sbn(hash_table[h]) == 2*quality) { 2005 STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality); 2006 _m3dstbiw___sbn(hash_table[h]) = quality; 2007 } 2008 _m3dstbiw___sbpush(hash_table[h],data+i); 2009 2010 if (bestloc) { 2011 h = _m3dstbiw___zhash(data+i+1)&(_m3dstbiw___ZHASH-1); 2012 hlist = hash_table[h]; 2013 n = _m3dstbiw___sbcount(hlist); 2014 for (j=0; j < n; ++j) { 2015 if (hlist[j]-data > i-32767) { 2016 int e = _m3dstbiw___zlib_countm(hlist[j], data+i+1, data_len-i-1); 2017 if (e > best) { 2018 bestloc = NULL; 2019 break; 2020 } 2021 } 2022 } 2023 } 2024 2025 if (bestloc) { 2026 int d = (int) (data+i - bestloc); 2027 STBIW_ASSERT(d <= 32767 && best <= 258); 2028 for (j=0; best > lengthc[j+1]-1; ++j); 2029 _m3dstbiw___zlib_huff(j+257); 2030 if (lengtheb[j]) _m3dstbiw___zlib_add(best - lengthc[j], lengtheb[j]); 2031 for (j=0; d > distc[j+1]-1; ++j); 2032 _m3dstbiw___zlib_add(_m3dstbiw___zlib_bitrev(j,5),5); 2033 if (disteb[j]) _m3dstbiw___zlib_add(d - distc[j], disteb[j]); 2034 i += best; 2035 } else { 2036 _m3dstbiw___zlib_huffb(data[i]); 2037 ++i; 2038 } 2039 } 2040 for (;i < data_len; ++i) 2041 _m3dstbiw___zlib_huffb(data[i]); 2042 _m3dstbiw___zlib_huff(256); 2043 while (bitcount) 2044 _m3dstbiw___zlib_add(0,1); 2045 2046 for (i=0; i < _m3dstbiw___ZHASH; ++i) 2047 (void) _m3dstbiw___sbfree(hash_table[i]); 2048 STBIW_FREE(hash_table); 2049 2050 { 2051 unsigned int s1=1, s2=0; 2052 int blocklen = (int) (data_len % 5552); 2053 j=0; 2054 while (j < data_len) { 2055 for (i=0; i < blocklen; ++i) s1 += data[j+i], s2 += s1; 2056 s1 %= 65521, s2 %= 65521; 2057 j += blocklen; 2058 blocklen = 5552; 2059 } 2060 _m3dstbiw___sbpush(out, STBIW_UCHAR(s2 >> 8)); 2061 _m3dstbiw___sbpush(out, STBIW_UCHAR(s2)); 2062 _m3dstbiw___sbpush(out, STBIW_UCHAR(s1 >> 8)); 2063 _m3dstbiw___sbpush(out, STBIW_UCHAR(s1)); 2064 } 2065 *out_len = _m3dstbiw___sbn(out); 2066 STBIW_MEMMOVE(_m3dstbiw___sbraw(out), out, *out_len); 2067 return (unsigned char *) _m3dstbiw___sbraw(out); 2068 } 2069 #define stbi_zlib_compress _m3dstbi_zlib_compress 2070 #else 2071 unsigned char * _m3dstbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality); 2072 #endif 2073 2074 #define M3D_CHUNKMAGIC(m, a,b,c,d) ((m)[0]==(a) && (m)[1]==(b) && (m)[2]==(c) && (m)[3]==(d)) 2075 2076 #ifdef M3D_ASCII 2077 #include <stdio.h> /* get sprintf */ 2078 #include <locale.h> /* sprintf and strtod cares about number locale */ 2079 #endif 2080 #ifdef M3D_PROFILING 2081 #include <sys/time.h> 2082 #endif 2083 2084 #if !defined(M3D_NOIMPORTER) && defined(M3D_ASCII) 2085 /* helper functions for the ASCII parser */ 2086 static char *_m3d_findarg(char *s) { 2087 while(s && *s && *s != ' ' && *s != '\t' && *s != '\r' && *s != '\n') s++; 2088 while(s && *s && (*s == ' ' || *s == '\t')) s++; 2089 return s; 2090 } 2091 static char *_m3d_findnl(char *s) { 2092 while(s && *s && *s != '\r' && *s != '\n') s++; 2093 if(*s == '\r') s++; 2094 if(*s == '\n') s++; 2095 return s; 2096 } 2097 static char *_m3d_gethex(char *s, uint32_t *ret) 2098 { 2099 if(*s == '#') s++; 2100 *ret = 0; 2101 for(; *s; s++) { 2102 if(*s >= '0' && *s <= '9') { *ret <<= 4; *ret += (uint32_t)(*s-'0'); } 2103 else if(*s >= 'a' && *s <= 'f') { *ret <<= 4; *ret += (uint32_t)(*s-'a'+10); } 2104 else if(*s >= 'A' && *s <= 'F') { *ret <<= 4; *ret += (uint32_t)(*s-'A'+10); } 2105 else break; 2106 } 2107 return _m3d_findarg(s); 2108 } 2109 static char *_m3d_getint(char *s, uint32_t *ret) 2110 { 2111 char *e = s; 2112 if(!s || !*s || *s == '\r' || *s == '\n') return s; 2113 for(; *e >= '0' && *e <= '9'; e++); 2114 *ret = atoi(s); 2115 return e; 2116 } 2117 static char *_m3d_getfloat(char *s, M3D_FLOAT *ret) 2118 { 2119 char *e = s; 2120 if(!s || !*s || *s == '\r' || *s == '\n') return s; 2121 for(; *e == '-' || *e == '+' || *e == '.' || (*e >= '0' && *e <= '9') || *e == 'e' || *e == 'E'; e++); 2122 *ret = (M3D_FLOAT)strtod(s, NULL); 2123 return _m3d_findarg(e); 2124 } 2125 #endif 2126 #if !defined(M3D_NODUP) && (!defined(M3D_NOIMPORTER) || defined(M3D_ASCII) || defined(M3D_EXPORTER)) 2127 /* helper function to create safe strings */ 2128 char *_m3d_safestr(char *in, int morelines) 2129 { 2130 char *out, *o, *i = in; 2131 int l; 2132 if(!in || !*in) { 2133 out = (char*)M3D_MALLOC(1); 2134 if(!out) return NULL; 2135 out[0] =0; 2136 } else { 2137 for(o = in, l = 0; *o && ((morelines & 1) || (*o != '\r' && *o != '\n')) && l < 256; o++, l++); 2138 out = o = (char*)M3D_MALLOC(l+1); 2139 if(!out) return NULL; 2140 while(*i == ' ' || *i == '\t' || *i == '\r' || (morelines && *i == '\n')) i++; 2141 for(; *i && (morelines || (*i != '\r' && *i != '\n')); i++) { 2142 if(*i == '\r') continue; 2143 if(*i == '\n') { 2144 if(morelines >= 3 && o > out && *(o-1) == '\n') break; 2145 if(i > in && *(i-1) == '\n') continue; 2146 if(morelines & 1) { 2147 if(morelines == 1) *o++ = '\r'; 2148 *o++ = '\n'; 2149 } else 2150 break; 2151 } else 2152 if(*i == ' ' || *i == '\t') { 2153 *o++ = morelines? ' ' : '_'; 2154 } else 2155 *o++ = !morelines && (*i == '/' || *i == '\\') ? '_' : *i; 2156 } 2157 for(; o > out && (*(o-1) == ' ' || *(o-1) == '\t' || *(o-1) == '\r' || *(o-1) == '\n'); o--); 2158 *o = 0; 2159 out = (char*)M3D_REALLOC(out, (uintptr_t)o - (uintptr_t)out + 1); 2160 } 2161 return out; 2162 } 2163 #endif 2164 #ifndef M3D_NOIMPORTER 2165 /* helper function to load and decode/generate a texture */ 2166 M3D_INDEX _m3d_gettx(m3d_t *model, m3dread_t readfilecb, m3dfree_t freecb, char *fn) 2167 { 2168 unsigned int i, len = 0; 2169 unsigned char *buff = NULL; 2170 char *fn2; 2171 unsigned int w, h; 2172 stbi__context s; 2173 stbi__result_info ri; 2174 2175 /* failsafe */ 2176 if(!fn || !*fn) return M3D_UNDEF; 2177 /* do we have loaded this texture already? */ 2178 for(i = 0; i < model->numtexture; i++) 2179 if(!strcmp(fn, model->texture[i].name)) return i; 2180 /* see if it's inlined in the model */ 2181 if(model->inlined) { 2182 for(i = 0; i < model->numinlined; i++) 2183 if(!strcmp(fn, model->inlined[i].name)) { 2184 buff = model->inlined[i].data; 2185 len = model->inlined[i].length; 2186 freecb = NULL; 2187 break; 2188 } 2189 } 2190 /* try to load from external source */ 2191 if(!buff && readfilecb) { 2192 i = (unsigned int)strlen(fn); 2193 if(i < 5 || fn[i - 4] != '.') { 2194 fn2 = (char*)M3D_MALLOC(i + 5); 2195 if(!fn2) { model->errcode = M3D_ERR_ALLOC; return M3D_UNDEF; } 2196 memcpy(fn2, fn, i); 2197 memcpy(fn2+i, ".png", 5); 2198 buff = (*readfilecb)(fn2, &len); 2199 M3D_FREE(fn2); 2200 } 2201 if(!buff) { 2202 buff = (*readfilecb)(fn, &len); 2203 if(!buff) return M3D_UNDEF; 2204 } 2205 } 2206 /* add to textures array */ 2207 i = model->numtexture++; 2208 model->texture = (m3dtx_t*)M3D_REALLOC(model->texture, model->numtexture * sizeof(m3dtx_t)); 2209 if(!model->texture) { 2210 if(buff && freecb) (*freecb)(buff); 2211 model->errcode = M3D_ERR_ALLOC; 2212 return M3D_UNDEF; 2213 } 2214 model->texture[i].name = fn; 2215 model->texture[i].w = model->texture[i].h = 0; model->texture[i].d = NULL; 2216 if(buff) { 2217 if(buff[0] == 0x89 && buff[1] == 'P' && buff[2] == 'N' && buff[3] == 'G') { 2218 s.read_from_callbacks = 0; 2219 s.img_buffer = s.img_buffer_original = (unsigned char *) buff; 2220 s.img_buffer_end = s.img_buffer_original_end = (unsigned char *) buff+len; 2221 /* don't use model->texture[i].w directly, it's a uint16_t */ 2222 w = h = len = 0; 2223 ri.bits_per_channel = 8; 2224 model->texture[i].d = (uint8_t*)stbi__png_load(&s, (int*)&w, (int*)&h, (int*)&len, 0, &ri); 2225 model->texture[i].w = w; 2226 model->texture[i].h = h; 2227 model->texture[i].f = (uint8_t)len; 2228 } else { 2229 #ifdef M3D_TX_INTERP 2230 if((model->errcode = M3D_TX_INTERP(fn, buff, len, &model->texture[i])) != M3D_SUCCESS) { 2231 M3D_LOG("Unable to generate texture"); 2232 M3D_LOG(fn); 2233 } 2234 #else 2235 M3D_LOG("Unimplemented interpreter"); 2236 M3D_LOG(fn); 2237 #endif 2238 } 2239 if(freecb) (*freecb)(buff); 2240 } 2241 if(!model->texture[i].d) 2242 model->errcode = M3D_ERR_UNKIMG; 2243 return i; 2244 } 2245 2246 /* helper function to load and generate a procedural surface */ 2247 void _m3d_getpr(m3d_t *model, _unused m3dread_t readfilecb, _unused m3dfree_t freecb, _unused char *fn) 2248 { 2249 #ifdef M3D_PR_INTERP 2250 unsigned int i, len = 0; 2251 unsigned char *buff = readfilecb && fn && *fn ? (*readfilecb)(fn, &len) : NULL; 2252 2253 if(!buff && fn && *fn && model->inlined) { 2254 for(i = 0; i < model->numinlined; i++) 2255 if(!strcmp(fn, model->inlined[i].name)) { 2256 buff = model->inlined[i].data; 2257 len = model->inlined[i].length; 2258 freecb = NULL; 2259 break; 2260 } 2261 } 2262 if(!buff || !len || (model->errcode = M3D_PR_INTERP(fn, buff, len, model)) != M3D_SUCCESS) { 2263 M3D_LOG("Unable to generate procedural surface"); 2264 M3D_LOG(fn); 2265 model->errcode = M3D_ERR_UNKIMG; 2266 } 2267 if(freecb && buff) (*freecb)(buff); 2268 #else 2269 (void)readfilecb; 2270 (void)freecb; 2271 (void)fn; 2272 M3D_LOG("Unimplemented interpreter"); 2273 M3D_LOG(fn); 2274 model->errcode = M3D_ERR_UNIMPL; 2275 #endif 2276 } 2277 /* helpers to read indices from data stream */ 2278 #define M3D_GETSTR(x) do{offs=0;data=_m3d_getidx(data,model->si_s,&offs);x=offs?((char*)model->raw+16+offs):NULL;}while(0) 2279 _inline static unsigned char *_m3d_getidx(unsigned char *data, char type, M3D_INDEX *idx) 2280 { 2281 switch(type) { 2282 case 1: *idx = data[0] > 253 ? (int8_t)data[0] : data[0]; data++; break; 2283 case 2: *idx = *((uint16_t*)data) > 65533 ? *((int16_t*)data) : *((uint16_t*)data); data += 2; break; 2284 case 4: *idx = *((int32_t*)data); data += 4; break; 2285 } 2286 return data; 2287 } 2288 2289 #ifndef M3D_NOANIMATION 2290 /* multiply 4 x 4 matrices. Do not use float *r[16] as argument, because some compilers misinterpret that as 2291 * 16 pointers each pointing to a float, but we need a single pointer to 16 floats. */ 2292 void _m3d_mul(M3D_FLOAT *r, M3D_FLOAT *a, M3D_FLOAT *b) 2293 { 2294 r[ 0] = b[ 0] * a[ 0] + b[ 4] * a[ 1] + b[ 8] * a[ 2] + b[12] * a[ 3]; 2295 r[ 1] = b[ 1] * a[ 0] + b[ 5] * a[ 1] + b[ 9] * a[ 2] + b[13] * a[ 3]; 2296 r[ 2] = b[ 2] * a[ 0] + b[ 6] * a[ 1] + b[10] * a[ 2] + b[14] * a[ 3]; 2297 r[ 3] = b[ 3] * a[ 0] + b[ 7] * a[ 1] + b[11] * a[ 2] + b[15] * a[ 3]; 2298 r[ 4] = b[ 0] * a[ 4] + b[ 4] * a[ 5] + b[ 8] * a[ 6] + b[12] * a[ 7]; 2299 r[ 5] = b[ 1] * a[ 4] + b[ 5] * a[ 5] + b[ 9] * a[ 6] + b[13] * a[ 7]; 2300 r[ 6] = b[ 2] * a[ 4] + b[ 6] * a[ 5] + b[10] * a[ 6] + b[14] * a[ 7]; 2301 r[ 7] = b[ 3] * a[ 4] + b[ 7] * a[ 5] + b[11] * a[ 6] + b[15] * a[ 7]; 2302 r[ 8] = b[ 0] * a[ 8] + b[ 4] * a[ 9] + b[ 8] * a[10] + b[12] * a[11]; 2303 r[ 9] = b[ 1] * a[ 8] + b[ 5] * a[ 9] + b[ 9] * a[10] + b[13] * a[11]; 2304 r[10] = b[ 2] * a[ 8] + b[ 6] * a[ 9] + b[10] * a[10] + b[14] * a[11]; 2305 r[11] = b[ 3] * a[ 8] + b[ 7] * a[ 9] + b[11] * a[10] + b[15] * a[11]; 2306 r[12] = b[ 0] * a[12] + b[ 4] * a[13] + b[ 8] * a[14] + b[12] * a[15]; 2307 r[13] = b[ 1] * a[12] + b[ 5] * a[13] + b[ 9] * a[14] + b[13] * a[15]; 2308 r[14] = b[ 2] * a[12] + b[ 6] * a[13] + b[10] * a[14] + b[14] * a[15]; 2309 r[15] = b[ 3] * a[12] + b[ 7] * a[13] + b[11] * a[14] + b[15] * a[15]; 2310 } 2311 /* calculate 4 x 4 matrix inverse */ 2312 void _m3d_inv(M3D_FLOAT *m) 2313 { 2314 M3D_FLOAT r[16]; 2315 M3D_FLOAT det = 2316 m[ 0]*m[ 5]*m[10]*m[15] - m[ 0]*m[ 5]*m[11]*m[14] + m[ 0]*m[ 6]*m[11]*m[13] - m[ 0]*m[ 6]*m[ 9]*m[15] 2317 + m[ 0]*m[ 7]*m[ 9]*m[14] - m[ 0]*m[ 7]*m[10]*m[13] - m[ 1]*m[ 6]*m[11]*m[12] + m[ 1]*m[ 6]*m[ 8]*m[15] 2318 - m[ 1]*m[ 7]*m[ 8]*m[14] + m[ 1]*m[ 7]*m[10]*m[12] - m[ 1]*m[ 4]*m[10]*m[15] + m[ 1]*m[ 4]*m[11]*m[14] 2319 + m[ 2]*m[ 7]*m[ 8]*m[13] - m[ 2]*m[ 7]*m[ 9]*m[12] + m[ 2]*m[ 4]*m[ 9]*m[15] - m[ 2]*m[ 4]*m[11]*m[13] 2320 + m[ 2]*m[ 5]*m[11]*m[12] - m[ 2]*m[ 5]*m[ 8]*m[15] - m[ 3]*m[ 4]*m[ 9]*m[14] + m[ 3]*m[ 4]*m[10]*m[13] 2321 - m[ 3]*m[ 5]*m[10]*m[12] + m[ 3]*m[ 5]*m[ 8]*m[14] - m[ 3]*m[ 6]*m[ 8]*m[13] + m[ 3]*m[ 6]*m[ 9]*m[12]; 2322 if(det == (M3D_FLOAT)0.0 || det == (M3D_FLOAT)-0.0) det = (M3D_FLOAT)1.0; else det = (M3D_FLOAT)1.0 / det; 2323 r[ 0] = det *(m[ 5]*(m[10]*m[15] - m[11]*m[14]) + m[ 6]*(m[11]*m[13] - m[ 9]*m[15]) + m[ 7]*(m[ 9]*m[14] - m[10]*m[13])); 2324 r[ 1] = -det*(m[ 1]*(m[10]*m[15] - m[11]*m[14]) + m[ 2]*(m[11]*m[13] - m[ 9]*m[15]) + m[ 3]*(m[ 9]*m[14] - m[10]*m[13])); 2325 r[ 2] = det *(m[ 1]*(m[ 6]*m[15] - m[ 7]*m[14]) + m[ 2]*(m[ 7]*m[13] - m[ 5]*m[15]) + m[ 3]*(m[ 5]*m[14] - m[ 6]*m[13])); 2326 r[ 3] = -det*(m[ 1]*(m[ 6]*m[11] - m[ 7]*m[10]) + m[ 2]*(m[ 7]*m[ 9] - m[ 5]*m[11]) + m[ 3]*(m[ 5]*m[10] - m[ 6]*m[ 9])); 2327 r[ 4] = -det*(m[ 4]*(m[10]*m[15] - m[11]*m[14]) + m[ 6]*(m[11]*m[12] - m[ 8]*m[15]) + m[ 7]*(m[ 8]*m[14] - m[10]*m[12])); 2328 r[ 5] = det *(m[ 0]*(m[10]*m[15] - m[11]*m[14]) + m[ 2]*(m[11]*m[12] - m[ 8]*m[15]) + m[ 3]*(m[ 8]*m[14] - m[10]*m[12])); 2329 r[ 6] = -det*(m[ 0]*(m[ 6]*m[15] - m[ 7]*m[14]) + m[ 2]*(m[ 7]*m[12] - m[ 4]*m[15]) + m[ 3]*(m[ 4]*m[14] - m[ 6]*m[12])); 2330 r[ 7] = det *(m[ 0]*(m[ 6]*m[11] - m[ 7]*m[10]) + m[ 2]*(m[ 7]*m[ 8] - m[ 4]*m[11]) + m[ 3]*(m[ 4]*m[10] - m[ 6]*m[ 8])); 2331 r[ 8] = det *(m[ 4]*(m[ 9]*m[15] - m[11]*m[13]) + m[ 5]*(m[11]*m[12] - m[ 8]*m[15]) + m[ 7]*(m[ 8]*m[13] - m[ 9]*m[12])); 2332 r[ 9] = -det*(m[ 0]*(m[ 9]*m[15] - m[11]*m[13]) + m[ 1]*(m[11]*m[12] - m[ 8]*m[15]) + m[ 3]*(m[ 8]*m[13] - m[ 9]*m[12])); 2333 r[10] = det *(m[ 0]*(m[ 5]*m[15] - m[ 7]*m[13]) + m[ 1]*(m[ 7]*m[12] - m[ 4]*m[15]) + m[ 3]*(m[ 4]*m[13] - m[ 5]*m[12])); 2334 r[11] = -det*(m[ 0]*(m[ 5]*m[11] - m[ 7]*m[ 9]) + m[ 1]*(m[ 7]*m[ 8] - m[ 4]*m[11]) + m[ 3]*(m[ 4]*m[ 9] - m[ 5]*m[ 8])); 2335 r[12] = -det*(m[ 4]*(m[ 9]*m[14] - m[10]*m[13]) + m[ 5]*(m[10]*m[12] - m[ 8]*m[14]) + m[ 6]*(m[ 8]*m[13] - m[ 9]*m[12])); 2336 r[13] = det *(m[ 0]*(m[ 9]*m[14] - m[10]*m[13]) + m[ 1]*(m[10]*m[12] - m[ 8]*m[14]) + m[ 2]*(m[ 8]*m[13] - m[ 9]*m[12])); 2337 r[14] = -det*(m[ 0]*(m[ 5]*m[14] - m[ 6]*m[13]) + m[ 1]*(m[ 6]*m[12] - m[ 4]*m[14]) + m[ 2]*(m[ 4]*m[13] - m[ 5]*m[12])); 2338 r[15] = det *(m[ 0]*(m[ 5]*m[10] - m[ 6]*m[ 9]) + m[ 1]*(m[ 6]*m[ 8] - m[ 4]*m[10]) + m[ 2]*(m[ 4]*m[ 9] - m[ 5]*m[ 8])); 2339 memcpy(m, &r, sizeof(r)); 2340 } 2341 /* compose a coloumn major 4 x 4 matrix from vec3 position and vec4 orientation/rotation quaternion */ 2342 void _m3d_mat(M3D_FLOAT *r, m3dv_t *p, m3dv_t *q) 2343 { 2344 if(q->x == (M3D_FLOAT)0.0 && q->y == (M3D_FLOAT)0.0 && q->z >=(M3D_FLOAT) 0.7071065 && q->z <= (M3D_FLOAT)0.7071075 && 2345 q->w == (M3D_FLOAT)0.0) { 2346 r[ 1] = r[ 2] = r[ 4] = r[ 6] = r[ 8] = r[ 9] = (M3D_FLOAT)0.0; 2347 r[ 0] = r[ 5] = r[10] = (M3D_FLOAT)-1.0; 2348 } else { 2349 r[ 0] = 1 - 2 * (q->y * q->y + q->z * q->z); if(r[ 0]>-M3D_EPSILON && r[ 0]<M3D_EPSILON) r[ 0]=(M3D_FLOAT)0.0; 2350 r[ 1] = 2 * (q->x * q->y - q->z * q->w); if(r[ 1]>-M3D_EPSILON && r[ 1]<M3D_EPSILON) r[ 1]=(M3D_FLOAT)0.0; 2351 r[ 2] = 2 * (q->x * q->z + q->y * q->w); if(r[ 2]>-M3D_EPSILON && r[ 2]<M3D_EPSILON) r[ 2]=(M3D_FLOAT)0.0; 2352 r[ 4] = 2 * (q->x * q->y + q->z * q->w); if(r[ 4]>-M3D_EPSILON && r[ 4]<M3D_EPSILON) r[ 4]=(M3D_FLOAT)0.0; 2353 r[ 5] = 1 - 2 * (q->x * q->x + q->z * q->z); if(r[ 5]>-M3D_EPSILON && r[ 5]<M3D_EPSILON) r[ 5]=(M3D_FLOAT)0.0; 2354 r[ 6] = 2 * (q->y * q->z - q->x * q->w); if(r[ 6]>-M3D_EPSILON && r[ 6]<M3D_EPSILON) r[ 6]=(M3D_FLOAT)0.0; 2355 r[ 8] = 2 * (q->x * q->z - q->y * q->w); if(r[ 8]>-M3D_EPSILON && r[ 8]<M3D_EPSILON) r[ 8]=(M3D_FLOAT)0.0; 2356 r[ 9] = 2 * (q->y * q->z + q->x * q->w); if(r[ 9]>-M3D_EPSILON && r[ 9]<M3D_EPSILON) r[ 9]=(M3D_FLOAT)0.0; 2357 r[10] = 1 - 2 * (q->x * q->x + q->y * q->y); if(r[10]>-M3D_EPSILON && r[10]<M3D_EPSILON) r[10]=(M3D_FLOAT)0.0; 2358 } 2359 r[ 3] = p->x; r[ 7] = p->y; r[11] = p->z; 2360 r[12] = 0; r[13] = 0; r[14] = 0; r[15] = 1; 2361 } 2362 #endif 2363 #if !defined(M3D_NOANIMATION) || !defined(M3D_NONORMALS) 2364 /* portable fast inverse square root calculation. returns 1/sqrt(x) */ 2365 static M3D_FLOAT _m3d_rsq(M3D_FLOAT x) 2366 { 2367 #ifdef M3D_DOUBLE 2368 return ((M3D_FLOAT)15.0/(M3D_FLOAT)8.0) + ((M3D_FLOAT)-5.0/(M3D_FLOAT)4.0)*x + ((M3D_FLOAT)3.0/(M3D_FLOAT)8.0)*x*x; 2369 #else 2370 /* John Carmack's */ 2371 float x2 = x * 0.5f; 2372 uint32_t *i = (uint32_t*)&x; 2373 *i = (0x5f3759df - (*i >> 1)); 2374 return x * (1.5f - (x2 * x * x)); 2375 #endif 2376 } 2377 #endif 2378 2379 /** 2380 * Function to decode a Model 3D into in-memory format 2381 */ 2382 m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d_t *mtllib) 2383 { 2384 unsigned char *end, *chunk, *buff, weights[8]; 2385 unsigned int i, j, k, l, n, am, len = 0, reclen, offs; 2386 #ifndef M3D_NOVOXELS 2387 int32_t min_x, min_y, min_z, max_x, max_y, max_z, sx, sy, sz, x, y, z; 2388 M3D_INDEX edge[8], enorm; 2389 #endif 2390 char *name, *lang; 2391 float f; 2392 m3d_t *model; 2393 M3D_INDEX mi; 2394 #ifdef M3D_VERTEXMAX 2395 M3D_INDEX pi; 2396 #endif 2397 M3D_FLOAT w; 2398 m3dcd_t *cd; 2399 m3dtx_t *tx; 2400 m3dh_t *h; 2401 m3dm_t *m; 2402 m3da_t *a; 2403 m3di_t *t; 2404 #ifndef M3D_NONORMALS 2405 char neednorm = 0; 2406 m3dv_t *norm = NULL, *v0, *v1, *v2, va, vb; 2407 #endif 2408 #ifndef M3D_NOANIMATION 2409 M3D_FLOAT r[16]; 2410 #endif 2411 #if !defined(M3D_NOWEIGHTS) || !defined(M3D_NOANIMATION) 2412 m3db_t *b; 2413 #endif 2414 #ifndef M3D_NOWEIGHTS 2415 m3ds_t *sk; 2416 #endif 2417 #ifdef M3D_ASCII 2418 m3ds_t s; 2419 M3D_INDEX bi[M3D_BONEMAXLEVEL+1], level; 2420 const char *ol; 2421 char *ptr, *pe, *fn; 2422 #endif 2423 #ifdef M3D_PROFILING 2424 struct timeval tv0, tv1, tvd; 2425 gettimeofday(&tv0, NULL); 2426 #endif 2427 2428 if(!data || (!M3D_CHUNKMAGIC(data, '3','D','M','O') 2429 #ifdef M3D_ASCII 2430 && !M3D_CHUNKMAGIC(data, '3','d','m','o') 2431 #endif 2432 )) return NULL; 2433 model = (m3d_t*)M3D_MALLOC(sizeof(m3d_t)); 2434 if(!model) { 2435 M3D_LOG("Out of memory"); 2436 return NULL; 2437 } 2438 memset(model, 0, sizeof(m3d_t)); 2439 2440 if(mtllib) { 2441 model->nummaterial = mtllib->nummaterial; 2442 model->material = mtllib->material; 2443 model->numtexture = mtllib->numtexture; 2444 model->texture = mtllib->texture; 2445 model->flags |= M3D_FLG_MTLLIB; 2446 } 2447 #ifdef M3D_ASCII 2448 /* ASCII variant? */ 2449 if(M3D_CHUNKMAGIC(data, '3','d','m','o')) { 2450 model->errcode = M3D_ERR_BADFILE; 2451 model->flags |= M3D_FLG_FREESTR; 2452 model->raw = (m3dhdr_t*)data; 2453 ptr = (char*)data; 2454 ol = setlocale(LC_NUMERIC, NULL); 2455 setlocale(LC_NUMERIC, "C"); 2456 /* parse header. Don't use sscanf, that's incredibly slow */ 2457 ptr = _m3d_findarg(ptr); 2458 if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; 2459 pe = _m3d_findnl(ptr); 2460 model->scale = (float)strtod(ptr, NULL); ptr = pe; 2461 if(model->scale <= (M3D_FLOAT)0.0) model->scale = (M3D_FLOAT)1.0; 2462 model->name = _m3d_safestr(ptr, 2); ptr = _m3d_findnl(ptr); 2463 if(!*ptr) goto asciiend; 2464 model->license = _m3d_safestr(ptr, 2); ptr = _m3d_findnl(ptr); 2465 if(!*ptr) goto asciiend; 2466 model->author = _m3d_safestr(ptr, 2); ptr = _m3d_findnl(ptr); 2467 if(!*ptr) goto asciiend; 2468 if(*ptr != '\r' && *ptr != '\n') 2469 model->desc = _m3d_safestr(ptr, 3); 2470 while(*ptr) { 2471 while(*ptr && *ptr!='\n') ptr++; 2472 ptr++; if(*ptr=='\r') ptr++; 2473 if(*ptr == '\n') break; 2474 } 2475 2476 /* the main chunk reader loop */ 2477 while(*ptr) { 2478 while(*ptr && (*ptr == '\r' || *ptr == '\n')) ptr++; 2479 if(!*ptr || (ptr[0]=='E' && ptr[1]=='n' && ptr[2]=='d')) break; 2480 /* make sure there's at least one data row */ 2481 pe = ptr; ptr = _m3d_findnl(ptr); 2482 if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; 2483 /* Preview chunk */ 2484 if(!memcmp(pe, "Preview", 7)) { 2485 if(readfilecb) { 2486 pe = _m3d_safestr(ptr, 0); 2487 if(!pe || !*pe) goto asciiend; 2488 model->preview.data = (*readfilecb)(pe, &model->preview.length); 2489 M3D_FREE(pe); 2490 } 2491 while(*ptr && *ptr != '\r' && *ptr != '\n') 2492 ptr = _m3d_findnl(ptr); 2493 } else 2494 /* texture map chunk */ 2495 if(!memcmp(pe, "Textmap", 7)) { 2496 if(model->tmap) { M3D_LOG("More texture map chunks, should be unique"); goto asciiend; } 2497 while(*ptr && *ptr != '\r' && *ptr != '\n') { 2498 i = model->numtmap++; 2499 model->tmap = (m3dti_t*)M3D_REALLOC(model->tmap, model->numtmap * sizeof(m3dti_t)); 2500 if(!model->tmap) goto memerr; 2501 ptr = _m3d_getfloat(ptr, &model->tmap[i].u); 2502 if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; 2503 _m3d_getfloat(ptr, &model->tmap[i].v); 2504 ptr = _m3d_findnl(ptr); 2505 } 2506 } else 2507 /* vertex chunk */ 2508 if(!memcmp(pe, "Vertex", 6)) { 2509 if(model->vertex) { M3D_LOG("More vertex chunks, should be unique"); goto asciiend; } 2510 while(*ptr && *ptr != '\r' && *ptr != '\n') { 2511 i = model->numvertex++; 2512 model->vertex = (m3dv_t*)M3D_REALLOC(model->vertex, model->numvertex * sizeof(m3dv_t)); 2513 if(!model->vertex) goto memerr; 2514 memset(&model->vertex[i], 0, sizeof(m3dv_t)); 2515 model->vertex[i].skinid = M3D_UNDEF; 2516 model->vertex[i].color = 0; 2517 model->vertex[i].w = (M3D_FLOAT)1.0; 2518 ptr = _m3d_getfloat(ptr, &model->vertex[i].x); 2519 if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; 2520 ptr = _m3d_getfloat(ptr, &model->vertex[i].y); 2521 if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; 2522 ptr = _m3d_getfloat(ptr, &model->vertex[i].z); 2523 if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; 2524 ptr = _m3d_getfloat(ptr, &model->vertex[i].w); 2525 if(!*ptr) goto asciiend; 2526 if(*ptr == '#') { 2527 ptr = _m3d_gethex(ptr, &model->vertex[i].color); 2528 if(!*ptr) goto asciiend; 2529 } 2530 /* parse skin */ 2531 memset(&s, 0, sizeof(m3ds_t)); 2532 for(j = 0, w = (M3D_FLOAT)0.0; j < M3D_NUMBONE && *ptr && *ptr != '\r' && *ptr != '\n'; j++) { 2533 ptr = _m3d_findarg(ptr); 2534 if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; 2535 ptr = _m3d_getint(ptr, &k); 2536 s.boneid[j] = (M3D_INDEX)k; 2537 if(*ptr == ':') { 2538 ptr++; 2539 ptr = _m3d_getfloat(ptr, &s.weight[j]); 2540 w += s.weight[j]; 2541 } else if(!j) 2542 s.weight[j] = (M3D_FLOAT)1.0; 2543 if(!*ptr) goto asciiend; 2544 } 2545 if(s.boneid[0] != M3D_UNDEF && s.weight[0] > (M3D_FLOAT)0.0) { 2546 if(w != (M3D_FLOAT)1.0 && w != (M3D_FLOAT)0.0) 2547 for(j = 0; j < M3D_NUMBONE && s.weight[j] > (M3D_FLOAT)0.0; j++) 2548 s.weight[j] /= w; 2549 k = M3D_NOTDEFINED; 2550 if(model->skin) { 2551 for(j = 0; j < model->numskin; j++) 2552 if(!memcmp(&model->skin[j], &s, sizeof(m3ds_t))) { k = j; break; } 2553 } 2554 if(k == M3D_NOTDEFINED) { 2555 k = model->numskin++; 2556 model->skin = (m3ds_t*)M3D_REALLOC(model->skin, model->numskin * sizeof(m3ds_t)); 2557 if(!model->skin) goto memerr; 2558 memcpy(&model->skin[k], &s, sizeof(m3ds_t)); 2559 } 2560 model->vertex[i].skinid = (M3D_INDEX)k; 2561 } 2562 ptr = _m3d_findnl(ptr); 2563 } 2564 } else 2565 /* Skeleton, bone hierarchy */ 2566 if(!memcmp(pe, "Bones", 5)) { 2567 if(model->bone) { M3D_LOG("More bones chunks, should be unique"); goto asciiend; } 2568 bi[0] = M3D_UNDEF; 2569 while(*ptr && *ptr != '\r' && *ptr != '\n') { 2570 i = model->numbone++; 2571 model->bone = (m3db_t*)M3D_REALLOC(model->bone, model->numbone * sizeof(m3db_t)); 2572 if(!model->bone) goto memerr; 2573 for(level = 0; *ptr == '/'; ptr++, level++); 2574 if(level > M3D_BONEMAXLEVEL || !*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; 2575 bi[level+1] = i; 2576 model->bone[i].numweight = 0; 2577 model->bone[i].weight = NULL; 2578 model->bone[i].parent = bi[level]; 2579 ptr = _m3d_getint(ptr, &k); 2580 ptr = _m3d_findarg(ptr); 2581 if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; 2582 model->bone[i].pos = (M3D_INDEX)k; 2583 ptr = _m3d_getint(ptr, &k); 2584 ptr = _m3d_findarg(ptr); 2585 if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; 2586 model->bone[i].ori = (M3D_INDEX)k; 2587 model->vertex[k].skinid = M3D_INDEXMAX; 2588 pe = _m3d_safestr(ptr, 0); 2589 if(!pe || !*pe) goto asciiend; 2590 model->bone[i].name = pe; 2591 ptr = _m3d_findnl(ptr); 2592 } 2593 } else 2594 /* material chunk */ 2595 if(!memcmp(pe, "Material", 8)) { 2596 pe = _m3d_findarg(pe); 2597 if(!*pe || *pe == '\r' || *pe == '\n') goto asciiend; 2598 pe = _m3d_safestr(pe, 0); 2599 if(!pe || !*pe) goto asciiend; 2600 for(i = 0; i < model->nummaterial; i++) 2601 if(!strcmp(pe, model->material[i].name)) { 2602 M3D_LOG("Multiple definitions for material"); 2603 M3D_LOG(pe); 2604 M3D_FREE(pe); 2605 pe = NULL; 2606 while(*ptr && *ptr != '\r' && *ptr != '\n') ptr = _m3d_findnl(ptr); 2607 break; 2608 } 2609 if(!pe) continue; 2610 i = model->nummaterial++; 2611 if(model->flags & M3D_FLG_MTLLIB) { 2612 m = model->material; 2613 model->material = (m3dm_t*)M3D_MALLOC(model->nummaterial * sizeof(m3dm_t)); 2614 if(!model->material) goto memerr; 2615 memcpy(model->material, m, (model->nummaterial - 1) * sizeof(m3dm_t)); 2616 if(model->texture) { 2617 tx = model->texture; 2618 model->texture = (m3dtx_t*)M3D_MALLOC(model->numtexture * sizeof(m3dtx_t)); 2619 if(!model->texture) goto memerr; 2620 memcpy(model->texture, tx, model->numtexture * sizeof(m3dm_t)); 2621 } 2622 model->flags &= ~M3D_FLG_MTLLIB; 2623 } else { 2624 model->material = (m3dm_t*)M3D_REALLOC(model->material, model->nummaterial * sizeof(m3dm_t)); 2625 if(!model->material) goto memerr; 2626 } 2627 m = &model->material[i]; 2628 m->name = pe; 2629 m->numprop = 0; 2630 m->prop = NULL; 2631 while(*ptr && *ptr != '\r' && *ptr != '\n') { 2632 k = n = 256; 2633 if(*ptr == 'm' && *(ptr+1) == 'a' && *(ptr+2) == 'p' && *(ptr+3) == '_') { 2634 k = m3dpf_map; 2635 ptr += 4; 2636 } 2637 for(j = 0; j < sizeof(m3d_propertytypes)/sizeof(m3d_propertytypes[0]); j++) 2638 if(!memcmp(ptr, m3d_propertytypes[j].key, strlen(m3d_propertytypes[j].key))) { 2639 n = m3d_propertytypes[j].id; 2640 if(k != m3dpf_map) k = m3d_propertytypes[j].format; 2641 break; 2642 } 2643 if(n != 256 && k != 256) { 2644 ptr = _m3d_findarg(ptr); 2645 if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; 2646 j = m->numprop++; 2647 m->prop = (m3dp_t*)M3D_REALLOC(m->prop, m->numprop * sizeof(m3dp_t)); 2648 if(!m->prop) goto memerr; 2649 m->prop[j].type = n + (k == m3dpf_map && n < 128 ? 128 : 0); 2650 switch(k) { 2651 case m3dpf_color: ptr = _m3d_gethex(ptr, &m->prop[j].value.color); break; 2652 case m3dpf_uint8: 2653 case m3dpf_uint16: 2654 case m3dpf_uint32: ptr = _m3d_getint(ptr, &m->prop[j].value.num); break; 2655 case m3dpf_float: ptr = _m3d_getfloat(ptr, &m->prop[j].value.fnum); break; 2656 case m3dpf_map: 2657 pe = _m3d_safestr(ptr, 0); 2658 if(!pe || !*pe) goto asciiend; 2659 m->prop[j].value.textureid = _m3d_gettx(model, readfilecb, freecb, pe); 2660 if(model->errcode == M3D_ERR_ALLOC) { M3D_FREE(pe); goto memerr; } 2661 /* this error code only returned if readfilecb was specified */ 2662 if(m->prop[j].value.textureid == M3D_UNDEF) { 2663 M3D_LOG("Texture not found"); 2664 M3D_LOG(pe); 2665 m->numprop--; 2666 } 2667 M3D_FREE(pe); 2668 break; 2669 } 2670 } else { 2671 M3D_LOG("Unknown material property in"); 2672 M3D_LOG(m->name); 2673 model->errcode = M3D_ERR_UNKPROP; 2674 } 2675 ptr = _m3d_findnl(ptr); 2676 } 2677 if(!m->numprop) model->nummaterial--; 2678 } else 2679 /* procedural */ 2680 if(!memcmp(pe, "Procedural", 10)) { 2681 pe = _m3d_safestr(ptr, 0); 2682 _m3d_getpr(model, readfilecb, freecb, pe); 2683 M3D_FREE(pe); 2684 while(*ptr && *ptr != '\r' && *ptr != '\n') ptr = _m3d_findnl(ptr); 2685 } else 2686 /* mesh */ 2687 if(!memcmp(pe, "Mesh", 4)) { 2688 mi = M3D_UNDEF; 2689 #ifdef M3D_VERTEXMAX 2690 pi = M3D_UNDEF; 2691 #endif 2692 while(*ptr && *ptr != '\r' && *ptr != '\n') { 2693 if(*ptr == 'u') { 2694 ptr = _m3d_findarg(ptr); 2695 if(!*ptr) goto asciiend; 2696 mi = M3D_UNDEF; 2697 if(*ptr != '\r' && *ptr != '\n') { 2698 pe = _m3d_safestr(ptr, 0); 2699 if(!pe || !*pe) goto asciiend; 2700 for(j = 0; j < model->nummaterial; j++) 2701 if(!strcmp(pe, model->material[j].name)) { mi = (M3D_INDEX)j; break; } 2702 if(mi == M3D_UNDEF && !(model->flags & M3D_FLG_MTLLIB)) { 2703 mi = model->nummaterial++; 2704 model->material = (m3dm_t*)M3D_REALLOC(model->material, model->nummaterial * sizeof(m3dm_t)); 2705 if(!model->material) goto memerr; 2706 model->material[mi].name = pe; 2707 model->material[mi].numprop = 1; 2708 model->material[mi].prop = NULL; 2709 } else 2710 M3D_FREE(pe); 2711 } 2712 } else 2713 if(*ptr == 'p') { 2714 ptr = _m3d_findarg(ptr); 2715 if(!*ptr) goto asciiend; 2716 #ifdef M3D_VERTEXMAX 2717 pi = M3D_UNDEF; 2718 if(*ptr != '\r' && *ptr != '\n') { 2719 pe = _m3d_safestr(ptr, 0); 2720 if(!pe || !*pe) goto asciiend; 2721 for(j = 0; j < model->numparam; j++) 2722 if(!strcmp(pe, model->param[j].name)) { pi = (M3D_INDEX)j; break; } 2723 if(pi == M3D_UNDEF) { 2724 pi = model->numparam++; 2725 model->param = (m3dvi_t*)M3D_REALLOC(model->param, model->numparam * sizeof(m3dvi_t)); 2726 if(!model->param) goto memerr; 2727 model->param[pi].name = pe; 2728 model->param[pi].count = 0; 2729 } else 2730 M3D_FREE(pe); 2731 } 2732 #endif 2733 } else { 2734 i = model->numface++; 2735 model->face = (m3df_t*)M3D_REALLOC(model->face, model->numface * sizeof(m3df_t)); 2736 if(!model->face) goto memerr; 2737 memset(&model->face[i], 255, sizeof(m3df_t)); /* set all index to -1 by default */ 2738 model->face[i].materialid = mi; 2739 #ifdef M3D_VERTEXMAX 2740 model->face[i].paramid = pi; 2741 #endif 2742 /* hardcoded triangles. */ 2743 for(j = 0; j < 3; j++) { 2744 /* vertex */ 2745 ptr = _m3d_getint(ptr, &k); 2746 model->face[i].vertex[j] = (M3D_INDEX)k; 2747 if(!*ptr) goto asciiend; 2748 if(*ptr == '/') { 2749 ptr++; 2750 if(*ptr != '/') { 2751 /* texcoord */ 2752 ptr = _m3d_getint(ptr, &k); 2753 model->face[i].texcoord[j] = (M3D_INDEX)k; 2754 if(!*ptr) goto asciiend; 2755 } 2756 if(*ptr == '/') { 2757 ptr++; 2758 /* normal */ 2759 ptr = _m3d_getint(ptr, &k); 2760 model->face[i].normal[j] = (M3D_INDEX)k; 2761 if(!*ptr) goto asciiend; 2762 } 2763 if(*ptr == '/') { 2764 ptr++; 2765 /* maximum */ 2766 ptr = _m3d_getint(ptr, &k); 2767 #ifdef M3D_VERTEXMAX 2768 model->face[i].vertmax[j] = (M3D_INDEX)k; 2769 #endif 2770 if(!*ptr) goto asciiend; 2771 } 2772 } 2773 #ifndef M3D_NONORMALS 2774 if(model->face[i].normal[j] == M3D_UNDEF) neednorm = 1; 2775 #endif 2776 ptr = _m3d_findarg(ptr); 2777 } 2778 } 2779 ptr = _m3d_findnl(ptr); 2780 } 2781 } else 2782 /* voxel types chunk */ 2783 if(!memcmp(pe, "VoxTypes", 8) || !memcmp(pe, "Voxtypes", 8)) { 2784 if(model->voxtype) { M3D_LOG("More voxel types chunks, should be unique"); goto asciiend; } 2785 while(*ptr && *ptr != '\r' && *ptr != '\n') { 2786 i = model->numvoxtype++; 2787 model->voxtype = (m3dvt_t*)M3D_REALLOC(model->voxtype, model->numvoxtype * sizeof(m3dvt_t)); 2788 if(!model->voxtype) goto memerr; 2789 memset(&model->voxtype[i], 0, sizeof(m3dvt_t)); 2790 model->voxtype[i].materialid = M3D_UNDEF; 2791 model->voxtype[i].skinid = M3D_UNDEF; 2792 ptr = _m3d_gethex(ptr, &model->voxtype[i].color); 2793 if(!*ptr) goto asciiend; 2794 if(*ptr == '/') { 2795 ptr = _m3d_gethex(ptr, &k); 2796 model->voxtype[i].rotation = k; 2797 if(!*ptr) goto asciiend; 2798 if(*ptr == '/') { 2799 ptr = _m3d_gethex(ptr, &k); 2800 model->voxtype[i].voxshape = k; 2801 if(!*ptr) goto asciiend; 2802 } 2803 } 2804 while(*ptr == ' ' || *ptr == '\t') ptr++; 2805 if(*ptr == '\r' || *ptr == '\n') { ptr = _m3d_findnl(ptr); continue; } 2806 /* name */ 2807 if(*ptr != '-') { 2808 pe = _m3d_safestr(ptr, 0); 2809 if(!pe || !*pe) goto asciiend; 2810 model->voxtype[i].name = pe; 2811 for(j = 0; j < model->nummaterial; j++) 2812 if(!strcmp(pe, model->material[j].name)) { model->voxtype[i].materialid = (M3D_INDEX)j; break; } 2813 } 2814 ptr = _m3d_findarg(ptr); 2815 /* parse skin */ 2816 memset(&s, 0, sizeof(m3ds_t)); 2817 for(j = 0, w = (M3D_FLOAT)0.0; j < M3D_NUMBONE && *ptr && *ptr != '{' && *ptr != '\r' && *ptr != '\n'; j++) { 2818 ptr = _m3d_getint(ptr, &k); 2819 s.boneid[j] = (M3D_INDEX)k; 2820 if(*ptr == ':') { 2821 ptr++; 2822 ptr = _m3d_getfloat(ptr, &s.weight[j]); 2823 w += s.weight[j]; 2824 } else if(!j) 2825 s.weight[j] = (M3D_FLOAT)1.0; 2826 if(!*ptr) goto asciiend; 2827 ptr = _m3d_findarg(ptr); 2828 } 2829 if(s.boneid[0] != M3D_UNDEF && s.weight[0] > (M3D_FLOAT)0.0) { 2830 if(w != (M3D_FLOAT)1.0 && w != (M3D_FLOAT)0.0) 2831 for(j = 0; j < M3D_NUMBONE && s.weight[j] > (M3D_FLOAT)0.0; j++) 2832 s.weight[j] /= w; 2833 k = M3D_NOTDEFINED; 2834 if(model->skin) { 2835 for(j = 0; j < model->numskin; j++) 2836 if(!memcmp(&model->skin[j], &s, sizeof(m3ds_t))) { k = j; break; } 2837 } 2838 if(k == M3D_NOTDEFINED) { 2839 k = model->numskin++; 2840 model->skin = (m3ds_t*)M3D_REALLOC(model->skin, model->numskin * sizeof(m3ds_t)); 2841 if(!model->skin) goto memerr; 2842 memcpy(&model->skin[k], &s, sizeof(m3ds_t)); 2843 } 2844 model->voxtype[i].skinid = (M3D_INDEX)k; 2845 } 2846 /* parse item list */ 2847 if(*ptr == '{') { 2848 while(*ptr == '{' || *ptr == ' ' || *ptr == '\t') ptr++; 2849 while(*ptr && *ptr != '}' && *ptr != '\r' && *ptr != '\n') { 2850 ptr = _m3d_getint(ptr, &k); 2851 ptr = _m3d_findarg(ptr); 2852 if(!*ptr || *ptr == '}' || *ptr == '\r' || *ptr == '\n') goto asciiend; 2853 pe = _m3d_safestr(ptr, 0); 2854 if(!pe || !*pe) goto asciiend; 2855 ptr = _m3d_findarg(ptr); 2856 j = model->voxtype[i].numitem++; 2857 model->voxtype[i].item = (m3dvi_t*)M3D_REALLOC(model->voxtype[i].item, 2858 model->voxtype[i].numitem * sizeof(m3dvi_t)); 2859 if(!model->voxtype[i].item) goto memerr; 2860 model->voxtype[i].item[j].count = k; 2861 model->voxtype[i].item[j].name = pe; 2862 } 2863 if(*ptr != '}') goto asciiend; 2864 } 2865 ptr = _m3d_findnl(ptr); 2866 } 2867 } else 2868 /* voxel data */ 2869 if(!memcmp(pe, "Voxel", 5)) { 2870 if(!model->voxtype) { M3D_LOG("No voxel type chunk before voxel data"); goto asciiend; } 2871 pe = _m3d_findarg(pe); 2872 if(!*pe) goto asciiend; 2873 if(*pe == '\r' || *pe == '\n') pe = NULL; 2874 else pe = _m3d_safestr(pe, 0); 2875 i = model->numvoxel++; 2876 model->voxel = (m3dvx_t*)M3D_REALLOC(model->voxel, model->numvoxel * sizeof(m3dvx_t)); 2877 if(!model->voxel) goto memerr; 2878 memset(&model->voxel[i], 0, sizeof(m3dvx_t)); 2879 model->voxel[i].name = pe; 2880 k = l = 0; 2881 while(*ptr && *ptr != '\r' && *ptr != '\n') { 2882 switch(*ptr) { 2883 case 'u': 2884 ptr = _m3d_findarg(ptr); 2885 if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; 2886 ptr = _m3d_getint(ptr, &n); 2887 model->voxel[i].uncertain = ((n > 0 && n < 256 ? n : 0) * 255) / 100; 2888 ptr = _m3d_findarg(ptr); 2889 if(*ptr && *ptr != '\r' && *ptr != '\n') { 2890 ptr = _m3d_getint(ptr, &n); 2891 model->voxel[i].groupid = n > 0 && n < 256 ? n : 0; 2892 } 2893 break; 2894 case 'p': 2895 ptr = _m3d_findarg(ptr); 2896 if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; 2897 ptr = _m3d_getint(ptr, &n); 2898 model->voxel[i].x = n; 2899 ptr = _m3d_findarg(ptr); 2900 if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; 2901 ptr = _m3d_getint(ptr, &n); 2902 model->voxel[i].y = n; 2903 ptr = _m3d_findarg(ptr); 2904 if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; 2905 ptr = _m3d_getint(ptr, &n); 2906 model->voxel[i].z = n; 2907 break; 2908 case 'd': 2909 ptr = _m3d_findarg(ptr); 2910 if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; 2911 ptr = _m3d_getint(ptr, &n); 2912 model->voxel[i].w = n; 2913 ptr = _m3d_findarg(ptr); 2914 if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; 2915 ptr = _m3d_getint(ptr, &n); 2916 model->voxel[i].h = n; 2917 ptr = _m3d_findarg(ptr); 2918 if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; 2919 ptr = _m3d_getint(ptr, &n); 2920 model->voxel[i].d = n; 2921 break; 2922 case 'l': 2923 if(model->voxel[i].data) { l++; k = 0; } 2924 else { 2925 if(!model->voxel[i].w || !model->voxel[i].h || !model->voxel[i].d) { 2926 M3D_LOG("No voxel dimension before layer data"); 2927 goto asciiend; 2928 } 2929 model->voxel[i].data = (M3D_VOXEL*)M3D_MALLOC( 2930 model->voxel[i].w * model->voxel[i].h * model->voxel[i].d * sizeof(M3D_VOXEL)); 2931 if(!model->voxel[i].data) goto memerr; 2932 } 2933 break; 2934 default: 2935 if(!model->voxel[i].data || l >= model->voxel[i].h || k >= model->voxel[i].d) { 2936 M3D_LOG("Missing voxel attributes or out of bound data"); 2937 goto asciiend; 2938 } 2939 for(n = l * model->voxel[i].w * model->voxel[i].d + k * model->voxel[i].w; 2940 j < model->voxel[i].w && *ptr && *ptr != '\r' && *ptr != '\n'; j++) { 2941 ptr = _m3d_getint(ptr, &am); 2942 if(am >= model->numvoxtype) goto asciiend; 2943 model->voxel[i].data[n + j] = am; 2944 } 2945 k++; 2946 break; 2947 } 2948 ptr = _m3d_findnl(ptr); 2949 } 2950 } else 2951 /* mathematical shape */ 2952 if(!memcmp(pe, "Shape", 5)) { 2953 pe = _m3d_findarg(pe); 2954 if(!*pe || *pe == '\r' || *pe == '\n') goto asciiend; 2955 pe = _m3d_safestr(pe, 0); 2956 if(!pe || !*pe) goto asciiend; 2957 i = model->numshape++; 2958 model->shape = (m3dh_t*)M3D_REALLOC(model->shape, model->numshape * sizeof(m3ds_t)); 2959 if(!model->shape) goto memerr; 2960 h = &model->shape[i]; 2961 h->name = pe; 2962 h->group = M3D_UNDEF; 2963 h->numcmd = 0; 2964 h->cmd = NULL; 2965 while(*ptr && *ptr != '\r' && *ptr != '\n') { 2966 if(!memcmp(ptr, "group", 5)) { 2967 ptr = _m3d_findarg(ptr); 2968 ptr = _m3d_getint(ptr, &h->group); 2969 ptr = _m3d_findnl(ptr); 2970 if(h->group != M3D_UNDEF && h->group >= model->numbone) { 2971 M3D_LOG("Unknown bone id as shape group in shape"); 2972 M3D_LOG(pe); 2973 h->group = M3D_UNDEF; 2974 model->errcode = M3D_ERR_SHPE; 2975 } 2976 continue; 2977 } 2978 for(cd = NULL, k = 0; k < (unsigned int)(sizeof(m3d_commandtypes)/sizeof(m3d_commandtypes[0])); k++) { 2979 j = (unsigned int)strlen(m3d_commandtypes[k].key); 2980 if(!memcmp(ptr, m3d_commandtypes[k].key, j) && (ptr[j] == ' ' || ptr[j] == '\r' || ptr[j] == '\n')) 2981 { cd = &m3d_commandtypes[k]; break; } 2982 } 2983 if(cd) { 2984 j = h->numcmd++; 2985 h->cmd = (m3dc_t*)M3D_REALLOC(h->cmd, h->numcmd * sizeof(m3dc_t)); 2986 if(!h->cmd) goto memerr; 2987 h->cmd[j].type = k; 2988 h->cmd[j].arg = (uint32_t*)M3D_MALLOC(cd->p * sizeof(uint32_t)); 2989 if(!h->cmd[j].arg) goto memerr; 2990 memset(h->cmd[j].arg, 0, cd->p * sizeof(uint32_t)); 2991 for(k = n = 0, l = cd->p; k < l; k++) { 2992 ptr = _m3d_findarg(ptr); 2993 if(!*ptr) goto asciiend; 2994 if(*ptr == '[') { 2995 ptr = _m3d_findarg(ptr + 1); 2996 if(!*ptr) goto asciiend; 2997 } 2998 if(*ptr == ']' || *ptr == '\r' || *ptr == '\n') break; 2999 switch(cd->a[((k - n) % (cd->p - n)) + n]) { 3000 case m3dcp_mi_t: 3001 mi = M3D_UNDEF; 3002 if(*ptr != '\r' && *ptr != '\n') { 3003 pe = _m3d_safestr(ptr, 0); 3004 if(!pe || !*pe) goto asciiend; 3005 for(n = 0; n < model->nummaterial; n++) 3006 if(!strcmp(pe, model->material[n].name)) { mi = (M3D_INDEX)n; break; } 3007 if(mi == M3D_UNDEF && !(model->flags & M3D_FLG_MTLLIB)) { 3008 mi = model->nummaterial++; 3009 model->material = (m3dm_t*)M3D_REALLOC(model->material, 3010 model->nummaterial * sizeof(m3dm_t)); 3011 if(!model->material) goto memerr; 3012 model->material[mi].name = pe; 3013 model->material[mi].numprop = 1; 3014 model->material[mi].prop = NULL; 3015 } else 3016 M3D_FREE(pe); 3017 } 3018 h->cmd[j].arg[k] = mi; 3019 break; 3020 case m3dcp_vc_t: 3021 #ifdef M3D_DOUBLE 3022 _m3d_getfloat(ptr, &w); f = w; 3023 memcpy(&h->cmd[j].arg[k], &f, 4); 3024 #else 3025 _m3d_getfloat(ptr, (float*)&h->cmd[j].arg[k]); 3026 #endif 3027 break; 3028 case m3dcp_va_t: 3029 ptr = _m3d_getint(ptr, &h->cmd[j].arg[k]); 3030 n = k + 1; l += (h->cmd[j].arg[k] - 1) * (cd->p - k - 1); 3031 h->cmd[j].arg = (uint32_t*)M3D_REALLOC(h->cmd[j].arg, l * sizeof(uint32_t)); 3032 if(!h->cmd[j].arg) goto memerr; 3033 memset(&h->cmd[j].arg[k + 1], 0, (l - k - 1) * sizeof(uint32_t)); 3034 break; 3035 case m3dcp_qi_t: 3036 ptr = _m3d_getint(ptr, &h->cmd[j].arg[k]); 3037 model->vertex[h->cmd[i].arg[k]].skinid = M3D_INDEXMAX; 3038 break; 3039 default: 3040 ptr = _m3d_getint(ptr, &h->cmd[j].arg[k]); 3041 break; 3042 } 3043 } 3044 } else { 3045 M3D_LOG("Unknown shape command in"); 3046 M3D_LOG(h->name); 3047 model->errcode = M3D_ERR_UNKCMD; 3048 } 3049 ptr = _m3d_findnl(ptr); 3050 } 3051 if(!h->numcmd) model->numshape--; 3052 } else 3053 /* annotation labels */ 3054 if(!memcmp(pe, "Labels", 6)) { 3055 pe = _m3d_findarg(pe); 3056 if(!*pe) goto asciiend; 3057 if(*pe == '\r' || *pe == '\n') pe = NULL; 3058 else pe = _m3d_safestr(pe, 0); 3059 k = 0; fn = NULL; 3060 while(*ptr && *ptr != '\r' && *ptr != '\n') { 3061 if(*ptr == 'c') { 3062 ptr = _m3d_findarg(ptr); 3063 if(!*pe || *pe == '\r' || *pe == '\n') goto asciiend; 3064 ptr = _m3d_gethex(ptr, &k); 3065 } else 3066 if(*ptr == 'l') { 3067 ptr = _m3d_findarg(ptr); 3068 if(!*pe || *pe == '\r' || *pe == '\n') goto asciiend; 3069 fn = _m3d_safestr(ptr, 2); 3070 } else { 3071 i = model->numlabel++; 3072 model->label = (m3dl_t*)M3D_REALLOC(model->label, model->numlabel * sizeof(m3dl_t)); 3073 if(!model->label) goto memerr; 3074 model->label[i].name = pe; 3075 model->label[i].lang = fn; 3076 model->label[i].color = k; 3077 ptr = _m3d_getint(ptr, &j); 3078 model->label[i].vertexid = (M3D_INDEX)j; 3079 ptr = _m3d_findarg(ptr); 3080 if(!*pe || *pe == '\r' || *pe == '\n') goto asciiend; 3081 model->label[i].text = _m3d_safestr(ptr, 2); 3082 } 3083 ptr = _m3d_findnl(ptr); 3084 } 3085 } else 3086 /* action */ 3087 if(!memcmp(pe, "Action", 6)) { 3088 pe = _m3d_findarg(pe); 3089 if(!*pe || *pe == '\r' || *pe == '\n') goto asciiend; 3090 pe = _m3d_getint(pe, &k); 3091 pe = _m3d_findarg(pe); 3092 if(!*pe || *pe == '\r' || *pe == '\n') goto asciiend; 3093 pe = _m3d_safestr(pe, 0); 3094 if(!pe || !*pe) goto asciiend; 3095 i = model->numaction++; 3096 model->action = (m3da_t*)M3D_REALLOC(model->action, model->numaction * sizeof(m3da_t)); 3097 if(!model->action) goto memerr; 3098 a = &model->action[i]; 3099 a->name = pe; 3100 a->durationmsec = k; 3101 /* skip the first frame marker as there's always at least one frame */ 3102 a->numframe = 1; 3103 a->frame = (m3dfr_t*)M3D_MALLOC(sizeof(m3dfr_t)); 3104 if(!a->frame) goto memerr; 3105 a->frame[0].msec = 0; 3106 a->frame[0].numtransform = 0; 3107 a->frame[0].transform = NULL; 3108 i = 0; 3109 if(*ptr == 'f') 3110 ptr = _m3d_findnl(ptr); 3111 while(*ptr && *ptr != '\r' && *ptr != '\n') { 3112 if(*ptr == 'f') { 3113 i = a->numframe++; 3114 a->frame = (m3dfr_t*)M3D_REALLOC(a->frame, a->numframe * sizeof(m3dfr_t)); 3115 if(!a->frame) goto memerr; 3116 ptr = _m3d_findarg(ptr); 3117 ptr = _m3d_getint(ptr, &a->frame[i].msec); 3118 a->frame[i].numtransform = 0; 3119 a->frame[i].transform = NULL; 3120 } else { 3121 j = a->frame[i].numtransform++; 3122 a->frame[i].transform = (m3dtr_t*)M3D_REALLOC(a->frame[i].transform, 3123 a->frame[i].numtransform * sizeof(m3dtr_t)); 3124 if(!a->frame[i].transform) goto memerr; 3125 ptr = _m3d_getint(ptr, &k); 3126 ptr = _m3d_findarg(ptr); 3127 if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; 3128 a->frame[i].transform[j].boneid = (M3D_INDEX)k; 3129 ptr = _m3d_getint(ptr, &k); 3130 ptr = _m3d_findarg(ptr); 3131 if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; 3132 a->frame[i].transform[j].pos = (M3D_INDEX)k; 3133 ptr = _m3d_getint(ptr, &k); 3134 if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; 3135 a->frame[i].transform[j].ori = (M3D_INDEX)k; 3136 model->vertex[k].skinid = M3D_INDEXMAX; 3137 } 3138 ptr = _m3d_findnl(ptr); 3139 } 3140 } else 3141 /* inlined assets chunk */ 3142 if(!memcmp(pe, "Assets", 6)) { 3143 while(*ptr && *ptr != '\r' && *ptr != '\n') { 3144 if(readfilecb) { 3145 pe = _m3d_safestr(ptr, 2); 3146 if(!pe || !*pe) goto asciiend; 3147 i = model->numinlined++; 3148 model->inlined = (m3di_t*)M3D_REALLOC(model->inlined, model->numinlined * sizeof(m3di_t)); 3149 if(!model->inlined) goto memerr; 3150 t = &model->inlined[i]; 3151 model->inlined[i].data = (*readfilecb)(pe, &model->inlined[i].length); 3152 if(model->inlined[i].data) { 3153 fn = strrchr(pe, '.'); 3154 if(fn && (fn[1] == 'p' || fn[1] == 'P') && (fn[2] == 'n' || fn[2] == 'N') && 3155 (fn[3] == 'g' || fn[3] == 'G')) *fn = 0; 3156 fn = strrchr(pe, '/'); 3157 if(!fn) fn = strrchr(pe, '\\'); 3158 if(!fn) fn = pe; else fn++; 3159 model->inlined[i].name = _m3d_safestr(fn, 0); 3160 } else 3161 model->numinlined--; 3162 M3D_FREE(pe); 3163 } 3164 ptr = _m3d_findnl(ptr); 3165 } 3166 } else 3167 /* extra chunks */ 3168 if(!memcmp(pe, "Extra", 5)) { 3169 pe = _m3d_findarg(pe); 3170 if(!*pe || *pe == '\r' || *pe == '\n') goto asciiend; 3171 buff = (unsigned char*)_m3d_findnl(ptr); 3172 k = ((uint32_t)((uintptr_t)buff - (uintptr_t)ptr) / 3) + 1; 3173 i = model->numextra++; 3174 model->extra = (m3dchunk_t**)M3D_REALLOC(model->extra, model->numextra * sizeof(m3dchunk_t*)); 3175 if(!model->extra) goto memerr; 3176 model->extra[i] = (m3dchunk_t*)M3D_MALLOC(k + sizeof(m3dchunk_t)); 3177 if(!model->extra[i]) goto memerr; 3178 memcpy(&model->extra[i]->magic, pe, 4); 3179 model->extra[i]->length = sizeof(m3dchunk_t); 3180 pe = (char*)model->extra[i] + sizeof(m3dchunk_t); 3181 while(*ptr && *ptr != '\r' && *ptr != '\n') { 3182 ptr = _m3d_gethex(ptr, &k); 3183 *pe++ = (uint8_t)k; 3184 model->extra[i]->length++; 3185 } 3186 } else 3187 goto asciiend; 3188 } 3189 model->errcode = M3D_SUCCESS; 3190 asciiend: 3191 setlocale(LC_NUMERIC, ol); 3192 goto postprocess; 3193 } 3194 #endif 3195 /* Binary variant */ 3196 len = ((m3dhdr_t*)data)->length - 8; 3197 data += 8; 3198 if(M3D_CHUNKMAGIC(data, 'P','R','V','W')) { 3199 /* optional preview chunk */ 3200 model->preview.length = ((m3dchunk_t*)data)->length; 3201 model->preview.data = data + sizeof(m3dchunk_t); 3202 data += model->preview.length; 3203 len -= model->preview.length; 3204 } 3205 if(!M3D_CHUNKMAGIC(data, 'H','E','A','D')) { 3206 buff = (unsigned char *)stbi_zlib_decode_malloc_guesssize_headerflag((const char*)data, len, 4096, (int*)&len, 1); 3207 if(!buff || !len || !M3D_CHUNKMAGIC(buff, 'H','E','A','D')) { 3208 if(buff) M3D_FREE(buff); 3209 M3D_FREE(model); 3210 return NULL; 3211 } 3212 buff = (unsigned char*)M3D_REALLOC(buff, len); 3213 model->flags |= M3D_FLG_FREERAW; /* mark that we have to free the raw buffer */ 3214 data = buff; 3215 #ifdef M3D_PROFILING 3216 gettimeofday(&tv1, NULL); 3217 tvd.tv_sec = tv1.tv_sec - tv0.tv_sec; 3218 tvd.tv_usec = tv1.tv_usec - tv0.tv_usec; 3219 if(tvd.tv_usec < 0) { tvd.tv_sec--; tvd.tv_usec += 1000000L; } 3220 printf(" Deflate model %ld.%06ld sec\n", tvd.tv_sec, tvd.tv_usec); 3221 memcpy(&tv0, &tv1, sizeof(struct timeval)); 3222 #endif 3223 } 3224 model->raw = (m3dhdr_t*)data; 3225 end = data + len; 3226 3227 /* parse header */ 3228 data += sizeof(m3dhdr_t); 3229 M3D_LOG((char*)data); 3230 model->name = (char*)data; 3231 for(; data < end && *data; data++) {}; data++; 3232 model->license = (char*)data; 3233 for(; data < end && *data; data++) {}; data++; 3234 model->author = (char*)data; 3235 for(; data < end && *data; data++) {}; data++; 3236 model->desc = (char*)data; 3237 chunk = (unsigned char*)model->raw + model->raw->length; 3238 model->scale = (M3D_FLOAT)model->raw->scale; 3239 if(model->scale <= (M3D_FLOAT)0.0) model->scale = (M3D_FLOAT)1.0; 3240 model->vc_s = 1 << ((model->raw->types >> 0) & 3); /* vertex coordinate size */ 3241 model->vi_s = 1 << ((model->raw->types >> 2) & 3); /* vertex index size */ 3242 model->si_s = 1 << ((model->raw->types >> 4) & 3); /* string offset size */ 3243 model->ci_s = 1 << ((model->raw->types >> 6) & 3); /* color index size */ 3244 model->ti_s = 1 << ((model->raw->types >> 8) & 3); /* tmap index size */ 3245 model->bi_s = 1 << ((model->raw->types >>10) & 3); /* bone index size */ 3246 model->nb_s = 1 << ((model->raw->types >>12) & 3); /* number of bones per vertex */ 3247 model->sk_s = 1 << ((model->raw->types >>14) & 3); /* skin index size */ 3248 model->fc_s = 1 << ((model->raw->types >>16) & 3); /* frame counter size */ 3249 model->hi_s = 1 << ((model->raw->types >>18) & 3); /* shape index size */ 3250 model->fi_s = 1 << ((model->raw->types >>20) & 3); /* face index size */ 3251 model->vd_s = 1 << ((model->raw->types >>22) & 3); /* voxel dimension size */ 3252 model->vp_s = 1 << ((model->raw->types >>24) & 3); /* voxel pixel size */ 3253 if(model->ci_s == 8) model->ci_s = 0; /* optional indices */ 3254 if(model->ti_s == 8) model->ti_s = 0; 3255 if(model->bi_s == 8) model->bi_s = 0; 3256 if(model->sk_s == 8) model->sk_s = 0; 3257 if(model->fc_s == 8) model->fc_s = 0; 3258 if(model->hi_s == 8) model->hi_s = 0; 3259 if(model->fi_s == 8) model->fi_s = 0; 3260 3261 /* variable limit checks */ 3262 if(sizeof(M3D_FLOAT) == 4 && model->vc_s > 4) { 3263 M3D_LOG("Double precision coordinates not supported, truncating to float..."); 3264 model->errcode = M3D_ERR_TRUNC; 3265 } 3266 if((sizeof(M3D_INDEX) == 2 && (model->vi_s > 2 || model->si_s > 2 || model->ci_s > 2 || model->ti_s > 2 || 3267 model->bi_s > 2 || model->sk_s > 2 || model->fc_s > 2 || model->hi_s > 2 || model->fi_s > 2)) || 3268 (sizeof(M3D_VOXEL) < (size_t)model->vp_s && model->vp_s != 8)) { 3269 M3D_LOG("32 bit indices not supported, unable to load model"); 3270 M3D_FREE(model); 3271 return NULL; 3272 } 3273 if(model->vi_s > 4 || model->si_s > 4 || model->vp_s == 4) { 3274 M3D_LOG("Invalid index size, unable to load model"); 3275 M3D_FREE(model); 3276 return NULL; 3277 } 3278 if(!M3D_CHUNKMAGIC(end - 4, 'O','M','D','3')) { 3279 M3D_LOG("Missing end chunk"); 3280 M3D_FREE(model); 3281 return NULL; 3282 } 3283 if(model->nb_s > M3D_NUMBONE) { 3284 M3D_LOG("Model has more bones per vertex than what importer was configured to support"); 3285 model->errcode = M3D_ERR_TRUNC; 3286 } 3287 3288 /* look for inlined assets in advance, material and procedural chunks may need them */ 3289 buff = chunk; 3290 while(buff < end && !M3D_CHUNKMAGIC(buff, 'O','M','D','3')) { 3291 data = buff; 3292 len = ((m3dchunk_t*)data)->length; 3293 buff += len; 3294 if(len < sizeof(m3dchunk_t) || buff >= end) { 3295 M3D_LOG("Invalid chunk size"); 3296 break; 3297 } 3298 len -= sizeof(m3dchunk_t) + model->si_s; 3299 3300 /* inlined assets */ 3301 if(M3D_CHUNKMAGIC(data, 'A','S','E','T') && len > 0) { 3302 M3D_LOG("Inlined asset"); 3303 i = model->numinlined++; 3304 model->inlined = (m3di_t*)M3D_REALLOC(model->inlined, model->numinlined * sizeof(m3di_t)); 3305 if(!model->inlined) { 3306 memerr: M3D_LOG("Out of memory"); 3307 model->errcode = M3D_ERR_ALLOC; 3308 return model; 3309 } 3310 data += sizeof(m3dchunk_t); 3311 t = &model->inlined[i]; 3312 M3D_GETSTR(t->name); 3313 M3D_LOG(t->name); 3314 t->data = (uint8_t*)data; 3315 t->length = len; 3316 } 3317 } 3318 3319 /* parse chunks */ 3320 while(chunk < end && !M3D_CHUNKMAGIC(chunk, 'O','M','D','3')) { 3321 data = chunk; 3322 len = ((m3dchunk_t*)chunk)->length; 3323 chunk += len; 3324 if(len < sizeof(m3dchunk_t) || chunk >= end) { 3325 M3D_LOG("Invalid chunk size"); 3326 break; 3327 } 3328 len -= sizeof(m3dchunk_t); 3329 3330 /* color map */ 3331 if(M3D_CHUNKMAGIC(data, 'C','M','A','P')) { 3332 M3D_LOG("Color map"); 3333 if(model->cmap) { M3D_LOG("More color map chunks, should be unique"); model->errcode = M3D_ERR_CMAP; continue; } 3334 if(!model->ci_s) { M3D_LOG("Color map chunk, shouldn't be any"); model->errcode = M3D_ERR_CMAP; continue; } 3335 model->numcmap = len / sizeof(uint32_t); 3336 model->cmap = (uint32_t*)(data + sizeof(m3dchunk_t)); 3337 } else 3338 /* texture map */ 3339 if(M3D_CHUNKMAGIC(data, 'T','M','A','P')) { 3340 M3D_LOG("Texture map"); 3341 if(model->tmap) { M3D_LOG("More texture map chunks, should be unique"); model->errcode = M3D_ERR_TMAP; continue; } 3342 if(!model->ti_s) { M3D_LOG("Texture map chunk, shouldn't be any"); model->errcode = M3D_ERR_TMAP; continue; } 3343 reclen = model->vc_s + model->vc_s; 3344 model->numtmap = len / reclen; 3345 model->tmap = (m3dti_t*)M3D_MALLOC(model->numtmap * sizeof(m3dti_t)); 3346 if(!model->tmap) goto memerr; 3347 for(i = 0, data += sizeof(m3dchunk_t); data < chunk; i++) { 3348 switch(model->vc_s) { 3349 case 1: 3350 model->tmap[i].u = (M3D_FLOAT)((uint8_t)data[0]) / (M3D_FLOAT)255.0; 3351 model->tmap[i].v = (M3D_FLOAT)((uint8_t)data[1]) / (M3D_FLOAT)255.0; 3352 break; 3353 case 2: 3354 model->tmap[i].u = (M3D_FLOAT)(*((uint16_t*)(data+0))) / (M3D_FLOAT)65535.0; 3355 model->tmap[i].v = (M3D_FLOAT)(*((uint16_t*)(data+2))) / (M3D_FLOAT)65535.0; 3356 break; 3357 case 4: 3358 model->tmap[i].u = (M3D_FLOAT)(*((float*)(data+0))); 3359 model->tmap[i].v = (M3D_FLOAT)(*((float*)(data+4))); 3360 break; 3361 case 8: 3362 model->tmap[i].u = (M3D_FLOAT)(*((double*)(data+0))); 3363 model->tmap[i].v = (M3D_FLOAT)(*((double*)(data+8))); 3364 break; 3365 } 3366 data += reclen; 3367 } 3368 } else 3369 /* vertex list */ 3370 if(M3D_CHUNKMAGIC(data, 'V','R','T','S')) { 3371 M3D_LOG("Vertex list"); 3372 if(model->vertex) { M3D_LOG("More vertex chunks, should be unique"); model->errcode = M3D_ERR_VRTS; continue; } 3373 if(model->ci_s && model->ci_s < 4 && !model->cmap) model->errcode = M3D_ERR_CMAP; 3374 reclen = model->ci_s + model->sk_s + 4 * model->vc_s; 3375 model->numvertex = len / reclen; 3376 model->vertex = (m3dv_t*)M3D_MALLOC(model->numvertex * sizeof(m3dv_t)); 3377 if(!model->vertex) goto memerr; 3378 memset(model->vertex, 0, model->numvertex * sizeof(m3dv_t)); 3379 for(i = 0, data += sizeof(m3dchunk_t); data < chunk && i < model->numvertex; i++) { 3380 switch(model->vc_s) { 3381 case 1: 3382 model->vertex[i].x = (M3D_FLOAT)((int8_t)data[0]) / (M3D_FLOAT)127.0; 3383 model->vertex[i].y = (M3D_FLOAT)((int8_t)data[1]) / (M3D_FLOAT)127.0; 3384 model->vertex[i].z = (M3D_FLOAT)((int8_t)data[2]) / (M3D_FLOAT)127.0; 3385 model->vertex[i].w = (M3D_FLOAT)((int8_t)data[3]) / (M3D_FLOAT)127.0; 3386 data += 4; 3387 break; 3388 case 2: 3389 model->vertex[i].x = (M3D_FLOAT)(*((int16_t*)(data+0))) / (M3D_FLOAT)32767.0; 3390 model->vertex[i].y = (M3D_FLOAT)(*((int16_t*)(data+2))) / (M3D_FLOAT)32767.0; 3391 model->vertex[i].z = (M3D_FLOAT)(*((int16_t*)(data+4))) / (M3D_FLOAT)32767.0; 3392 model->vertex[i].w = (M3D_FLOAT)(*((int16_t*)(data+6))) / (M3D_FLOAT)32767.0; 3393 data += 8; 3394 break; 3395 case 4: 3396 model->vertex[i].x = (M3D_FLOAT)(*((float*)(data+0))); 3397 model->vertex[i].y = (M3D_FLOAT)(*((float*)(data+4))); 3398 model->vertex[i].z = (M3D_FLOAT)(*((float*)(data+8))); 3399 model->vertex[i].w = (M3D_FLOAT)(*((float*)(data+12))); 3400 data += 16; 3401 break; 3402 case 8: 3403 model->vertex[i].x = (M3D_FLOAT)(*((double*)(data+0))); 3404 model->vertex[i].y = (M3D_FLOAT)(*((double*)(data+8))); 3405 model->vertex[i].z = (M3D_FLOAT)(*((double*)(data+16))); 3406 model->vertex[i].w = (M3D_FLOAT)(*((double*)(data+24))); 3407 data += 32; 3408 break; 3409 } 3410 switch(model->ci_s) { 3411 case 1: model->vertex[i].color = model->cmap ? model->cmap[data[0]] : 0; data++; break; 3412 case 2: model->vertex[i].color = model->cmap ? model->cmap[*((uint16_t*)data)] : 0; data += 2; break; 3413 case 4: model->vertex[i].color = *((uint32_t*)data); data += 4; break; 3414 /* case 8: break; */ 3415 } 3416 model->vertex[i].skinid = M3D_UNDEF; 3417 data = _m3d_getidx(data, model->sk_s, &model->vertex[i].skinid); 3418 } 3419 } else 3420 /* skeleton: bone hierarchy and skin */ 3421 if(M3D_CHUNKMAGIC(data, 'B','O','N','E')) { 3422 M3D_LOG("Skeleton"); 3423 if(model->bone) { M3D_LOG("More bone chunks, should be unique"); model->errcode = M3D_ERR_BONE; continue; } 3424 if(!model->bi_s) { M3D_LOG("Bone chunk, shouldn't be any"); model->errcode=M3D_ERR_BONE; continue; } 3425 if(!model->vertex) { M3D_LOG("No vertex chunk before bones"); model->errcode = M3D_ERR_VRTS; break; } 3426 data += sizeof(m3dchunk_t); 3427 model->numbone = 0; 3428 data = _m3d_getidx(data, model->bi_s, &model->numbone); 3429 if(model->numbone) { 3430 model->bone = (m3db_t*)M3D_MALLOC(model->numbone * sizeof(m3db_t)); 3431 if(!model->bone) goto memerr; 3432 } 3433 model->numskin = 0; 3434 data = _m3d_getidx(data, model->sk_s, &model->numskin); 3435 /* read bone hierarchy */ 3436 for(i = 0; data < chunk && i < model->numbone; i++) { 3437 data = _m3d_getidx(data, model->bi_s, &model->bone[i].parent); 3438 M3D_GETSTR(model->bone[i].name); 3439 data = _m3d_getidx(data, model->vi_s, &model->bone[i].pos); 3440 data = _m3d_getidx(data, model->vi_s, &model->bone[i].ori); 3441 model->bone[i].numweight = 0; 3442 model->bone[i].weight = NULL; 3443 } 3444 if(i != model->numbone) { M3D_LOG("Truncated bone chunk"); model->numbone = i; model->numskin = 0; model->errcode = M3D_ERR_BONE; } 3445 /* read skin definitions */ 3446 if(model->numskin) { 3447 model->skin = (m3ds_t*)M3D_MALLOC(model->numskin * sizeof(m3ds_t)); 3448 if(!model->skin) goto memerr; 3449 for(i = 0; data < chunk && i < model->numskin; i++) { 3450 for(j = 0; j < M3D_NUMBONE; j++) { 3451 model->skin[i].boneid[j] = M3D_UNDEF; 3452 model->skin[i].weight[j] = (M3D_FLOAT)0.0; 3453 } 3454 memset(&weights, 0, sizeof(weights)); 3455 if(model->nb_s == 1) weights[0] = 255; 3456 else { 3457 memcpy(&weights, data, model->nb_s); 3458 data += model->nb_s; 3459 } 3460 for(j = 0, w = (M3D_FLOAT)0.0; j < (unsigned int)model->nb_s; j++) { 3461 if(weights[j]) { 3462 if(j >= M3D_NUMBONE) 3463 data += model->bi_s; 3464 else { 3465 model->skin[i].weight[j] = (M3D_FLOAT)(weights[j]) / (M3D_FLOAT)255.0; 3466 w += model->skin[i].weight[j]; 3467 data = _m3d_getidx(data, model->bi_s, &model->skin[i].boneid[j]); 3468 } 3469 } 3470 } 3471 /* this can occur if model has more bones than what the importer is configured to handle */ 3472 if(w != (M3D_FLOAT)1.0 && w != (M3D_FLOAT)0.0) { 3473 for(j = 0; j < M3D_NUMBONE; j++) 3474 model->skin[i].weight[j] /= w; 3475 } 3476 } 3477 if(i != model->numskin) { M3D_LOG("Truncated skin in bone chunk"); model->numskin = i; model->errcode = M3D_ERR_BONE; } 3478 } 3479 } else 3480 /* material */ 3481 if(M3D_CHUNKMAGIC(data, 'M','T','R','L')) { 3482 data += sizeof(m3dchunk_t); 3483 M3D_GETSTR(name); 3484 M3D_LOG("Material"); 3485 M3D_LOG(name); 3486 if(model->ci_s < 4 && !model->numcmap) model->errcode = M3D_ERR_CMAP; 3487 for(i = 0; i < model->nummaterial; i++) 3488 if(!strcmp(name, model->material[i].name)) { 3489 model->errcode = M3D_ERR_MTRL; 3490 M3D_LOG("Multiple definitions for material"); 3491 M3D_LOG(name); 3492 name = NULL; 3493 break; 3494 } 3495 if(name) { 3496 i = model->nummaterial++; 3497 if(model->flags & M3D_FLG_MTLLIB) { 3498 m = model->material; 3499 model->material = (m3dm_t*)M3D_MALLOC(model->nummaterial * sizeof(m3dm_t)); 3500 if(!model->material) goto memerr; 3501 memcpy(model->material, m, (model->nummaterial - 1) * sizeof(m3dm_t)); 3502 if(model->texture) { 3503 tx = model->texture; 3504 model->texture = (m3dtx_t*)M3D_MALLOC(model->numtexture * sizeof(m3dtx_t)); 3505 if(!model->texture) goto memerr; 3506 memcpy(model->texture, tx, model->numtexture * sizeof(m3dm_t)); 3507 } 3508 model->flags &= ~M3D_FLG_MTLLIB; 3509 } else { 3510 model->material = (m3dm_t*)M3D_REALLOC(model->material, model->nummaterial * sizeof(m3dm_t)); 3511 if(!model->material) goto memerr; 3512 } 3513 m = &model->material[i]; 3514 m->numprop = 0; 3515 m->name = name; 3516 m->prop = (m3dp_t*)M3D_MALLOC((len / 2) * sizeof(m3dp_t)); 3517 if(!m->prop) goto memerr; 3518 while(data < chunk) { 3519 i = m->numprop++; 3520 m->prop[i].type = *data++; 3521 m->prop[i].value.num = 0; 3522 if(m->prop[i].type >= 128) 3523 k = m3dpf_map; 3524 else { 3525 for(k = 256, j = 0; j < sizeof(m3d_propertytypes)/sizeof(m3d_propertytypes[0]); j++) 3526 if(m->prop[i].type == m3d_propertytypes[j].id) { k = m3d_propertytypes[j].format; break; } 3527 } 3528 switch(k) { 3529 case m3dpf_color: 3530 switch(model->ci_s) { 3531 case 1: m->prop[i].value.color = model->cmap ? model->cmap[data[0]] : 0; data++; break; 3532 case 2: m->prop[i].value.color = model->cmap ? model->cmap[*((uint16_t*)data)] : 0; data += 2; break; 3533 case 4: m->prop[i].value.color = *((uint32_t*)data); data += 4; break; 3534 } 3535 break; 3536 3537 case m3dpf_uint8: m->prop[i].value.num = *data++; break; 3538 case m3dpf_uint16:m->prop[i].value.num = *((uint16_t*)data); data += 2; break; 3539 case m3dpf_uint32:m->prop[i].value.num = *((uint32_t*)data); data += 4; break; 3540 case m3dpf_float: m->prop[i].value.fnum = *((float*)data); data += 4; break; 3541 3542 case m3dpf_map: 3543 M3D_GETSTR(name); 3544 m->prop[i].value.textureid = _m3d_gettx(model, readfilecb, freecb, name); 3545 if(model->errcode == M3D_ERR_ALLOC) goto memerr; 3546 /* this error code only returned if readfilecb was specified */ 3547 if(m->prop[i].value.textureid == M3D_UNDEF) { 3548 M3D_LOG("Texture not found"); 3549 M3D_LOG(m->name); 3550 m->numprop--; 3551 } 3552 break; 3553 3554 default: 3555 M3D_LOG("Unknown material property in"); 3556 M3D_LOG(m->name); 3557 model->errcode = M3D_ERR_UNKPROP; 3558 data = chunk; 3559 break; 3560 } 3561 } 3562 m->prop = (m3dp_t*)M3D_REALLOC(m->prop, m->numprop * sizeof(m3dp_t)); 3563 if(!m->prop) goto memerr; 3564 } 3565 } else 3566 /* face */ 3567 if(M3D_CHUNKMAGIC(data, 'P','R','O','C')) { 3568 /* procedural surface */ 3569 M3D_GETSTR(name); 3570 M3D_LOG("Procedural surface"); 3571 M3D_LOG(name); 3572 _m3d_getpr(model, readfilecb, freecb, name); 3573 } else 3574 if(M3D_CHUNKMAGIC(data, 'M','E','S','H')) { 3575 M3D_LOG("Mesh data"); 3576 if(!model->vertex) { M3D_LOG("No vertex chunk before mesh"); model->errcode = M3D_ERR_VRTS; } 3577 /* mesh */ 3578 data += sizeof(m3dchunk_t); 3579 mi = M3D_UNDEF; 3580 #ifdef M3D_VERTEXMAX 3581 pi = M3D_UNDEF; 3582 #endif 3583 am = model->numface; 3584 while(data < chunk) { 3585 k = *data++; 3586 n = k >> 4; 3587 k &= 15; 3588 if(!n) { 3589 if(!k) { 3590 /* use material */ 3591 mi = M3D_UNDEF; 3592 M3D_GETSTR(name); 3593 if(name) { 3594 for(j = 0; j < model->nummaterial; j++) 3595 if(!strcmp(name, model->material[j].name)) { 3596 mi = (M3D_INDEX)j; 3597 break; 3598 } 3599 if(mi == M3D_UNDEF) model->errcode = M3D_ERR_MTRL; 3600 } 3601 } else { 3602 /* use parameter */ 3603 M3D_GETSTR(name); 3604 #ifdef M3D_VERTEXMAX 3605 pi = M3D_UNDEF; 3606 if(name) { 3607 for(j = 0; j < model->numparam; j++) 3608 if(!strcmp(name, model->param[j].name)) { 3609 pi = (M3D_INDEX)j; 3610 break; 3611 } 3612 if(pi == M3D_UNDEF) { 3613 pi = model->numparam++; 3614 model->param = (m3dvi_t*)M3D_REALLOC(model->param, model->numparam * sizeof(m3dvi_t)); 3615 if(!model->param) goto memerr; 3616 model->param[pi].name = name; 3617 model->param[pi].count = 0; 3618 } 3619 } 3620 #endif 3621 } 3622 continue; 3623 } 3624 if(n != 3) { M3D_LOG("Only triangle mesh supported for now"); model->errcode = M3D_ERR_UNKMESH; return model; } 3625 i = model->numface++; 3626 if(model->numface > am) { 3627 am = model->numface + 4095; 3628 model->face = (m3df_t*)M3D_REALLOC(model->face, am * sizeof(m3df_t)); 3629 if(!model->face) goto memerr; 3630 } 3631 memset(&model->face[i], 255, sizeof(m3df_t)); /* set all index to -1 by default */ 3632 model->face[i].materialid = mi; 3633 #ifdef M3D_VERTEXMAX 3634 model->face[i].paramid = pi; 3635 #endif 3636 for(j = 0; data < chunk && j < n; j++) { 3637 /* vertex */ 3638 data = _m3d_getidx(data, model->vi_s, &model->face[i].vertex[j]); 3639 /* texcoord */ 3640 if(k & 1) 3641 data = _m3d_getidx(data, model->ti_s, &model->face[i].texcoord[j]); 3642 /* normal */ 3643 if(k & 2) 3644 data = _m3d_getidx(data, model->vi_s, &model->face[i].normal[j]); 3645 #ifndef M3D_NONORMALS 3646 if(model->face[i].normal[j] == M3D_UNDEF) neednorm = 1; 3647 #endif 3648 /* maximum */ 3649 if(k & 4) 3650 #ifdef M3D_VERTEXMAX 3651 data = _m3d_getidx(data, model->vi_s, &model->face[i].vertmax[j]); 3652 #else 3653 data += model->vi_s; 3654 #endif 3655 } 3656 if(j != n) { M3D_LOG("Invalid mesh"); model->numface = 0; model->errcode = M3D_ERR_UNKMESH; return model; } 3657 } 3658 model->face = (m3df_t*)M3D_REALLOC(model->face, model->numface * sizeof(m3df_t)); 3659 } else 3660 if(M3D_CHUNKMAGIC(data, 'V','O','X','T')) { 3661 /* voxel types */ 3662 M3D_LOG("Voxel types list"); 3663 if(model->voxtype) { M3D_LOG("More voxel type chunks, should be unique"); model->errcode = M3D_ERR_VOXT; continue; } 3664 if(model->ci_s && model->ci_s < 4 && !model->cmap) model->errcode = M3D_ERR_CMAP; 3665 reclen = model->ci_s + model->si_s + 3 + model->sk_s; 3666 k = len / reclen; 3667 model->voxtype = (m3dvt_t*)M3D_MALLOC(k * sizeof(m3dvt_t)); 3668 if(!model->voxtype) goto memerr; 3669 memset(model->voxtype, 0, k * sizeof(m3dvt_t)); 3670 model->numvoxtype = 0; 3671 for(i = 0, data += sizeof(m3dchunk_t); data < chunk && i < k; i++) { 3672 switch(model->ci_s) { 3673 case 1: model->voxtype[i].color = model->cmap ? model->cmap[data[0]] : 0; data++; break; 3674 case 2: model->voxtype[i].color = model->cmap ? model->cmap[*((uint16_t*)data)] : 0; data += 2; break; 3675 case 4: model->voxtype[i].color = *((uint32_t*)data); data += 4; break; 3676 /* case 8: break; */ 3677 } 3678 M3D_GETSTR(name); 3679 model->voxtype[i].materialid = M3D_UNDEF; 3680 if(name) { 3681 model->voxtype[i].name = name; 3682 /* 3683 for(j = 0; j < model->nummaterial; j++) 3684 if(!strcmp(name, model->material[j].name)) { 3685 model->voxtype[i].materialid = (M3D_INDEX)j; 3686 break; 3687 } 3688 */ 3689 } 3690 j = *data++; 3691 model->voxtype[i].rotation = j & 0xBF; 3692 model->voxtype[i].voxshape = ((j & 0x40) << 2) | *data++; 3693 model->voxtype[i].numitem = *data++; 3694 model->voxtype[i].skinid = M3D_UNDEF; 3695 data = _m3d_getidx(data, model->sk_s, &model->voxtype[i].skinid); 3696 if(model->voxtype[i].numitem) { 3697 model->voxtype[i].item = (m3dvi_t*)M3D_MALLOC(model->voxtype[i].numitem * sizeof(m3dvi_t)); 3698 if(!model->voxtype[i].item) goto memerr; 3699 memset(model->voxtype[i].item, 0, model->voxtype[i].numitem * sizeof(m3dvi_t)); 3700 for(j = 0; j < model->voxtype[i].numitem; j++) { 3701 model->voxtype[i].item[j].count = *data++; 3702 model->voxtype[i].item[j].count |= (*data++) << 8; 3703 M3D_GETSTR(model->voxtype[i].item[j].name); 3704 } 3705 } 3706 } 3707 model->numvoxtype = i; 3708 if(k != model->numvoxtype) { 3709 model->voxtype = (m3dvt_t*)M3D_REALLOC(model->voxtype, model->numvoxtype * sizeof(m3dvt_t)); 3710 if(!model->voxtype) goto memerr; 3711 } 3712 } else 3713 if(M3D_CHUNKMAGIC(data, 'V','O','X','D')) { 3714 /* voxel data */ 3715 data += sizeof(m3dchunk_t); 3716 M3D_GETSTR(name); 3717 M3D_LOG("Voxel Data Layer"); 3718 M3D_LOG(name); 3719 if(model->vd_s > 4 || model->vp_s > 2) { M3D_LOG("No voxel index size"); model->errcode = M3D_ERR_UNKVOX; continue; } 3720 if(!model->voxtype) { M3D_LOG("No voxel type chunk before voxel data"); model->errcode = M3D_ERR_VOXT; } 3721 i = model->numvoxel++; 3722 model->voxel = (m3dvx_t*)M3D_REALLOC(model->voxel, model->numvoxel * sizeof(m3dvx_t)); 3723 if(!model->voxel) goto memerr; 3724 memset(&model->voxel[i], 0, sizeof(m3dvx_t)); 3725 model->voxel[i].name = name; 3726 switch(model->vd_s) { 3727 case 1: 3728 model->voxel[i].x = (int32_t)((int8_t)data[0]); 3729 model->voxel[i].y = (int32_t)((int8_t)data[1]); 3730 model->voxel[i].z = (int32_t)((int8_t)data[2]); 3731 model->voxel[i].w = (uint32_t)(data[3]); 3732 model->voxel[i].h = (uint32_t)(data[4]); 3733 model->voxel[i].d = (uint32_t)(data[5]); 3734 data += 6; 3735 break; 3736 case 2: 3737 model->voxel[i].x = (int32_t)(*((int16_t*)(data+0))); 3738 model->voxel[i].y = (int32_t)(*((int16_t*)(data+2))); 3739 model->voxel[i].z = (int32_t)(*((int16_t*)(data+4))); 3740 model->voxel[i].w = (uint32_t)(*((uint16_t*)(data+6))); 3741 model->voxel[i].h = (uint32_t)(*((uint16_t*)(data+8))); 3742 model->voxel[i].d = (uint32_t)(*((uint16_t*)(data+10))); 3743 data += 12; 3744 break; 3745 case 4: 3746 model->voxel[i].x = *((int32_t*)(data+0)); 3747 model->voxel[i].y = *((int32_t*)(data+4)); 3748 model->voxel[i].z = *((int32_t*)(data+8)); 3749 model->voxel[i].w = *((uint32_t*)(data+12)); 3750 model->voxel[i].h = *((uint32_t*)(data+16)); 3751 model->voxel[i].d = *((uint32_t*)(data+20)); 3752 data += 24; 3753 break; 3754 } 3755 model->voxel[i].uncertain = *data++; 3756 model->voxel[i].groupid = *data++; 3757 k = model->voxel[i].w * model->voxel[i].h * model->voxel[i].d; 3758 model->voxel[i].data = (M3D_VOXEL*)M3D_MALLOC(k * sizeof(M3D_VOXEL)); 3759 if(!model->voxel[i].data) goto memerr; 3760 memset(model->voxel[i].data, 0xff, k * sizeof(M3D_VOXEL)); 3761 for(j = 0; data < chunk && j < k;) { 3762 l = ((*data++) & 0x7F) + 1; 3763 if(data[-1] & 0x80) { 3764 data = _m3d_getidx(data, model->vp_s, &mi); 3765 while(l-- && j < k) model->voxel[i].data[j++] = (M3D_VOXEL)mi; 3766 } else 3767 while(l-- && j < k) { 3768 data = _m3d_getidx(data, model->vp_s, &mi); 3769 model->voxel[i].data[j++] = (M3D_VOXEL)mi; 3770 } 3771 } 3772 } else 3773 if(M3D_CHUNKMAGIC(data, 'S','H','P','E')) { 3774 /* mathematical shape */ 3775 data += sizeof(m3dchunk_t); 3776 M3D_GETSTR(name); 3777 M3D_LOG("Mathematical Shape"); 3778 M3D_LOG(name); 3779 i = model->numshape++; 3780 model->shape = (m3dh_t*)M3D_REALLOC(model->shape, model->numshape * sizeof(m3dh_t)); 3781 if(!model->shape) goto memerr; 3782 h = &model->shape[i]; 3783 h->numcmd = 0; 3784 h->cmd = NULL; 3785 h->name = name; 3786 h->group = M3D_UNDEF; 3787 data = _m3d_getidx(data, model->bi_s, &h->group); 3788 if(h->group != M3D_UNDEF && h->group >= model->numbone) { 3789 M3D_LOG("Unknown bone id as shape group in shape"); 3790 M3D_LOG(name); 3791 h->group = M3D_UNDEF; 3792 model->errcode = M3D_ERR_SHPE; 3793 } 3794 while(data < chunk) { 3795 i = h->numcmd++; 3796 h->cmd = (m3dc_t*)M3D_REALLOC(h->cmd, h->numcmd * sizeof(m3dc_t)); 3797 if(!h->cmd) goto memerr; 3798 h->cmd[i].type = *data++; 3799 if(h->cmd[i].type & 0x80) { 3800 h->cmd[i].type &= 0x7F; 3801 h->cmd[i].type |= (*data++ << 7); 3802 } 3803 if(h->cmd[i].type >= (unsigned int)(sizeof(m3d_commandtypes)/sizeof(m3d_commandtypes[0]))) { 3804 M3D_LOG("Unknown shape command in"); 3805 M3D_LOG(h->name); 3806 model->errcode = M3D_ERR_UNKCMD; 3807 break; 3808 } 3809 cd = &m3d_commandtypes[h->cmd[i].type]; 3810 h->cmd[i].arg = (uint32_t*)M3D_MALLOC(cd->p * sizeof(uint32_t)); 3811 if(!h->cmd[i].arg) goto memerr; 3812 memset(h->cmd[i].arg, 0, cd->p * sizeof(uint32_t)); 3813 for(k = n = 0, l = cd->p; k < l; k++) 3814 switch(cd->a[((k - n) % (cd->p - n)) + n]) { 3815 case m3dcp_mi_t: 3816 h->cmd[i].arg[k] = M3D_NOTDEFINED; 3817 M3D_GETSTR(name); 3818 if(name) { 3819 for(n = 0; n < model->nummaterial; n++) 3820 if(!strcmp(name, model->material[n].name)) { 3821 h->cmd[i].arg[k] = n; 3822 break; 3823 } 3824 if(h->cmd[i].arg[k] == M3D_NOTDEFINED) model->errcode = M3D_ERR_MTRL; 3825 } 3826 break; 3827 case m3dcp_vc_t: 3828 f = 0.0f; 3829 switch(model->vc_s) { 3830 case 1: f = (float)((int8_t)data[0]) / 127; break; 3831 case 2: f = (float)(*((int16_t*)(data+0))) / 32767; break; 3832 case 4: f = (float)(*((float*)(data+0))); break; 3833 case 8: f = (float)(*((double*)(data+0))); break; 3834 } 3835 memcpy(&h->cmd[i].arg[k], &f, 4); 3836 data += model->vc_s; 3837 break; 3838 case m3dcp_hi_t: data = _m3d_getidx(data, model->hi_s, &h->cmd[i].arg[k]); break; 3839 case m3dcp_fi_t: data = _m3d_getidx(data, model->fi_s, &h->cmd[i].arg[k]); break; 3840 case m3dcp_ti_t: data = _m3d_getidx(data, model->ti_s, &h->cmd[i].arg[k]); break; 3841 case m3dcp_qi_t: 3842 case m3dcp_vi_t: data = _m3d_getidx(data, model->vi_s, &h->cmd[i].arg[k]); break; 3843 case m3dcp_i1_t: data = _m3d_getidx(data, 1, &h->cmd[i].arg[k]); break; 3844 case m3dcp_i2_t: data = _m3d_getidx(data, 2, &h->cmd[i].arg[k]); break; 3845 case m3dcp_i4_t: data = _m3d_getidx(data, 4, &h->cmd[i].arg[k]); break; 3846 case m3dcp_va_t: data = _m3d_getidx(data, 4, &h->cmd[i].arg[k]); 3847 n = k + 1; l += (h->cmd[i].arg[k] - 1) * (cd->p - k - 1); 3848 h->cmd[i].arg = (uint32_t*)M3D_REALLOC(h->cmd[i].arg, l * sizeof(uint32_t)); 3849 if(!h->cmd[i].arg) goto memerr; 3850 memset(&h->cmd[i].arg[k + 1], 0, (l - k - 1) * sizeof(uint32_t)); 3851 break; 3852 } 3853 } 3854 } else 3855 /* annotation label list */ 3856 if(M3D_CHUNKMAGIC(data, 'L','B','L','S')) { 3857 data += sizeof(m3dchunk_t); 3858 M3D_GETSTR(name); 3859 M3D_GETSTR(lang); 3860 M3D_LOG("Label list"); 3861 if(name) { M3D_LOG(name); } 3862 if(lang) { M3D_LOG(lang); } 3863 if(model->ci_s && model->ci_s < 4 && !model->cmap) model->errcode = M3D_ERR_CMAP; 3864 k = 0; 3865 switch(model->ci_s) { 3866 case 1: k = model->cmap ? model->cmap[data[0]] : 0; data++; break; 3867 case 2: k = model->cmap ? model->cmap[*((uint16_t*)data)] : 0; data += 2; break; 3868 case 4: k = *((uint32_t*)data); data += 4; break; 3869 /* case 8: break; */ 3870 } 3871 reclen = model->vi_s + model->si_s; 3872 i = model->numlabel; model->numlabel += len / reclen; 3873 model->label = (m3dl_t*)M3D_REALLOC(model->label, model->numlabel * sizeof(m3dl_t)); 3874 if(!model->label) goto memerr; 3875 memset(&model->label[i], 0, (model->numlabel - i) * sizeof(m3dl_t)); 3876 for(; data < chunk && i < model->numlabel; i++) { 3877 model->label[i].name = name; 3878 model->label[i].lang = lang; 3879 model->label[i].color = k; 3880 data = _m3d_getidx(data, model->vi_s, &model->label[i].vertexid); 3881 M3D_GETSTR(model->label[i].text); 3882 } 3883 } else 3884 /* action */ 3885 if(M3D_CHUNKMAGIC(data, 'A','C','T','N')) { 3886 M3D_LOG("Action"); 3887 i = model->numaction++; 3888 model->action = (m3da_t*)M3D_REALLOC(model->action, model->numaction * sizeof(m3da_t)); 3889 if(!model->action) goto memerr; 3890 a = &model->action[i]; 3891 data += sizeof(m3dchunk_t); 3892 M3D_GETSTR(a->name); 3893 M3D_LOG(a->name); 3894 a->numframe = *((uint16_t*)data); data += 2; 3895 if(a->numframe < 1) { 3896 model->numaction--; 3897 } else { 3898 a->durationmsec = *((uint32_t*)data); data += 4; 3899 a->frame = (m3dfr_t*)M3D_MALLOC(a->numframe * sizeof(m3dfr_t)); 3900 if(!a->frame) goto memerr; 3901 for(i = 0; data < chunk && i < a->numframe; i++) { 3902 a->frame[i].msec = *((uint32_t*)data); data += 4; 3903 a->frame[i].numtransform = 0; a->frame[i].transform = NULL; 3904 data = _m3d_getidx(data, model->fc_s, &a->frame[i].numtransform); 3905 if(a->frame[i].numtransform > 0) { 3906 a->frame[i].transform = (m3dtr_t*)M3D_MALLOC(a->frame[i].numtransform * sizeof(m3dtr_t)); 3907 for(j = 0; j < a->frame[i].numtransform; j++) { 3908 data = _m3d_getidx(data, model->bi_s, &a->frame[i].transform[j].boneid); 3909 data = _m3d_getidx(data, model->vi_s, &a->frame[i].transform[j].pos); 3910 data = _m3d_getidx(data, model->vi_s, &a->frame[i].transform[j].ori); 3911 } 3912 } 3913 } 3914 } 3915 } else { 3916 i = model->numextra++; 3917 model->extra = (m3dchunk_t**)M3D_REALLOC(model->extra, model->numextra * sizeof(m3dchunk_t*)); 3918 if(!model->extra) goto memerr; 3919 model->extra[i] = (m3dchunk_t*)data; 3920 } 3921 } 3922 /* calculate normals, normalize skin weights, create bone/vertex cross-references and calculate transform matrices */ 3923 #ifdef M3D_ASCII 3924 postprocess: 3925 #endif 3926 if(model) { 3927 M3D_LOG("Post-process"); 3928 #ifdef M3D_PROFILING 3929 gettimeofday(&tv1, NULL); 3930 tvd.tv_sec = tv1.tv_sec - tv0.tv_sec; 3931 tvd.tv_usec = tv1.tv_usec - tv0.tv_usec; 3932 if(tvd.tv_usec < 0) { tvd.tv_sec--; tvd.tv_usec += 1000000L; } 3933 printf(" Parsing chunks %ld.%06ld sec\n", tvd.tv_sec, tvd.tv_usec); 3934 #endif 3935 #ifndef M3D_NOVOXELS 3936 if(model->numvoxel && model->voxel) { 3937 M3D_LOG("Converting voxels into vertices and mesh"); 3938 /* add normals */ 3939 enorm = model->numvertex; model->numvertex += 6; 3940 model->vertex = (m3dv_t*)M3D_REALLOC(model->vertex, model->numvertex * sizeof(m3dv_t)); 3941 if(!model->vertex) goto memerr; 3942 memset(&model->vertex[enorm], 0, 6 * sizeof(m3dv_t)); 3943 for(l = 0; l < 6; l++) 3944 model->vertex[enorm+l].skinid = M3D_UNDEF; 3945 model->vertex[enorm+0].y = (M3D_FLOAT)-1.0; 3946 model->vertex[enorm+1].z = (M3D_FLOAT)-1.0; 3947 model->vertex[enorm+2].x = (M3D_FLOAT)-1.0; 3948 model->vertex[enorm+3].y = (M3D_FLOAT)1.0; 3949 model->vertex[enorm+4].z = (M3D_FLOAT)1.0; 3950 model->vertex[enorm+5].x = (M3D_FLOAT)1.0; 3951 /* this is a fast, not so memory efficient version, only basic face culling used */ 3952 min_x = min_y = min_z = 2147483647L; 3953 max_x = max_y = max_z = -2147483647L; 3954 for(i = 0; i < model->numvoxel; i++) { 3955 if(model->voxel[i].x + (int32_t)model->voxel[i].w > max_x) max_x = model->voxel[i].x + (int32_t)model->voxel[i].w; 3956 if(model->voxel[i].x < min_x) min_x = model->voxel[i].x; 3957 if(model->voxel[i].y + (int32_t)model->voxel[i].h > max_y) max_y = model->voxel[i].y + (int32_t)model->voxel[i].h; 3958 if(model->voxel[i].y < min_y) min_y = model->voxel[i].y; 3959 if(model->voxel[i].z + (int32_t)model->voxel[i].d > max_z) max_z = model->voxel[i].z + (int32_t)model->voxel[i].d; 3960 if(model->voxel[i].z < min_z) min_z = model->voxel[i].z; 3961 } 3962 i = (-min_x > max_x ? -min_x : max_x); 3963 j = (-min_y > max_y ? -min_y : max_y); 3964 k = (-min_z > max_z ? -min_z : max_z); 3965 if(j > i) i = j; 3966 if(k > i) i = k; 3967 if(i <= 1) i = 1; 3968 w = (M3D_FLOAT)1.0 / (M3D_FLOAT)i; 3969 if(i >= 254) model->vc_s = 2; 3970 if(i >= 65534) model->vc_s = 4; 3971 for(i = 0; i < model->numvoxel; i++) { 3972 sx = model->voxel[i].w; sz = model->voxel[i].d; sy = model->voxel[i].h; 3973 for(y = 0, j = 0; y < sy; y++) 3974 for(z = 0; z < sz; z++) 3975 for(x = 0; x < sx; x++, j++) 3976 if(model->voxel[i].data[j] < model->numvoxtype) { 3977 k = 0; 3978 /* 16__32 ____ 3979 * /| /| /|2 /| 3980 *64_128 | /_8_/ 32 3981 * | 1_|_2 |4|_|_| 3982 * |/ |/ |/ 1|/ 3983 * 4___8 |16_| */ 3984 k = n = am = 0; 3985 if(!y || model->voxel[i].data[j - sx*sz] >= model->numvoxtype) { n++; am |= 1; k |= 1|2|4|8; } 3986 if(!z || model->voxel[i].data[j - sx] >= model->numvoxtype) { n++; am |= 2; k |= 1|2|16|32; } 3987 if(!x || model->voxel[i].data[j - 1] >= model->numvoxtype) { n++; am |= 4; k |= 1|4|16|64; } 3988 if(y == sy-1 || model->voxel[i].data[j + sx*sz] >= model->numvoxtype) { n++; am |= 8; k |= 16|32|64|128; } 3989 if(z == sz-1 || model->voxel[i].data[j + sx] >= model->numvoxtype) { n++; am |= 16; k |= 4|8|64|128; } 3990 if(x == sx-1 || model->voxel[i].data[j + 1] >= model->numvoxtype) { n++; am |= 32; k |= 2|8|32|128; } 3991 if(k) { 3992 memset(edge, 255, sizeof(edge)); 3993 for(l = 0, len = 1, reclen = model->numvertex; l < 8; l++, len <<= 1) 3994 if(k & len) edge[l] = model->numvertex++; 3995 model->vertex = (m3dv_t*)M3D_REALLOC(model->vertex, model->numvertex * sizeof(m3dv_t)); 3996 if(!model->vertex) goto memerr; 3997 memset(&model->vertex[reclen], 0, (model->numvertex-reclen) * sizeof(m3dv_t)); 3998 for(l = reclen; l < model->numvertex; l++) { 3999 model->vertex[l].skinid = model->voxtype[model->voxel[i].data[j]].skinid; 4000 model->vertex[l].color = model->voxtype[model->voxel[i].data[j]].color; 4001 } 4002 l = reclen; 4003 if(k & 1) { 4004 model->vertex[l].x = (model->voxel[i].x + x) * w; 4005 model->vertex[l].y = (model->voxel[i].y + y) * w; 4006 model->vertex[l].z = (model->voxel[i].z + z) * w; 4007 l++; 4008 } 4009 if(k & 2) { 4010 model->vertex[l].x = (model->voxel[i].x + x + 1) * w; 4011 model->vertex[l].y = (model->voxel[i].y + y) * w; 4012 model->vertex[l].z = (model->voxel[i].z + z) * w; 4013 l++; 4014 } 4015 if(k & 4) { 4016 model->vertex[l].x = (model->voxel[i].x + x) * w; 4017 model->vertex[l].y = (model->voxel[i].y + y) * w; 4018 model->vertex[l].z = (model->voxel[i].z + z + 1) * w; 4019 l++; 4020 } 4021 if(k & 8) { 4022 model->vertex[l].x = (model->voxel[i].x + x + 1) * w; 4023 model->vertex[l].y = (model->voxel[i].y + y) * w; 4024 model->vertex[l].z = (model->voxel[i].z + z + 1) * w; 4025 l++; 4026 } 4027 if(k & 16) { 4028 model->vertex[l].x = (model->voxel[i].x + x) * w; 4029 model->vertex[l].y = (model->voxel[i].y + y + 1) * w; 4030 model->vertex[l].z = (model->voxel[i].z + z) * w; 4031 l++; 4032 } 4033 if(k & 32) { 4034 model->vertex[l].x = (model->voxel[i].x + x + 1) * w; 4035 model->vertex[l].y = (model->voxel[i].y + y + 1) * w; 4036 model->vertex[l].z = (model->voxel[i].z + z) * w; 4037 l++; 4038 } 4039 if(k & 64) { 4040 model->vertex[l].x = (model->voxel[i].x + x) * w; 4041 model->vertex[l].y = (model->voxel[i].y + y + 1) * w; 4042 model->vertex[l].z = (model->voxel[i].z + z + 1) * w; 4043 l++; 4044 } 4045 if(k & 128) { 4046 model->vertex[l].x = (model->voxel[i].x + x + 1) * w; 4047 model->vertex[l].y = (model->voxel[i].y + y + 1) * w; 4048 model->vertex[l].z = (model->voxel[i].z + z + 1) * w; 4049 l++; 4050 } 4051 n <<= 1; 4052 l = model->numface; model->numface += n; 4053 model->face = (m3df_t*)M3D_REALLOC(model->face, model->numface * sizeof(m3df_t)); 4054 if(!model->face) goto memerr; 4055 memset(&model->face[l], 255, n * sizeof(m3df_t)); 4056 for(reclen = l; reclen < model->numface; reclen++) 4057 model->face[reclen].materialid = model->voxtype[model->voxel[i].data[j]].materialid; 4058 if(am & 1) { /* bottom */ 4059 model->face[l].vertex[0] = edge[0]; model->face[l].vertex[1] = edge[1]; model->face[l].vertex[2] = edge[2]; 4060 model->face[l+1].vertex[0] = edge[2]; model->face[l+1].vertex[1] = edge[1]; model->face[l+1].vertex[2] = edge[3]; 4061 model->face[l].normal[0] = model->face[l].normal[1] = model->face[l].normal[2] = 4062 model->face[l+1].normal[0] = model->face[l+1].normal[1] = model->face[l+1].normal[2] = enorm; 4063 l += 2; 4064 } 4065 if(am & 2) { /* north */ 4066 model->face[l].vertex[0] = edge[0]; model->face[l].vertex[1] = edge[4]; model->face[l].vertex[2] = edge[1]; 4067 model->face[l+1].vertex[0] = edge[1]; model->face[l+1].vertex[1] = edge[4]; model->face[l+1].vertex[2] = edge[5]; 4068 model->face[l].normal[0] = model->face[l].normal[1] = model->face[l].normal[2] = 4069 model->face[l+1].normal[0] = model->face[l+1].normal[1] = model->face[l+1].normal[2] = enorm+1; 4070 l += 2; 4071 } 4072 if(am & 4) { /* west */ 4073 model->face[l].vertex[0] = edge[0]; model->face[l].vertex[1] = edge[2]; model->face[l].vertex[2] = edge[4]; 4074 model->face[l+1].vertex[0] = edge[2]; model->face[l+1].vertex[1] = edge[6]; model->face[l+1].vertex[2] = edge[4]; 4075 model->face[l].normal[0] = model->face[l].normal[1] = model->face[l].normal[2] = 4076 model->face[l+1].normal[0] = model->face[l+1].normal[1] = model->face[l+1].normal[2] = enorm+2; 4077 l += 2; 4078 } 4079 if(am & 8) { /* top */ 4080 model->face[l].vertex[0] = edge[4]; model->face[l].vertex[1] = edge[6]; model->face[l].vertex[2] = edge[5]; 4081 model->face[l+1].vertex[0] = edge[5]; model->face[l+1].vertex[1] = edge[6]; model->face[l+1].vertex[2] = edge[7]; 4082 model->face[l].normal[0] = model->face[l].normal[1] = model->face[l].normal[2] = 4083 model->face[l+1].normal[0] = model->face[l+1].normal[1] = model->face[l+1].normal[2] = enorm+3; 4084 l += 2; 4085 } 4086 if(am & 16) { /* south */ 4087 model->face[l].vertex[0] = edge[2]; model->face[l].vertex[1] = edge[7]; model->face[l].vertex[2] = edge[6]; 4088 model->face[l+1].vertex[0] = edge[7]; model->face[l+1].vertex[1] = edge[2]; model->face[l+1].vertex[2] = edge[3]; 4089 model->face[l].normal[0] = model->face[l].normal[1] = model->face[l].normal[2] = 4090 model->face[l+1].normal[0] = model->face[l+1].normal[1] = model->face[l+1].normal[2] = enorm+4; 4091 l += 2; 4092 } 4093 if(am & 32) { /* east */ 4094 model->face[l].vertex[0] = edge[1]; model->face[l].vertex[1] = edge[5]; model->face[l].vertex[2] = edge[7]; 4095 model->face[l+1].vertex[0] = edge[1]; model->face[l+1].vertex[1] = edge[7]; model->face[l+1].vertex[2] = edge[3]; 4096 model->face[l].normal[0] = model->face[l].normal[1] = model->face[l].normal[2] = 4097 model->face[l+1].normal[0] = model->face[l+1].normal[1] = model->face[l+1].normal[2] = enorm+5; 4098 l += 2; 4099 } 4100 } 4101 } 4102 } 4103 } 4104 #endif 4105 #ifndef M3D_NONORMALS 4106 if(model->numface && model->face && neednorm) { 4107 /* if they are missing, calculate triangle normals into a temporary buffer */ 4108 norm = (m3dv_t*)M3D_MALLOC(model->numface * sizeof(m3dv_t)); 4109 if(!norm) goto memerr; 4110 for(i = 0, n = model->numvertex; i < model->numface; i++) 4111 if(model->face[i].normal[0] == M3D_UNDEF) { 4112 v0 = &model->vertex[model->face[i].vertex[0]]; 4113 v1 = &model->vertex[model->face[i].vertex[1]]; 4114 v2 = &model->vertex[model->face[i].vertex[2]]; 4115 va.x = v1->x - v0->x; va.y = v1->y - v0->y; va.z = v1->z - v0->z; 4116 vb.x = v2->x - v0->x; vb.y = v2->y - v0->y; vb.z = v2->z - v0->z; 4117 v0 = &norm[i]; 4118 v0->x = (va.y * vb.z) - (va.z * vb.y); 4119 v0->y = (va.z * vb.x) - (va.x * vb.z); 4120 v0->z = (va.x * vb.y) - (va.y * vb.x); 4121 w = _m3d_rsq((v0->x * v0->x) + (v0->y * v0->y) + (v0->z * v0->z)); 4122 v0->x *= w; v0->y *= w; v0->z *= w; 4123 model->face[i].normal[0] = model->face[i].vertex[0] + n; 4124 model->face[i].normal[1] = model->face[i].vertex[1] + n; 4125 model->face[i].normal[2] = model->face[i].vertex[2] + n; 4126 } 4127 /* this is the fast way, we don't care if a normal is repeated in model->vertex */ 4128 M3D_LOG("Generating normals"); 4129 model->flags |= M3D_FLG_GENNORM; 4130 model->numvertex <<= 1; 4131 model->vertex = (m3dv_t*)M3D_REALLOC(model->vertex, model->numvertex * sizeof(m3dv_t)); 4132 if(!model->vertex) goto memerr; 4133 memset(&model->vertex[n], 0, n * sizeof(m3dv_t)); 4134 for(i = 0; i < model->numface; i++) 4135 for(j = 0; j < 3; j++) { 4136 v0 = &model->vertex[model->face[i].vertex[j] + n]; 4137 v0->x += norm[i].x; 4138 v0->y += norm[i].y; 4139 v0->z += norm[i].z; 4140 } 4141 /* for each vertex, take the average of the temporary normals and use that */ 4142 for(i = 0, v0 = &model->vertex[n]; i < n; i++, v0++) { 4143 w = _m3d_rsq((v0->x * v0->x) + (v0->y * v0->y) + (v0->z * v0->z)); 4144 v0->x *= w; v0->y *= w; v0->z *= w; 4145 v0->skinid = M3D_UNDEF; 4146 } 4147 M3D_FREE(norm); 4148 } 4149 #endif 4150 if(model->numbone && model->bone && model->numskin && model->skin && model->numvertex && model->vertex) { 4151 #ifndef M3D_NOWEIGHTS 4152 M3D_LOG("Generating weight cross-reference"); 4153 for(i = 0; i < model->numvertex; i++) { 4154 if(model->vertex[i].skinid < model->numskin) { 4155 sk = &model->skin[model->vertex[i].skinid]; 4156 w = (M3D_FLOAT)0.0; 4157 for(j = 0; j < M3D_NUMBONE && sk->boneid[j] != M3D_UNDEF && sk->weight[j] > (M3D_FLOAT)0.0; j++) 4158 w += sk->weight[j]; 4159 for(j = 0; j < M3D_NUMBONE && sk->boneid[j] != M3D_UNDEF && sk->weight[j] > (M3D_FLOAT)0.0; j++) { 4160 sk->weight[j] /= w; 4161 b = &model->bone[sk->boneid[j]]; 4162 k = b->numweight++; 4163 b->weight = (m3dw_t*)M3D_REALLOC(b->weight, b->numweight * sizeof(m3da_t)); 4164 if(!b->weight) goto memerr; 4165 b->weight[k].vertexid = i; 4166 b->weight[k].weight = sk->weight[j]; 4167 } 4168 } 4169 } 4170 #endif 4171 #ifndef M3D_NOANIMATION 4172 M3D_LOG("Calculating bone transformation matrices"); 4173 for(i = 0; i < model->numbone; i++) { 4174 b = &model->bone[i]; 4175 if(model->bone[i].parent == M3D_UNDEF) { 4176 _m3d_mat((M3D_FLOAT*)&b->mat4, &model->vertex[b->pos], &model->vertex[b->ori]); 4177 } else { 4178 _m3d_mat((M3D_FLOAT*)&r, &model->vertex[b->pos], &model->vertex[b->ori]); 4179 _m3d_mul((M3D_FLOAT*)&b->mat4, (M3D_FLOAT*)&model->bone[b->parent].mat4, (M3D_FLOAT*)&r); 4180 } 4181 } 4182 for(i = 0; i < model->numbone; i++) 4183 _m3d_inv((M3D_FLOAT*)&model->bone[i].mat4); 4184 #endif 4185 } 4186 #ifdef M3D_PROFILING 4187 gettimeofday(&tv0, NULL); 4188 tvd.tv_sec = tv0.tv_sec - tv1.tv_sec; 4189 tvd.tv_usec = tv0.tv_usec - tv1.tv_usec; 4190 if(tvd.tv_usec < 0) { tvd.tv_sec--; tvd.tv_usec += 1000000L; } 4191 printf(" Post-process %ld.%06ld sec\n", tvd.tv_sec, tvd.tv_usec); 4192 #endif 4193 } 4194 return model; 4195 } 4196 4197 /** 4198 * Calculates skeletons for animation frames, returns a working copy (should be freed after use) 4199 */ 4200 m3dtr_t *m3d_frame(m3d_t *model, M3D_INDEX actionid, M3D_INDEX frameid, m3dtr_t *skeleton) 4201 { 4202 unsigned int i; 4203 M3D_INDEX s = frameid; 4204 m3dfr_t *fr; 4205 4206 if(!model || !model->numbone || !model->bone || (actionid != M3D_UNDEF && (!model->action || 4207 actionid >= model->numaction || frameid >= model->action[actionid].numframe))) { 4208 model->errcode = M3D_ERR_UNKFRAME; 4209 return skeleton; 4210 } 4211 model->errcode = M3D_SUCCESS; 4212 if(!skeleton) { 4213 skeleton = (m3dtr_t*)M3D_MALLOC(model->numbone * sizeof(m3dtr_t)); 4214 if(!skeleton) { 4215 model->errcode = M3D_ERR_ALLOC; 4216 return NULL; 4217 } 4218 goto gen; 4219 } 4220 if(actionid == M3D_UNDEF || !frameid) { 4221 gen: s = 0; 4222 for(i = 0; i < model->numbone; i++) { 4223 skeleton[i].boneid = i; 4224 skeleton[i].pos = model->bone[i].pos; 4225 skeleton[i].ori = model->bone[i].ori; 4226 } 4227 } 4228 if(actionid < model->numaction && (frameid || !model->action[actionid].frame[0].msec)) { 4229 for(; s <= frameid; s++) { 4230 fr = &model->action[actionid].frame[s]; 4231 for(i = 0; i < fr->numtransform; i++) { 4232 skeleton[fr->transform[i].boneid].pos = fr->transform[i].pos; 4233 skeleton[fr->transform[i].boneid].ori = fr->transform[i].ori; 4234 } 4235 } 4236 } 4237 return skeleton; 4238 } 4239 4240 #ifndef M3D_NOANIMATION 4241 /** 4242 * Returns interpolated animation-pose, a working copy (should be freed after use) 4243 */ 4244 m3db_t *m3d_pose(m3d_t *model, M3D_INDEX actionid, uint32_t msec) 4245 { 4246 unsigned int i, j, l; 4247 M3D_FLOAT r[16], t, c, d, s; 4248 m3db_t *ret; 4249 m3dv_t *v, *p, *f; 4250 m3dtr_t *tmp; 4251 m3dfr_t *fr; 4252 4253 if(!model || !model->numbone || !model->bone) { 4254 model->errcode = M3D_ERR_UNKFRAME; 4255 return NULL; 4256 } 4257 ret = (m3db_t*)M3D_MALLOC(model->numbone * sizeof(m3db_t)); 4258 if(!ret) { 4259 model->errcode = M3D_ERR_ALLOC; 4260 return NULL; 4261 } 4262 memcpy(ret, model->bone, model->numbone * sizeof(m3db_t)); 4263 for(i = 0; i < model->numbone; i++) 4264 _m3d_inv((M3D_FLOAT*)&ret[i].mat4); 4265 if(!model->action || actionid >= model->numaction) { 4266 model->errcode = M3D_ERR_UNKFRAME; 4267 return ret; 4268 } 4269 msec %= model->action[actionid].durationmsec; 4270 model->errcode = M3D_SUCCESS; 4271 fr = &model->action[actionid].frame[0]; 4272 for(j = l = 0; j < model->action[actionid].numframe && model->action[actionid].frame[j].msec <= msec; j++) { 4273 fr = &model->action[actionid].frame[j]; 4274 l = fr->msec; 4275 for(i = 0; i < fr->numtransform; i++) { 4276 ret[fr->transform[i].boneid].pos = fr->transform[i].pos; 4277 ret[fr->transform[i].boneid].ori = fr->transform[i].ori; 4278 } 4279 } 4280 if(l != msec) { 4281 model->vertex = (m3dv_t*)M3D_REALLOC(model->vertex, (model->numvertex + 2 * model->numbone) * sizeof(m3dv_t)); 4282 if(!model->vertex) { 4283 free(ret); 4284 model->errcode = M3D_ERR_ALLOC; 4285 return NULL; 4286 } 4287 tmp = (m3dtr_t*)M3D_MALLOC(model->numbone * sizeof(m3dtr_t)); 4288 if(tmp) { 4289 for(i = 0; i < model->numbone; i++) { 4290 tmp[i].pos = ret[i].pos; 4291 tmp[i].ori = ret[i].ori; 4292 } 4293 fr = &model->action[actionid].frame[j % model->action[actionid].numframe]; 4294 t = l >= fr->msec ? (M3D_FLOAT)1.0 : (M3D_FLOAT)(msec - l) / (M3D_FLOAT)(fr->msec - l); 4295 for(i = 0; i < fr->numtransform; i++) { 4296 tmp[fr->transform[i].boneid].pos = fr->transform[i].pos; 4297 tmp[fr->transform[i].boneid].ori = fr->transform[i].ori; 4298 } 4299 for(i = 0, j = model->numvertex; i < model->numbone; i++) { 4300 /* interpolation of position */ 4301 if(ret[i].pos != tmp[i].pos) { 4302 p = &model->vertex[ret[i].pos]; 4303 f = &model->vertex[tmp[i].pos]; 4304 v = &model->vertex[j]; 4305 v->x = p->x + t * (f->x - p->x); 4306 v->y = p->y + t * (f->y - p->y); 4307 v->z = p->z + t * (f->z - p->z); 4308 ret[i].pos = j++; 4309 } 4310 /* interpolation of orientation */ 4311 if(ret[i].ori != tmp[i].ori) { 4312 p = &model->vertex[ret[i].ori]; 4313 f = &model->vertex[tmp[i].ori]; 4314 v = &model->vertex[j]; 4315 d = p->w * f->w + p->x * f->x + p->y * f->y + p->z * f->z; 4316 if(d < 0) { d = -d; s = (M3D_FLOAT)-1.0; } else s = (M3D_FLOAT)1.0; 4317 #if 0 4318 /* don't use SLERP, requires two more variables, libm linkage and it is slow (but nice) */ 4319 a = (M3D_FLOAT)1.0 - t; b = t; 4320 if(d < (M3D_FLOAT)0.999999) { c = acosf(d); b = 1 / sinf(c); a = sinf(a * c) * b; b *= sinf(t * c) * s; } 4321 v->x = p->x * a + f->x * b; 4322 v->y = p->y * a + f->y * b; 4323 v->z = p->z * a + f->z * b; 4324 v->w = p->w * a + f->w * b; 4325 #else 4326 /* approximated NLERP, original approximation by Arseny Kapoulkine, heavily optimized by me */ 4327 c = t - (M3D_FLOAT)0.5; t += t * c * (t - (M3D_FLOAT)1.0) * (((M3D_FLOAT)1.0904 + d * ((M3D_FLOAT)-3.2452 + 4328 d * ((M3D_FLOAT)3.55645 - d * (M3D_FLOAT)1.43519))) * c * c + ((M3D_FLOAT)0.848013 + d * 4329 ((M3D_FLOAT)-1.06021 + d * (M3D_FLOAT)0.215638))); 4330 v->x = p->x + t * (s * f->x - p->x); 4331 v->y = p->y + t * (s * f->y - p->y); 4332 v->z = p->z + t * (s * f->z - p->z); 4333 v->w = p->w + t * (s * f->w - p->w); 4334 d = _m3d_rsq(v->w * v->w + v->x * v->x + v->y * v->y + v->z * v->z); 4335 v->x *= d; v->y *= d; v->z *= d; v->w *= d; 4336 #endif 4337 ret[i].ori = j++; 4338 } 4339 } 4340 M3D_FREE(tmp); 4341 } 4342 } 4343 for(i = 0; i < model->numbone; i++) { 4344 if(ret[i].parent == M3D_UNDEF) { 4345 _m3d_mat((M3D_FLOAT*)&ret[i].mat4, &model->vertex[ret[i].pos], &model->vertex[ret[i].ori]); 4346 } else { 4347 _m3d_mat((M3D_FLOAT*)&r, &model->vertex[ret[i].pos], &model->vertex[ret[i].ori]); 4348 _m3d_mul((M3D_FLOAT*)&ret[i].mat4, (M3D_FLOAT*)&ret[ret[i].parent].mat4, (M3D_FLOAT*)&r); 4349 } 4350 } 4351 return ret; 4352 } 4353 4354 #endif /* M3D_NOANIMATION */ 4355 4356 #endif /* M3D_IMPLEMENTATION */ 4357 4358 #if !defined(M3D_NODUP) && (!defined(M3D_NOIMPORTER) || defined(M3D_EXPORTER)) 4359 /** 4360 * Free the in-memory model 4361 */ 4362 void m3d_free(m3d_t *model) 4363 { 4364 unsigned int i, j; 4365 4366 if(!model) return; 4367 #ifdef M3D_ASCII 4368 /* if model imported from ASCII, we have to free all strings as well */ 4369 if(model->flags & M3D_FLG_FREESTR) { 4370 if(model->name) M3D_FREE(model->name); 4371 if(model->license) M3D_FREE(model->license); 4372 if(model->author) M3D_FREE(model->author); 4373 if(model->desc) M3D_FREE(model->desc); 4374 if(model->bone) 4375 for(i = 0; i < model->numbone; i++) 4376 if(model->bone[i].name) 4377 M3D_FREE(model->bone[i].name); 4378 if(model->shape) 4379 for(i = 0; i < model->numshape; i++) 4380 if(model->shape[i].name) 4381 M3D_FREE(model->shape[i].name); 4382 if(model->numvoxtype) 4383 for(i = 0; i < model->numvoxtype; i++) { 4384 if(model->voxtype[i].name) 4385 M3D_FREE(model->voxtype[i].name); 4386 for(j = 0; j < model->voxtype[i].numitem; j++) 4387 if(model->voxtype[i].item[j].name) 4388 M3D_FREE(model->voxtype[i].item[j].name); 4389 } 4390 if(model->numvoxel) 4391 for(i = 0; i < model->numvoxel; i++) 4392 if(model->voxel[i].name) 4393 M3D_FREE(model->voxel[i].name); 4394 if(model->material) 4395 for(i = 0; i < model->nummaterial; i++) 4396 if(model->material[i].name) 4397 M3D_FREE(model->material[i].name); 4398 if(model->action) 4399 for(i = 0; i < model->numaction; i++) 4400 if(model->action[i].name) 4401 M3D_FREE(model->action[i].name); 4402 if(model->texture) 4403 for(i = 0; i < model->numtexture; i++) 4404 if(model->texture[i].name) 4405 M3D_FREE(model->texture[i].name); 4406 if(model->inlined) 4407 for(i = 0; i < model->numinlined; i++) { 4408 if(model->inlined[i].name) 4409 M3D_FREE(model->inlined[i].name); 4410 if(model->inlined[i].data) 4411 M3D_FREE(model->inlined[i].data); 4412 } 4413 if(model->extra) 4414 for(i = 0; i < model->numextra; i++) 4415 if(model->extra[i]) 4416 M3D_FREE(model->extra[i]); 4417 if(model->label) 4418 for(i = 0; i < model->numlabel; i++) { 4419 if(model->label[i].name) { 4420 for(j = i + 1; j < model->numlabel; j++) 4421 if(model->label[j].name == model->label[i].name) 4422 model->label[j].name = NULL; 4423 M3D_FREE(model->label[i].name); 4424 } 4425 if(model->label[i].lang) { 4426 for(j = i + 1; j < model->numlabel; j++) 4427 if(model->label[j].lang == model->label[i].lang) 4428 model->label[j].lang = NULL; 4429 M3D_FREE(model->label[i].lang); 4430 } 4431 if(model->label[i].text) 4432 M3D_FREE(model->label[i].text); 4433 } 4434 if(model->preview.data) 4435 M3D_FREE(model->preview.data); 4436 } 4437 #endif 4438 if(model->flags & M3D_FLG_FREERAW) M3D_FREE(model->raw); 4439 4440 if(model->tmap) M3D_FREE(model->tmap); 4441 if(model->bone) { 4442 for(i = 0; i < model->numbone; i++) 4443 if(model->bone[i].weight) 4444 M3D_FREE(model->bone[i].weight); 4445 M3D_FREE(model->bone); 4446 } 4447 if(model->skin) M3D_FREE(model->skin); 4448 if(model->vertex) M3D_FREE(model->vertex); 4449 if(model->face) M3D_FREE(model->face); 4450 if(model->voxtype) { 4451 for(i = 0; i < model->numvoxtype; i++) 4452 if(model->voxtype[i].item) 4453 M3D_FREE(model->voxtype[i].item); 4454 M3D_FREE(model->voxtype); 4455 } 4456 if(model->voxel) { 4457 for(i = 0; i < model->numvoxel; i++) 4458 if(model->voxel[i].data) 4459 M3D_FREE(model->voxel[i].data); 4460 M3D_FREE(model->voxel); 4461 } 4462 if(model->shape) { 4463 for(i = 0; i < model->numshape; i++) { 4464 if(model->shape[i].cmd) { 4465 for(j = 0; j < model->shape[i].numcmd; j++) 4466 if(model->shape[i].cmd[j].arg) M3D_FREE(model->shape[i].cmd[j].arg); 4467 M3D_FREE(model->shape[i].cmd); 4468 } 4469 } 4470 M3D_FREE(model->shape); 4471 } 4472 if(model->material && !(model->flags & M3D_FLG_MTLLIB)) { 4473 for(i = 0; i < model->nummaterial; i++) 4474 if(model->material[i].prop) M3D_FREE(model->material[i].prop); 4475 M3D_FREE(model->material); 4476 } 4477 if(model->texture) { 4478 for(i = 0; i < model->numtexture; i++) 4479 if(model->texture[i].d) M3D_FREE(model->texture[i].d); 4480 M3D_FREE(model->texture); 4481 } 4482 if(model->action) { 4483 for(i = 0; i < model->numaction; i++) { 4484 if(model->action[i].frame) { 4485 for(j = 0; j < model->action[i].numframe; j++) 4486 if(model->action[i].frame[j].transform) M3D_FREE(model->action[i].frame[j].transform); 4487 M3D_FREE(model->action[i].frame); 4488 } 4489 } 4490 M3D_FREE(model->action); 4491 } 4492 if(model->label) M3D_FREE(model->label); 4493 if(model->inlined) M3D_FREE(model->inlined); 4494 if(model->extra) M3D_FREE(model->extra); 4495 free(model); 4496 } 4497 #endif 4498 4499 #ifdef M3D_EXPORTER 4500 typedef struct { 4501 char *str; 4502 uint32_t offs; 4503 } m3dstr_t; 4504 4505 typedef struct { 4506 m3dti_t data; 4507 M3D_INDEX oldidx; 4508 M3D_INDEX newidx; 4509 } m3dtisave_t; 4510 4511 typedef struct { 4512 m3dv_t data; 4513 M3D_INDEX oldidx; 4514 M3D_INDEX newidx; 4515 unsigned char norm; 4516 } m3dvsave_t; 4517 4518 typedef struct { 4519 m3ds_t data; 4520 M3D_INDEX oldidx; 4521 M3D_INDEX newidx; 4522 } m3dssave_t; 4523 4524 typedef struct { 4525 m3df_t data; 4526 int group; 4527 uint8_t opacity; 4528 } m3dfsave_t; 4529 4530 /* create unique list of strings */ 4531 static m3dstr_t *_m3d_addstr(m3dstr_t *str, uint32_t *numstr, char *s) 4532 { 4533 uint32_t i; 4534 if(!s || !*s) return str; 4535 if(str) { 4536 for(i = 0; i < *numstr; i++) 4537 if(str[i].str == s || !strcmp(str[i].str, s)) return str; 4538 } 4539 str = (m3dstr_t*)M3D_REALLOC(str, ((*numstr) + 1) * sizeof(m3dstr_t)); 4540 str[*numstr].str = s; 4541 str[*numstr].offs = 0; 4542 (*numstr)++; 4543 return str; 4544 } 4545 4546 /* add strings to header */ 4547 m3dhdr_t *_m3d_addhdr(m3dhdr_t *h, m3dstr_t *s) 4548 { 4549 int i; 4550 char *safe = _m3d_safestr(s->str, 0); 4551 i = (int)strlen(safe); 4552 h = (m3dhdr_t*)M3D_REALLOC(h, h->length + i+1); 4553 if(!h) { M3D_FREE(safe); return NULL; } 4554 memcpy((uint8_t*)h + h->length, safe, i+1); 4555 s->offs = h->length - 16; 4556 h->length += i+1; 4557 M3D_FREE(safe); 4558 return h; 4559 } 4560 4561 /* return offset of string */ 4562 static uint32_t _m3d_stridx(m3dstr_t *str, uint32_t numstr, char *s) 4563 { 4564 uint32_t i; 4565 char *safe; 4566 if(!s || !*s) return 0; 4567 if(str) { 4568 safe = _m3d_safestr(s, 0); 4569 if(!safe) return 0; 4570 if(!*safe) { 4571 free(safe); 4572 return 0; 4573 } 4574 for(i = 0; i < numstr; i++) 4575 if(!strcmp(str[i].str, s)) { 4576 free(safe); 4577 return str[i].offs; 4578 } 4579 free(safe); 4580 } 4581 return 0; 4582 } 4583 4584 /* compare to faces by their material */ 4585 static int _m3d_facecmp(const void *a, const void *b) { 4586 const m3dfsave_t *A = (const m3dfsave_t*)a, *B = (const m3dfsave_t*)b; 4587 return A->group != B->group ? A->group - B->group : (A->opacity != B->opacity ? (int)B->opacity - (int)A->opacity : 4588 (int)A->data.materialid - (int)B->data.materialid); 4589 } 4590 /* compare face groups */ 4591 static int _m3d_grpcmp(const void *a, const void *b) { return *((uint32_t*)a) - *((uint32_t*)b); } 4592 /* compare UVs */ 4593 static int _m3d_ticmp(const void *a, const void *b) { return memcmp(a, b, sizeof(m3dti_t)); } 4594 /* compare skin groups */ 4595 static int _m3d_skincmp(const void *a, const void *b) { return memcmp(a, b, sizeof(m3ds_t)); } 4596 /* compare vertices */ 4597 static int _m3d_vrtxcmp(const void *a, const void *b) { 4598 int c = memcmp(a, b, 3 * sizeof(M3D_FLOAT)); 4599 if(c) return c; 4600 c = ((m3dvsave_t*)a)->norm - ((m3dvsave_t*)b)->norm; 4601 if(c) return c; 4602 return memcmp(a, b, sizeof(m3dv_t)); 4603 } 4604 /* compare labels */ 4605 static _inline int _m3d_strcmp(char *a, char *b) 4606 { 4607 if(a == NULL && b != NULL) return -1; 4608 if(a != NULL && b == NULL) return 1; 4609 if(a == NULL && b == NULL) return 0; 4610 return strcmp(a, b); 4611 } 4612 static int _m3d_lblcmp(const void *a, const void *b) { 4613 const m3dl_t *A = (const m3dl_t*)a, *B = (const m3dl_t*)b; 4614 int c = _m3d_strcmp(A->lang, B->lang); 4615 if(!c) c = _m3d_strcmp(A->name, B->name); 4616 if(!c) c = _m3d_strcmp(A->text, B->text); 4617 return c; 4618 } 4619 /* compare two colors by HSV value */ 4620 _inline static int _m3d_cmapcmp(const void *a, const void *b) 4621 { 4622 uint8_t *A = (uint8_t*)a, *B = (uint8_t*)b; 4623 _register int m, vA, vB; 4624 /* get HSV value for A */ 4625 m = A[2] < A[1]? A[2] : A[1]; if(A[0] < m) m = A[0]; 4626 vA = A[2] > A[1]? A[2] : A[1]; if(A[0] > vA) vA = A[0]; 4627 /* get HSV value for B */ 4628 m = B[2] < B[1]? B[2] : B[1]; if(B[0] < m) m = B[0]; 4629 vB = B[2] > B[1]? B[2] : B[1]; if(B[0] > vB) vB = B[0]; 4630 return vA - vB; 4631 } 4632 4633 /* create sorted list of colors */ 4634 static uint32_t *_m3d_addcmap(uint32_t *cmap, uint32_t *numcmap, uint32_t color) 4635 { 4636 uint32_t i; 4637 if(cmap) { 4638 for(i = 0; i < *numcmap; i++) 4639 if(cmap[i] == color) return cmap; 4640 } 4641 cmap = (uint32_t*)M3D_REALLOC(cmap, ((*numcmap) + 1) * sizeof(uint32_t)); 4642 for(i = 0; i < *numcmap && _m3d_cmapcmp(&color, &cmap[i]) > 0; i++); 4643 if(i < *numcmap) memmove(&cmap[i+1], &cmap[i], ((*numcmap) - i)*sizeof(uint32_t)); 4644 cmap[i] = color; 4645 (*numcmap)++; 4646 return cmap; 4647 } 4648 4649 /* look up a color and return its index */ 4650 static uint32_t _m3d_cmapidx(uint32_t *cmap, uint32_t numcmap, uint32_t color) 4651 { 4652 uint32_t i; 4653 if(numcmap >= 65536) 4654 return color; 4655 for(i = 0; i < numcmap; i++) 4656 if(cmap[i] == color) return i; 4657 return 0; 4658 } 4659 4660 /* add index to output */ 4661 static unsigned char *_m3d_addidx(unsigned char *out, char type, uint32_t idx) { 4662 switch(type) { 4663 case 1: *out++ = (uint8_t)(idx); break; 4664 case 2: *((uint16_t*)out) = (uint16_t)(idx); out += 2; break; 4665 case 4: *((uint32_t*)out) = (uint32_t)(idx); out += 4; break; 4666 /* case 0: case 8: break; */ 4667 } 4668 return out; 4669 } 4670 4671 /* round a vertex position */ 4672 static void _m3d_round(int quality, m3dv_t *src, m3dv_t *dst) 4673 { 4674 _register int t; 4675 /* copy additional attributes */ 4676 if(src != dst) memcpy(dst, src, sizeof(m3dv_t)); 4677 /* round according to quality */ 4678 switch(quality) { 4679 case M3D_EXP_INT8: 4680 t = (int)(src->x * 127 + (src->x >= 0 ? (M3D_FLOAT)0.5 : (M3D_FLOAT)-0.5)); dst->x = (M3D_FLOAT)t / (M3D_FLOAT)127.0; 4681 t = (int)(src->y * 127 + (src->y >= 0 ? (M3D_FLOAT)0.5 : (M3D_FLOAT)-0.5)); dst->y = (M3D_FLOAT)t / (M3D_FLOAT)127.0; 4682 t = (int)(src->z * 127 + (src->z >= 0 ? (M3D_FLOAT)0.5 : (M3D_FLOAT)-0.5)); dst->z = (M3D_FLOAT)t / (M3D_FLOAT)127.0; 4683 t = (int)(src->w * 127 + (src->w >= 0 ? (M3D_FLOAT)0.5 : (M3D_FLOAT)-0.5)); dst->w = (M3D_FLOAT)t / (M3D_FLOAT)127.0; 4684 break; 4685 case M3D_EXP_INT16: 4686 t = (int)(src->x * 32767 + (src->x >= 0 ? (M3D_FLOAT)0.5 : (M3D_FLOAT)-0.5)); dst->x = (M3D_FLOAT)t / (M3D_FLOAT)32767.0; 4687 t = (int)(src->y * 32767 + (src->y >= 0 ? (M3D_FLOAT)0.5 : (M3D_FLOAT)-0.5)); dst->y = (M3D_FLOAT)t / (M3D_FLOAT)32767.0; 4688 t = (int)(src->z * 32767 + (src->z >= 0 ? (M3D_FLOAT)0.5 : (M3D_FLOAT)-0.5)); dst->z = (M3D_FLOAT)t / (M3D_FLOAT)32767.0; 4689 t = (int)(src->w * 32767 + (src->w >= 0 ? (M3D_FLOAT)0.5 : (M3D_FLOAT)-0.5)); dst->w = (M3D_FLOAT)t / (M3D_FLOAT)32767.0; 4690 break; 4691 } 4692 if(dst->x == (M3D_FLOAT)-0.0) dst->x = (M3D_FLOAT)0.0; 4693 if(dst->y == (M3D_FLOAT)-0.0) dst->y = (M3D_FLOAT)0.0; 4694 if(dst->z == (M3D_FLOAT)-0.0) dst->z = (M3D_FLOAT)0.0; 4695 if(dst->w == (M3D_FLOAT)-0.0) dst->w = (M3D_FLOAT)0.0; 4696 } 4697 4698 #ifdef M3D_ASCII 4699 /* add a bone to ascii output */ 4700 static char *_m3d_prtbone(char *ptr, m3db_t *bone, M3D_INDEX numbone, M3D_INDEX parent, uint32_t level, M3D_INDEX *vrtxidx) 4701 { 4702 uint32_t i, j; 4703 char *sn; 4704 4705 if(level > M3D_BONEMAXLEVEL || !bone) return ptr; 4706 for(i = 0; i < numbone; i++) { 4707 if(bone[i].parent == parent) { 4708 for(j = 0; j < level; j++) *ptr++ = '/'; 4709 sn = _m3d_safestr(bone[i].name, 0); 4710 ptr += sprintf(ptr, "%d %d %s\r\n", vrtxidx[bone[i].pos], vrtxidx[bone[i].ori], sn); 4711 M3D_FREE(sn); 4712 ptr = _m3d_prtbone(ptr, bone, numbone, i, level + 1, vrtxidx); 4713 } 4714 } 4715 return ptr; 4716 } 4717 #endif 4718 4719 /** 4720 * Function to encode an in-memory model into on storage Model 3D format 4721 */ 4722 unsigned char *m3d_save(m3d_t *model, int quality, int flags, unsigned int *size) 4723 { 4724 #ifdef M3D_ASCII 4725 const char *ol; 4726 char *ptr; 4727 #endif 4728 char vc_s, vi_s, si_s, ci_s, ti_s, bi_s, nb_s, sk_s, fc_s, hi_s, fi_s, vd_s, vp_s; 4729 char *sn = NULL, *sl = NULL, *sa = NULL, *sd = NULL; 4730 unsigned char *out = NULL, *z = NULL, weights[M3D_NUMBONE < 8 ? 8 : M3D_NUMBONE], *norm = NULL; 4731 unsigned int i, j, k, l, n, o, len, chunklen, *length; 4732 int maxvox = 0, minvox = 0; 4733 M3D_FLOAT scale = (M3D_FLOAT)0.0, min_x, max_x, min_y, max_y, min_z, max_z, mw; 4734 M3D_INDEX last, *vrtxidx = NULL, *mtrlidx = NULL, *tmapidx = NULL, *skinidx = NULL; 4735 #ifdef M3D_VERTEXMAX 4736 M3D_INDEX lastp; 4737 #endif 4738 uint32_t idx, numcmap = 0, *cmap = NULL, numvrtx = 0, maxvrtx = 0, numtmap = 0, maxtmap = 0, numproc = 0; 4739 uint32_t numskin = 0, maxskin = 0, numstr = 0, maxt = 0, maxbone = 0, numgrp = 0, maxgrp = 0, *grpidx = NULL; 4740 uint8_t *opa = NULL; 4741 m3dcd_t *cd; 4742 m3dc_t *cmd; 4743 m3dstr_t *str = NULL; 4744 m3dvsave_t *vrtx = NULL, vertex; 4745 m3dtisave_t *tmap = NULL, tcoord; 4746 m3dssave_t *skin = NULL, sk; 4747 m3dfsave_t *face = NULL; 4748 m3dhdr_t *h = NULL; 4749 m3dm_t *m; 4750 m3da_t *a; 4751 4752 if(!model) { 4753 if(size) *size = 0; 4754 return NULL; 4755 } 4756 model->errcode = M3D_SUCCESS; 4757 #ifdef M3D_ASCII 4758 if(flags & M3D_EXP_ASCII) quality = M3D_EXP_DOUBLE; 4759 #endif 4760 vrtxidx = (M3D_INDEX*)M3D_MALLOC(model->numvertex * sizeof(M3D_INDEX)); 4761 if(!vrtxidx) goto memerr; 4762 memset(vrtxidx, 255, model->numvertex * sizeof(M3D_INDEX)); 4763 if(model->numvertex && !(flags & M3D_EXP_NONORMAL)){ 4764 norm = (unsigned char*)M3D_MALLOC(model->numvertex * sizeof(unsigned char)); 4765 if(!norm) goto memerr; 4766 memset(norm, 0, model->numvertex * sizeof(unsigned char)); 4767 } 4768 if(model->nummaterial && !(flags & M3D_EXP_NOMATERIAL)) { 4769 mtrlidx = (M3D_INDEX*)M3D_MALLOC(model->nummaterial * sizeof(M3D_INDEX)); 4770 if(!mtrlidx) goto memerr; 4771 memset(mtrlidx, 255, model->nummaterial * sizeof(M3D_INDEX)); 4772 opa = (uint8_t*)M3D_MALLOC(model->nummaterial * 2 * sizeof(M3D_INDEX)); 4773 if(!opa) goto memerr; 4774 memset(opa, 255, model->nummaterial * 2 * sizeof(M3D_INDEX)); 4775 } 4776 if(model->numtmap && !(flags & M3D_EXP_NOTXTCRD)) { 4777 tmapidx = (M3D_INDEX*)M3D_MALLOC(model->numtmap * sizeof(M3D_INDEX)); 4778 if(!tmapidx) goto memerr; 4779 memset(tmapidx, 255, model->numtmap * sizeof(M3D_INDEX)); 4780 } 4781 /** collect array elements that are actually referenced **/ 4782 if(!(flags & M3D_EXP_NOFACE)) { 4783 /* face */ 4784 if(model->numface && model->face) { 4785 M3D_LOG("Processing mesh face"); 4786 face = (m3dfsave_t*)M3D_MALLOC(model->numface * sizeof(m3dfsave_t)); 4787 if(!face) goto memerr; 4788 for(i = 0; i < model->numface; i++) { 4789 memcpy(&face[i].data, &model->face[i], sizeof(m3df_t)); 4790 face[i].group = 0; 4791 face[i].opacity = 255; 4792 if(!(flags & M3D_EXP_NOMATERIAL) && model->face[i].materialid < model->nummaterial) { 4793 if(model->material[model->face[i].materialid].numprop) { 4794 mtrlidx[model->face[i].materialid] = 0; 4795 if(opa[model->face[i].materialid * 2]) { 4796 m = &model->material[model->face[i].materialid]; 4797 for(j = 0; j < m->numprop; j++) 4798 if(m->prop[j].type == m3dp_Kd) { 4799 opa[model->face[i].materialid * 2 + 1] = ((uint8_t*)&m->prop[j].value.color)[3]; 4800 break; 4801 } 4802 for(j = 0; j < m->numprop; j++) 4803 if(m->prop[j].type == m3dp_d) { 4804 opa[model->face[i].materialid * 2 + 1] = (uint8_t)(m->prop[j].value.fnum * 255); 4805 break; 4806 } 4807 opa[model->face[i].materialid * 2] = 0; 4808 } 4809 face[i].opacity = opa[model->face[i].materialid * 2 + 1]; 4810 } else 4811 face[i].data.materialid = M3D_UNDEF; 4812 } 4813 for(j = 0; j < 3; j++) { 4814 k = model->face[i].vertex[j]; 4815 if(k < model->numvertex) 4816 vrtxidx[k] = 0; 4817 if(!(flags & M3D_EXP_NOCMAP)) { 4818 cmap = _m3d_addcmap(cmap, &numcmap, model->vertex[k].color); 4819 if(!cmap) goto memerr; 4820 } 4821 k = model->face[i].normal[j]; 4822 if(k < model->numvertex && !(flags & M3D_EXP_NONORMAL)) { 4823 vrtxidx[k] = 0; 4824 norm[k] = 1; 4825 } 4826 k = model->face[i].texcoord[j]; 4827 if(k < model->numtmap && !(flags & M3D_EXP_NOTXTCRD)) 4828 tmapidx[k] = 0; 4829 #ifdef M3D_VERTEXMAX 4830 k = model->face[i].vertmax[j]; 4831 if(k < model->numvertex && !(flags & M3D_EXP_NOVRTMAX)) 4832 vrtxidx[k] = 0; 4833 #endif 4834 } 4835 /* convert from CW to CCW */ 4836 if(flags & M3D_EXP_IDOSUCK) { 4837 j = face[i].data.vertex[1]; 4838 face[i].data.vertex[1] = face[i].data.vertex[2]; 4839 face[i].data.vertex[2] = j; 4840 j = face[i].data.normal[1]; 4841 face[i].data.normal[1] = face[i].data.normal[2]; 4842 face[i].data.normal[2] = j; 4843 j = face[i].data.texcoord[1]; 4844 face[i].data.texcoord[1] = face[i].data.texcoord[2]; 4845 face[i].data.texcoord[2] = j; 4846 #ifdef M3D_VERTEXMAX 4847 j = face[i].data.vertmax[1]; 4848 face[i].data.vertmax[1] = face[i].data.vertmax[2]; 4849 face[i].data.vertmax[2] = j; 4850 #endif 4851 } 4852 } 4853 } 4854 if((model->numvoxtype && model->voxtype) || (model->numvoxel && model->voxel)) { 4855 M3D_LOG("Processing voxel face"); 4856 for(i = 0; i < model->numvoxtype; i++) { 4857 str = _m3d_addstr(str, &numstr, model->voxtype[i].name); 4858 if(model->voxtype[i].name && !str) goto memerr; 4859 if(!(flags & M3D_EXP_NOCMAP)) { 4860 cmap = _m3d_addcmap(cmap, &numcmap, model->voxtype[i].color); 4861 if(!cmap) goto memerr; 4862 } 4863 for(j = 0; j < model->voxtype[i].numitem; j++) { 4864 str = _m3d_addstr(str, &numstr, model->voxtype[i].item[j].name); 4865 if(model->voxtype[i].item[j].name && !str) goto memerr; 4866 } 4867 } 4868 for(i = 0; i < model->numvoxel; i++) { 4869 str = _m3d_addstr(str, &numstr, model->voxel[i].name); 4870 if(model->voxel[i].name && !str) goto memerr; 4871 if(model->voxel[i].x < minvox) minvox = model->voxel[i].x; 4872 if(model->voxel[i].x + (int)model->voxel[i].w > maxvox) maxvox = model->voxel[i].x + model->voxel[i].w; 4873 if(model->voxel[i].y < minvox) minvox = model->voxel[i].y; 4874 if(model->voxel[i].y + (int)model->voxel[i].h > maxvox) maxvox = model->voxel[i].y + model->voxel[i].h; 4875 if(model->voxel[i].z < minvox) minvox = model->voxel[i].z; 4876 if(model->voxel[i].z + (int)model->voxel[i].d > maxvox) maxvox = model->voxel[i].z + model->voxel[i].d; 4877 } 4878 } 4879 if(model->numshape && model->shape) { 4880 M3D_LOG("Processing shape face"); 4881 for(i = 0; i < model->numshape; i++) { 4882 if(!model->shape[i].numcmd) continue; 4883 str = _m3d_addstr(str, &numstr, model->shape[i].name); 4884 if(model->shape[i].name && !str) goto memerr; 4885 for(j = 0; j < model->shape[i].numcmd; j++) { 4886 cmd = &model->shape[i].cmd[j]; 4887 if(cmd->type >= (unsigned int)(sizeof(m3d_commandtypes)/sizeof(m3d_commandtypes[0])) || !cmd->arg) 4888 continue; 4889 if(cmd->type == m3dc_mesh) { 4890 if(numgrp + 2 < maxgrp) { 4891 maxgrp += 1024; 4892 grpidx = (uint32_t*)realloc(grpidx, maxgrp * sizeof(uint32_t)); 4893 if(!grpidx) goto memerr; 4894 if(!numgrp) { 4895 grpidx[0] = 0; 4896 grpidx[1] = model->numface; 4897 numgrp += 2; 4898 } 4899 } 4900 grpidx[numgrp + 0] = cmd->arg[0]; 4901 grpidx[numgrp + 1] = cmd->arg[0] + cmd->arg[1]; 4902 numgrp += 2; 4903 } 4904 cd = &m3d_commandtypes[cmd->type]; 4905 for(k = n = 0, l = cd->p; k < l; k++) 4906 switch(cd->a[((k - n) % (cd->p - n)) + n]) { 4907 case m3dcp_mi_t: 4908 if(!(flags & M3D_EXP_NOMATERIAL) && cmd->arg[k] < model->nummaterial) 4909 mtrlidx[cmd->arg[k]] = 0; 4910 break; 4911 case m3dcp_ti_t: 4912 if(!(flags & M3D_EXP_NOTXTCRD) && cmd->arg[k] < model->numtmap) 4913 tmapidx[cmd->arg[k]] = 0; 4914 break; 4915 case m3dcp_qi_t: 4916 case m3dcp_vi_t: 4917 if(cmd->arg[k] < model->numvertex) 4918 vrtxidx[cmd->arg[k]] = 0; 4919 break; 4920 case m3dcp_va_t: 4921 n = k + 1; l += (cmd->arg[k] - 1) * (cd->p - k - 1); 4922 break; 4923 } 4924 } 4925 } 4926 } 4927 if(model->numface && face) { 4928 if(numgrp && grpidx) { 4929 qsort(grpidx, numgrp, sizeof(uint32_t), _m3d_grpcmp); 4930 for(i = j = 0; i < model->numface && j < numgrp; i++) { 4931 while(j < numgrp && grpidx[j] < i) j++; 4932 face[i].group = j; 4933 } 4934 } 4935 qsort(face, model->numface, sizeof(m3dfsave_t), _m3d_facecmp); 4936 } 4937 if(grpidx) { M3D_FREE(grpidx); grpidx = NULL; } 4938 if(model->numlabel && model->label) { 4939 M3D_LOG("Processing annotation labels"); 4940 for(i = 0; i < model->numlabel; i++) { 4941 str = _m3d_addstr(str, &numstr, model->label[i].name); 4942 str = _m3d_addstr(str, &numstr, model->label[i].lang); 4943 str = _m3d_addstr(str, &numstr, model->label[i].text); 4944 if(!(flags & M3D_EXP_NOCMAP)) { 4945 cmap = _m3d_addcmap(cmap, &numcmap, model->label[i].color); 4946 if(!cmap) goto memerr; 4947 } 4948 if(model->label[i].vertexid < model->numvertex) 4949 vrtxidx[model->label[i].vertexid] = 0; 4950 } 4951 qsort(model->label, model->numlabel, sizeof(m3dl_t), _m3d_lblcmp); 4952 } 4953 } else if(!(flags & M3D_EXP_NOMATERIAL)) { 4954 /* without a face, simply add all materials, because it can be an mtllib */ 4955 for(i = 0; i < model->nummaterial; i++) 4956 mtrlidx[i] = i; 4957 } 4958 /* bind-pose skeleton */ 4959 if(model->numbone && model->bone && !(flags & M3D_EXP_NOBONE)) { 4960 M3D_LOG("Processing bones"); 4961 for(i = 0; i < model->numbone; i++) { 4962 str = _m3d_addstr(str, &numstr, model->bone[i].name); 4963 if(!str) goto memerr; 4964 k = model->bone[i].pos; 4965 if(k < model->numvertex) 4966 vrtxidx[k] = 0; 4967 k = model->bone[i].ori; 4968 if(k < model->numvertex) 4969 vrtxidx[k] = 0; 4970 } 4971 } 4972 /* actions, animated skeleton poses */ 4973 if(model->numaction && model->action && !(flags & M3D_EXP_NOACTION)) { 4974 M3D_LOG("Processing action list"); 4975 for(j = 0; j < model->numaction; j++) { 4976 a = &model->action[j]; 4977 str = _m3d_addstr(str, &numstr, a->name); 4978 if(!str) goto memerr; 4979 if(a->numframe > 65535) a->numframe = 65535; 4980 for(i = 0; i < a->numframe; i++) { 4981 for(l = 0; l < a->frame[i].numtransform; l++) { 4982 k = a->frame[i].transform[l].pos; 4983 if(k < model->numvertex) 4984 vrtxidx[k] = 0; 4985 k = a->frame[i].transform[l].ori; 4986 if(k < model->numvertex) 4987 vrtxidx[k] = 0; 4988 } 4989 if(l > maxt) maxt = l; 4990 } 4991 } 4992 } 4993 /* add colors to color map and texture names to string table */ 4994 if(!(flags & M3D_EXP_NOMATERIAL)) { 4995 M3D_LOG("Processing materials"); 4996 for(i = k = 0; i < model->nummaterial; i++) { 4997 if(mtrlidx[i] == M3D_UNDEF || !model->material[i].numprop) continue; 4998 mtrlidx[i] = k++; 4999 m = &model->material[i]; 5000 str = _m3d_addstr(str, &numstr, m->name); 5001 if(!str) goto memerr; 5002 if(m->prop) 5003 for(j = 0; j < m->numprop; j++) { 5004 if(!(flags & M3D_EXP_NOCMAP) && m->prop[j].type < 128) { 5005 for(l = 0; l < sizeof(m3d_propertytypes)/sizeof(m3d_propertytypes[0]); l++) { 5006 if(m->prop[j].type == m3d_propertytypes[l].id && m3d_propertytypes[l].format == m3dpf_color) { 5007 ((uint8_t*)&m->prop[j].value.color)[3] = opa[i * 2 + 1]; 5008 cmap = _m3d_addcmap(cmap, &numcmap, m->prop[j].value.color); 5009 if(!cmap) goto memerr; 5010 break; 5011 } 5012 } 5013 } 5014 if(m->prop[j].type >= 128 && m->prop[j].value.textureid < model->numtexture && 5015 model->texture[m->prop[j].value.textureid].name) { 5016 str = _m3d_addstr(str, &numstr, model->texture[m->prop[j].value.textureid].name); 5017 if(!str) goto memerr; 5018 } 5019 } 5020 } 5021 } 5022 /* if there's only one black color, don't store it */ 5023 if(numcmap == 1 && cmap && !cmap[0]) numcmap = 0; 5024 5025 /** compress lists **/ 5026 if(model->numtmap && !(flags & M3D_EXP_NOTXTCRD)) { 5027 M3D_LOG("Compressing tmap"); 5028 tmap = (m3dtisave_t*)M3D_MALLOC(model->numtmap * sizeof(m3dtisave_t)); 5029 if(!tmap) goto memerr; 5030 for(i = 0; i < model->numtmap; i++) { 5031 if(tmapidx[i] == M3D_UNDEF) continue; 5032 switch(quality) { 5033 case M3D_EXP_INT8: 5034 l = (unsigned int)(model->tmap[i].u * 255); tcoord.data.u = (M3D_FLOAT)l / (M3D_FLOAT)255.0; 5035 l = (unsigned int)(model->tmap[i].v * 255); tcoord.data.v = (M3D_FLOAT)l / (M3D_FLOAT)255.0; 5036 break; 5037 case M3D_EXP_INT16: 5038 l = (unsigned int)(model->tmap[i].u * 65535); tcoord.data.u = (M3D_FLOAT)l / (M3D_FLOAT)65535.0; 5039 l = (unsigned int)(model->tmap[i].v * 65535); tcoord.data.v = (M3D_FLOAT)l / (M3D_FLOAT)65535.0; 5040 break; 5041 default: 5042 tcoord.data.u = model->tmap[i].u; 5043 tcoord.data.v = model->tmap[i].v; 5044 break; 5045 } 5046 if(flags & M3D_EXP_FLIPTXTCRD) 5047 tcoord.data.v = (M3D_FLOAT)1.0 - tcoord.data.v; 5048 tcoord.oldidx = i; 5049 memcpy(&tmap[numtmap++], &tcoord, sizeof(m3dtisave_t)); 5050 } 5051 if(numtmap) { 5052 qsort(tmap, numtmap, sizeof(m3dtisave_t), _m3d_ticmp); 5053 memcpy(&tcoord.data, &tmap[0], sizeof(m3dti_t)); 5054 for(i = 0; i < numtmap; i++) { 5055 if(memcmp(&tcoord.data, &tmap[i].data, sizeof(m3dti_t))) { 5056 memcpy(&tcoord.data, &tmap[i].data, sizeof(m3dti_t)); 5057 maxtmap++; 5058 } 5059 tmap[i].newidx = maxtmap; 5060 tmapidx[tmap[i].oldidx] = maxtmap; 5061 } 5062 maxtmap++; 5063 } 5064 } 5065 if(model->numskin && model->skin && !(flags & M3D_EXP_NOBONE)) { 5066 M3D_LOG("Compressing skin"); 5067 skinidx = (M3D_INDEX*)M3D_MALLOC(model->numskin * sizeof(M3D_INDEX)); 5068 if(!skinidx) goto memerr; 5069 skin = (m3dssave_t*)M3D_MALLOC(model->numskin * sizeof(m3dssave_t)); 5070 if(!skin) goto memerr; 5071 memset(skinidx, 255, model->numskin * sizeof(M3D_INDEX)); 5072 for(i = 0; i < model->numvertex; i++) { 5073 if(vrtxidx[i] != M3D_UNDEF && model->vertex[i].skinid < model->numskin) 5074 skinidx[model->vertex[i].skinid] = 0; 5075 } 5076 for(i = 0; i < model->numskin; i++) { 5077 if(skinidx[i] == M3D_UNDEF) continue; 5078 memset(&sk, 0, sizeof(m3dssave_t)); 5079 for(j = 0, min_x = (M3D_FLOAT)0.0; j < M3D_NUMBONE && model->skin[i].boneid[j] != M3D_UNDEF; j++) { 5080 sk.data.boneid[j] = model->skin[i].boneid[j]; 5081 sk.data.weight[j] = model->skin[i].weight[j] > (M3D_FLOAT)0.0 ? model->skin[i].weight[j] : (M3D_FLOAT)0.01; 5082 min_x += sk.data.weight[j]; 5083 } 5084 if(j > maxbone) maxbone = j; 5085 if(min_x != (M3D_FLOAT)1.0 && min_x != (M3D_FLOAT)0.0) 5086 for(j = 0; j < M3D_NUMBONE && sk.data.weight[j] > (M3D_FLOAT)0.0; j++) 5087 sk.data.weight[j] /= min_x; 5088 sk.oldidx = i; 5089 memcpy(&skin[numskin++], &sk, sizeof(m3dssave_t)); 5090 } 5091 if(numskin) { 5092 qsort(skin, numskin, sizeof(m3dssave_t), _m3d_skincmp); 5093 memcpy(&sk.data, &skin[0].data, sizeof(m3ds_t)); 5094 for(i = 0; i < numskin; i++) { 5095 if(memcmp(&sk.data, &skin[i].data, sizeof(m3ds_t))) { 5096 memcpy(&sk.data, &skin[i].data, sizeof(m3ds_t)); 5097 maxskin++; 5098 } 5099 skin[i].newidx = maxskin; 5100 skinidx[skin[i].oldidx] = maxskin; 5101 } 5102 maxskin++; 5103 } 5104 } 5105 5106 M3D_LOG("Compressing vertex list"); 5107 min_x = min_y = min_z = (M3D_FLOAT)1e10; 5108 max_x = max_y = max_z = (M3D_FLOAT)-1e10; 5109 if(vrtxidx) { 5110 vrtx = (m3dvsave_t*)M3D_MALLOC(model->numvertex * sizeof(m3dvsave_t)); 5111 if(!vrtx) goto memerr; 5112 for(i = numvrtx = 0; i < model->numvertex; i++) { 5113 if(vrtxidx[i] == M3D_UNDEF) continue; 5114 _m3d_round(quality, &model->vertex[i], &vertex.data); 5115 vertex.norm = norm ? norm[i] : 0; 5116 if(vertex.data.skinid != M3D_INDEXMAX && !vertex.norm) { 5117 vertex.data.skinid = vertex.data.skinid != M3D_UNDEF && skinidx ? skinidx[vertex.data.skinid] : M3D_UNDEF; 5118 if(vertex.data.x > max_x) max_x = vertex.data.x; 5119 if(vertex.data.x < min_x) min_x = vertex.data.x; 5120 if(vertex.data.y > max_y) max_y = vertex.data.y; 5121 if(vertex.data.y < min_y) min_y = vertex.data.y; 5122 if(vertex.data.z > max_z) max_z = vertex.data.z; 5123 if(vertex.data.z < min_z) min_z = vertex.data.z; 5124 } 5125 #ifdef M3D_VERTEXTYPE 5126 vertex.data.type = 0; 5127 #endif 5128 vertex.oldidx = i; 5129 memcpy(&vrtx[numvrtx++], &vertex, sizeof(m3dvsave_t)); 5130 } 5131 if(numvrtx) { 5132 qsort(vrtx, numvrtx, sizeof(m3dvsave_t), _m3d_vrtxcmp); 5133 memcpy(&vertex.data, &vrtx[0].data, sizeof(m3dv_t)); 5134 for(i = 0; i < numvrtx; i++) { 5135 if(memcmp(&vertex.data, &vrtx[i].data, vrtx[i].norm ? 3 * sizeof(M3D_FLOAT) : sizeof(m3dv_t))) { 5136 memcpy(&vertex.data, &vrtx[i].data, sizeof(m3dv_t)); 5137 maxvrtx++; 5138 } 5139 vrtx[i].newidx = maxvrtx; 5140 vrtxidx[vrtx[i].oldidx] = maxvrtx; 5141 } 5142 maxvrtx++; 5143 } 5144 } 5145 if(norm) { M3D_FREE(norm); norm = NULL; } 5146 5147 /* normalize to bounding cube */ 5148 if(numvrtx && !(flags & M3D_EXP_NORECALC)) { 5149 M3D_LOG("Normalizing coordinates"); 5150 if(min_x < (M3D_FLOAT)0.0) min_x = -min_x; 5151 if(max_x < (M3D_FLOAT)0.0) max_x = -max_x; 5152 if(min_y < (M3D_FLOAT)0.0) min_y = -min_y; 5153 if(max_y < (M3D_FLOAT)0.0) max_y = -max_y; 5154 if(min_z < (M3D_FLOAT)0.0) min_z = -min_z; 5155 if(max_z < (M3D_FLOAT)0.0) max_z = -max_z; 5156 scale = min_x; 5157 if(max_x > scale) scale = max_x; 5158 if(min_y > scale) scale = min_y; 5159 if(max_y > scale) scale = max_y; 5160 if(min_z > scale) scale = min_z; 5161 if(max_z > scale) scale = max_z; 5162 if(scale <= (M3D_FLOAT)0.0) scale = (M3D_FLOAT)1.0; 5163 if(scale != (M3D_FLOAT)1.0) { 5164 for(i = 0; i < numvrtx; i++) { 5165 if(vrtx[i].data.skinid == M3D_INDEXMAX) continue; 5166 vrtx[i].data.x /= scale; 5167 vrtx[i].data.y /= scale; 5168 vrtx[i].data.z /= scale; 5169 } 5170 } 5171 } 5172 if(model->scale > (M3D_FLOAT)0.0) scale = model->scale; 5173 if(scale <= (M3D_FLOAT)0.0) scale = (M3D_FLOAT)1.0; 5174 5175 /* meta info */ 5176 sn = _m3d_safestr(model->name && *model->name ? model->name : (char*)"(noname)", 2); 5177 sl = _m3d_safestr(model->license ? model->license : (char*)"MIT", 2); 5178 sa = _m3d_safestr(model->author ? model->author : getenv("LOGNAME"), 2); 5179 if(!sn || !sl || !sa) { 5180 memerr: if(vrtxidx) M3D_FREE(vrtxidx); 5181 if(mtrlidx) M3D_FREE(mtrlidx); 5182 if(tmapidx) M3D_FREE(tmapidx); 5183 if(skinidx) M3D_FREE(skinidx); 5184 if(grpidx) M3D_FREE(grpidx); 5185 if(norm) M3D_FREE(norm); 5186 if(face) M3D_FREE(face); 5187 if(cmap) M3D_FREE(cmap); 5188 if(tmap) M3D_FREE(tmap); 5189 if(skin) M3D_FREE(skin); 5190 if(str) M3D_FREE(str); 5191 if(vrtx) M3D_FREE(vrtx); 5192 if(sn) M3D_FREE(sn); 5193 if(sl) M3D_FREE(sl); 5194 if(sa) M3D_FREE(sa); 5195 if(sd) M3D_FREE(sd); 5196 if(out) M3D_FREE(out); 5197 if(opa) free(opa); 5198 if(h) M3D_FREE(h); 5199 M3D_LOG("Out of memory"); 5200 model->errcode = M3D_ERR_ALLOC; 5201 return NULL; 5202 } 5203 5204 M3D_LOG("Serializing model"); 5205 #ifdef M3D_ASCII 5206 if(flags & M3D_EXP_ASCII) { 5207 /* use CRLF to make model creators on Win happy... */ 5208 sd = _m3d_safestr(model->desc, 1); 5209 if(!sd) goto memerr; 5210 ol = setlocale(LC_NUMERIC, NULL); 5211 setlocale(LC_NUMERIC, "C"); 5212 /* header */ 5213 len = 64 + (unsigned int)(strlen(sn) + strlen(sl) + strlen(sa) + strlen(sd)); 5214 out = (unsigned char*)M3D_MALLOC(len); 5215 if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } 5216 ptr = (char*)out; 5217 ptr += sprintf(ptr, "3dmodel %g\r\n%s\r\n%s\r\n%s\r\n%s\r\n\r\n", scale, 5218 sn, sl, sa, sd); 5219 M3D_FREE(sl); M3D_FREE(sa); M3D_FREE(sd); 5220 sl = sa = sd = NULL; 5221 /* preview chunk */ 5222 if(model->preview.data && model->preview.length) { 5223 sl = _m3d_safestr(sn, 0); 5224 if(sl) { 5225 /* gcc thinks that "ptr is used after free", well, gcc is simply wrong. */ 5226 #ifdef __GNUC__ 5227 #pragma GCC diagnostic push 5228 #pragma GCC diagnostic ignored "-Wuse-after-free" 5229 #endif 5230 ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)20 + strlen(sl)); 5231 out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; 5232 #ifdef __GNUC__ 5233 #pragma GCC diagnostic pop 5234 #endif 5235 if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } 5236 ptr += sprintf(ptr, "Preview\r\n%s.png\r\n\r\n", sl); 5237 M3D_FREE(sl); sl = NULL; 5238 } 5239 } 5240 M3D_FREE(sn); sn = NULL; 5241 /* texture map */ 5242 if(numtmap && tmap && !(flags & M3D_EXP_NOTXTCRD) && !(flags & M3D_EXP_NOFACE)) { 5243 /* interestingly gcc does not complain about "ptr is used after free" here, although the code is 100% the same */ 5244 ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)(maxtmap * 32) + (uintptr_t)12); 5245 out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; 5246 if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } 5247 ptr += sprintf(ptr, "Textmap\r\n"); 5248 last = M3D_UNDEF; 5249 for(i = 0; i < numtmap; i++) { 5250 if(tmap[i].newidx == last) continue; 5251 last = tmap[i].newidx; 5252 ptr += sprintf(ptr, "%g %g\r\n", tmap[i].data.u, tmap[i].data.v); 5253 } 5254 ptr += sprintf(ptr, "\r\n"); 5255 } 5256 /* vertex chunk */ 5257 if(numvrtx && vrtx && !(flags & M3D_EXP_NOFACE)) { 5258 ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)(maxvrtx * 128) + (uintptr_t)10); 5259 out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; 5260 if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } 5261 ptr += sprintf(ptr, "Vertex\r\n"); 5262 last = M3D_UNDEF; 5263 for(i = 0; i < numvrtx; i++) { 5264 if(vrtx[i].newidx == last) continue; 5265 last = vrtx[i].newidx; 5266 ptr += sprintf(ptr, "%g %g %g %g", vrtx[i].data.x, vrtx[i].data.y, vrtx[i].data.z, vrtx[i].data.w); 5267 if(!(flags & M3D_EXP_NOCMAP) && vrtx[i].data.color) 5268 ptr += sprintf(ptr, " #%08x", vrtx[i].data.color); 5269 if(!(flags & M3D_EXP_NOBONE) && model->numbone && maxskin && vrtx[i].data.skinid < M3D_INDEXMAX) { 5270 if(skin[vrtx[i].data.skinid].data.weight[0] == (M3D_FLOAT)1.0) 5271 ptr += sprintf(ptr, " %d", skin[vrtx[i].data.skinid].data.boneid[0]); 5272 else 5273 for(j = 0; j < M3D_NUMBONE && skin[vrtx[i].data.skinid].data.boneid[j] != M3D_UNDEF && 5274 skin[vrtx[i].data.skinid].data.weight[j] > (M3D_FLOAT)0.0; j++) 5275 ptr += sprintf(ptr, " %d:%g", skin[vrtx[i].data.skinid].data.boneid[j], 5276 skin[vrtx[i].data.skinid].data.weight[j]); 5277 } 5278 ptr += sprintf(ptr, "\r\n"); 5279 } 5280 ptr += sprintf(ptr, "\r\n"); 5281 } 5282 /* bones chunk */ 5283 if(model->numbone && model->bone && !(flags & M3D_EXP_NOBONE)) { 5284 ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)9); 5285 for(i = 0; i < model->numbone; i++) { 5286 len += (unsigned int)strlen(model->bone[i].name) + 128; 5287 } 5288 out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; 5289 if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } 5290 ptr += sprintf(ptr, "Bones\r\n"); 5291 ptr = _m3d_prtbone(ptr, model->bone, model->numbone, M3D_UNDEF, 0, vrtxidx); 5292 ptr += sprintf(ptr, "\r\n"); 5293 } 5294 /* materials */ 5295 if(model->nummaterial && !(flags & M3D_EXP_NOMATERIAL)) { 5296 for(j = 0; j < model->nummaterial; j++) { 5297 if(mtrlidx[j] == M3D_UNDEF || !model->material[j].numprop || !model->material[j].prop) continue; 5298 m = &model->material[j]; 5299 sn = _m3d_safestr(m->name, 0); 5300 if(!sn) { setlocale(LC_NUMERIC, ol); goto memerr; } 5301 ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)strlen(sn) + (uintptr_t)12); 5302 for(i = 0; i < m->numprop; i++) { 5303 if(m->prop[i].type < 128) 5304 len += 32; 5305 else if(m->prop[i].value.textureid < model->numtexture && model->texture[m->prop[i].value.textureid].name) 5306 len += (unsigned int)strlen(model->texture[m->prop[i].value.textureid].name) + 16; 5307 } 5308 out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; 5309 if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } 5310 ptr += sprintf(ptr, "Material %s\r\n", sn); 5311 M3D_FREE(sn); sn = NULL; 5312 for(i = 0; i < m->numprop; i++) { 5313 k = 256; 5314 if(m->prop[i].type >= 128) { 5315 for(l = 0; l < sizeof(m3d_propertytypes)/sizeof(m3d_propertytypes[0]); l++) 5316 if(m->prop[i].type == m3d_propertytypes[l].id) { 5317 sn = m3d_propertytypes[l].key; 5318 break; 5319 } 5320 if(!sn) 5321 for(l = 0; l < sizeof(m3d_propertytypes)/sizeof(m3d_propertytypes[0]); l++) 5322 if(m->prop[i].type - 128 == m3d_propertytypes[l].id) { 5323 sn = m3d_propertytypes[l].key; 5324 break; 5325 } 5326 k = sn ? m3dpf_map : 256; 5327 } else { 5328 for(l = 0; l < sizeof(m3d_propertytypes)/sizeof(m3d_propertytypes[0]); l++) 5329 if(m->prop[i].type == m3d_propertytypes[l].id) { 5330 sn = m3d_propertytypes[l].key; 5331 k = m3d_propertytypes[l].format; 5332 break; 5333 } 5334 } 5335 switch(k) { 5336 case m3dpf_color: ptr += sprintf(ptr, "%s #%08x\r\n", sn, m->prop[i].value.color); break; 5337 case m3dpf_uint8: 5338 case m3dpf_uint16: 5339 case m3dpf_uint32: ptr += sprintf(ptr, "%s %d\r\n", sn, m->prop[i].value.num); break; 5340 case m3dpf_float: ptr += sprintf(ptr, "%s %g\r\n", sn, m->prop[i].value.fnum); break; 5341 case m3dpf_map: 5342 if(m->prop[i].value.textureid < model->numtexture && 5343 model->texture[m->prop[i].value.textureid].name) { 5344 sl = _m3d_safestr(model->texture[m->prop[i].value.textureid].name, 0); 5345 if(!sl) { setlocale(LC_NUMERIC, ol); goto memerr; } 5346 if(*sl) 5347 ptr += sprintf(ptr, "map_%s %s\r\n", sn, sl); 5348 M3D_FREE(sn); M3D_FREE(sl); sl = NULL; 5349 } 5350 break; 5351 } 5352 sn = NULL; 5353 } 5354 ptr += sprintf(ptr, "\r\n"); 5355 } 5356 } 5357 /* procedural face */ 5358 if(model->numinlined && model->inlined && !(flags & M3D_EXP_NOFACE)) { 5359 /* all inlined assets which are not textures should be procedural surfaces */ 5360 for(j = 0; j < model->numinlined; j++) { 5361 if(!model->inlined[j].name || !*model->inlined[j].name || !model->inlined[j].length || !model->inlined[j].data || 5362 (model->inlined[j].data[1] == 'P' && model->inlined[j].data[2] == 'N' && model->inlined[j].data[3] == 'G')) 5363 continue; 5364 for(i = k = 0; i < model->numtexture; i++) { 5365 if(!strcmp(model->inlined[j].name, model->texture[i].name)) { k = 1; break; } 5366 } 5367 if(k) continue; 5368 sn = _m3d_safestr(model->inlined[j].name, 0); 5369 if(!sn) { setlocale(LC_NUMERIC, ol); goto memerr; } 5370 ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)strlen(sn) + (uintptr_t)18); 5371 out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; 5372 if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } 5373 ptr += sprintf(ptr, "Procedural\r\n%s\r\n\r\n", sn); 5374 M3D_FREE(sn); sn = NULL; 5375 } 5376 } 5377 /* mesh face */ 5378 if(model->numface && face && !(flags & M3D_EXP_NOFACE)) { 5379 ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)(model->numface * 128) + (uintptr_t)6); 5380 last = M3D_UNDEF; 5381 #ifdef M3D_VERTEXMAX 5382 lastp = M3D_UNDEF; 5383 #endif 5384 if(!(flags & M3D_EXP_NOMATERIAL)) 5385 for(i = 0; i < model->numface; i++) { 5386 j = face[i].data.materialid < model->nummaterial ? face[i].data.materialid : M3D_UNDEF; 5387 if(j != last) { 5388 last = j; 5389 if(last < model->nummaterial) 5390 len += (unsigned int)strlen(model->material[last].name); 5391 len += 6; 5392 } 5393 #ifdef M3D_VERTEXMAX 5394 j = face[i].data.paramid < model->numparam ? face[i].data.paramid : M3D_UNDEF; 5395 if(j != lastp) { 5396 lastp = j; 5397 if(lastp < model->numparam) 5398 len += (unsigned int)strlen(model->param[lastp].name); 5399 len += 6; 5400 } 5401 #endif 5402 } 5403 out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; 5404 if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } 5405 ptr += sprintf(ptr, "Mesh\r\n"); 5406 last = M3D_UNDEF; 5407 #ifdef M3D_VERTEXMAX 5408 lastp = M3D_UNDEF; 5409 #endif 5410 for(i = 0; i < model->numface; i++) { 5411 j = face[i].data.materialid < model->nummaterial ? face[i].data.materialid : M3D_UNDEF; 5412 if(!(flags & M3D_EXP_NOMATERIAL) && j != last) { 5413 last = j; 5414 if(last < model->nummaterial) { 5415 sn = _m3d_safestr(model->material[last].name, 0); 5416 if(!sn) { setlocale(LC_NUMERIC, ol); goto memerr; } 5417 ptr += sprintf(ptr, "use %s\r\n", sn); 5418 M3D_FREE(sn); sn = NULL; 5419 } else 5420 ptr += sprintf(ptr, "use\r\n"); 5421 } 5422 #ifdef M3D_VERTEXMAX 5423 j = face[i].data.paramid < model->numparam ? face[i].data.paramid : M3D_UNDEF; 5424 if(!(flags & M3D_EXP_NOVRTMAX) && j != lastp) { 5425 lastp = j; 5426 if(lastp < model->numparam) { 5427 sn = _m3d_safestr(model->param[lastp].name, 0); 5428 if(!sn) { setlocale(LC_NUMERIC, ol); goto memerr; } 5429 ptr += sprintf(ptr, "par %s\r\n", sn); 5430 M3D_FREE(sn); sn = NULL; 5431 } else 5432 ptr += sprintf(ptr, "par\r\n"); 5433 } 5434 #endif 5435 /* hardcoded triangles. Should be repeated as many times as the number of edges in polygon */ 5436 for(j = 0; j < 3; j++) { 5437 ptr += sprintf(ptr, "%s%d", j?" ":"", vrtxidx[face[i].data.vertex[j]]); 5438 k = l = M3D_NOTDEFINED; 5439 if(!(flags & M3D_EXP_NOTXTCRD) && (face[i].data.texcoord[j] != M3D_UNDEF) && 5440 (tmapidx[face[i].data.texcoord[j]] != M3D_UNDEF)) { 5441 k = tmapidx[face[i].data.texcoord[j]]; 5442 ptr += sprintf(ptr, "/%d", k); 5443 } 5444 if(!(flags & M3D_EXP_NONORMAL) && (face[i].data.normal[j] != M3D_UNDEF)) { 5445 l = vrtxidx[face[i].data.normal[j]]; 5446 ptr += sprintf(ptr, "%s/%d", k == M3D_NOTDEFINED? "/" : "", l); 5447 } 5448 #ifdef M3D_VERTEXMAX 5449 if(!(flags & M3D_EXP_NOVRTMAX) && (face[i].data.vertmax[j] != M3D_UNDEF)) { 5450 ptr += sprintf(ptr, "%s%s/%d", k == M3D_NOTDEFINED? "/" : "", l == M3D_NOTDEFINED? "/" : "", 5451 vrtxidx[face[i].data.vertmax[j]]); 5452 } 5453 #endif 5454 } 5455 ptr += sprintf(ptr, "\r\n"); 5456 } 5457 ptr += sprintf(ptr, "\r\n"); 5458 } 5459 /* voxel face */ 5460 if(model->numvoxtype && model->voxtype && !(flags & M3D_EXP_NOFACE)) { 5461 ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)(model->numvoxtype * 128) + (uintptr_t)10); 5462 for(i = 0; i < model->numvoxtype; i++) { 5463 if(model->voxtype[i].name) len += (unsigned int)strlen(model->voxtype[i].name); 5464 for(j = 0; j < model->voxtype[i].numitem; j++) 5465 if(model->voxtype[i].item[j].name) 5466 len += (unsigned int)strlen(model->voxtype[i].item[j].name) + 6; 5467 } 5468 out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; 5469 if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } 5470 ptr += sprintf(ptr, "VoxTypes\r\n"); 5471 for(i = 0; i < model->numvoxtype; i++) { 5472 ptr += sprintf(ptr, "#%08x", model->voxtype[i].color); 5473 if(model->voxtype[i].rotation) 5474 ptr += sprintf(ptr, "/%02x", model->voxtype[i].rotation); 5475 if(model->voxtype[i].voxshape) 5476 ptr += sprintf(ptr, "%s/%03x", model->voxtype[i].rotation ? "" : "/", model->voxtype[i].voxshape); 5477 sn = _m3d_safestr(model->voxtype[i].name, 0); 5478 if(!sn) { setlocale(LC_NUMERIC, ol); goto memerr; } 5479 ptr += sprintf(ptr, " %s", sn && sn[0] ? sn : "-"); 5480 M3D_FREE(sn); sn = NULL; 5481 if(!(flags & M3D_EXP_NOBONE) && model->numbone && maxskin && model->voxtype[i].skinid < M3D_INDEXMAX) { 5482 if(skin[skinidx[model->voxtype[i].skinid]].data.weight[0] == (M3D_FLOAT)1.0) 5483 ptr += sprintf(ptr, " %d", skin[skinidx[model->voxtype[i].skinid]].data.boneid[0]); 5484 else 5485 for(j = 0; j < M3D_NUMBONE && skin[skinidx[model->voxtype[i].skinid]].data.boneid[j] != M3D_UNDEF && 5486 skin[skinidx[model->voxtype[i].skinid]].data.weight[j] > (M3D_FLOAT)0.0; j++) 5487 ptr += sprintf(ptr, " %d:%g", skin[skinidx[model->voxtype[i].skinid]].data.boneid[j], 5488 skin[skinidx[model->voxtype[i].skinid]].data.weight[j]); 5489 } 5490 if(model->voxtype[i].numitem && model->voxtype[i].item) { 5491 for(j = k = 0; j < model->voxtype[i].numitem; j++) { 5492 if(!model->voxtype[i].item[j].count || !model->voxtype[i].item[j].name || 5493 !model->voxtype[i].item[j].name[0]) continue; 5494 if(!k) { ptr += sprintf(ptr, " {"); k = 1; } 5495 sn = _m3d_safestr(model->voxtype[i].item[j].name, 0); 5496 if(!sn) { setlocale(LC_NUMERIC, ol); goto memerr; } 5497 ptr += sprintf(ptr, " %d %s", model->voxtype[i].item[j].count, sn); 5498 M3D_FREE(sn); sn = NULL; 5499 } 5500 if(k) ptr += sprintf(ptr, " }"); 5501 } 5502 while(ptr[-1] == '-' || ptr[-1] == ' ') ptr--; 5503 ptr += sprintf(ptr, "\r\n"); 5504 } 5505 ptr += sprintf(ptr, "\r\n"); 5506 } 5507 if(model->numvoxel && model->voxel && !(flags & M3D_EXP_NOFACE)) { 5508 for(i = 0; i < model->numvoxel; i++) { 5509 ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)128); 5510 if(model->voxel[i].name) len += (unsigned int)strlen(model->voxel[i].name); 5511 len += model->voxel[i].h * ((model->voxel[i].w * 6 + 2) * model->voxel[i].d + 9); 5512 out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; 5513 if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } 5514 ptr += sprintf(ptr, "Voxel"); 5515 sn = _m3d_safestr(model->voxel[i].name, 0); 5516 if(!sn) { setlocale(LC_NUMERIC, ol); goto memerr; } 5517 if(sn && sn[0]) 5518 ptr += sprintf(ptr, " %s", sn); 5519 M3D_FREE(sn); sn = NULL; 5520 ptr += sprintf(ptr, "\r\n"); 5521 if(model->voxel[i].uncertain) 5522 ptr += sprintf(ptr, "uncertain %d %d\r\n", (model->voxel[i].uncertain * 100) / 255, model->voxel[i].groupid); 5523 if(model->voxel[i].x || model->voxel[i].y || model->voxel[i].z) 5524 ptr += sprintf(ptr, "pos %d %d %d\r\n", model->voxel[i].x, model->voxel[i].y, model->voxel[i].z); 5525 ptr += sprintf(ptr, "dim %d %d %d\r\n", model->voxel[i].w, model->voxel[i].h, model->voxel[i].d); 5526 for(j = n = 0; j < model->voxel[i].h; j++) { 5527 ptr += sprintf(ptr, "layer\r\n"); 5528 for(k = 0; k < model->voxel[i].d; k++) { 5529 for(l = 0; l < model->voxel[i].w; l++, n++) { 5530 switch(model->voxel[i].data[n]) { 5531 case M3D_VOXCLEAR: *ptr++ = '-'; break; 5532 case M3D_VOXUNDEF: *ptr++ = '.'; break; 5533 default: ptr += sprintf(ptr, "%d", model->voxel[i].data[n]); break; 5534 } 5535 *ptr++ = ' '; 5536 } 5537 ptr--; 5538 ptr += sprintf(ptr, "\r\n"); 5539 } 5540 } 5541 ptr += sprintf(ptr, "\r\n"); 5542 } 5543 } 5544 /* mathematical shapes face */ 5545 if(model->numshape && model->numshape && !(flags & M3D_EXP_NOFACE)) { 5546 for(j = 0; j < model->numshape; j++) { 5547 sn = _m3d_safestr(model->shape[j].name, 0); 5548 if(!sn) { setlocale(LC_NUMERIC, ol); goto memerr; } 5549 ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)strlen(sn) + (uintptr_t)33); 5550 out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; 5551 if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } 5552 ptr += sprintf(ptr, "Shape %s\r\n", sn); 5553 M3D_FREE(sn); sn = NULL; 5554 if(model->shape[j].group != M3D_UNDEF && !(flags & M3D_EXP_NOBONE)) 5555 ptr += sprintf(ptr, "group %d\r\n", model->shape[j].group); 5556 for(i = 0; i < model->shape[j].numcmd; i++) { 5557 cmd = &model->shape[j].cmd[i]; 5558 if(cmd->type >= (unsigned int)(sizeof(m3d_commandtypes)/sizeof(m3d_commandtypes[0])) || !cmd->arg) 5559 continue; 5560 cd = &m3d_commandtypes[cmd->type]; 5561 ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)strlen(cd->key) + (uintptr_t)3); 5562 for(k = 0; k < cd->p; k++) 5563 switch(cd->a[k]) { 5564 case m3dcp_mi_t: if(cmd->arg[k] != M3D_NOTDEFINED) { len += (unsigned int)strlen(model->material[cmd->arg[k]].name) + 1; } break; 5565 case m3dcp_va_t: len += cmd->arg[k] * (cd->p - k - 1) * 16; k = cd->p; break; 5566 default: len += 16; break; 5567 } 5568 out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; 5569 if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } 5570 ptr += sprintf(ptr, "%s", cd->key); 5571 for(k = n = 0, l = cd->p; k < l; k++) { 5572 switch(cd->a[((k - n) % (cd->p - n)) + n]) { 5573 case m3dcp_mi_t: 5574 if(cmd->arg[k] != M3D_NOTDEFINED) { 5575 sn = _m3d_safestr(model->material[cmd->arg[k]].name, 0); 5576 if(!sn) { setlocale(LC_NUMERIC, ol); goto memerr; } 5577 ptr += sprintf(ptr, " %s", sn); 5578 M3D_FREE(sn); sn = NULL; 5579 } 5580 break; 5581 case m3dcp_vc_t: ptr += sprintf(ptr, " %g", *((float*)&cmd->arg[k])); break; 5582 case m3dcp_va_t: ptr += sprintf(ptr, " %d[", cmd->arg[k]); 5583 n = k + 1; l += (cmd->arg[k] - 1) * (cd->p - k - 1); 5584 break; 5585 default: ptr += sprintf(ptr, " %d", cmd->arg[k]); break; 5586 } 5587 } 5588 ptr += sprintf(ptr, "%s\r\n", l > cd->p ? " ]" : ""); 5589 } 5590 ptr += sprintf(ptr, "\r\n"); 5591 } 5592 } 5593 /* annotation labels */ 5594 if(model->numlabel && model->label && !(flags & M3D_EXP_NOFACE)) { 5595 for(i = 0, j = 3, length = NULL; i < model->numlabel; i++) { 5596 if(model->label[i].name) j += (unsigned int)strlen(model->label[i].name); 5597 if(model->label[i].lang) j += (unsigned int)strlen(model->label[i].lang); 5598 if(model->label[i].text) j += (unsigned int)strlen(model->label[i].text); 5599 j += 40; 5600 } 5601 ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)j); 5602 out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; 5603 if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } 5604 for(i = 0; i < model->numlabel; i++) { 5605 if(!i || _m3d_strcmp(sl, model->label[i].lang) || _m3d_strcmp(sn, model->label[i].name)) { 5606 sl = model->label[i].lang; 5607 sn = model->label[i].name; 5608 sd = _m3d_safestr(sn, 0); 5609 if(!sd) { setlocale(LC_NUMERIC, ol); sn = sl = NULL; goto memerr; } 5610 if(i) ptr += sprintf(ptr, "\r\n"); 5611 ptr += sprintf(ptr, "Labels %s\r\n", sd); 5612 M3D_FREE(sd); sd = NULL; 5613 if(model->label[i].color) 5614 ptr += sprintf(ptr, "color #0x%08x\r\n", model->label[i].color); 5615 if(sl && *sl) { 5616 sd = _m3d_safestr(sl, 0); 5617 if(!sd) { setlocale(LC_NUMERIC, ol); sn = sl = NULL; goto memerr; } 5618 ptr += sprintf(ptr, "lang %s\r\n", sd); 5619 M3D_FREE(sd); sd = NULL; 5620 } 5621 } 5622 sd = _m3d_safestr(model->label[i].text, 2); 5623 if(!sd) { setlocale(LC_NUMERIC, ol); sn = sl = NULL; goto memerr; } 5624 ptr += sprintf(ptr, "%d %s\r\n", model->label[i].vertexid, sd); 5625 M3D_FREE(sd); sd = NULL; 5626 } 5627 ptr += sprintf(ptr, "\r\n"); 5628 sn = sl = NULL; 5629 } 5630 /* actions */ 5631 if(model->numaction && model->action && !(flags & M3D_EXP_NOACTION)) { 5632 for(j = 0; j < model->numaction; j++) { 5633 a = &model->action[j]; 5634 sn = _m3d_safestr(a->name, 0); 5635 if(!sn) { setlocale(LC_NUMERIC, ol); goto memerr; } 5636 ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)strlen(sn) + (uintptr_t)48); 5637 for(i = 0; i < a->numframe; i++) 5638 len += a->frame[i].numtransform * 128 + 8; 5639 out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; 5640 if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } 5641 ptr += sprintf(ptr, "Action %d %s\r\n", a->durationmsec, sn); 5642 M3D_FREE(sn); sn = NULL; 5643 for(i = 0; i < a->numframe; i++) { 5644 ptr += sprintf(ptr, "frame %d\r\n", a->frame[i].msec); 5645 for(k = 0; k < a->frame[i].numtransform; k++) { 5646 ptr += sprintf(ptr, "%d %d %d\r\n", a->frame[i].transform[k].boneid, 5647 vrtxidx[a->frame[i].transform[k].pos], vrtxidx[a->frame[i].transform[k].ori]); 5648 } 5649 } 5650 ptr += sprintf(ptr, "\r\n"); 5651 } 5652 } 5653 /* inlined assets */ 5654 if(model->numinlined && model->inlined) { 5655 for(i = j = 0; i < model->numinlined; i++) 5656 if(model->inlined[i].name) 5657 j += (unsigned int)strlen(model->inlined[i].name) + 6; 5658 if(j > 0) { 5659 ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)j + (uintptr_t)16); 5660 out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; 5661 if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } 5662 ptr += sprintf(ptr, "Assets\r\n"); 5663 for(i = 0; i < model->numinlined; i++) 5664 if(model->inlined[i].name) 5665 ptr += sprintf(ptr, "%s%s\r\n", model->inlined[i].name, strrchr(model->inlined[i].name, '.') ? "" : ".png"); 5666 ptr += sprintf(ptr, "\r\n"); 5667 } 5668 } 5669 /* extra info */ 5670 if(model->numextra && (flags & M3D_EXP_EXTRA)) { 5671 for(i = 0; i < model->numextra; i++) { 5672 if(model->extra[i]->length < 9) continue; 5673 ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)17 + (uintptr_t)(model->extra[i]->length * 3)); 5674 out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; 5675 if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } 5676 ptr += sprintf(ptr, "Extra %c%c%c%c\r\n", 5677 model->extra[i]->magic[0] > ' ' ? model->extra[i]->magic[0] : '_', 5678 model->extra[i]->magic[1] > ' ' ? model->extra[i]->magic[1] : '_', 5679 model->extra[i]->magic[2] > ' ' ? model->extra[i]->magic[2] : '_', 5680 model->extra[i]->magic[3] > ' ' ? model->extra[i]->magic[3] : '_'); 5681 for(j = 0; j < model->extra[i]->length; j++) 5682 ptr += sprintf(ptr, "%02x ", *((unsigned char *)model->extra + sizeof(m3dchunk_t) + j)); 5683 ptr--; 5684 ptr += sprintf(ptr, "\r\n\r\n"); 5685 } 5686 } 5687 setlocale(LC_NUMERIC, ol); 5688 len = (unsigned int)((uintptr_t)ptr - (uintptr_t)out); 5689 out = (unsigned char*)M3D_REALLOC(out, len + 1); 5690 if(!out) goto memerr; 5691 out[len] = 0; 5692 } else 5693 #endif 5694 { 5695 /* stricly only use LF (newline) in binary */ 5696 sd = _m3d_safestr(model->desc, 3); 5697 if(!sd) goto memerr; 5698 /* header */ 5699 h = (m3dhdr_t*)M3D_MALLOC(sizeof(m3dhdr_t) + strlen(sn) + strlen(sl) + strlen(sa) + strlen(sd) + 4); 5700 if(!h) goto memerr; 5701 memcpy((uint8_t*)h, "HEAD", 4); 5702 h->length = sizeof(m3dhdr_t); 5703 h->scale = scale; 5704 i = (unsigned int)strlen(sn); memcpy((uint8_t*)h + h->length, sn, i+1); h->length += i+1; M3D_FREE(sn); 5705 i = (unsigned int)strlen(sl); memcpy((uint8_t*)h + h->length, sl, i+1); h->length += i+1; M3D_FREE(sl); 5706 i = (unsigned int)strlen(sa); memcpy((uint8_t*)h + h->length, sa, i+1); h->length += i+1; M3D_FREE(sa); 5707 i = (unsigned int)strlen(sd); memcpy((uint8_t*)h + h->length, sd, i+1); h->length += i+1; M3D_FREE(sd); 5708 sn = sl = sa = sd = NULL; 5709 if(model->inlined) 5710 for(i = 0; i < model->numinlined; i++) { 5711 if(model->inlined[i].name && *model->inlined[i].name && model->inlined[i].length > 0) { 5712 str = _m3d_addstr(str, &numstr, model->inlined[i].name); 5713 if(!str) goto memerr; 5714 } 5715 } 5716 if(str) 5717 for(i = 0; i < numstr; i++) { 5718 h = _m3d_addhdr(h, &str[i]); 5719 if(!h) goto memerr; 5720 } 5721 vc_s = quality == M3D_EXP_INT8? 1 : (quality == M3D_EXP_INT16? 2 : (quality == M3D_EXP_DOUBLE? 8 : 4)); 5722 vi_s = maxvrtx < 254 ? 1 : (maxvrtx < 65534 ? 2 : 4); 5723 si_s = h->length - 16 < 254 ? 1 : (h->length - 16 < 65534 ? 2 : 4); 5724 ci_s = !numcmap || !cmap ? 0 : (numcmap < 254 ? 1 : (numcmap < 65534 ? 2 : 4)); 5725 ti_s = !maxtmap || !tmap ? 0 : (maxtmap < 254 ? 1 : (maxtmap < 65534 ? 2 : 4)); 5726 bi_s = !model->numbone || !model->bone || (flags & M3D_EXP_NOBONE)? 0 : (model->numbone < 254 ? 1 : 5727 (model->numbone < 65534 ? 2 : 4)); 5728 nb_s = maxbone < 2 ? 1 : (maxbone == 2 ? 2 : (maxbone <= 4 ? 4 : 8)); 5729 sk_s = !bi_s || !maxskin || !skin ? 0 : (maxskin < 254 ? 1 : (maxskin < 65534 ? 2 : 4)); 5730 fc_s = maxt < 254 ? 1 : (maxt < 65534 ? 2 : 4); 5731 hi_s = !model->numshape || !model->shape || (flags & M3D_EXP_NOFACE)? 0 : (model->numshape < 254 ? 1 : 5732 (model->numshape < 65534 ? 2 : 4)); 5733 fi_s = !model->numface || !model->face || (flags & M3D_EXP_NOFACE)? 0 : (model->numface < 254 ? 1 : 5734 (model->numface < 65534 ? 2 : 4)); 5735 vd_s = !model->numvoxel || !model->voxel || (flags & M3D_EXP_NOFACE)? 0 : (minvox >= -128 && maxvox <= 127 ? 1 : 5736 (minvox >= -32768 && maxvox <= 32767 ? 2 : 4)); 5737 vp_s = !model->numvoxtype || !model->voxtype || (flags & M3D_EXP_NOFACE)? 0 : (model->numvoxtype < 254 ? 1 : 5738 (model->numvoxtype < 65534 ? 2 : 4)); 5739 h->types = (vc_s == 8 ? (3<<0) : (vc_s == 2 ? (1<<0) : (vc_s == 1 ? (0<<0) : (2<<0)))) | 5740 (vi_s == 2 ? (1<<2) : (vi_s == 1 ? (0<<2) : (2<<2))) | 5741 (si_s == 2 ? (1<<4) : (si_s == 1 ? (0<<4) : (2<<4))) | 5742 (ci_s == 2 ? (1<<6) : (ci_s == 1 ? (0<<6) : (ci_s == 4 ? (2<<6) : (3<<6)))) | 5743 (ti_s == 2 ? (1<<8) : (ti_s == 1 ? (0<<8) : (ti_s == 4 ? (2<<8) : (3<<8)))) | 5744 (bi_s == 2 ? (1<<10): (bi_s == 1 ? (0<<10): (bi_s == 4 ? (2<<10) : (3<<10)))) | 5745 (nb_s == 2 ? (1<<12): (nb_s == 1 ? (0<<12): (2<<12))) | 5746 (sk_s == 2 ? (1<<14): (sk_s == 1 ? (0<<14): (sk_s == 4 ? (2<<14) : (3<<14)))) | 5747 (fc_s == 2 ? (1<<16): (fc_s == 1 ? (0<<16): (2<<16))) | 5748 (hi_s == 2 ? (1<<18): (hi_s == 1 ? (0<<18): (hi_s == 4 ? (2<<18) : (3<<18)))) | 5749 (fi_s == 2 ? (1<<20): (fi_s == 1 ? (0<<20): (fi_s == 4 ? (2<<20) : (3<<20)))) | 5750 (vd_s == 2 ? (1<<22): (vd_s == 1 ? (0<<22): (vd_s == 4 ? (2<<22) : (3<<22)))) | 5751 (vp_s == 2 ? (1<<24): (vp_s == 1 ? (0<<24): (vp_s == 4 ? (2<<24) : (3<<24)))); 5752 len = h->length; 5753 /* color map */ 5754 if(numcmap && cmap && ci_s < 4 && !(flags & M3D_EXP_NOCMAP)) { 5755 chunklen = 8 + numcmap * sizeof(uint32_t); 5756 h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); 5757 if(!h) goto memerr; 5758 memcpy((uint8_t*)h + len, "CMAP", 4); 5759 *((uint32_t*)((uint8_t*)h + len + 4)) = chunklen; 5760 memcpy((uint8_t*)h + len + 8, cmap, chunklen - 8); 5761 len += chunklen; 5762 } else numcmap = 0; 5763 /* texture map */ 5764 if(numtmap && tmap && !(flags & M3D_EXP_NOTXTCRD) && !(flags & M3D_EXP_NOFACE)) { 5765 chunklen = 8 + maxtmap * vc_s * 2; 5766 h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); 5767 if(!h) goto memerr; 5768 memcpy((uint8_t*)h + len, "TMAP", 4); 5769 length = (uint32_t*)((uint8_t*)h + len + 4); 5770 out = (uint8_t*)h + len + 8; 5771 last = M3D_UNDEF; 5772 for(i = 0; i < numtmap; i++) { 5773 if(tmap[i].newidx == last) continue; 5774 last = tmap[i].newidx; 5775 switch(vc_s) { 5776 case 1: *out++ = (uint8_t)(tmap[i].data.u * 255); *out++ = (uint8_t)(tmap[i].data.v * 255); break; 5777 case 2: 5778 *((uint16_t*)out) = (uint16_t)(tmap[i].data.u * 65535); out += 2; 5779 *((uint16_t*)out) = (uint16_t)(tmap[i].data.v * 65535); out += 2; 5780 break; 5781 case 4: *((float*)out) = tmap[i].data.u; out += 4; *((float*)out) = tmap[i].data.v; out += 4; break; 5782 case 8: *((double*)out) = tmap[i].data.u; out += 8; *((double*)out) = tmap[i].data.v; out += 8; break; 5783 } 5784 } 5785 *length = (uint32_t)((uintptr_t)out - (uintptr_t)((uint8_t*)h + len)); 5786 out = NULL; 5787 len += *length; 5788 } 5789 /* vertex */ 5790 if(numvrtx && vrtx) { 5791 chunklen = 8 + maxvrtx * (ci_s + sk_s + 4 * vc_s); 5792 h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); 5793 if(!h) goto memerr; 5794 memcpy((uint8_t*)h + len, "VRTS", 4); 5795 length = (uint32_t*)((uint8_t*)h + len + 4); 5796 out = (uint8_t*)h + len + 8; 5797 last = M3D_UNDEF; 5798 for(i = 0; i < numvrtx; i++) { 5799 if(vrtx[i].newidx == last) continue; 5800 last = vrtx[i].newidx; 5801 switch(vc_s) { 5802 case 1: 5803 *out++ = (int8_t)(vrtx[i].data.x * 127); 5804 *out++ = (int8_t)(vrtx[i].data.y * 127); 5805 *out++ = (int8_t)(vrtx[i].data.z * 127); 5806 *out++ = (int8_t)(vrtx[i].data.w * 127); 5807 break; 5808 case 2: 5809 *((int16_t*)out) = (int16_t)(vrtx[i].data.x * 32767); out += 2; 5810 *((int16_t*)out) = (int16_t)(vrtx[i].data.y * 32767); out += 2; 5811 *((int16_t*)out) = (int16_t)(vrtx[i].data.z * 32767); out += 2; 5812 *((int16_t*)out) = (int16_t)(vrtx[i].data.w * 32767); out += 2; 5813 break; 5814 case 4: 5815 *((float*)out) = vrtx[i].data.x; out += 4; 5816 *((float*)out) = vrtx[i].data.y; out += 4; 5817 *((float*)out) = vrtx[i].data.z; out += 4; 5818 *((float*)out) = vrtx[i].data.w; out += 4; 5819 break; 5820 case 8: 5821 *((double*)out) = vrtx[i].data.x; out += 8; 5822 *((double*)out) = vrtx[i].data.y; out += 8; 5823 *((double*)out) = vrtx[i].data.z; out += 8; 5824 *((double*)out) = vrtx[i].data.w; out += 8; 5825 break; 5826 } 5827 idx = _m3d_cmapidx(cmap, numcmap, vrtx[i].data.color); 5828 switch(ci_s) { 5829 case 1: *out++ = (uint8_t)(idx); break; 5830 case 2: *((uint16_t*)out) = (uint16_t)(idx); out += 2; break; 5831 case 4: *((uint32_t*)out) = vrtx[i].data.color; out += 4; break; 5832 } 5833 out = _m3d_addidx(out, sk_s, vrtx[i].data.skinid); 5834 } 5835 *length = (uint32_t)((uintptr_t)out - (uintptr_t)((uint8_t*)h + len)); 5836 out = NULL; 5837 len += *length; 5838 } 5839 /* bones chunk */ 5840 if(model->numbone && model->bone && !(flags & M3D_EXP_NOBONE)) { 5841 i = 8 + bi_s + sk_s + model->numbone * (bi_s + si_s + 2*vi_s); 5842 chunklen = i + numskin * nb_s * (bi_s + 1); 5843 h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); 5844 if(!h) goto memerr; 5845 memcpy((uint8_t*)h + len, "BONE", 4); 5846 length = (uint32_t*)((uint8_t*)h + len + 4); 5847 out = (uint8_t*)h + len + 8; 5848 out = _m3d_addidx(out, bi_s, model->numbone); 5849 out = _m3d_addidx(out, sk_s, maxskin); 5850 for(i = 0; i < model->numbone; i++) { 5851 out = _m3d_addidx(out, bi_s, model->bone[i].parent); 5852 out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, model->bone[i].name)); 5853 out = _m3d_addidx(out, vi_s, vrtxidx[model->bone[i].pos]); 5854 out = _m3d_addidx(out, vi_s, vrtxidx[model->bone[i].ori]); 5855 } 5856 if(numskin && skin && sk_s) { 5857 last = M3D_UNDEF; 5858 for(i = 0; i < numskin; i++) { 5859 if(skin[i].newidx == last) continue; 5860 last = skin[i].newidx; 5861 memset(&weights, 0, nb_s); 5862 for(j = k = l = 0, mw = 0.0; j < (uint32_t)nb_s && skin[i].data.boneid[j] != M3D_UNDEF && 5863 skin[i].data.weight[j] > (M3D_FLOAT)0.0; j++) { 5864 if(mw < skin[i].data.weight[j]) { mw = skin[i].data.weight[j]; k = j; } 5865 weights[j] = (uint8_t)(skin[i].data.weight[j] * 255); 5866 if(!weights[j]) { weights[j]++; l--; } 5867 } 5868 weights[k] += l; 5869 switch(nb_s) { 5870 case 1: weights[0] = 255; break; 5871 case 2: memcpy(out, weights, 2); out += 2; break; 5872 case 4: memcpy(out, weights, 4); out += 4; break; 5873 case 8: memcpy(out, weights, 8); out += 8; break; 5874 } 5875 for(j = 0; j < (uint32_t)nb_s && skin[i].data.boneid[j] != M3D_UNDEF && weights[j]; j++) { 5876 out = _m3d_addidx(out, bi_s, skin[i].data.boneid[j]); 5877 *length += bi_s; 5878 } 5879 } 5880 } 5881 *length = (uint32_t)((uintptr_t)out - (uintptr_t)((uint8_t*)h + len)); 5882 out = NULL; 5883 len += *length; 5884 } 5885 /* materials */ 5886 if(model->nummaterial && !(flags & M3D_EXP_NOMATERIAL)) { 5887 for(j = 0; j < model->nummaterial; j++) { 5888 if(mtrlidx[j] == M3D_UNDEF || !model->material[j].numprop || !model->material[j].prop) continue; 5889 m = &model->material[j]; 5890 chunklen = 12 + si_s + m->numprop * 5; 5891 h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); 5892 if(!h) goto memerr; 5893 memcpy((uint8_t*)h + len, "MTRL", 4); 5894 length = (uint32_t*)((uint8_t*)h + len + 4); 5895 out = (uint8_t*)h + len + 8; 5896 out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, m->name)); 5897 for(i = 0; i < m->numprop; i++) { 5898 if(m->prop[i].type >= 128) { 5899 if(m->prop[i].value.textureid >= model->numtexture || 5900 !model->texture[m->prop[i].value.textureid].name) continue; 5901 k = m3dpf_map; 5902 } else { 5903 for(k = 256, l = 0; l < sizeof(m3d_propertytypes)/sizeof(m3d_propertytypes[0]); l++) 5904 if(m->prop[i].type == m3d_propertytypes[l].id) { k = m3d_propertytypes[l].format; break; } 5905 } 5906 if(k == 256) continue; 5907 *out++ = m->prop[i].type; 5908 switch(k) { 5909 case m3dpf_color: 5910 if(!(flags & M3D_EXP_NOCMAP)) { 5911 idx = _m3d_cmapidx(cmap, numcmap, m->prop[i].value.color); 5912 switch(ci_s) { 5913 case 1: *out++ = (uint8_t)(idx); break; 5914 case 2: *((uint16_t*)out) = (uint16_t)(idx); out += 2; break; 5915 case 4: *((uint32_t*)out) = (uint32_t)(m->prop[i].value.color); out += 4; break; 5916 } 5917 } else out--; 5918 break; 5919 case m3dpf_uint8: *out++ = m->prop[i].value.num; break; 5920 case m3dpf_uint16: *((uint16_t*)out) = m->prop[i].value.num; out += 2; break; 5921 case m3dpf_uint32: *((uint32_t*)out) = m->prop[i].value.num; out += 4; break; 5922 case m3dpf_float: *((float*)out) = m->prop[i].value.fnum; out += 4; break; 5923 5924 case m3dpf_map: 5925 idx = _m3d_stridx(str, numstr, model->texture[m->prop[i].value.textureid].name); 5926 out = _m3d_addidx(out, si_s, idx); 5927 break; 5928 } 5929 } 5930 *length = (uint32_t)((uintptr_t)out - (uintptr_t)((uint8_t*)h + len)); 5931 len += *length; 5932 out = NULL; 5933 } 5934 } 5935 /* procedural face */ 5936 if(model->numinlined && model->inlined && !(flags & M3D_EXP_NOFACE)) { 5937 /* all inlined assets which are not textures should be procedural surfaces */ 5938 for(j = 0; j < model->numinlined; j++) { 5939 if(!model->inlined[j].name || !model->inlined[j].name[0] || model->inlined[j].length < 4 || 5940 !model->inlined[j].data || (model->inlined[j].data[1] == 'P' && model->inlined[j].data[2] == 'N' && 5941 model->inlined[j].data[3] == 'G')) 5942 continue; 5943 for(i = k = 0; i < model->numtexture; i++) { 5944 if(!strcmp(model->inlined[j].name, model->texture[i].name)) { k = 1; break; } 5945 } 5946 if(k) continue; 5947 numproc++; 5948 chunklen = 8 + si_s; 5949 h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); 5950 if(!h) goto memerr; 5951 memcpy((uint8_t*)h + len, "PROC", 4); 5952 *((uint32_t*)((uint8_t*)h + len + 4)) = chunklen; 5953 out = (uint8_t*)h + len + 8; 5954 out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, model->inlined[j].name)); 5955 out = NULL; 5956 len += chunklen; 5957 } 5958 } 5959 /* mesh face */ 5960 if(model->numface && face && !(flags & M3D_EXP_NOFACE)) { 5961 chunklen = 8 + si_s + model->numface * (9 * vi_s + 3 * ti_s + si_s + 1); 5962 h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); 5963 if(!h) goto memerr; 5964 memcpy((uint8_t*)h + len, "MESH", 4); 5965 length = (uint32_t*)((uint8_t*)h + len + 4); 5966 out = (uint8_t*)h + len + 8; 5967 last = M3D_UNDEF; 5968 #ifdef M3D_VERTEXMAX 5969 lastp = M3D_UNDEF; 5970 #endif 5971 for(i = 0; i < model->numface; i++) { 5972 if(!(flags & M3D_EXP_NOMATERIAL) && face[i].data.materialid != last) { 5973 last = face[i].data.materialid; 5974 idx = last < model->nummaterial ? _m3d_stridx(str, numstr, model->material[last].name) : 0; 5975 *out++ = 0; 5976 out = _m3d_addidx(out, si_s, idx); 5977 } 5978 #ifdef M3D_VERTEXMAX 5979 if(!(flags & M3D_EXP_NOVRTMAX) && face[i].data.paramid != lastp) { 5980 lastp = face[i].data.paramid; 5981 idx = lastp < model->numparam ? _m3d_stridx(str, numstr, model->param[lastp].name) : 0; 5982 *out++ = 0; 5983 out = _m3d_addidx(out, si_s, idx); 5984 } 5985 #endif 5986 /* hardcoded triangles. */ 5987 k = (3 << 4) | 5988 (((flags & M3D_EXP_NOTXTCRD) || !ti_s || face[i].data.texcoord[0] == M3D_UNDEF || 5989 face[i].data.texcoord[1] == M3D_UNDEF || face[i].data.texcoord[2] == M3D_UNDEF) ? 0 : 1) | 5990 (((flags & M3D_EXP_NONORMAL) || face[i].data.normal[0] == M3D_UNDEF || 5991 face[i].data.normal[1] == M3D_UNDEF || face[i].data.normal[2] == M3D_UNDEF) ? 0 : 2) 5992 #ifdef M3D_VERTEXMAX 5993 | (((flags & M3D_EXP_NOVRTMAX) || face[i].data.vertmax[0] == M3D_UNDEF || 5994 face[i].data.vertmax[1] == M3D_UNDEF || face[i].data.vertmax[2] == M3D_UNDEF) ? 0 : 4) 5995 #endif 5996 ; 5997 *out++ = k; 5998 for(j = 0; j < 3; j++) { 5999 out = _m3d_addidx(out, vi_s, vrtxidx[face[i].data.vertex[j]]); 6000 if(k & 1) 6001 out = _m3d_addidx(out, ti_s, tmapidx[face[i].data.texcoord[j]]); 6002 if(k & 2) 6003 out = _m3d_addidx(out, vi_s, vrtxidx[face[i].data.normal[j]]); 6004 #ifdef M3D_VERTEXMAX 6005 if(k & 4) 6006 out = _m3d_addidx(out, vi_s, vrtxidx[face[i].data.vertmax[j]]); 6007 #endif 6008 } 6009 } 6010 *length = (uint32_t)((uintptr_t)out - (uintptr_t)((uint8_t*)h + len)); 6011 len += *length; 6012 out = NULL; 6013 } 6014 /* voxel face */ 6015 if(model->numvoxtype && model->voxtype && !(flags & M3D_EXP_NOFACE)) { 6016 chunklen = 8 + si_s + model->numvoxtype * (ci_s + si_s + 3 + sk_s); 6017 for(i = 0; i < model->numvoxtype; i++) 6018 chunklen += model->voxtype[i].numitem * (2 + si_s); 6019 h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); 6020 if(!h) goto memerr; 6021 memcpy((uint8_t*)h + len, "VOXT", 4); 6022 length = (uint32_t*)((uint8_t*)h + len + 4); 6023 out = (uint8_t*)h + len + 8; 6024 for(i = 0; i < model->numvoxtype; i++) { 6025 if(!(flags & M3D_EXP_NOCMAP)) { 6026 idx = _m3d_cmapidx(cmap, numcmap, model->voxtype[i].color); 6027 switch(ci_s) { 6028 case 1: *out++ = (uint8_t)(idx); break; 6029 case 2: *((uint16_t*)out) = (uint16_t)(idx); out += 2; break; 6030 case 4: *((uint32_t*)out) = (uint32_t)(model->voxtype[i].color); out += 4; break; 6031 } 6032 } 6033 out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, model->voxtype[i].name)); 6034 *out++ = (model->voxtype[i].rotation & 0xBF) | (((model->voxtype[i].voxshape >> 8) & 1) << 6); 6035 *out++ = model->voxtype[i].voxshape; 6036 *out++ = model->voxtype[i].numitem; 6037 if(!(flags & M3D_EXP_NOBONE) && model->numbone && maxskin) 6038 out = _m3d_addidx(out, sk_s, skinidx[model->voxtype[i].skinid]); 6039 for(j = 0; j < model->voxtype[i].numitem; j++) { 6040 out = _m3d_addidx(out, 2, model->voxtype[i].item[j].count); 6041 out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, model->voxtype[i].item[j].name)); 6042 } 6043 } 6044 *length = (uint32_t)((uintptr_t)out - (uintptr_t)((uint8_t*)h + len)); 6045 len += *length; 6046 out = NULL; 6047 } 6048 if(model->numvoxel && model->voxel && !(flags & M3D_EXP_NOFACE)) { 6049 for(j = 0; j < model->numvoxel; j++) { 6050 chunklen = 8 + si_s + 6 * vd_s + 2 + model->voxel[j].w * model->voxel[j].h * model->voxel[j].d * 3; 6051 h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); 6052 if(!h) goto memerr; 6053 memcpy((uint8_t*)h + len, "VOXD", 4); 6054 length = (uint32_t*)((uint8_t*)h + len + 4); 6055 out = (uint8_t*)h + len + 8; 6056 out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, model->voxel[j].name)); 6057 out = _m3d_addidx(out, vd_s, model->voxel[j].x); 6058 out = _m3d_addidx(out, vd_s, model->voxel[j].y); 6059 out = _m3d_addidx(out, vd_s, model->voxel[j].z); 6060 out = _m3d_addidx(out, vd_s, model->voxel[j].w); 6061 out = _m3d_addidx(out, vd_s, model->voxel[j].h); 6062 out = _m3d_addidx(out, vd_s, model->voxel[j].d); 6063 *out++ = model->voxel[j].uncertain; 6064 *out++ = model->voxel[j].groupid; 6065 /* RLE compress voxel data */ 6066 n = model->voxel[j].w * model->voxel[j].h * model->voxel[j].d; 6067 k = o = 0; out[o++] = 0; 6068 for(i = 0; i < n; i++) { 6069 for(l = 1; l < 128 && i + l < n && model->voxel[j].data[i] == model->voxel[j].data[i + l]; l++); 6070 if(l > 1) { 6071 l--; 6072 if(out[k]) { out[k]--; out[o++] = 0x80 | l; } 6073 else out[k] = 0x80 | l; 6074 switch(vp_s) { 6075 case 1: out[o++] = model->voxel[j].data[i]; break; 6076 default: *((uint16_t*)(out + o)) = model->voxel[j].data[i]; o += 2; break; 6077 } 6078 k = o; out[o++] = 0; 6079 i += l; 6080 continue; 6081 } 6082 out[k]++; 6083 switch(vp_s) { 6084 case 1: out[o++] = model->voxel[j].data[i]; break; 6085 default: *((uint16_t*)(out + o)) = model->voxel[j].data[i]; o += 2; break; 6086 } 6087 if(out[k] > 127) { out[k]--; k = o; out[o++] = 0; } 6088 } 6089 if(!(out[k] & 0x80)) { if(out[k]) out[k]--; else o--; } 6090 *length = (uint32_t)((uintptr_t)out + (uintptr_t)o - (uintptr_t)((uint8_t*)h + len)); 6091 len += *length; 6092 out = NULL; 6093 } 6094 } 6095 /* mathematical shapes face */ 6096 if(model->numshape && model->shape && !(flags & M3D_EXP_NOFACE)) { 6097 for(j = 0; j < model->numshape; j++) { 6098 chunklen = 12 + si_s + model->shape[j].numcmd * (M3D_CMDMAXARG + 1) * 4; 6099 h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); 6100 if(!h) goto memerr; 6101 memcpy((uint8_t*)h + len, "SHPE", 4); 6102 length = (uint32_t*)((uint8_t*)h + len + 4); 6103 out = (uint8_t*)h + len + 8; 6104 out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, model->shape[j].name)); 6105 out = _m3d_addidx(out, bi_s, model->shape[j].group); 6106 for(i = 0; i < model->shape[j].numcmd; i++) { 6107 cmd = &model->shape[j].cmd[i]; 6108 if(cmd->type >= (unsigned int)(sizeof(m3d_commandtypes)/sizeof(m3d_commandtypes[0])) || !cmd->arg) 6109 continue; 6110 cd = &m3d_commandtypes[cmd->type]; 6111 *out++ = (cmd->type & 0x7F) | (cmd->type > 127 ? 0x80 : 0); 6112 if(cmd->type > 127) *out++ = (cmd->type >> 7) & 0xff; 6113 for(k = n = 0, l = cd->p; k < l; k++) { 6114 switch(cd->a[((k - n) % (cd->p - n)) + n]) { 6115 case m3dcp_mi_t: 6116 out = _m3d_addidx(out, si_s, cmd->arg[k] < model->nummaterial ? 6117 _m3d_stridx(str, numstr, model->material[cmd->arg[k]].name) : 0); 6118 break; 6119 case m3dcp_vc_t: 6120 min_x = *((float*)&cmd->arg[k]); 6121 switch(vc_s) { 6122 case 1: *out++ = (int8_t)(min_x * 127); break; 6123 case 2: *((int16_t*)out) = (int16_t)(min_x * 32767); out += 2; break; 6124 case 4: *((float*)out) = min_x; out += 4; break; 6125 case 8: *((double*)out) = min_x; out += 8; break; 6126 } 6127 break; 6128 case m3dcp_hi_t: out = _m3d_addidx(out, hi_s, cmd->arg[k]); break; 6129 case m3dcp_fi_t: out = _m3d_addidx(out, fi_s, cmd->arg[k]); break; 6130 case m3dcp_ti_t: out = _m3d_addidx(out, ti_s, cmd->arg[k]); break; 6131 case m3dcp_qi_t: 6132 case m3dcp_vi_t: out = _m3d_addidx(out, vi_s, cmd->arg[k]); break; 6133 case m3dcp_i1_t: out = _m3d_addidx(out, 1, cmd->arg[k]); break; 6134 case m3dcp_i2_t: out = _m3d_addidx(out, 2, cmd->arg[k]); break; 6135 case m3dcp_i4_t: out = _m3d_addidx(out, 4, cmd->arg[k]); break; 6136 case m3dcp_va_t: out = _m3d_addidx(out, 4, cmd->arg[k]); 6137 n = k + 1; l += (cmd->arg[k] - 1) * (cd->p - k - 1); 6138 break; 6139 } 6140 } 6141 } 6142 *length = (uint32_t)((uintptr_t)out - (uintptr_t)((uint8_t*)h + len)); 6143 len += *length; 6144 out = NULL; 6145 } 6146 } 6147 /* annotation labels */ 6148 if(model->numlabel && model->label) { 6149 for(i = 0, length = NULL; i < model->numlabel; i++) { 6150 if(!i || _m3d_strcmp(sl, model->label[i].lang) || _m3d_strcmp(sn, model->label[i].name)) { 6151 sl = model->label[i].lang; 6152 sn = model->label[i].name; 6153 if(length) { 6154 *length = (uint32_t)((uintptr_t)out - (uintptr_t)((uint8_t*)h + len)); 6155 len += *length; 6156 } 6157 chunklen = 8 + 2 * si_s + ci_s + model->numlabel * (vi_s + si_s); 6158 h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); 6159 if(!h) { sn = NULL; sl = NULL; goto memerr; } 6160 memcpy((uint8_t*)h + len, "LBLS", 4); 6161 length = (uint32_t*)((uint8_t*)h + len + 4); 6162 out = (uint8_t*)h + len + 8; 6163 out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, model->label[l].name)); 6164 out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, model->label[l].lang)); 6165 idx = _m3d_cmapidx(cmap, numcmap, model->label[i].color); 6166 switch(ci_s) { 6167 case 1: *out++ = (uint8_t)(idx); break; 6168 case 2: *((uint16_t*)out) = (uint16_t)(idx); out += 2; break; 6169 case 4: *((uint32_t*)out) = model->label[i].color; out += 4; break; 6170 } 6171 } 6172 out = _m3d_addidx(out, vi_s, vrtxidx[model->label[i].vertexid]); 6173 out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, model->label[l].text)); 6174 } 6175 if(length) { 6176 *length = (uint32_t)((uintptr_t)out - (uintptr_t)((uint8_t*)h + len)); 6177 len += *length; 6178 } 6179 out = NULL; 6180 sn = sl = NULL; 6181 } 6182 /* actions */ 6183 if(model->numaction && model->action && model->numbone && model->bone && !(flags & M3D_EXP_NOACTION)) { 6184 for(j = 0; j < model->numaction; j++) { 6185 a = &model->action[j]; 6186 chunklen = 14 + si_s + a->numframe * (4 + fc_s + maxt * (bi_s + 2 * vi_s)); 6187 h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); 6188 if(!h) goto memerr; 6189 memcpy((uint8_t*)h + len, "ACTN", 4); 6190 length = (uint32_t*)((uint8_t*)h + len + 4); 6191 out = (uint8_t*)h + len + 8; 6192 out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, a->name)); 6193 *((uint16_t*)out) = (uint16_t)(a->numframe); out += 2; 6194 *((uint32_t*)out) = (uint32_t)(a->durationmsec); out += 4; 6195 for(i = 0; i < a->numframe; i++) { 6196 *((uint32_t*)out) = (uint32_t)(a->frame[i].msec); out += 4; 6197 out = _m3d_addidx(out, fc_s, a->frame[i].numtransform); 6198 for(k = 0; k < a->frame[i].numtransform; k++) { 6199 out = _m3d_addidx(out, bi_s, a->frame[i].transform[k].boneid); 6200 out = _m3d_addidx(out, vi_s, vrtxidx[a->frame[i].transform[k].pos]); 6201 out = _m3d_addidx(out, vi_s, vrtxidx[a->frame[i].transform[k].ori]); 6202 } 6203 } 6204 *length = (uint32_t)((uintptr_t)out - (uintptr_t)((uint8_t*)h + len)); 6205 len += *length; 6206 out = NULL; 6207 } 6208 } 6209 /* inlined assets */ 6210 if(model->numinlined && model->inlined && (numproc || (flags & M3D_EXP_INLINE))) { 6211 for(j = 0; j < model->numinlined; j++) { 6212 if(!model->inlined[j].name || !model->inlined[j].name[0] || model->inlined[j].length<4 || !model->inlined[j].data) 6213 continue; 6214 if(!(flags & M3D_EXP_INLINE)) { 6215 if(model->inlined[j].data[1] == 'P' && model->inlined[j].data[2] == 'N' && model->inlined[j].data[3] == 'G') 6216 continue; 6217 for(i = k = 0; i < model->numtexture; i++) { 6218 if(!strcmp(model->inlined[j].name, model->texture[i].name)) { k = 1; break; } 6219 } 6220 if(k) continue; 6221 } 6222 chunklen = 8 + si_s + model->inlined[j].length; 6223 h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); 6224 if(!h) goto memerr; 6225 memcpy((uint8_t*)h + len, "ASET", 4); 6226 *((uint32_t*)((uint8_t*)h + len + 4)) = chunklen; 6227 out = (uint8_t*)h + len + 8; 6228 out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, model->inlined[j].name)); 6229 memcpy(out, model->inlined[j].data, model->inlined[j].length); 6230 out = NULL; 6231 len += chunklen; 6232 } 6233 } 6234 /* extra chunks */ 6235 if(model->numextra && model->extra && (flags & M3D_EXP_EXTRA)) { 6236 for(j = 0; j < model->numextra; j++) { 6237 if(!model->extra[j] || model->extra[j]->length < 8) 6238 continue; 6239 chunklen = model->extra[j]->length; 6240 h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); 6241 if(!h) goto memerr; 6242 memcpy((uint8_t*)h + len, model->extra[j], chunklen); 6243 len += chunklen; 6244 } 6245 } 6246 /* add end chunk */ 6247 h = (m3dhdr_t*)M3D_REALLOC(h, len + 4); 6248 if(!h) goto memerr; 6249 memcpy((uint8_t*)h + len, "OMD3", 4); 6250 len += 4; 6251 /* zlib compress */ 6252 if(!(flags & M3D_EXP_NOZLIB)) { 6253 M3D_LOG("Deflating chunks"); 6254 z = stbi_zlib_compress((unsigned char *)h, len, (int*)&l, 9); 6255 if(z && l > 0 && l < len) { len = l; M3D_FREE(h); h = (m3dhdr_t*)z; } 6256 } 6257 /* add file header at the begining */ 6258 len += 8; 6259 out = (unsigned char*)M3D_MALLOC(len); 6260 if(!out) goto memerr; 6261 memcpy(out, "3DMO", 4); 6262 *((uint32_t*)(out + 4)) = len; 6263 /* preview image chunk, must be the first if exists */ 6264 if(model->preview.data && model->preview.length) { 6265 chunklen = 8 + model->preview.length; 6266 out = (unsigned char*)M3D_REALLOC(out, len + chunklen); 6267 if(!out) goto memerr; 6268 memcpy((uint8_t*)out + 8, "PRVW", 4); 6269 *((uint32_t*)((uint8_t*)out + 8 + 4)) = chunklen; 6270 memcpy((uint8_t*)out + 8 + 8, model->preview.data, model->preview.length); 6271 *((uint32_t*)(out + 4)) += chunklen; 6272 } else 6273 chunklen = 0; 6274 memcpy(out + 8 + chunklen, h, len - 8); 6275 } 6276 if(size) *size = out ? len : 0; 6277 if(vrtxidx) M3D_FREE(vrtxidx); 6278 if(mtrlidx) M3D_FREE(mtrlidx); 6279 if(tmapidx) M3D_FREE(tmapidx); 6280 if(skinidx) M3D_FREE(skinidx); 6281 if(norm) M3D_FREE(norm); 6282 if(face) M3D_FREE(face); 6283 if(cmap) M3D_FREE(cmap); 6284 if(tmap) M3D_FREE(tmap); 6285 if(skin) M3D_FREE(skin); 6286 if(str) M3D_FREE(str); 6287 if(vrtx) M3D_FREE(vrtx); 6288 if(opa) free(opa); 6289 if(h) M3D_FREE(h); 6290 return out; 6291 } 6292 #endif 6293 6294 #endif 6295 6296 #ifdef __cplusplus 6297 } 6298 #ifdef M3D_CPPWRAPPER 6299 #include <vector> 6300 #include <string> 6301 #include <memory> 6302 6303 /*** C++ wrapper class ***/ 6304 namespace M3D { 6305 #ifdef M3D_IMPLEMENTATION 6306 6307 class Model { 6308 public: 6309 m3d_t *model; 6310 6311 public: 6312 Model() { 6313 this->model = (m3d_t*)malloc(sizeof(m3d_t)); memset(this->model, 0, sizeof(m3d_t)); 6314 } 6315 Model(_unused const std::string &data, _unused m3dread_t ReadFileCB, 6316 _unused m3dfree_t FreeCB, _unused M3D::Model mtllib) { 6317 #ifndef M3D_NOIMPORTER 6318 this->model = m3d_load((unsigned char *)data.data(), ReadFileCB, FreeCB, mtllib.model); 6319 #else 6320 Model(); 6321 #endif 6322 } 6323 Model(_unused const std::vector<unsigned char> data, _unused m3dread_t ReadFileCB, 6324 _unused m3dfree_t FreeCB, _unused M3D::Model mtllib) { 6325 #ifndef M3D_NOIMPORTER 6326 this->model = m3d_load((unsigned char *)&data[0], ReadFileCB, FreeCB, mtllib.model); 6327 #else 6328 Model(); 6329 #endif 6330 } 6331 Model(_unused const unsigned char *data, _unused m3dread_t ReadFileCB, 6332 _unused m3dfree_t FreeCB, _unused M3D::Model mtllib) { 6333 #ifndef M3D_NOIMPORTER 6334 this->model = m3d_load((unsigned char*)data, ReadFileCB, FreeCB, mtllib.model); 6335 #else 6336 Model(); 6337 #endif 6338 } 6339 ~Model() { m3d_free(this->model); } 6340 6341 public: 6342 m3d_t *getCStruct() { return this->model; } 6343 std::string getName() { return std::string(this->model->name); } 6344 void setName(std::string name) { this->model->name = (char*)name.c_str(); } 6345 std::string getLicense() { return std::string(this->model->license); } 6346 void setLicense(std::string license) { this->model->license = (char*)license.c_str(); } 6347 std::string getAuthor() { return std::string(this->model->author); } 6348 void setAuthor(std::string author) { this->model->author = (char*)author.c_str(); } 6349 std::string getDescription() { return std::string(this->model->desc); } 6350 void setDescription(std::string desc) { this->model->desc = (char*)desc.c_str(); } 6351 float getScale() { return this->model->scale; } 6352 void setScale(float scale) { this->model->scale = scale; } 6353 std::vector<unsigned char> getPreview() { return this->model->preview.data ? 6354 std::vector<unsigned char>(this->model->preview.data, this->model->preview.data + this->model->preview.length) : 6355 std::vector<unsigned char>(); } 6356 std::vector<uint32_t> getColorMap() { return this->model->cmap ? std::vector<uint32_t>(this->model->cmap, 6357 this->model->cmap + this->model->numcmap) : std::vector<uint32_t>(); } 6358 std::vector<m3dti_t> getTextureMap() { return this->model->tmap ? std::vector<m3dti_t>(this->model->tmap, 6359 this->model->tmap + this->model->numtmap) : std::vector<m3dti_t>(); } 6360 std::vector<m3dtx_t> getTextures() { return this->model->texture ? std::vector<m3dtx_t>(this->model->texture, 6361 this->model->texture + this->model->numtexture) : std::vector<m3dtx_t>(); } 6362 std::string getTextureName(int idx) { return idx >= 0 && (unsigned int)idx < this->model->numtexture ? 6363 std::string(this->model->texture[idx].name) : nullptr; } 6364 std::vector<m3db_t> getBones() { return this->model->bone ? std::vector<m3db_t>(this->model->bone, this->model->bone + 6365 this->model->numbone) : std::vector<m3db_t>(); } 6366 std::string getBoneName(int idx) { return idx >= 0 && (unsigned int)idx < this->model->numbone ? 6367 std::string(this->model->bone[idx].name) : nullptr; } 6368 std::vector<m3dm_t> getMaterials() { return this->model->material ? std::vector<m3dm_t>(this->model->material, 6369 this->model->material + this->model->nummaterial) : std::vector<m3dm_t>(); } 6370 std::string getMaterialName(int idx) { return idx >= 0 && (unsigned int)idx < this->model->nummaterial ? 6371 std::string(this->model->material[idx].name) : nullptr; } 6372 int getMaterialPropertyInt(int idx, int type) { 6373 if (idx < 0 || (unsigned int)idx >= this->model->nummaterial || type < 0 || type >= 127 || 6374 !this->model->material[idx].prop) return -1; 6375 for (int i = 0; i < this->model->material[idx].numprop; i++) { 6376 if (this->model->material[idx].prop[i].type == type) 6377 return this->model->material[idx].prop[i].value.num; 6378 } 6379 return -1; 6380 } 6381 uint32_t getMaterialPropertyColor(int idx, int type) { return this->getMaterialPropertyInt(idx, type); } 6382 float getMaterialPropertyFloat(int idx, int type) { 6383 if (idx < 0 || (unsigned int)idx >= this->model->nummaterial || type < 0 || type >= 127 || 6384 !this->model->material[idx].prop) return -1.0f; 6385 for (int i = 0; i < this->model->material[idx].numprop; i++) { 6386 if (this->model->material[idx].prop[i].type == type) 6387 return this->model->material[idx].prop[i].value.fnum; 6388 } 6389 return -1.0f; 6390 } 6391 m3dtx_t* getMaterialPropertyMap(int idx, int type) { 6392 if (idx < 0 || (unsigned int)idx >= this->model->nummaterial || type < 128 || type > 255 || 6393 !this->model->material[idx].prop) return nullptr; 6394 for (int i = 0; i < this->model->material[idx].numprop; i++) { 6395 if (this->model->material[idx].prop[i].type == type) 6396 return this->model->material[idx].prop[i].value.textureid < this->model->numtexture ? 6397 &this->model->texture[this->model->material[idx].prop[i].value.textureid] : nullptr; 6398 } 6399 return nullptr; 6400 } 6401 std::vector<m3dv_t> getVertices() { return this->model->vertex ? std::vector<m3dv_t>(this->model->vertex, 6402 this->model->vertex + this->model->numvertex) : std::vector<m3dv_t>(); } 6403 std::vector<m3df_t> getFace() { return this->model->face ? std::vector<m3df_t>(this->model->face, this->model->face + 6404 this->model->numface) : std::vector<m3df_t>(); } 6405 std::vector<m3dvt_t> getVoxelTypes() { return this->model->voxtype ? std::vector<m3dvt_t>(this->model->voxtype, 6406 this->model->voxtype + this->model->numvoxtype) : std::vector<m3dvt_t>(); } 6407 std::string getVoxelTypeName(int idx) { return idx >= 0 && (unsigned int)idx < this->model->numvoxtype && 6408 this->model->voxtype[idx].name && this->model->voxtype[idx].name[0] ? 6409 std::string(this->model->voxtype[idx].name) : nullptr; } 6410 std::vector<m3dvi_t> getVoxelTypeItems(int idx) { return idx >= 0 && (unsigned int)idx < this->model->numvoxtype && 6411 this->model->voxtype[idx].item ? std::vector<m3dvi_t>(this->model->voxtype[idx].item, 6412 this->model->voxtype[idx].item + this->model->voxtype[idx].numitem) : std::vector<m3dvi_t>(); } 6413 std::vector<m3dvx_t> getVoxelBlocks() { return this->model->voxel ? std::vector<m3dvx_t>(this->model->voxel, 6414 this->model->voxel + this->model->numvoxel) : std::vector<m3dvx_t>(); } 6415 std::string getVoxelBlockName(int idx) { return idx >= 0 && (unsigned int)idx < this->model->numvoxel && 6416 this->model->voxel[idx].name && this->model->voxel[idx].name[0] ? 6417 std::string(this->model->voxel[idx].name) : nullptr; } 6418 std::vector<M3D_VOXEL> getVoxelBlockData(int idx) { return idx >= 0 && (unsigned int)idx < this->model->numvoxel && 6419 this->model->voxel[idx].data ? std::vector<M3D_VOXEL>(this->model->voxel[idx].data, 6420 this->model->voxel[idx].data + this->model->voxel[idx].w*this->model->voxel[idx].h*this->model->voxel[idx].d) : 6421 std::vector<M3D_VOXEL>(); } 6422 std::vector<m3dh_t> getShape() { return this->model->shape ? std::vector<m3dh_t>(this->model->shape, 6423 this->model->shape + this->model->numshape) : std::vector<m3dh_t>(); } 6424 std::string getShapeName(int idx) { return idx >= 0 && (unsigned int)idx < this->model->numshape && 6425 this->model->shape[idx].name && this->model->shape[idx].name[0] ? 6426 std::string(this->model->shape[idx].name) : nullptr; } 6427 unsigned int getShapeGroup(int idx) { return idx >= 0 && (unsigned int)idx < this->model->numshape ? 6428 this->model->shape[idx].group : 0xFFFFFFFF; } 6429 std::vector<m3dc_t> getShapeCommands(int idx) { return idx >= 0 && (unsigned int)idx < this->model->numshape && 6430 this->model->shape[idx].cmd ? std::vector<m3dc_t>(this->model->shape[idx].cmd, this->model->shape[idx].cmd + 6431 this->model->shape[idx].numcmd) : std::vector<m3dc_t>(); } 6432 std::vector<m3dl_t> getAnnotationLabels() { return this->model->label ? std::vector<m3dl_t>(this->model->label, 6433 this->model->label + this->model->numlabel) : std::vector<m3dl_t>(); } 6434 std::vector<m3ds_t> getSkin() { return this->model->skin ? std::vector<m3ds_t>(this->model->skin, this->model->skin + 6435 this->model->numskin) : std::vector<m3ds_t>(); } 6436 std::vector<m3da_t> getActions() { return this->model->action ? std::vector<m3da_t>(this->model->action, 6437 this->model->action + this->model->numaction) : std::vector<m3da_t>(); } 6438 std::string getActionName(int aidx) { return aidx >= 0 && (unsigned int)aidx < this->model->numaction ? 6439 std::string(this->model->action[aidx].name) : nullptr; } 6440 unsigned int getActionDuration(int aidx) { return aidx >= 0 && (unsigned int)aidx < this->model->numaction ? 6441 this->model->action[aidx].durationmsec : 0; } 6442 std::vector<m3dfr_t> getActionFrames(int aidx) { return aidx >= 0 && (unsigned int)aidx < this->model->numaction ? 6443 std::vector<m3dfr_t>(this->model->action[aidx].frame, this->model->action[aidx].frame + 6444 this->model->action[aidx].numframe) : std::vector<m3dfr_t>(); } 6445 unsigned int getActionFrameTimestamp(int aidx, int fidx) { return aidx >= 0 && (unsigned int)aidx < this->model->numaction? 6446 (fidx >= 0 && (unsigned int)fidx < this->model->action[aidx].numframe ? 6447 this->model->action[aidx].frame[fidx].msec : 0) : 0; } 6448 std::vector<m3dtr_t> getActionFrameTransforms(int aidx, int fidx) { 6449 return aidx >= 0 && (unsigned int)aidx < this->model->numaction ? ( 6450 fidx >= 0 && (unsigned int)fidx < this->model->action[aidx].numframe ? 6451 std::vector<m3dtr_t>(this->model->action[aidx].frame[fidx].transform, 6452 this->model->action[aidx].frame[fidx].transform + this->model->action[aidx].frame[fidx].numtransform) : 6453 std::vector<m3dtr_t>()) : std::vector<m3dtr_t>(); } 6454 std::vector<m3dtr_t> getActionFrame(int aidx, int fidx, std::vector<m3dtr_t> skeleton) { 6455 m3dtr_t *pose = m3d_frame(this->model, (unsigned int)aidx, (unsigned int)fidx, 6456 skeleton.size() ? &skeleton[0] : nullptr); 6457 return std::vector<m3dtr_t>(pose, pose + this->model->numbone); } 6458 std::vector<m3db_t> getActionPose(int aidx, unsigned int msec) { 6459 m3db_t *pose = m3d_pose(this->model, (unsigned int)aidx, (unsigned int)msec); 6460 return std::vector<m3db_t>(pose, pose + this->model->numbone); } 6461 std::vector<m3di_t> getInlinedAssets() { return this->model->inlined ? std::vector<m3di_t>(this->model->inlined, 6462 this->model->inlined + this->model->numinlined) : std::vector<m3di_t>(); } 6463 std::vector<std::unique_ptr<m3dchunk_t>> getExtras() { return this->model->extra ? 6464 std::vector<std::unique_ptr<m3dchunk_t>>(this->model->extra, 6465 this->model->extra + this->model->numextra) : std::vector<std::unique_ptr<m3dchunk_t>>(); } 6466 std::vector<unsigned char> Save(_unused int quality, _unused int flags) { 6467 #ifdef M3D_EXPORTER 6468 unsigned int size; 6469 unsigned char *ptr = m3d_save(this->model, quality, flags, &size); 6470 return ptr && size ? std::vector<unsigned char>(ptr, ptr + size) : std::vector<unsigned char>(); 6471 #else 6472 return std::vector<unsigned char>(); 6473 #endif 6474 } 6475 }; 6476 6477 #else 6478 class Model { 6479 private: 6480 m3d_t *model; 6481 6482 public: 6483 Model(const std::string &data, m3dread_t ReadFileCB, m3dfree_t FreeCB); 6484 Model(const std::vector<unsigned char> data, m3dread_t ReadFileCB, m3dfree_t FreeCB); 6485 Model(const unsigned char *data, m3dread_t ReadFileCB, m3dfree_t FreeCB); 6486 Model(); 6487 ~Model(); 6488 6489 public: 6490 m3d_t *getCStruct(); 6491 std::string getName(); 6492 void setName(std::string name); 6493 std::string getLicense(); 6494 void setLicense(std::string license); 6495 std::string getAuthor(); 6496 void setAuthor(std::string author); 6497 std::string getDescription(); 6498 void setDescription(std::string desc); 6499 float getScale(); 6500 void setScale(float scale); 6501 std::vector<unsigned char> getPreview(); 6502 std::vector<uint32_t> getColorMap(); 6503 std::vector<m3dti_t> getTextureMap(); 6504 std::vector<m3dtx_t> getTextures(); 6505 std::string getTextureName(int idx); 6506 std::vector<m3db_t> getBones(); 6507 std::string getBoneName(int idx); 6508 std::vector<m3dm_t> getMaterials(); 6509 std::string getMaterialName(int idx); 6510 int getMaterialPropertyInt(int idx, int type); 6511 uint32_t getMaterialPropertyColor(int idx, int type); 6512 float getMaterialPropertyFloat(int idx, int type); 6513 m3dtx_t* getMaterialPropertyMap(int idx, int type); 6514 std::vector<m3dv_t> getVertices(); 6515 std::vector<m3df_t> getFace(); 6516 std::vector<m3dvt_t> getVoxelTypes(); 6517 std::string getVoxelTypeName(int idx); 6518 std::vector<m3dvi_t> getVoxelTypeItems(int idx); 6519 std::vector<m3dvx_t> getVoxelBlocks(); 6520 std::string getVoxelBlockName(int idx); 6521 std::vector<M3D_VOXEL> getVoxelBlockData(int idx); 6522 std::vector<m3dh_t> getShape(); 6523 std::string getShapeName(int idx); 6524 unsigned int getShapeGroup(int idx); 6525 std::vector<m3dc_t> getShapeCommands(int idx); 6526 std::vector<m3dl_t> getAnnotationLabels(); 6527 std::vector<m3ds_t> getSkin(); 6528 std::vector<m3da_t> getActions(); 6529 std::string getActionName(int aidx); 6530 unsigned int getActionDuration(int aidx); 6531 std::vector<m3dfr_t> getActionFrames(int aidx); 6532 unsigned int getActionFrameTimestamp(int aidx, int fidx); 6533 std::vector<m3dtr_t> getActionFrameTransforms(int aidx, int fidx); 6534 std::vector<m3dtr_t> getActionFrame(int aidx, int fidx, std::vector<m3dtr_t> skeleton); 6535 std::vector<m3db_t> getActionPose(int aidx, unsigned int msec); 6536 std::vector<m3di_t> getInlinedAssets(); 6537 std::vector<std::unique_ptr<m3dchunk_t>> getExtras(); 6538 std::vector<unsigned char> Save(int quality, int flags); 6539 }; 6540 6541 #endif /* impl */ 6542 } 6543 #endif 6544 6545 #endif /* __cplusplus */ 6546 6547 #endif