aboutsummaryrefslogtreecommitdiff
path: root/src/model.c
diff options
context:
space:
mode:
authortaw27 <taw27@84d2e878-0bd5-11dd-ad15-13eda11d74c5>2008-04-16 16:57:56 +0000
committertaw27 <taw27@84d2e878-0bd5-11dd-ad15-13eda11d74c5>2008-04-16 16:57:56 +0000
commitf0a0118393a3d121bcb83047b5b9ac95eb0621ba (patch)
treecfc4f3f7955b4829317fa9b7865e328ccabfb129 /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.c399
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;
+
+}
+