OBJ model loader implemented.
This commit is contained in:
parent
31d6665d21
commit
13e5f310a7
11 changed files with 371 additions and 37 deletions
|
@ -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
40
models/test.obj
Normal 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
|
|
@ -54,6 +54,7 @@ set(SRCs
|
|||
resource/font.c
|
||||
resource/shader.c
|
||||
resource/audio.c
|
||||
resource/model.c
|
||||
${BISON_cfgparser_OUTPUTS}
|
||||
${FLEX_cfgscanner_OUTPUTS})
|
||||
|
||||
|
|
16
src/main.c
16
src/main.c
|
@ -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
224
src/resource/model.c
Normal 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
53
src/resource/model.h
Normal 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
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue