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 +}