diff options
author | taw27 <taw27@84d2e878-0bd5-11dd-ad15-13eda11d74c5> | 2008-04-16 16:57:56 +0000 |
---|---|---|
committer | taw27 <taw27@84d2e878-0bd5-11dd-ad15-13eda11d74c5> | 2008-04-16 16:57:56 +0000 |
commit | f0a0118393a3d121bcb83047b5b9ac95eb0621ba (patch) | |
tree | cfc4f3f7955b4829317fa9b7865e328ccabfb129 /src/model.c |
Initial import
git-svn-id: svn://cook.msm.cam.ac.uk:745/thrust3d/thrust3d@1 84d2e878-0bd5-11dd-ad15-13eda11d74c5
Diffstat (limited to 'src/model.c')
-rw-r--r-- | src/model.c | 399 |
1 files changed, 399 insertions, 0 deletions
diff --git a/src/model.c b/src/model.c new file mode 100644 index 0000000..a10c55d --- /dev/null +++ b/src/model.c @@ -0,0 +1,399 @@ +/* + * model.c + * + * Basic functions to handle models + * + * (c) 2008 Thomas White <taw27@cam.ac.uk> + * + * thrust3d - a silly game + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <gl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#include "types.h" +#include "model.h" +#include "utils.h" +#include "texture.h" +#include "render.h" + +/* Maximum number of vertices per primitive */ +#define MAX_VERTICES 256 + +ModelContext *model_init() { + + ModelContext *ctx; + + ctx = malloc(sizeof(ModelContext)); + if ( ctx == NULL ) return NULL; + + ctx->num_models = 0; + ctx->models = NULL; + + return ctx; + +} + +static int model_add(ModelContext *ctx, Model *model) { + + ctx->models = realloc(ctx->models, (ctx->num_models+1)*sizeof(Model *)); + if ( ctx->models == NULL ) { + return 1; + } + ctx->models[ctx->num_models] = model; + ctx->num_models++; + + return 0; + +} + +static Model *model_new(const char *name) { + + Model *model; + + model = malloc(sizeof(Model)); + if ( model == NULL ) return NULL; + + model->num_primitives = 0; + model->attrib_total = ATTRIB_NONE; + model->primitives = NULL; + model->name = strdup(name); + + return model; + + +} + +static Primitive *model_add_primitive(Model *model, GLenum type, GLfloat *vertices, GLfloat *normals, GLfloat *texcoords, + int n, PrimitiveAttrib attribs, GLfloat r, GLfloat g, GLfloat b, char *texture) { + + Primitive *p; + + p = malloc(sizeof(Primitive)); + if ( p == NULL ) return NULL; + + p->vertices = malloc(n * sizeof(GLfloat) * 3); + if ( p->vertices == NULL ) { + free(p); + return NULL; + } + + p->normals = malloc(n * sizeof(GLfloat) * 3); + if ( p->normals == NULL ) { + free(p); + free(p->vertices); + return NULL; + } + + p->texcoords = malloc(n * sizeof(GLfloat) * 2); + if ( p->texcoords == NULL ) { + free(p); + free(p->vertices); + free(p->normals); + return NULL; + } + + /* Copy the vertices into memory */ + memcpy(p->vertices, vertices, 3*n*sizeof(GLfloat)); + memcpy(p->normals, normals, 3*n*sizeof(GLfloat)); + memcpy(p->texcoords, texcoords, 2*n*sizeof(GLfloat)); + p->num_vertices = n; + p->type = type; + p->attribs = attribs; + p->col_r = r; + p->col_g = g; + p->col_b = b; + p->texture = texture; + + model->attrib_total = model->attrib_total | attribs; + model->primitives = realloc(model->primitives, sizeof(Primitive *) * (model->num_primitives+1)); + model->primitives[model->num_primitives] = p; + model->num_primitives++; + + return 0; + +} + +static void model_calculate_normals(GLfloat *vertices, GLfloat *normals, int first, int last, int centre, int v1, int v2) { + + GLfloat ax, ay, az; + GLfloat bx, by, bz; + GLfloat nx, ny, nz, n; + unsigned int i; + + ax = vertices[3*v1+0] - vertices[3*centre+0]; + ay = vertices[3*v1+1] - vertices[3*centre+1]; + az = vertices[3*v1+2] - vertices[3*centre+2]; + bx = vertices[3*v2+0] - vertices[3*centre+0]; + by = vertices[3*v2+1] - vertices[3*centre+1]; + bz = vertices[3*v2+2] - vertices[3*centre+2]; + nx = ay*bz - az*by; + ny = - ax*bz + az*bx; + nz = ax*by - ay*bx; + n = sqrtf(nx*nx + ny*ny + nz*nz); + nx = nx / n; ny = ny / n; nz = nz / n; + + for ( i=first; i<=last; i++ ) { + normals[3*i+0] = nx; + normals[3*i+1] = ny; + normals[3*i+2] = nz; + } + +} + +static int model_load_obj(ModelContext *ctx, const char *name, RenderContext *render) { + + FILE *fh; + char tmp[64]; + Model *model; + int num_vertices; + GLfloat *vertices; + GLfloat *normals; + GLfloat *texcoords; + GLfloat vtmp[3*MAX_VERTICES]; + GLfloat vntmp[3*MAX_VERTICES]; + int n_vtmp, n_vntmp; + char *texture; + + snprintf(tmp, 63, "%s/models/%s.obj", DATADIR, name); + fh = fopen(tmp, "r"); + if ( fh == NULL ) { + return -1; + } + + model = model_new(name); + vertices = malloc(MAX_VERTICES*3*sizeof(GLfloat)); + normals = malloc(MAX_VERTICES*3*sizeof(GLfloat)); + texcoords = malloc(MAX_VERTICES*2*sizeof(GLfloat)); + num_vertices = 0; + n_vtmp = 0; + texture = NULL; + while ( !feof(fh) ) { + + char line[1024]; + GLfloat x, y, z; + unsigned int v1, v2, v3; + GLfloat texx, texy; + size_t s; + + texx = 0.0; texy = 0.0; /* Default texture coordinates */ + + fgets(line, 1023, fh); + s = 0; + for ( ; s<strlen(line); s++ ) { + if ( line[s] != ' ' ) break; + } + + if ( line[s] == '#' ) { + continue; + } + + if ( sscanf(line+s, "v %f %f %f\n", &x, &y, &z) == 3 ) { + vtmp[3*n_vtmp+0] = x; + vtmp[3*n_vtmp+1] = y; + vtmp[3*n_vtmp+2] = z; + n_vtmp++; + continue; + } + + if ( sscanf(line+s, "vn %f %f %f\n", &x, &y, &z) == 3 ) { + vntmp[3*n_vntmp+0] = x; + vntmp[3*n_vntmp+1] = y; + vntmp[3*n_vntmp+2] = z; + n_vntmp++; + continue; + } + + if ( line[s] == 'f' ) { + regex_t r; + regcomp(&r, "$f\s+([0-9\.]+)/([0-9\.]+)/([0-9\.]+)\s+^", 0); + regfree(&r); + } + + } + + fclose(fh); + + return model_add(ctx, model); + +} + +static int model_load(ModelContext *ctx, const char *name, RenderContext *render) { + + FILE *fh; + char tmp[64]; + Model *model; + GLenum type; + int num_vertices; + GLfloat *vertices; + GLfloat *normals; + GLfloat *texcoords; + GLfloat col_r = 0.0; + GLfloat col_g = 0.0; + GLfloat col_b = 0.0; + PrimitiveAttrib attribs; + char *texture; + + snprintf(tmp, 63, "%s/models/%s", DATADIR, name); + fh = fopen(tmp, "r"); + if ( fh == NULL ) { + return -1; + } + + model = model_new(name); + vertices = malloc(MAX_VERTICES*3*sizeof(GLfloat)); + normals = malloc(MAX_VERTICES*3*sizeof(GLfloat)); + texcoords = malloc(MAX_VERTICES*2*sizeof(GLfloat)); + num_vertices = 0; + type = GL_TRIANGLES; + attribs = ATTRIB_NONE; + texture = NULL; + while ( !feof(fh) ) { + + char line[1024]; + GLfloat x, y, z; + GLfloat r, g, b; + GLfloat texx, texy, forget; + + texx = 0.0; texy = 0.0; /* Default texture coordinates */ + + fgets(line, 1023, fh); + + if ( line[0] == '#' ) { + continue; + } + + if ( line[0] == '\n' ) { + if ( num_vertices > 0 ) { + model_add_primitive(model, type, vertices, normals, texcoords, num_vertices, + attribs, col_r, col_g, col_b, texture); + num_vertices = 0; + type = GL_TRIANGLES; + attribs = ATTRIB_NONE; + texture = NULL; + } + } + + if ( strncmp(line, "QUADS", 5) == 0 ) { + type = GL_QUADS; + } + if ( strncmp(line, "TRIANGLES", 9) == 0 ) { + type = GL_TRIANGLES; + } + + if ( sscanf(line, "%f %f %f %f %f", &forget, &forget, &forget, &x, &y) == 5 ) { + texx = x; texy = y; + } + + if ( sscanf(line, "%f %f %f", &x, &y, &z) == 3 ) { + vertices[3*num_vertices+0] = x; + vertices[3*num_vertices+1] = y; + vertices[3*num_vertices+2] = z; + texcoords[2*num_vertices+0] = texx; + texcoords[2*num_vertices+1] = texy; + num_vertices++; + if ( (type == GL_QUADS) && ((num_vertices % 4)==0) ) { + model_calculate_normals(vertices, normals, num_vertices-4, num_vertices-1, + num_vertices-4, num_vertices-3, num_vertices-2); + } + if ( (type == GL_TRIANGLES) && ((num_vertices % 3)==0) ) { + model_calculate_normals(vertices, normals, num_vertices-3, num_vertices-1, + num_vertices-3, num_vertices-2, num_vertices-1); + } + if ( num_vertices > MAX_VERTICES ) { + fprintf(stderr, "Too many vertices in primitive\n"); + return 1; + } + } + + if ( sscanf(line, "pulse %f %f %f", &r, &g, &b) == 3 ) { + attribs = attribs | ATTRIB_COLOUR; + attribs = attribs | ATTRIB_PULSE; + col_r = r; col_g = g; col_b = b; + } + if ( sscanf(line, "colour %f %f %f", &r, &g, &b) == 3 ) { + attribs = attribs | ATTRIB_COLOUR; + col_r = r; col_g = g; col_b = b; + } + if ( strncmp(line, "texture", 7) == 0 ) { + if ( strlen(line) < 9 ) { + fprintf(stderr, "Invalid texture specification\n"); + return 1; + } + texture = strdup(line+8); + chomp(texture); + if ( texture_lookup(render, texture) == NULL ) { + texture_load(render, texture); + if ( texture_lookup(render, texture) == NULL ) { + fprintf(stderr, "Couldn't find texture %s\n", texture); + } + } + } + + } + + fclose(fh); + + return model_add(ctx, model); + +} + +static Model *model_lookup(ModelContext *ctx, const char *name) { + + int i, found; + + found = 0; + for ( i=0; i<ctx->num_models; i++ ) { + if ( strcmp(ctx->models[i]->name, name) == 0 ) { + found = 1; + break; + } + } + + if ( found == 0 ) { + return NULL; + } + + return ctx->models[i]; +} + +ModelInstance *model_instance_new(ModelContext *ctx, const char *name, RenderContext *render) { + + ModelInstance *instance; + + instance = malloc(sizeof(ModelInstance)); + instance->model = model_lookup(ctx, name); + + if ( instance->model == NULL ) { + /* Couldn't find model, so try to load it */ + model_load(ctx, name, render); + instance->model = model_lookup(ctx, name); + if ( instance->model == NULL ) { + model_load_obj(ctx, name, render); + instance->model = model_lookup(ctx, name); + if ( instance->model == NULL ) { + free(instance); + printf("Couldn't find model %s\n", name); + return NULL; + } + } + } + + instance->vx = 0.0; + instance->vy = 0.0; + instance->vz = 0.0; + instance->yaw = 0.0; + instance->yawspeed = 0.0; + + return instance; + +} + |