glstuff

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

commit 3434b95ff7c5bb581e116d70cc1ec4149c7bf429
parent 6377884c65418b193716b320c274f489ca5a69ef
Author: Brian Swetland <swetland@frotz.net>
Date:   Mon, 14 Jan 2013 00:08:45 -0800

minimal wavefront obj loader

Diffstat:
MMakefile | 11++++++++---
Acube.mtl | 7+++++++
Acube.obj | 95+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aloadobj.c | 239+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atest3.c | 124+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mutil.h | 10++++++++++
6 files changed, 483 insertions(+), 3 deletions(-)

diff --git a/Makefile b/Makefile @@ -8,9 +8,9 @@ SDLLIBS := $(shell $(SDLCFG) --libs) CFLAGS := $(SDLFLAGS) -DWITH_SDL2=0 -Wall LIBS := $(SDLLIBS) -lGL -lm -lpng -COMMONOBJS := util.o sdlglue.o loadpng.o loadfile.o +COMMONOBJS := util.o sdlglue.o loadpng.o loadfile.o loadobj.o -all: test1 test2 +all: test1 test2 test3 TEST1OBJS := test1.o $(COMMONOBJS) @@ -22,5 +22,10 @@ TEST2OBJS := test2.o $(COMMONOBJS) test2: $(TEST2OBJS) $(CC) -o test2 $(TEST2OBJS) $(LIBS) +TEST3OBJS := test3.o $(COMMONOBJS) + +test3: $(TEST3OBJS) + $(CC) -o test3 $(TEST3OBJS) $(LIBS) + clean:: - rm -f test1 test2 *.o + rm -f test1 test2 test3 *.o diff --git a/cube.mtl b/cube.mtl @@ -0,0 +1,7 @@ +newmtl mat0 +Kd 1 1 1 +Ka 0.2 0.2 0.2 +Ks 0.2 0.2 0.2 +Ns 128 +Tr 0 +map_Kd cube-texture.png diff --git a/cube.obj b/cube.obj @@ -0,0 +1,95 @@ +mtllib cube.mtl +g g0 +v -1 1 -1 +v 1 1 -1 +v 1 1 1 +v -1 1 1 +v -1 -1 1 +v 1 -1 1 +v 1 -1 -1 +v -1 -1 -1 +vn 0 -1 0 +vn 0 -1 0 +vn 0 -1 0 +vn 0 -1 0 +vn 0 -1 0 +vn 0 -1 0 +vn 0 1 0 +vn 0 1 0 +vn 0 1 0 +vn 0 1 0 +vn 0 1 0 +vn 0 1 0 +vn 0 0 1 +vn 0 0 1 +vn 0 0 1 +vn 0 0 1 +vn 0 0 1 +vn 0 0 1 +vn 0 0 -1 +vn 0 0 -1 +vn 0 0 -1 +vn 0 0 -1 +vn 0 0 -1 +vn 0 0 -1 +vn -1 0 0 +vn -1 0 0 +vn -1 0 0 +vn -1 0 0 +vn -1 0 0 +vn -1 0 0 +vn 1 0 0 +vn 1 0 0 +vn 1 0 0 +vn 1 0 0 +vn 1 0 0 +vn 1 0 0 +vt 0.25 0.25 +vt 0.5 0.5 +vt 0.25 0.5 +vt 0.5 0.5 +vt 0.25 0.25 +vt 0.5 0.25 +vt 0.5 1 +vt 0.25 0.75 +vt 0.5 0.75 +vt 0.25 0.75 +vt 0.5 1 +vt 0.25 1 +vt 0.25 0.75 +vt 0.5 0.5 +vt 0.5 0.75 +vt 0.5 0.5 +vt 0.25 0.75 +vt 0.25 0.5 +vt 1 0.5 +vt 0.75 0.75 +vt 0.75 0.5 +vt 0.75 0.75 +vt 1 0.5 +vt 1 0.75 +vt 0 0.5 +vt 0.25 0.75 +vt 0 0.75 +vt 0.25 0.75 +vt 0 0.5 +vt 0.25 0.5 +vt 0.5 0.5 +vt 0.75 0.75 +vt 0.5 0.75 +vt 0.75 0.75 +vt 0.5 0.5 +vt 0.75 0.5 +usemtl mat0 +f 8/1/1 6/2/2 5/3/3 +f 6/4/4 8/5/5 7/6/6 +f 2/7/7 4/8/8 3/9/9 +f 4/10/10 2/11/11 1/12/12 +f 4/13/13 6/14/14 3/15/15 +f 6/16/16 4/17/17 5/18/18 +f 8/19/19 2/20/20 7/21/21 +f 2/22/22 8/23/23 1/24/24 +f 8/25/25 4/26/26 1/27/27 +f 4/28/28 8/29/29 5/30/30 +f 6/31/31 2/32/32 3/33/33 +f 2/34/34 6/35/35 7/36/36 diff --git a/loadobj.c b/loadobj.c @@ -0,0 +1,239 @@ +/* Copyright 2013 Brian Swetland <swetland@frotz.net> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "util.h" + +struct v3 { + float x; + float y; + float z; +}; + +struct v2 { + float u; + float v; +}; + +struct i3 { + unsigned v; + unsigned vt; + unsigned vn; +}; + +struct obj { + struct v3 *v; + struct v3 *vn; + struct v2 *vt; + struct i3 *f; + unsigned max_v, num_v; + unsigned max_vn, num_vn; + unsigned max_vt, num_vt; + unsigned max_f, num_f; +}; + +static void obj_destroy(struct obj *o) { + if (o->v) free(o->v); + if (o->vn) free(o->vn); + if (o->vt) free(o->vt); + if (o->f) free(o->f); + free(o); +} + +static void *resize(void *array, unsigned *max, unsigned esz) { + void *tmp; + unsigned n = *max ? *max * 2 : 32; + tmp = realloc(array, esz * n); + if (!tmp) + free(array); + *max = n; + return tmp; +} + +static int obj_add_v(struct obj *o, float x, float y, float z) { + unsigned n = o->num_v; + if (n == o->max_v) + if(!(o->v = resize(o->v, &o->max_v, sizeof(struct v3)))) + return -1; + o->v[n].x = x; + o->v[n].y = y; + o->v[n].z = z; + o->num_v = n + 1; + return 0; +} + +static int obj_add_vn(struct obj *o, float x, float y, float z) { + unsigned n = o->num_vn; + if (n == o->max_vn) + if(!(o->vn = resize(o->vn, &o->max_vn, sizeof(struct v3)))) + return -1; + o->vn[n].x = x; + o->vn[n].y = y; + o->vn[n].z = z; + o->num_vn = n + 1; + return 0; +} + +static int obj_add_vt(struct obj *o, float u, float v) { + unsigned n = o->num_vt; + if (n == o->max_vt) + if(!(o->vt = resize(o->vt, &o->max_vt, sizeof(struct v3)))) + return -1; + o->vt[n].u = u; + o->vt[n].v = v; + o->num_vt = n + 1; + return 0; +} + +static int obj_add_f(struct obj *o, int v, int vt, int vn) { + unsigned n = o->num_f; + if (n == o->max_f) + if(!(o->f = resize(o->f, &o->max_f, sizeof(struct v3)))) + return -1; + + /* XXX: range check */ + v -= 1; + vt -= 1; + vn -= 1; + + o->f[n].v = v; + o->f[n].vt = vt; + o->f[n].vn = vn; + o->num_f = n + 1; + return 0; +} + +struct obj *load_obj(const char *fn) { + char buf[128]; + FILE *fp; + struct obj *o; + float x, y, z; + int a, b, c; + + if (!(fp = fopen(fn, "r"))) + goto exit; + + o = malloc(sizeof(struct obj)); + if (!o) + goto close_and_exit; + memset(o, 0, sizeof(struct obj)); + + while (fgets(buf, sizeof(buf), fp) != 0) { + if (!strncmp(buf, "v ", 2)) { + sscanf(buf + 2, "%f %f %f", &x, &y, &z); + obj_add_v(o, x, y, z); + } else if (!strncmp(buf, "vn ", 3)) { + sscanf(buf + 3, "%f %f %f", &x, &y, &z); + obj_add_vn(o, x, y, z); + } else if (!strncmp(buf, "vt ", 3)) { + sscanf(buf + 3, "%f %f", &x, &y); + obj_add_vt(o, x, y); + } else if (!strncmp(buf, "f ", 2)) { + char *tmp = buf + 2; + /* XXX: handle non-triangles */ + while (sscanf(tmp, "%d/%d/%d", &a, &b, &c) == 3) { + obj_add_f(o, a, b, c); + tmp = strstr(tmp, " "); + if (!tmp) break; + tmp++; + } + } else { +// fprintf(stderr,"ignoring: %s", buf); + } + } + +close_and_exit: + fclose(fp); +exit: + return o; +} + +static struct model *obj_to_model(struct obj *o) { + int i, j, n; + struct model *m; + + if(!(m = malloc(sizeof(struct model)))) + return 0; + memset(m, 0, sizeof(struct model)); + + if (!(m->vdata = malloc(sizeof(float) * 8 * o->num_f))) { + free(m); + return 0; + } + if (!(m->idx = malloc(sizeof(short) * o->num_f))) { + free(m->vdata); + free(m); + return 0; + } + + for (n = 0, i = 0; i < o->num_f; i++) { + float data[8]; + data[0] = o->v[o->f[i].v].x; + data[1] = o->v[o->f[i].v].y; + data[2] = o->v[o->f[i].v].z; + data[3] = o->vn[o->f[i].vn].x; + data[4] = o->vn[o->f[i].vn].y; + data[5] = o->vn[o->f[i].vn].z; + data[6] = o->vt[o->f[i].vt].u; + data[7] = o->vt[o->f[i].vt].v; + for (j = 0; j < n; j++) + if (!memcmp(data, &m->vdata[8 * j], sizeof(float) * 8)) + goto found_it; + memcpy(&m->vdata[8 * j], data, sizeof(float) * 8); + n++; +found_it: + m->idx[i] = j; + } + + m->vcount = n; + m->icount = o->num_f; + + return m; +} + +#if 0 +void model_dump(struct model *m, FILE *fp) { + int i; + fprintf(fp, "struct model M = {\n"); + fprintf(fp, " .vdata = {\n"); + for (i = 0; i < m->vcount; i++) + fprintf(fp, " %f, %f, %f,\n %f, %f, %f, %f, %f,\n", + m->vdata[i*8+0], m->vdata[i*8+1], + m->vdata[i*8+2], m->vdata[i*8+3], + m->vdata[i*8+4], m->vdata[i*8+5], + m->vdata[i*8+6], m->vdata[i*8+7]); + fprintf(fp, " },\n .idx[] = {\n"); + for (i = 0; i < m->icount; i += 3) + fprintf(fp, " %d, %d, %d,\n", + m->idx[i+0], m->idx[i+1], m->idx[i+2]); + fprintf(fp, " },\n .vcount = %d,\n .icount = %d,\n};\n", + m->vcount, m->icount); +} +#endif + +struct model *load_wavefront_obj(const char *fn) { + struct obj *o; + struct model *m; + o = load_obj(fn); + if (!o) + return 0; + m = obj_to_model(o); + obj_destroy(o); + return m; +} + diff --git a/test3.c b/test3.c @@ -0,0 +1,124 @@ +/* Copyright 2013 Brian Swetland <swetland@frotz.net> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#include "util.h" +#include "glue.h" + +#include <math.h> + +void *texdata; +unsigned texw, texh; + +const char *vert_src, *frag_src; + +GLuint pgm, vshd, fshd, tex0; +GLuint _vPosition, _vUV; +GLuint _uMVP, _uSampler; + +mat4 perspective; +mat4 MVP; + +float a = 0.0; + +struct model *m; + +int scene_init(struct ctxt *c) { + float aspect = ((float) c->width) / ((float) c->height); + + if (!(texdata = load_png_rgba("cube-texture.png", &texw, &texh))) + return -1; + if (!(vert_src = load_file("test1.vertex.glsl", 0))) + return -1; + if (!(frag_src = load_file("test1.fragment.glsl", 0))) + return -1; + + if (!(m = load_wavefront_obj("cube.obj"))) + return -1; + + mtx_identity(MVP); + mtx_perspective(perspective, 60.0, aspect, 1.0, 10.0); + + glViewport(0, 0, c->width, c->height); + glClearColor(0, 0, 0, 0); + glClearDepth(1.0f); + + if (shader_compile(vert_src, frag_src, &pgm, &vshd, &fshd)) + return -1; + + _vPosition = glGetAttribLocation(pgm, "vPosition"); + _vUV = glGetAttribLocation(pgm, "vUV"); + _uMVP = glGetUniformLocation(pgm, "uMVP"); + _uSampler = glGetUniformLocation(pgm, "uSampler"); + + if(glGetError() != GL_NO_ERROR) fprintf(stderr,"OOPS!\n"); + + glEnable(GL_TEXTURE_2D); + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); + glFrontFace(GL_CCW); +// glEnable(GL_BLEND); +// glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + + glGenTextures(1, &tex0); + + glBindTexture(GL_TEXTURE_2D, tex0); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texw, texh, 0, GL_RGBA, + GL_UNSIGNED_BYTE, texdata); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + return 0; +} + +#include "data.h" + +int scene_draw(struct ctxt *c) { + mat4 camera; + + mtx_identity(camera); + mtx_translate(camera, 0, 0, -5.0); + mtx_rotate_y(camera, a); + mtx_rotate_x(camera, 25.0); + + mtx_mul_unsafe(MVP, camera, perspective); + + a += 1.0; + if (a > 360.0) a = 0.0; + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glUseProgram(pgm); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, tex0); + + glUniformMatrix4fv(_uMVP, 1, GL_FALSE, (void*) MVP); + glUniform1i(_uSampler, 0); + + glVertexAttribPointer(_vPosition, 3, GL_FLOAT, GL_FALSE, 8*4, m->vdata); + glEnableVertexAttribArray(_vPosition); + + glVertexAttribPointer(_vUV, 2, GL_FLOAT, GL_FALSE, 8*4, m->vdata + 6); + glEnableVertexAttribArray(_vUV); + + glDrawElements(GL_TRIANGLES, m->icount, GL_UNSIGNED_SHORT, m->idx); + + return 0; +} + diff --git a/util.h b/util.h @@ -52,5 +52,15 @@ void mtx_perspective(mat4 out, void *load_png_rgba(const char *fn, unsigned *width, unsigned *height); void *load_file(const char *fn, unsigned *sz); +/* model helpers */ + +struct model { + float *vdata; /* { vertex[3], normal[3], texcoord[2] } * vcount */ + unsigned short *idx; + unsigned vcount; + unsigned icount; +}; + +struct model *load_wavefront_obj(const char *fn); #endif