OBJ model loader implemented.

This commit is contained in:
laochailan 2012-07-15 08:15:47 +02:00
parent 31d6665d21
commit 13e5f310a7
11 changed files with 371 additions and 37 deletions

View file

@ -25,6 +25,7 @@ install(DIRECTORY gfx DESTINATION ${DATA_DIR}
FILES_MATCHING PATTERN "*.ttf")
install(DIRECTORY sfx DESTINATION ${DATA_DIR})
install(DIRECTORY shader DESTINATION ${DATA_DIR})
install(DIRECTORY models DESTINATION ${DATA_DIR})
# uninstall target
configure_file(

40
models/test.obj Normal file
View file

@ -0,0 +1,40 @@
# Blender v2.63 (sub 0) OBJ File: ''
# www.blender.org
mtllib test.mtl
o Cube
v 1.000000 -1.000000 -1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 -1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v 1.000000 1.000000 -0.999999
v 0.999999 1.000000 1.000001
v -1.000000 1.000000 1.000000
v -1.000000 1.000000 -1.000000
vt 0.000000 0.500000
vt 0.000000 0.250000
vt 0.250000 0.250000
vt 0.250000 0.500000
vt 0.750000 0.500000
vt 0.500000 0.500000
vt 0.500000 0.250000
vt 0.750000 0.250000
vt 1.000000 0.500000
vt 1.000000 0.249999
vt 0.250000 0.000000
vt 0.500000 0.000000
vt 0.500000 0.750000
vt 0.250000 0.750000
vn 0.000000 -1.000000 0.000000
vn 0.000000 1.000000 0.000000
vn 1.000000 0.000000 0.000000
vn -0.000000 -0.000000 1.000000
vn -1.000000 -0.000000 -0.000000
vn 0.000000 0.000000 -1.000000
usemtl Material_untitled
s off
f 1/1/1 2/2/1 3/3/1 4/4/1
f 5/5/2 8/6/2 7/7/2 6/8/2
f 1/9/3 5/5/3 6/8/3 2/10/3
f 2/11/4 6/12/4 7/7/4 3/3/4
f 3/3/5 7/7/5 8/6/5 4/4/5
f 5/13/6 1/14/6 4/4/6 8/6/6

View file

@ -54,6 +54,7 @@ set(SRCs
resource/font.c
resource/shader.c
resource/audio.c
resource/model.c
${BISON_cfgparser_OUTPUTS}
${FLEX_cfgscanner_OUTPUTS})

View file

@ -31,22 +31,8 @@ void init_gl() {
void taisei_shutdown() {
printf("\nshutdown:\n");
if(resources.state & RS_SfxLoaded) {
printf("-- alutExit()\n");
alutExit();
}
printf("-- freeing textures\n");
delete_textures();
printf("-- freeing FBOs\n");
delete_fbo(&resources.fbg[0]);
delete_fbo(&resources.fbg[1]);
delete_fbo(&resources.fsec);
printf("-- freeing VBOs\n");
delete_vbo(&_vbo);
printf("-- freeing shaders\n");
delete_shaders();
free_resources();
SDL_FreeSurface(display);
SDL_Quit();

224
src/resource/model.c Normal file
View file

@ -0,0 +1,224 @@
/*
* This software is licensed under the terms of the MIT-License
* See COPYING for further information.
* ---
* Copyright (C) 2011, Lukas Weber <laochailan@web.de>
*/
#include "model.h"
#include "list.h"
#include "resource.h"
#include "taisei_err.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void parse_obj(char *filename, ObjFileData *data) {
FILE *fp = fopen(filename, "rb");
char line[256];
char cbuf[128];
Vector buf;
char mode;
int linen = 0;
memset(data, 0, sizeof(ObjFileData));
while(fgets(line, sizeof(line), fp)) {
linen++;
char *first;
first = strtok(line, " \n");
if(strcmp(first, "v") == 0)
mode = 'v';
else if(strcmp(first, "vt") == 0)
mode = 't';
else if(strcmp(first, "vn") == 0)
mode = 'n';
else if(strcmp(first, "f") == 0)
mode = 'f';
else
mode = 0;
if(mode != 0 && mode != 'f') {
buf[0] = atof(strtok(NULL, " \n"));
buf[1] = atof(strtok(NULL, " \n"));
if(mode != 't')
buf[2] = atof(strtok(NULL, " \n"));
switch(mode) {
case 'v':
data->xs = realloc(data->xs, sizeof(Vector)*(++data->xcount));
memcpy(data->xs[data->xcount-1], buf, sizeof(Vector));
break;
case 't':
data->texcoords = realloc(data->texcoords, sizeof(Vector)*(++data->tcount));
memcpy(data->texcoords[data->tcount-1], buf, sizeof(Vector));
break;
case 'n':
data->normals = realloc(data->normals, sizeof(Vector)*(++data->ncount));
memcpy(data->normals[data->ncount-1], buf, sizeof(Vector));
break;
}
} else if(mode == 'f') {
char *segment, *seg;
char *ctmp;
int j = 0, jj;
IVector ibuf;
memset(ibuf, 0, sizeof(ibuf));
while((segment = strtok(NULL, " \n"))) {
memset(cbuf, 0, sizeof(cbuf));
strncpy(cbuf, segment, sizeof(cbuf));
j++;
jj = 0;
while((seg = strtok_r(jj == 0 ? cbuf : NULL, "/", &ctmp))) {
if(jj >= 3)
break;
ibuf[jj] = atoi(seg);
jj++;
}
if(strstr(segment, "//")) {
ibuf[2] = ibuf[1];
ibuf[1] = 0;
}
if(jj == 0 || jj > 3 || segment[0] == '/')
errx(-1, "parse_obj():\n!- OBJ file '%s:%d': Parsing error: Corrupt face definition\n", filename,linen);
data->indices = realloc(data->indices, sizeof(IVector)*(++data->icount));
memcpy(data->indices[data->icount-1], ibuf, sizeof(IVector));
}
if(data->fverts == 0)
data->fverts = j;
if(data->fverts != j)
errx(-1, "parse_obj():\n!- OBJ file '%s:%d': Parsing error: face vertex count must stay the same in the whole file\n", filename, linen);
if(data->fverts != 3 && data->fverts != 4)
errx(-1, "parse_obj():\n!- OBJ file '%s:%d': Parsing error: face vertex count must be either 3 or 4\n", filename, linen);
}
}
}
static inline void bad_reference_error(char *filename, char *aux, int n) {
errx(-1, "load_model():\n!- OBJ file '%s': Index %d: bad %s index reference\n", filename, n, aux);
}
Model *load_model(char *filename) {
Model *m = create_element((void **)&resources.models, sizeof(Model));
ObjFileData data;
unsigned int i;
Vertex *verts;
unsigned int ioffset = _vbo.offset;
char *beg = strstr(filename, "models/") + 7;
char *end = strrchr(filename, '.');
m->name = malloc(end - beg + 1);
memset(m->name, 0, end-beg + 1);
strncpy(m->name, beg, end-beg);
parse_obj(filename, &data);
m->fverts = data.fverts;
m->indices = calloc(data.icount, sizeof(int));
m->icount = data.icount;
verts = calloc(data.icount, sizeof(Vertex));
memset(verts, 0, data.icount*sizeof(Vertex));
for(i = 0; i < data.icount; i++) {
int xi, ni, ti;
xi = data.indices[i][0]-1;
if(xi < 0 || xi >= data.xcount)
bad_reference_error(filename, "vertex", i);
memcpy(verts[i].x, data.xs[xi], sizeof(Vector));
if(data.tcount) {
ti = data.indices[i][1]-1;
if(ti < 0 || ti >= data.tcount)
bad_reference_error(filename, "texcoord", i);
verts[i].s = data.texcoords[ti][0];
verts[i].t = data.texcoords[ti][1];
}
if(data.ncount) {
ni = data.indices[i][2]-1;
if(ni < 0 || ni >= data.ncount)
bad_reference_error(filename, "normal", ni);
memcpy(verts[i].n, data.normals[ni], sizeof(Vector));
}
m->indices[i] = i+ioffset;
}
vbo_add_verts(&_vbo, verts, data.icount);
printf("-- loaded '%s' as '%s'\n", filename, m->name);
free(verts);
free(data.xs);
free(data.normals);
free(data.texcoords);
free(data.indices);
return m;
}
Model *get_model(char *name) {
Model *m, *res = NULL;
for(m = resources.models; m; m = m->next) {
if(strcmp(m->name, name) == 0)
res = m;
}
if(res == NULL)
errx(-1,"get_model():\n!- cannot load model '%s'", name);
return res;
}
void draw_model_p(Model *model) {
GLenum flag;
switch(model->fverts) {
case 3:
flag = GL_TRIANGLES;
break;
case 4:
flag = GL_QUADS;
break;
default:
errx(-1, "draw_model_p():\n!- Model '%s': invalid face vertex count");
}
glDrawElements(flag, model->icount, GL_UNSIGNED_INT, model->indices);
}
void draw_model(char *name) {
draw_model_p(get_model(name));
}
void delete_model(void **models, void *model) {
free(((Model *)model)->name);
free(((Model *)model)->indices);
delete_element(models, model);
}
void delete_models() { // Does not delete elements from the VBO, so doing this at runtime is leaking VBO space
delete_all_elements((void **)&resources.models, delete_model);
}

53
src/resource/model.h Normal file
View file

@ -0,0 +1,53 @@
/*
* This software is licensed under the terms of the MIT-License
* See COPYING for further information.
* ---
* Copyright (C) 2011, Lukas Weber <laochailan@web.de>
*/
#ifndef MODEL_H
#define MODEL_H
#include "matrix.h"
typedef int IVector[3];
typedef struct ObjFileData ObjFileData;
struct ObjFileData {
Vector *xs;
int xcount;
Vector *normals;
int ncount;
Vector *texcoords;
int tcount;
IVector *indices;
int icount;
int fverts;
};
typedef struct Model Model;
struct Model {
struct Model *next;
struct Model *prev;
char *name;
unsigned int *indices;
int icount;
int fverts;
};
Model *load_model(char *filename);
Model *get_model(char *name);
void draw_model_p(Model *model);
void draw_model(char *name);
void delete_models(); // Does not delete elements from the VBO, so doing this at runtime is leaking VBO space
#endif

View file

@ -41,6 +41,8 @@ void recurse_dir(char *path) {
load_sound(buf);
} else if(strcmp(dp->d_name + strlen(dp->d_name)-4, ".sha") == 0) {
load_shader(buf);
} else if(strcmp(dp->d_name + strlen(dp->d_name)-4, ".obj") == 0) {
load_model(buf);
}
free(buf);
@ -89,17 +91,40 @@ void load_resources() {
resources.state |= RS_ShaderLoaded;
}
if(!(resources.state & RS_ModelsLoaded)) {
printf("- models:\n");
strcpy(path, get_prefix());
strcat(path, "models");
recurse_dir(path);
resources.state |= RS_ModelsLoaded;
}
}
void free_resources() {
delete_textures();
delete_animations();
if(!tconfig.intval[NO_SHADER])
delete_shaders();
if(!tconfig.intval[NO_AUDIO]) {
void free_resources() {
if(resources.state & RS_SfxLoaded) {
printf("-- freeing sounds\n");
delete_sounds();
printf("-- alutExit()\n");
alutExit();
}
printf("-- freeing textures\n");
delete_textures();
printf("-- freeing models\n");
delete_animations();
printf("-- freeing VBOs\n");
delete_vbo(&_vbo);
if(resources.state & RS_ShaderLoaded) {
printf("-- freeing FBOs\n");
delete_fbo(&resources.fbg[0]);
delete_fbo(&resources.fbg[1]);
delete_fbo(&resources.fsec);
printf("-- freeing shaders\n");
delete_shaders();
}
}

View file

@ -15,13 +15,15 @@
#include "audio.h"
#include "shader.h"
#include "font.h"
#include "model.h"
typedef struct Resources Resources;
typedef enum ResourceState {
RS_GfxLoaded = 1,
RS_SfxLoaded = 2,
RS_ShaderLoaded = 4
RS_ShaderLoaded = 4,
RS_ModelsLoaded = 8
} ResourceState;
enum {
@ -35,6 +37,7 @@ struct Resources {
Animation *animations;
Sound *sounds;
Shader *shaders;
Model *models;
ALuint sndsrc[SNDSRC_COUNT];
@ -45,5 +48,5 @@ struct Resources {
extern Resources resources;
void load_resources();
void free_resources();
#endif

View file

@ -30,13 +30,13 @@ void stage2_bg_tunnel_draw(Vector pos) {
glPushMatrix();
glTranslatef(pos[0], pos[1], pos[2]);
glBindTexture(GL_TEXTURE_2D, get_tex("stage1/border")->gltex);
for(i = 0; i < n; i++) {
glPushMatrix();
glRotatef(360/n*i, 0, 1, 0);
glTranslatef(0,0,-r);
glScalef(2*r/tan((n-2)*M_PI/n), 3000, 1);
glBindTexture(GL_TEXTURE_2D, get_tex("stage1/border")->gltex);
draw_quad();
glPopMatrix();
}
@ -45,6 +45,7 @@ void stage2_bg_tunnel_draw(Vector pos) {
glPopMatrix();
glDisable(GL_TEXTURE_2D);
}
void stage2_fog(int fbonum) {

View file

@ -16,8 +16,8 @@ void init_stage3d(Stage3D *s) {
s->projangle = 45;
}
void add_model(Stage3D *s, ModelDrawRule draw, ModelPositionRule pos) {
s->models = realloc(s->models, (++s->msize)*sizeof(Model));
void add_model(Stage3D *s, SegmentDrawRule draw, SegmentPositionRule pos) {
s->models = realloc(s->models, (++s->msize)*sizeof(StageSegment));
s->models[s->msize - 1].draw = draw;
s->models[s->msize - 1].pos = pos;

View file

@ -10,19 +10,19 @@
#include "matrix.h"
typedef struct Model Model;
typedef struct StageSegment StageSegment;
typedef void (*ModelDrawRule)(Vector pos);
typedef Vector **(*ModelPositionRule)(Vector q, float maxrange); // returns NULL-terminated array
typedef void (*SegmentDrawRule)(Vector pos);
typedef Vector **(*SegmentPositionRule)(Vector q, float maxrange); // returns NULL-terminated array
struct Model {
ModelDrawRule draw;
ModelPositionRule pos;
struct StageSegment {
SegmentDrawRule draw;
SegmentPositionRule pos;
};
typedef struct Stage3D Stage3D;
struct Stage3D {
Model *models;
StageSegment *models;
int msize;
// Camera
@ -36,7 +36,7 @@ struct Stage3D {
void init_stage3d(Stage3D *s);
void add_model(Stage3D *s, ModelDrawRule draw, ModelPositionRule pos);
void add_model(Stage3D *s, SegmentDrawRule draw, SegmentPositionRule pos);
void set_perspective(Stage3D *s, float near, float far);
void draw_stage3d(Stage3D *s, float maxrange);