dbf_amiga
diff src/scnload_obj.cc @ 0:87dfe0e10235
initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Mon, 31 Aug 2015 07:38:37 +0300 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/scnload_obj.cc Mon Aug 31 07:38:37 2015 +0300 1.3 @@ -0,0 +1,263 @@ 1.4 +#include <stdio.h> 1.5 +#include <string.h> 1.6 +#include <ctype.h> 1.7 +#include <limits.h> 1.8 +#include <errno.h> 1.9 +#include <vector> 1.10 +#include "mesh.h" 1.11 +#include "scene.h" 1.12 +#include "scnload.h" 1.13 + 1.14 +enum { 1.15 + CMD_VERTEX, 1.16 + CMD_NORMAL, 1.17 + CMD_TEXCOORD, 1.18 + CMD_FACE, 1.19 + CMD_OBJECT, 1.20 + CMD_GROUP, 1.21 + CMD_MTLLIB 1.22 +}; 1.23 + 1.24 +static struct { 1.25 + const char *s; 1.26 + int cmd; 1.27 +} commands[] = { 1.28 + {"v", CMD_VERTEX}, 1.29 + {"vn", CMD_NORMAL}, 1.30 + {"vt", CMD_TEXCOORD}, 1.31 + {"f", CMD_FACE}, 1.32 + {"o", CMD_OBJECT}, 1.33 + {"g", CMD_GROUP}, 1.34 + {"mtllib", CMD_MTLLIB}, 1.35 + {0, -1} 1.36 +}; 1.37 + 1.38 +struct Face { 1.39 + int vnum; 1.40 + int vidx[4]; 1.41 + int nidx[4]; 1.42 + int tidx[4]; 1.43 +}; 1.44 + 1.45 +struct ObjMesh { 1.46 + std::vector<Vector3> varr; 1.47 + std::vector<Vector3> narr; 1.48 + std::vector<Vector2> tarr; 1.49 + std::vector<Face> faces; 1.50 +}; 1.51 + 1.52 +struct ParserState { 1.53 + FILE *fp; 1.54 + Scene *scn; 1.55 + const char *fname; 1.56 + 1.57 + unsigned int voffs, noffs, toffs; 1.58 + ObjMesh omesh; 1.59 +}; 1.60 + 1.61 +static bool parse_line(ParserState *ps, char *line); 1.62 +static void flush_mesh(ParserState *ps); 1.63 +static char *clean_input(char *s); 1.64 + 1.65 +bool load_obj(Scene *scn, const char *fname) 1.66 +{ 1.67 + FILE *fp; 1.68 + char buf[256]; 1.69 + bool result = false; 1.70 + ParserState ps; 1.71 + 1.72 + if(!(fp = fopen(fname, "r"))) { 1.73 + fprintf(stderr, "failed to open obj file: %s: %s\n", fname, strerror(errno)); 1.74 + return false; 1.75 + } 1.76 + ps.fp = fp; 1.77 + ps.scn = scn; 1.78 + ps.fname = fname; 1.79 + ps.voffs = ps.noffs = ps.toffs = 0; 1.80 + 1.81 + int nline = 0; 1.82 + while(fgets(buf, sizeof buf, fp)) { 1.83 + ++nline; 1.84 + char *line = clean_input(buf); 1.85 + if(!*line) continue; 1.86 + 1.87 + if(!parse_line(&ps, line)) { 1.88 + fprintf(stderr, "[obj] %s:%d: failed to parse\n", fname, nline); 1.89 + goto done; 1.90 + } 1.91 + } 1.92 + flush_mesh(&ps); 1.93 + result = true; 1.94 + 1.95 +done: 1.96 + fclose(fp); 1.97 + return result; 1.98 +} 1.99 + 1.100 +static int parse_cmd(char *line, char **endp) 1.101 +{ 1.102 + char *end = line; 1.103 + while(*end && !isspace(*end)) end++; 1.104 + *end = 0; 1.105 + *endp = end; 1.106 + 1.107 + for(int i=0; commands[i].s; i++) { 1.108 + if(strcmp(commands[i].s, line) == 0) { 1.109 + return commands[i].cmd; 1.110 + } 1.111 + } 1.112 + return -1; 1.113 +} 1.114 + 1.115 +static bool parse_vec3(Vector3 *vp, char *line) 1.116 +{ 1.117 + return sscanf(line, "%f %f %f", &vp->x, &vp->y, &vp->z) == 3; 1.118 +} 1.119 + 1.120 +static bool parse_vec2(Vector2 *vp, char *line) 1.121 +{ 1.122 + return sscanf(line, "%f %f", &vp->x, &vp->y) == 2; 1.123 +} 1.124 + 1.125 +#define INVAL_IDX INT_MIN 1.126 + 1.127 +static bool parse_face(Face *fp, char *line) 1.128 +{ 1.129 + fp->vnum = 0; 1.130 + 1.131 + int res; 1.132 + char *tok, *ptr = line; 1.133 + for(int i=0; i<4; i++) { 1.134 + while(*ptr && isspace(*ptr)) ptr++; 1.135 + if(!*ptr) break; 1.136 + tok = ptr; 1.137 + 1.138 + fp->vnum++; 1.139 + 1.140 + while(*ptr && !isspace(*ptr)) ptr++; 1.141 + if(*ptr) *ptr++ = 0; 1.142 + 1.143 + // parse the index descriptor vidx[/[tidx]/[nidx]] 1.144 + if(sscanf(tok, "%d//%d", &fp->vidx[i], &fp->nidx[i]) == 2) { 1.145 + fp->tidx[i] = INVAL_IDX; 1.146 + continue; 1.147 + } 1.148 + res = sscanf(tok, "%d/%d/%d", &fp->vidx[i], &fp->tidx[i], &fp->nidx[i]); 1.149 + if(res > 2) { 1.150 + if(res != 3) { 1.151 + fp->nidx[i] = INVAL_IDX; 1.152 + } 1.153 + continue; 1.154 + } 1.155 + char *endp; 1.156 + fp->vidx[i] = strtol(tok, &endp, 10); 1.157 + if(endp == tok) { 1.158 + return false; 1.159 + } 1.160 + fp->nidx[i] = fp->tidx[i] = INVAL_IDX; 1.161 + } 1.162 + return fp->vnum >= 3 ? true : false; 1.163 +} 1.164 + 1.165 +static bool parse_line(ParserState *ps, char *line) 1.166 +{ 1.167 + char *endp; 1.168 + int cmd = parse_cmd(line, &endp); 1.169 + if(cmd == -1) return true; // ignore unknown commands 1.170 + line = endp + 1; 1.171 + while(*line && isspace(*line)) line++; 1.172 + 1.173 + Vector3 v; 1.174 + Vector2 v2; 1.175 + Face f; 1.176 + 1.177 + switch(cmd) { 1.178 + case CMD_VERTEX: 1.179 + if(!parse_vec3(&v, line)) return false; 1.180 + ps->omesh.varr.push_back(v); 1.181 + break; 1.182 + 1.183 + case CMD_NORMAL: 1.184 + if(!parse_vec3(&v, line)) return false; 1.185 + ps->omesh.narr.push_back(v); 1.186 + break; 1.187 + 1.188 + case CMD_TEXCOORD: 1.189 + if(!parse_vec2(&v2, line)) return false; 1.190 + ps->omesh.tarr.push_back(v2); 1.191 + break; 1.192 + 1.193 + case CMD_FACE: 1.194 + if(!parse_face(&f, line)) return false; 1.195 + ps->omesh.faces.push_back(f); 1.196 + break; 1.197 + 1.198 + case CMD_OBJECT: 1.199 + case CMD_GROUP: 1.200 + flush_mesh(ps); 1.201 + break; 1.202 + 1.203 + default: 1.204 + break; 1.205 + } 1.206 + return true; 1.207 +} 1.208 + 1.209 +static void flush_mesh(ParserState *ps) 1.210 +{ 1.211 + if(!ps->omesh.varr.empty() && !ps->omesh.faces.empty()) { 1.212 + int num_verts = (int)ps->omesh.varr.size(); 1.213 + int num_faces = (int)ps->omesh.faces.size(); 1.214 + 1.215 + Mesh *m = new Mesh; 1.216 + m->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, (float*)&ps->omesh.varr[0]); 1.217 + 1.218 + if(!ps->omesh.narr.empty()) { 1.219 + m->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, (float*)&ps->omesh.narr[0]); 1.220 + } 1.221 + if(!ps->omesh.tarr.empty()) { 1.222 + m->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, (float*)&ps->omesh.tarr[0]); 1.223 + } 1.224 + 1.225 + unsigned int *idxarr = m->set_index_data(num_faces * 3); 1.226 + for(int i=0; i<num_faces; i++) { 1.227 + for(int j=0; j<3; j++) { 1.228 + int idx = ps->omesh.faces[i].vidx[j] - ps->voffs - 1; // TODO normalize indices 1.229 + *idxarr++ = idx; 1.230 + } 1.231 + } 1.232 + 1.233 + Object *o = new Object; 1.234 + o->set_mesh(m); 1.235 + 1.236 + // TODO material & textures 1.237 + 1.238 + ps->scn->add_object(o); 1.239 + 1.240 + printf("added object with %d vertices and %d faces\n", num_verts, num_faces); 1.241 + } 1.242 + 1.243 + ps->voffs += ps->omesh.varr.size(); 1.244 + ps->noffs += ps->omesh.narr.size(); 1.245 + ps->toffs += ps->omesh.tarr.size(); 1.246 + 1.247 + ps->omesh.varr.clear(); 1.248 + ps->omesh.narr.clear(); 1.249 + ps->omesh.tarr.clear(); 1.250 + ps->omesh.faces.clear(); 1.251 +} 1.252 + 1.253 +static char *clean_input(char *s) 1.254 +{ 1.255 + while(*s && isspace(*s)) s++; 1.256 + if(!*s) return s; 1.257 + 1.258 + char *end = strchr(s, '#'); 1.259 + if(end) *end = 0; 1.260 + 1.261 + end = s + strlen(s) - 1; 1.262 + while(end > s && isspace(*end)) end--; 1.263 + end[1] = 0; 1.264 + 1.265 + return s; 1.266 +}