| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397 |
- /*
- *
- * MIT License
- *
- * Copyright (c) 2018 Richard Knight
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
- #ifndef FAST_OBJ_HDR
- #define FAST_OBJ_HDR
- typedef struct
- {
- /* Texture name from .mtl file */
- char* name;
- /* Resolved path to texture */
- char* path;
- } fastObjTexture;
- typedef struct
- {
- /* Material name */
- char* name;
- /* Parameters */
- float Ka[3]; /* Ambient */
- float Kd[3]; /* Diffuse */
- float Ks[3]; /* Specular */
- float Ke[3]; /* Emission */
- float Kt[3]; /* Transmittance */
- float Ns; /* Shininess */
- float Ni; /* Index of refraction */
- float Tf[3]; /* Transmission filter */
- float d; /* Disolve (alpha) */
- int illum; /* Illumination model */
- /* Texture maps */
- fastObjTexture map_Ka;
- fastObjTexture map_Kd;
- fastObjTexture map_Ks;
- fastObjTexture map_Ke;
- fastObjTexture map_Kt;
- fastObjTexture map_Ns;
- fastObjTexture map_Ni;
- fastObjTexture map_d;
- fastObjTexture map_bump;
-
- } fastObjMaterial;
- typedef struct
- {
- unsigned int p;
- unsigned int t;
- unsigned int n;
- } fastObjIndex;
- typedef struct
- {
- /* Group name */
- char* name;
- /* Number of faces */
- unsigned int face_count;
- /* First face in fastObjMesh face_* arrays */
- unsigned int face_offset;
- /* First index in fastObjMesh indices array */
- unsigned int index_offset;
- } fastObjGroup;
- typedef struct
- {
- /* Vertex data */
- unsigned int position_count;
- float* positions;
- unsigned int texcoord_count;
- float* texcoords;
- unsigned int normal_count;
- float* normals;
- /* Face data: one element for each face */
- unsigned int face_count;
- unsigned int* face_vertices;
- unsigned int* face_materials;
- /* Index data: one element for each face vertex */
- fastObjIndex* indices;
- /* Materials */
- unsigned int material_count;
- fastObjMaterial* materials;
- /* Mesh groups */
- unsigned int group_count;
- fastObjGroup* groups;
- } fastObjMesh;
- fastObjMesh* fast_obj_read(const char* path);
- void fast_obj_destroy(fastObjMesh* mesh);
- #endif
- #ifdef FAST_OBJ_IMPLEMENTATION
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #ifndef FAST_OBJ_REALLOC
- #define FAST_OBJ_REALLOC realloc
- #endif
- #ifndef FAST_OBJ_FREE
- #define FAST_OBJ_FREE free
- #endif
- #ifdef _WIN32
- #define FAST_OBJ_SEPARATOR '\\'
- #define FAST_OBJ_OTHER_SEP '/'
- #else
- #define FAST_OBJ_SEPARATOR '/'
- #define FAST_OBJ_OTHER_SEP '\\'
- #endif
- /* Size of buffer to read into */
- #define BUFFER_SIZE 65536
- /* Max supported power when parsing float */
- #define MAX_POWER 20
- typedef struct
- {
- /* Final mesh */
- fastObjMesh* mesh;
- /* Current group */
- fastObjGroup group;
- /* Current material index */
- unsigned int material;
- /* Current line in file */
- unsigned int line;
- /* Base path for materials/textures */
- char* base;
- } fastObjData;
- static const
- double POWER_10_POS[MAX_POWER] =
- {
- 1.0e0, 1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5, 1.0e6, 1.0e7, 1.0e8, 1.0e9,
- 1.0e10, 1.0e11, 1.0e12, 1.0e13, 1.0e14, 1.0e15, 1.0e16, 1.0e17, 1.0e18, 1.0e19,
- };
- static const
- double POWER_10_NEG[MAX_POWER] =
- {
- 1.0e0, 1.0e-1, 1.0e-2, 1.0e-3, 1.0e-4, 1.0e-5, 1.0e-6, 1.0e-7, 1.0e-8, 1.0e-9,
- 1.0e-10, 1.0e-11, 1.0e-12, 1.0e-13, 1.0e-14, 1.0e-15, 1.0e-16, 1.0e-17, 1.0e-18, 1.0e-19,
- };
- static
- void* memory_realloc(void* ptr, size_t bytes)
- {
- return FAST_OBJ_REALLOC(ptr, bytes);
- }
- static
- void memory_dealloc(void* ptr)
- {
- FAST_OBJ_FREE(ptr);
- }
- #define array_clean(_arr) ((_arr) ? memory_dealloc(_array_header(_arr)), 0 : 0)
- #define array_push(_arr, _val) (_array_mgrow(_arr, 1) ? ((_arr)[_array_size(_arr)++] = (_val), _array_size(_arr) - 1) : 0)
- #define array_size(_arr) ((_arr) ? _array_size(_arr) : 0)
- #define array_capacity(_arr) ((_arr) ? _array_capacity(_arr) : 0)
- #define array_empty(_arr) (array_size(_arr) == 0)
- #define _array_header(_arr) ((unsigned int*)(_arr) - 2)
- #define _array_size(_arr) (_array_header(_arr)[0])
- #define _array_capacity(_arr) (_array_header(_arr)[1])
- #define _array_ngrow(_arr, _n) ((_arr) == 0 || (_array_size(_arr) + (_n) >= _array_capacity(_arr)))
- #define _array_mgrow(_arr, _n) (_array_ngrow(_arr, _n) ? (_array_grow(_arr, _n) != 0) : 1)
- #define _array_grow(_arr, _n) (*((void**)&(_arr)) = array_realloc(_arr, _n, sizeof(*(_arr))))
- static
- void* array_realloc(void* ptr, unsigned int n, unsigned int b)
- {
- unsigned int sz = array_size(ptr);
- unsigned int nsz = sz + n;
- unsigned int cap = array_capacity(ptr);
- unsigned int ncap = 3 * cap / 2;
- unsigned int* r;
- if (ncap < nsz)
- ncap = nsz;
- ncap = (ncap + 15) & ~15u;
- r = (unsigned int*)(memory_realloc(ptr ? _array_header(ptr) : 0, b * ncap + 2 * sizeof(unsigned int)));
- if (!r)
- return 0;
- r[0] = sz;
- r[1] = ncap;
- return (r + 2);
- }
- static
- void* file_open(const char* path)
- {
- return fopen(path, "rb");
- }
- static
- void file_close(void* file)
- {
- FILE* f;
-
- f = (FILE*)(file);
- fclose(f);
- }
- static
- size_t file_read(void* file, void* dst, size_t bytes)
- {
- FILE* f;
-
- f = (FILE*)(file);
- return fread(dst, 1, bytes, f);
- }
- static
- unsigned long file_size(void* file)
- {
- FILE* f;
- long p;
- long n;
-
- f = (FILE*)(file);
- p = ftell(f);
- fseek(f, 0, SEEK_END);
- n = ftell(f);
- fseek(f, p, SEEK_SET);
- if (n > 0)
- return (unsigned long)(n);
- else
- return 0;
- }
- static
- char* string_copy(const char* s, const char* e)
- {
- size_t n;
- char* p;
-
- n = (size_t)(e - s);
- p = (char*)(memory_realloc(0, n + 1));
- if (p)
- {
- memcpy(p, s, n);
- p[n] = '\0';
- }
- return p;
- }
- static
- char* string_substr(const char* s, size_t a, size_t b)
- {
- return string_copy(s + a, s + b);
- }
- static
- char* string_concat(const char* a, const char* s, const char* e)
- {
- size_t an;
- size_t sn;
- char* p;
-
- an = a ? strlen(a) : 0;
- sn = (size_t)(e - s);
- p = (char*)(memory_realloc(0, an + sn + 1));
- if (p)
- {
- if (a)
- memcpy(p, a, an);
- memcpy(p + an, s, sn);
- p[an + sn] = '\0';
- }
- return p;
- }
- static
- int string_equal(const char* a, const char* s, const char* e)
- {
- while (*a++ == *s++ && s != e)
- ;
- return (*a == '\0' && s == e);
- }
- static
- int string_find_last(const char* s, char c, size_t* p)
- {
- const char* e;
- e = s + strlen(s);
- while (e > s)
- {
- e--;
- if (*e == c)
- {
- *p = (size_t)(e - s);
- return 1;
- }
- }
- return 0;
- }
- static
- void string_fix_separators(char* s)
- {
- while (*s)
- {
- if (*s == FAST_OBJ_OTHER_SEP)
- *s = FAST_OBJ_SEPARATOR;
- s++;
- }
- }
- static
- int is_whitespace(char c)
- {
- return (c == ' ' || c == '\t' || c == '\r');
- }
- static
- int is_newline(char c)
- {
- return (c == '\n');
- }
- static
- int is_digit(char c)
- {
- return (c >= '0' && c <= '9');
- }
- static
- int is_exponent(char c)
- {
- return (c == 'e' || c == 'E');
- }
- static
- const char* skip_whitespace(const char* ptr)
- {
- while (is_whitespace(*ptr))
- ptr++;
- return ptr;
- }
- static
- const char* skip_line(const char* ptr)
- {
- while (!is_newline(*ptr++))
- ;
- return ptr;
- }
- static
- fastObjGroup group_default(void)
- {
- fastObjGroup group;
- group.name = 0;
- group.face_count = 0;
- group.face_offset = 0;
- group.index_offset = 0;
- return group;
- }
- static
- void group_clean(fastObjGroup* group)
- {
- memory_dealloc(group->name);
- }
- static
- void flush_output(fastObjData* data)
- {
- /* Add group if not empty */
- if (data->group.face_count > 0)
- array_push(data->mesh->groups, data->group);
- else
- group_clean(&data->group);
- /* Reset for more data */
- data->group = group_default();
- data->group.face_offset = array_size(data->mesh->face_vertices);
- data->group.index_offset = array_size(data->mesh->indices);
- }
- static
- const char* parse_int(const char* ptr, int* val)
- {
- int sign;
- int num;
- if (*ptr == '-')
- {
- sign = -1;
- ptr++;
- }
- else
- {
- sign = +1;
- }
- num = 0;
- while (is_digit(*ptr))
- num = 10 * num + (*ptr++ - '0');
- *val = sign * num;
- return ptr;
- }
- static
- const char* parse_float(const char* ptr, float* val)
- {
- double sign;
- double num;
- double fra;
- double div;
- int eval;
- const double* powers;
- ptr = skip_whitespace(ptr);
- switch (*ptr)
- {
- case '+':
- sign = 1.0;
- ptr++;
- break;
- case '-':
- sign = -1.0;
- ptr++;
- break;
- default:
- sign = 1.0;
- break;
- }
- num = 0.0;
- while (is_digit(*ptr))
- num = 10.0 * num + (double)(*ptr++ - '0');
- if (*ptr == '.')
- ptr++;
- fra = 0.0;
- div = 1.0;
- while (is_digit(*ptr))
- {
- fra = 10.0 * fra + (double)(*ptr++ - '0');
- div *= 10.0;
- }
- num += fra / div;
- if (is_exponent(*ptr))
- {
- ptr++;
- switch (*ptr)
- {
- case '+':
- powers = POWER_10_POS;
- ptr++;
- break;
- case '-':
- powers = POWER_10_NEG;
- ptr++;
- break;
- default:
- powers = POWER_10_POS;
- break;
- }
- eval = 0;
- while (is_digit(*ptr))
- eval = 10 * eval + (*ptr++ - '0');
- num *= (eval >= MAX_POWER) ? 0.0 : powers[eval];
- }
- *val = (float)(sign * num);
- return ptr;
- }
- static
- const char* parse_vertex(fastObjData* data, const char* ptr)
- {
- unsigned int ii;
- float v;
- for (ii = 0; ii < 3; ii++)
- {
- ptr = parse_float(ptr, &v);
- array_push(data->mesh->positions, v);
- }
- return ptr;
- }
- static
- const char* parse_texcoord(fastObjData* data, const char* ptr)
- {
- unsigned int ii;
- float v;
- for (ii = 0; ii < 2; ii++)
- {
- ptr = parse_float(ptr, &v);
- array_push(data->mesh->texcoords, v);
- }
- return ptr;
- }
- static
- const char* parse_normal(fastObjData* data, const char* ptr)
- {
- unsigned int ii;
- float v;
- for (ii = 0; ii < 3; ii++)
- {
- ptr = parse_float(ptr, &v);
- array_push(data->mesh->normals, v);
- }
- return ptr;
- }
- static
- const char* parse_face(fastObjData* data, const char* ptr)
- {
- unsigned int count;
- fastObjIndex vn;
- int v;
- int t;
- int n;
- ptr = skip_whitespace(ptr);
- count = 0;
- while (!is_newline(*ptr))
- {
- v = 0;
- t = 0;
- n = 0;
- ptr = parse_int(ptr, &v);
- if (*ptr == '/')
- {
- ptr++;
- if (*ptr != '/')
- ptr = parse_int(ptr, &t);
- if (*ptr == '/')
- {
- ptr++;
- ptr = parse_int(ptr, &n);
- }
- }
- if (v < 0)
- vn.p = (array_size(data->mesh->positions) / 3) - (unsigned int)(-v);
- else
- vn.p = (unsigned int)(v);
- if (t < 0)
- vn.t = (array_size(data->mesh->texcoords) / 2) - (unsigned int)(-t);
- else if (t > 0)
- vn.t = (unsigned int)(t);
- else
- vn.t = 0;
- if (n < 0)
- vn.n = (array_size(data->mesh->normals) / 3) - (unsigned int)(-n);
- else if (n > 0)
- vn.n = (unsigned int)(n);
- else
- vn.n = 0;
- array_push(data->mesh->indices, vn);
- count++;
- ptr = skip_whitespace(ptr);
- }
- array_push(data->mesh->face_vertices, count);
- array_push(data->mesh->face_materials, data->material);
- data->group.face_count++;
- return ptr;
- }
- static
- const char* parse_group(fastObjData* data, const char* ptr)
- {
- const char* s;
- const char* e;
- ptr = skip_whitespace(ptr);
- s = ptr;
- while (!is_whitespace(*ptr) && !is_newline(*ptr))
- ptr++;
- e = ptr;
- flush_output(data);
- data->group.name = string_copy(s, e);
- return ptr;
- }
- static
- fastObjTexture map_default(void)
- {
- fastObjTexture map;
- map.name = 0;
- map.path = 0;
- return map;
- }
- static
- fastObjMaterial mtl_default(void)
- {
- fastObjMaterial mtl;
- mtl.name = 0;
- mtl.Ka[0] = 0.0;
- mtl.Ka[1] = 0.0;
- mtl.Ka[2] = 0.0;
- mtl.Kd[0] = 1.0;
- mtl.Kd[1] = 1.0;
- mtl.Kd[2] = 1.0;
- mtl.Ks[0] = 0.0;
- mtl.Ks[1] = 0.0;
- mtl.Ks[2] = 0.0;
- mtl.Ke[0] = 0.0;
- mtl.Ke[1] = 0.0;
- mtl.Ke[2] = 0.0;
- mtl.Kt[0] = 0.0;
- mtl.Kt[1] = 0.0;
- mtl.Kt[2] = 0.0;
- mtl.Ns = 1.0;
- mtl.Ni = 1.0;
- mtl.Tf[0] = 1.0;
- mtl.Tf[1] = 1.0;
- mtl.Tf[2] = 1.0;
- mtl.d = 1.0;
- mtl.illum = 1;
- mtl.map_Ka = map_default();
- mtl.map_Kd = map_default();
- mtl.map_Ks = map_default();
- mtl.map_Ke = map_default();
- mtl.map_Kt = map_default();
- mtl.map_Ns = map_default();
- mtl.map_Ni = map_default();
- mtl.map_d = map_default();
- mtl.map_bump = map_default();
- return mtl;
- }
- static
- const char* parse_usemtl(fastObjData* data, const char* ptr)
- {
- const char* s;
- const char* e;
- unsigned int idx;
- fastObjMaterial* mtl;
- ptr = skip_whitespace(ptr);
- /* Parse the material name */
- s = ptr;
- while (!is_whitespace(*ptr) && !is_newline(*ptr))
- ptr++;
- e = ptr;
- /* If there are no materials yet, add a dummy invalid material at index 0 */
- if (array_empty(data->mesh->materials))
- array_push(data->mesh->materials, mtl_default());
- /* Find an existing material with the same name */
- idx = 0;
- while (idx < array_size(data->mesh->materials))
- {
- mtl = &data->mesh->materials[idx];
- if (mtl->name && string_equal(mtl->name, s, e))
- break;
- idx++;
- }
- if (idx == array_size(data->mesh->materials))
- idx = 0;
- data->material = idx;
- return ptr;
- }
- static
- void map_clean(fastObjTexture* map)
- {
- memory_dealloc(map->name);
- memory_dealloc(map->path);
- }
- static
- void mtl_clean(fastObjMaterial* mtl)
- {
- map_clean(&mtl->map_Ka);
- map_clean(&mtl->map_Kd);
- map_clean(&mtl->map_Ks);
- map_clean(&mtl->map_Ke);
- map_clean(&mtl->map_Kt);
- map_clean(&mtl->map_Ns);
- map_clean(&mtl->map_Ni);
- map_clean(&mtl->map_d);
- map_clean(&mtl->map_bump);
- memory_dealloc(mtl->name);
- }
- static
- const char* read_mtl_int(const char* p, int* v)
- {
- return parse_int(p, v);
- }
- static
- const char* read_mtl_single(const char* p, float* v)
- {
- return parse_float(p, v);
- }
- static
- const char* read_mtl_triple(const char* p, float v[3])
- {
- p = read_mtl_single(p, &v[0]);
- p = read_mtl_single(p, &v[1]);
- p = read_mtl_single(p, &v[2]);
- return p;
- }
- static
- const char* read_map(fastObjData* data, const char* ptr, fastObjTexture* map)
- {
- const char* s;
- const char* e;
- char* name;
- char* path;
- ptr = skip_whitespace(ptr);
- /* Don't support options at present */
- if (*ptr == '-')
- return ptr;
- /* Read name */
- s = ptr;
- while (!is_whitespace(*ptr) && !is_newline(*ptr))
- ptr++;
- e = ptr;
- name = string_copy(s, e);
- path = string_concat(data->base, s, e);
- string_fix_separators(path);
- map->name = name;
- map->path = path;
- return e;
- }
- static
- int read_mtllib(fastObjData* data, void* file)
- {
- unsigned long n;
- const char* s;
- char* contents;
- size_t l;
- const char* p;
- const char* e;
- int found_d;
- fastObjMaterial mtl;
- /* Read entire file */
- n = file_size(file);
- contents = (char*)(memory_realloc(0, n + 1));
- if (!contents)
- return 0;
- l = file_read(file, contents, n);
- contents[l] = '\n';
- mtl = mtl_default();
- found_d = 0;
- p = contents;
- e = contents + l;
- while (p < e)
- {
- p = skip_whitespace(p);
- switch (*p)
- {
- case 'n':
- p++;
- if (p[0] == 'e' &&
- p[1] == 'w' &&
- p[2] == 'm' &&
- p[3] == 't' &&
- p[4] == 'l' &&
- is_whitespace(p[5]))
- {
- /* Push previous material (if there is one) */
- if (mtl.name)
- {
- array_push(data->mesh->materials, mtl);
- mtl = mtl_default();
- }
- /* Read name */
- p += 5;
- while (is_whitespace(*p))
- p++;
- s = p;
- while (!is_whitespace(*p) && !is_newline(*p))
- p++;
- mtl.name = string_copy(s, p);
- }
- break;
- case 'K':
- if (p[1] == 'a')
- p = read_mtl_triple(p + 2, mtl.Ka);
- else if (p[1] == 'd')
- p = read_mtl_triple(p + 2, mtl.Kd);
- else if (p[1] == 's')
- p = read_mtl_triple(p + 2, mtl.Ks);
- else if (p[1] == 'e')
- p = read_mtl_triple(p + 2, mtl.Ke);
- else if (p[1] == 't')
- p = read_mtl_triple(p + 2, mtl.Kt);
- break;
- case 'N':
- if (p[1] == 's')
- p = read_mtl_single(p + 2, &mtl.Ns);
- else if (p[1] == 'i')
- p = read_mtl_single(p + 2, &mtl.Ni);
- break;
- case 'T':
- if (p[1] == 'r')
- {
- float Tr;
- p = read_mtl_single(p + 2, &Tr);
- if (!found_d)
- {
- /* Ignore Tr if we've already read d */
- mtl.d = 1.0f - Tr;
- }
- }
- else if (p[1] == 'f')
- p = read_mtl_triple(p + 2, mtl.Tf);
- break;
- case 'd':
- if (is_whitespace(p[1]))
- {
- p = read_mtl_single(p + 1, &mtl.d);
- found_d = 1;
- }
- break;
- case 'i':
- p++;
- if (p[0] == 'l' &&
- p[1] == 'l' &&
- p[2] == 'u' &&
- p[3] == 'm' &&
- is_whitespace(p[4]))
- {
- p = read_mtl_int(p + 4, &mtl.illum);
- }
- break;
- case 'm':
- p++;
- if (p[0] == 'a' &&
- p[1] == 'p' &&
- p[2] == '_')
- {
- p += 3;
- if (*p == 'K')
- {
- p++;
- if (is_whitespace(p[1]))
- {
- if (*p == 'a')
- p = read_map(data, p + 1, &mtl.map_Ka);
- else if (*p == 'd')
- p = read_map(data, p + 1, &mtl.map_Kd);
- else if (*p == 's')
- p = read_map(data, p + 1, &mtl.map_Ks);
- else if (*p == 'e')
- p = read_map(data, p + 1, &mtl.map_Ke);
- else if (*p == 't')
- p = read_map(data, p + 1, &mtl.map_Kt);
- }
- }
- else if (*p == 'N')
- {
- p++;
- if (is_whitespace(p[1]))
- {
- if (*p == 's')
- p = read_map(data, p + 1, &mtl.map_Ns);
- else if (*p == 'i')
- p = read_map(data, p + 1, &mtl.map_Ni);
- }
- }
- else if (*p == 'd')
- {
- p++;
- if (is_whitespace(*p))
- p = read_map(data, p, &mtl.map_d);
- }
- else if (p[0] == 'b' &&
- p[1] == 'u' &&
- p[2] == 'm' &&
- p[3] == 'p' &&
- is_whitespace(p[4]))
- {
- p = read_map(data, p + 4, &mtl.map_d);
- }
- }
- break;
- case '#':
- break;
- }
- p = skip_line(p);
- }
- /* Push final material */
- if (mtl.name)
- array_push(data->mesh->materials, mtl);
- memory_dealloc(contents);
- return 1;
- }
- static
- const char* parse_mtllib(fastObjData* data, const char* ptr)
- {
- const char* s;
- const char* e;
- char* lib;
- void* file;
- ptr = skip_whitespace(ptr);
- s = ptr;
- while (!is_whitespace(*ptr) && !is_newline(*ptr))
- ptr++;
- e = ptr;
- lib = string_concat(data->base, s, e);
- if (lib)
- {
- string_fix_separators(lib);
- file = file_open(lib);
- if (file)
- {
- read_mtllib(data, file);
- file_close(file);
- }
- memory_dealloc(lib);
- }
- return ptr;
- }
- static
- void parse_buffer(fastObjData* data, const char* ptr, const char* end)
- {
- const char* p;
-
-
- p = ptr;
- while (p != end)
- {
- p = skip_whitespace(p);
- switch (*p)
- {
- case 'v':
- p++;
- switch (*p++)
- {
- case ' ':
- case '\t':
- p = parse_vertex(data, p);
- break;
- case 't':
- p = parse_texcoord(data, p);
- break;
- case 'n':
- p = parse_normal(data, p);
- break;
- default:
- p--; /* roll p++ back in case *p was a newline */
- }
- break;
- case 'f':
- p++;
- switch (*p++)
- {
- case ' ':
- case '\t':
- p = parse_face(data, p);
- break;
- default:
- p--; /* roll p++ back in case *p was a newline */
- }
- break;
- case 'g':
- p++;
- switch (*p++)
- {
- case ' ':
- case '\t':
- p = parse_group(data, p);
- break;
- default:
- p--; /* roll p++ back in case *p was a newline */
- }
- break;
- case 'm':
- p++;
- if (p[0] == 't' &&
- p[1] == 'l' &&
- p[2] == 'l' &&
- p[3] == 'i' &&
- p[4] == 'b' &&
- is_whitespace(p[5]))
- p = parse_mtllib(data, p + 5);
- break;
- case 'u':
- p++;
- if (p[0] == 's' &&
- p[1] == 'e' &&
- p[2] == 'm' &&
- p[3] == 't' &&
- p[4] == 'l' &&
- is_whitespace(p[5]))
- p = parse_usemtl(data, p + 5);
- break;
- case '#':
- break;
- }
- p = skip_line(p);
- data->line++;
- }
- }
- void fast_obj_destroy(fastObjMesh* m)
- {
- unsigned int ii;
- for (ii = 0; ii < array_size(m->groups); ii++)
- group_clean(&m->groups[ii]);
- for (ii = 0; ii < array_size(m->materials); ii++)
- mtl_clean(&m->materials[ii]);
- array_clean(m->positions);
- array_clean(m->texcoords);
- array_clean(m->normals);
- array_clean(m->face_vertices);
- array_clean(m->face_materials);
- array_clean(m->indices);
- array_clean(m->groups);
- array_clean(m->materials);
- memory_dealloc(m);
- }
- fastObjMesh* fast_obj_read(const char* path)
- {
- fastObjData data;
- fastObjMesh* m;
- void* file;
- char* buffer;
- char* start;
- char* end;
- char* last;
- unsigned int read;
- size_t sep;
- unsigned int bytes;
- /* Open file */
- file = file_open(path);
- if (!file)
- return 0;
- /* Empty mesh */
- m = (fastObjMesh*)(memory_realloc(0, sizeof(fastObjMesh)));
- if (!m)
- return 0;
- m->positions = 0;
- m->texcoords = 0;
- m->normals = 0;
- m->face_vertices = 0;
- m->face_materials = 0;
- m->indices = 0;
- m->materials = 0;
- m->groups = 0;
- /* Add dummy position/texcoord/normal */
- array_push(m->positions, 0.0f);
- array_push(m->positions, 0.0f);
- array_push(m->positions, 0.0f);
- array_push(m->texcoords, 0.0f);
- array_push(m->texcoords, 0.0f);
- array_push(m->normals, 0.0f);
- array_push(m->normals, 0.0f);
- array_push(m->normals, 1.0f);
- /* Data needed during parsing */
- data.mesh = m;
- data.group = group_default();
- data.material = 0;
- data.line = 1;
- data.base = 0;
- /* Find base path for materials/textures */
- if (string_find_last(path, FAST_OBJ_SEPARATOR, &sep))
- data.base = string_substr(path, 0, sep + 1);
- /* Create buffer for reading file */
- buffer = (char*)(memory_realloc(0, 2 * BUFFER_SIZE * sizeof(char)));
- if (!buffer)
- return 0;
- start = buffer;
- for (;;)
- {
- /* Read another buffer's worth from file */
- read = (unsigned int)(file_read(file, start, BUFFER_SIZE));
- if (read == 0 && start == buffer)
- break;
- /* Ensure buffer ends in a newline */
- if (read < BUFFER_SIZE)
- {
- if (read == 0 || start[read - 1] != '\n')
- start[read++] = '\n';
- }
- end = start + read;
- if (end == buffer)
- break;
- /* Find last new line */
- last = end;
- while (last > buffer)
- {
- last--;
- if (*last == '\n')
- break;
- }
- /* Check there actually is a new line */
- if (*last != '\n')
- break;
- last++;
- /* Process buffer */
- parse_buffer(&data, buffer, last);
- /* Copy overflow for next buffer */
- bytes = (unsigned int)(end - last);
- memcpy(buffer, last, bytes);
- start = buffer + bytes;
- }
- /* Flush final group */
- flush_output(&data);
- group_clean(&data.group);
- m->position_count = array_size(m->positions) / 3;
- m->texcoord_count = array_size(m->texcoords) / 2;
- m->normal_count = array_size(m->normals) / 3;
- m->face_count = array_size(m->face_vertices);
- m->material_count = array_size(m->materials);
- m->group_count = array_size(m->groups);
- /* Clean up */
- memory_dealloc(buffer);
- memory_dealloc(data.base);
- file_close(file);
- return m;
- }
- #endif
|