diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | cube.fmd | bin | 0 -> 948 bytes | |||
-rw-r--r-- | faqe.c | 96 | ||||
-rw-r--r-- | fmd.c | 113 | ||||
-rw-r--r-- | fmd.h | 32 | ||||
-rw-r--r-- | gl.h | 7 | ||||
-rw-r--r-- | glfunc.h | 3 | ||||
-rw-r--r-- | ieee754.c | 39 | ||||
-rw-r--r-- | ieee754.h | 6 | ||||
-rw-r--r-- | model.c | 60 | ||||
-rw-r--r-- | model.h | 30 | ||||
-rw-r--r-- | test_ieee754.c | 38 | ||||
-rw-r--r-- | vert.glsl | 9 | ||||
-rw-r--r-- | vertex.h | 16 |
15 files changed, 404 insertions, 49 deletions
@@ -1,5 +1,6 @@ *.o faqe +test_ieee754 *.exe *.dll @@ -15,7 +15,7 @@ CFLAGS += $(shell $(PKG_CONFIG) --cflags $(LIBS)) -std=c11 -MMD -MP LDFLAGS += -Wl,--as-needed LDLIBS += $(shell $(PKG_CONFIG) --libs $(LIBS)) -lm -OBJ := faqe.o gl.o eprintf.o glprog.o +OBJ := faqe.o eprintf.o fmd.o gl.o glprog.o ieee754.o model.o all: $(PROG) @@ -24,6 +24,7 @@ include $(EPRINTF_PATH)/module.mk include $(LINMATH_PATH)/module.mk $(PROG): $(OBJ) +test_ieee754: ieee754.o faqe.o: assets.h deplinks: $(EPRINTF_FILES) $(LINMATH_FILES) diff --git a/cube.fmd b/cube.fmd Binary files differnew file mode 100644 index 0000000..6177d5d --- /dev/null +++ b/cube.fmd @@ -11,33 +11,37 @@ #include "glprog.h" #include "linmath.h" #include "nelem.h" +#include "model.h" enum { WIDTH = 800, HEIGHT = 600, }; +# define PI 3.14159265358979323846 +#define FOV (PI * 0.5) + +void viewport(GLuint proj, int width, int height) +{ + mat4x4 pers; + gl_viewport(0, 0, width, height); + mat4x4_perspective(pers, FOV, (float)width / (float)height, 0.1, 100); + gl_uni_setm4fv(proj, 1, GL_FALSE, pers[0]); +} + int main(int argc, char **argv) { bool running = true; SDL_Window *win; SDL_GLContext *glc; - GLuint ebo, vbo, vao, prog; - GLint ucolor; - struct vertex { - vec3 pos; - vec3 col; - vec2 uv; - } verts[] = { - {{ 0.5, 0.5, 0.0 }, { 1.0, 0.0, 0.0 }, { 1.0, 1.0 }}, - {{ 0.5, -0.5, 0.0 }, { 0.0, 1.0, 0.0 }, { 1.0, 0.0 }}, - {{ -0.5, -0.5, 0.0 }, { 0.0, 0.0, 1.0 }, { 0.0, 0.0 }}, - {{ -0.5, 0.5, 0.0 }, { 1.0, 1.0, 0.0 }, { 0.0, 1.0 }}, - }; - GLuint idxs[] = { - 0, 1, 3, - 1, 2, 3, - }; + GLuint prog; + struct { + GLint model, view, proj; + } uni; + mat4x4 view; + FILE *cube_file; + struct fmd cube_fmd; + struct model cube_model; setprogname(argc >= 1 && argv[0] != NULL ? argv[0] : "faqe"); @@ -62,37 +66,37 @@ int main(int argc, char **argv) gl_load((gl_loadfunc *)SDL_GL_GetProcAddress); - gl_viewport(0, 0, WIDTH, HEIGHT); - - gl_buf_gen(1, &vbo); - gl_buf_gen(1, &ebo); - gl_va_gen(1, &vao); - - gl_va_bind(vao); - - gl_buf_bind(GL_ARRAY_BUFFER, vbo); - gl_buf_data(GL_ARRAY_BUFFER, sizeof verts, verts, GL_STATIC_DRAW); - - gl_buf_bind(GL_ELEMENT_ARRAY_BUFFER, ebo); - gl_buf_data(GL_ELEMENT_ARRAY_BUFFER, sizeof idxs, idxs, GL_STATIC_DRAW); - - gl_va_define(0, NELEM(verts[0].pos), GL_FLOAT, GL_FALSE, sizeof *verts, (void *)offsetof(struct vertex, pos)); - gl_va_enable(0); - gl_va_define(1, NELEM(verts[0].col), GL_FLOAT, GL_FALSE, sizeof *verts, (void *)offsetof(struct vertex, col)); - gl_va_enable(1); - gl_va_define(2, NELEM(verts[0].uv), GL_FLOAT, GL_FALSE, sizeof *verts, (void *)offsetof(struct vertex, uv)); - gl_va_enable(2); + cube_file = fopen("cube.fmd", "rb"); + if (cube_file == NULL) + eprintf("Could not open 'cube.fmd':"); + fmd_load(&cube_fmd, cube_file); + model_load(&cube_model, &cube_fmd); + fmd_free(&cube_fmd); + fclose(cube_file); prog = glprog_load(2, (struct shdrdat []){ { GL_VERTEX_SHADER, vert_glsl.data, vert_glsl.size }, { GL_FRAGMENT_SHADER, frag_glsl.data, frag_glsl.size }, }, - 1, &(struct unidat){ "ucolor", &ucolor }); + 3, (struct unidat []){ + { "model", &uni.model }, + { "view", &uni.view }, + { "proj", &uni.proj }, + }); - gl_poly_mode(GL_FRONT_AND_BACK, GL_LINE); + viewport(uni.proj, WIDTH, HEIGHT); + + gl_enable(GL_DEPTH_TEST); while (running) { + mat4x4 model; SDL_Event ev; + float secs; + + secs = SDL_GetTicks() * 0.0001; + + mat4x4_look_at(view, (vec3){ 0, 0, 3 }, (vec3){ 0, 0, 0 }, (vec3){ 0, 1, 0 }); + gl_uni_setm4fv(uni.view, 1, GL_FALSE, view[0]); while (SDL_PollEvent(&ev)) { switch (ev.type) { @@ -108,19 +112,23 @@ int main(int argc, char **argv) case SDL_WINDOWEVENT: switch (ev.window.event) { case SDL_WINDOWEVENT_SIZE_CHANGED: - gl_viewport(0, 0, - ev.window.data1, - ev.window.data2); + viewport(uni.proj, + ev.window.data1, + ev.window.data2); } break; } } gl_clearcolor(0.2, 0.3, 0.3, 1.0); - gl_clear(GL_COLOR_BUFFER_BIT); + gl_clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); gl_prog_use(prog); - gl_va_bind(vao); - gl_draw_elems(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); + mat4x4_identity(model); + mat4x4_rotate_X(model, model, secs * 3); + mat4x4_rotate_Y(model, model, secs * 2); + mat4x4_rotate_Z(model, model, secs * 4); + gl_uni_setm4fv(uni.model, 1, GL_TRUE, model[0]); + model_render(&cube_model); gl_va_bind(0); SDL_GL_SwapWindow(win); @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2018 Tomasz Kramkowski <tk@the-tk.com> + * SPDX-License-Identifier: MIT + */ +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +#include "eprintf.h" +#include "fmd.h" +#include "ieee754.h" +#include "nelem.h" + +static const char *MAGIC = "FMD001\r\n"; + +static void checkmagic(FILE *f) +{ + for (size_t i = 0; i < strlen(MAGIC); i++) + assert(fgetc(f) == MAGIC[i]); +} + +static inline unsigned long betoul(FILE *src) +{ + unsigned long ret = 0; + + assert(src != NULL); + + for (int i = 0; i < 4; i++) { + int c = fgetc(src); + assert(c != EOF); + ret += (unsigned long)(c & 0xff) << (3 - i) * 8; + } + + return ret; +} + +void readfloats(float *dest, int count, FILE *src) +{ + assert(dest != NULL); + assert(src != NULL); + + for (int i = 0; i < count; i++) + dest[i] = ieee754f(betoul(src)); +} + +void fmd_load(struct fmd *fmd, FILE *f) +{ + assert(fmd != NULL); + assert(f != NULL); + + checkmagic(f); + + fmd->nverts = betoul(f); + if (fmd->nverts > 0) + fmd->verts = emalloc(fmd->nverts * sizeof *fmd->verts); + else + fmd->verts = NULL; + for (int i = 0; i < fmd->nverts; i++) { + struct vertex *v = &fmd->verts[i]; + readfloats(v->pos, 3, f); + readfloats(v->norm, 3, f); + readfloats(v->uv, 2, f); + } + fmd->ntris = betoul(f); + if (fmd->ntris > 0) + fmd->tris = emalloc(fmd->ntris * sizeof *fmd->tris); + else + fmd->tris = NULL; + for (int i = 0; i < fmd->ntris; i++) + for (size_t j = 0; j < NELEM(fmd->tris[j]); j++) + fmd->tris[i][j] = betoul(f); + + fmd->nmtls = betoul(f); + if (fmd->nmtls > 0) + fmd->mtls = emalloc(fmd->nmtls * sizeof *fmd->mtls); + else + fmd->mtls = NULL; + for (int i = 0; i < fmd->nmtls; i++) { + unsigned long len = betoul(f); + char **m = &fmd->mtls[i]; + size_t ret; + + *m = emalloc(len + 1); + + ret = fread(*m, len, 1, f); + assert(ret == 1); + *m[len] = '\0'; + } + + fmd->nmeshes = betoul(f); + if (fmd->nmeshes > 0) + fmd->meshes = emalloc(fmd->nmeshes * sizeof *fmd->meshes); + else + fmd->meshes = NULL; + for (int i = 0; i < fmd->nmeshes; i++) { + struct fmd_mesh *m = &fmd->meshes[i]; + m->midx = betoul(f); + m->tidx = betoul(f); + m->tcnt = betoul(f); + } +} + +void fmd_free(struct fmd *fmd) +{ + assert(fmd); + + free(fmd->verts); + free(fmd->tris); + for (int i = 0; i < fmd->nmtls; i++) + free(fmd->mtls[i]); + free(fmd->mtls); + free(fmd->meshes); +} @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2018 Tomasz Kramkowski <tk@the-tk.com> + * SPDX-License-Identifier: MIT + */ +#ifndef FMD_H +#define FMD_H + +#include <stdio.h> + +#include "gl.h" +#include "vertex.h" + +typedef GLuint tri[3]; +struct fmd { + int nverts; + struct vertex *verts; + int ntris; + tri *tris; + int nmtls; + char **mtls; + int nmeshes; + struct fmd_mesh { + int midx; + int tidx; + int tcnt; + } *meshes; +}; + +void fmd_load(struct fmd *fmd, FILE *f); +void fmd_free(struct fmd *fmd); + +#endif // FMD_H @@ -32,6 +32,11 @@ typedef double GLdouble; typedef double GLclampd; enum { + GL_DEPTH_BUFFER_BIT = 0x100, + GL_COLOR_BUFFER_BIT = 0x4000, +}; + +enum { GL_NO_ERROR = 0, GL_FALSE = 0, GL_TRUE = 1, @@ -45,10 +50,10 @@ enum { GL_OUT_OF_MEMORY = 0x0505, GL_INVALID_FRAMEBUFFER_OPERATION = 0x0506, GL_CONTEXT_LOST = 0x0507, + GL_DEPTH_TEST = 0x0b71, GL_UNSIGNED_INT = 0x1405, GL_FLOAT = 0x1406, GL_LINE = 0x1B01, - GL_COLOR_BUFFER_BIT = 0x4000, GL_ARRAY_BUFFER = 0x8892, GL_ELEMENT_ARRAY_BUFFER = 0x8893, GL_STREAM_DRAW = 0x88e0, @@ -43,3 +43,6 @@ GL_FUNC(glUniform3fv, void, gl_uni_set3fv, GLint location, GLsizei count, const GL_FUNC(glUniform4fv, void, gl_uni_set4fv, GLint location, GLsizei count, const GLfloat *value) GL_FUNC(glUniformMatrix3fv, void, gl_uni_setm3fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) GL_FUNC(glUniformMatrix4fv, void, gl_uni_setm4fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +GL_FUNC(glGetIntegerv, void, gl_geti, GLenum pname, GLint *data) +GL_FUNC(glEnable, void, gl_enable, GLenum cap) +GL_FUNC(glDisable, void, gl_disable, GLenum cap) diff --git a/ieee754.c b/ieee754.c new file mode 100644 index 0000000..3b21351 --- /dev/null +++ b/ieee754.c @@ -0,0 +1,39 @@ +#include <assert.h> +#include <math.h> +#include <stdbool.h> +#include <stdio.h> + +#include "ieee754.h" + +// ieee754f: convert f32 to float +float ieee754f(unsigned long b) +{ + bool isneg; + int exp; + float n; + + isneg = (b >> 31) & 0x1; + exp = (b >> 23) & 0xff; + n = b & 0x7fffff; + + if (exp == 0xff) { + if (n) { + /* TODO: work out what a negative NaN means */ + assert(!isneg); + return NAN; + } else { + return isneg ? -INFINITY : INFINITY; + } + } else if (exp == 0) { + if (n == 0) + return isneg ? -0 : 0; + exp = -126; + } else { + n += 0x1p23f; + exp -= 127; + } + + n = ldexpf(n, exp - 23); + + return isneg ? -n : n; +} diff --git a/ieee754.h b/ieee754.h new file mode 100644 index 0000000..58f886d --- /dev/null +++ b/ieee754.h @@ -0,0 +1,6 @@ +#ifndef IEEE754_H +#define IEEE754_H + +float ieee754f(unsigned long l); + +#endif // IEEE754_H @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2018 Tomasz Kramkowski <tk@the-tk.com> + * SPDX-License-Identifier: MIT + */ +#include <assert.h> + +#include "eprintf.h" +#include "linmath.h" +#include "model.h" +#include "nelem.h" +#include "vertex.h" + +void model_load(struct model *mdl, const struct fmd *fmd) +{ + GLuint vbo, ebo; + struct vertex *v; + + assert(mdl != NULL); + assert(fmd != NULL); + + gl_va_gen(1, &mdl->vao); + gl_va_bind(mdl->vao); + + gl_buf_gen(1, &vbo); + gl_buf_bind(GL_ARRAY_BUFFER, vbo); + gl_buf_data(GL_ARRAY_BUFFER, fmd->nverts * sizeof *fmd->verts, fmd->verts, GL_STATIC_DRAW); + + gl_buf_gen(1, &ebo); + gl_buf_bind(GL_ELEMENT_ARRAY_BUFFER, ebo); + gl_buf_data(GL_ELEMENT_ARRAY_BUFFER, fmd->ntris * sizeof *fmd->tris, fmd->tris, GL_STATIC_DRAW); + + v = &fmd->verts[0]; + gl_va_define(0, NELEM(v->pos), GL_FLOAT, GL_FALSE, sizeof *v, (void *)offsetof(struct vertex, pos)); + gl_va_enable(0); + gl_va_define(1, NELEM(v->norm), GL_FLOAT, GL_FALSE, sizeof *v, (void *)offsetof(struct vertex, norm)); + gl_va_enable(1); + gl_va_define(2, NELEM(v->uv), GL_FLOAT, GL_FALSE, sizeof *v, (void *)offsetof(struct vertex, uv)); + gl_va_enable(2); + + // TODO: materials, use a shared material set + + mdl->nmeshes = fmd->nmeshes; + mdl->meshes = emalloc(mdl->nmeshes * sizeof *mdl->meshes); + for (int i = 0; i < fmd->nmeshes; i++) { + struct mesh *m = &mdl->meshes[i]; + struct fmd_mesh *fm = &fmd->meshes[i]; + m->mtl = NULL; + m->elems.idx = fm->tidx * NELEM(*fmd->tris); + m->elems.cnt = fm->tcnt * NELEM(*fmd->tris); + } +} + +void model_render(struct model *mdl) +{ + gl_va_bind(mdl->vao); + for (int i = 0; i < mdl->nmeshes; i++) { + struct mesh *m = &mdl->meshes[i]; + gl_draw_elems(GL_TRIANGLES, m->elems.cnt, GL_UNSIGNED_INT, &((GLuint *)NULL)[m->elems.idx]); + } +} @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2018 Tomasz Kramkowski <tk@the-tk.com> + * SPDX-License-Identifier: MIT + */ +#ifndef MODEL_H +#define MODEL_H + +#include "gl.h" +#include "fmd.h" + +struct mesh { + struct material { + GLuint diffuse; + } *mtl; + struct { + GLuint idx; + GLuint cnt; + } elems; +}; + +struct model { + struct mesh *meshes; + int nmeshes; + GLuint vao; +}; + +void model_load(struct model *mdl, const struct fmd *fmd); +void model_render(struct model *mdl); + +#endif // MODEL_H diff --git a/test_ieee754.c b/test_ieee754.c new file mode 100644 index 0000000..44873c9 --- /dev/null +++ b/test_ieee754.c @@ -0,0 +1,38 @@ +#include <math.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +#include "ieee754.h" + +static unsigned long naiive(float n) +{ + union { + float f; + uint32_t u; + } u = { .f = n }; + + return u.u; +} + +void test(float a) +{ + float b = ieee754f(naiive(a)); + + if (!((isnan(a) && isnan(b)) || a == b)) { + fprintf(stderr, "%lu: %.40f != %.40f\n", naiive(a), a, b); + exit(EXIT_FAILURE); + } +} + +int main(void) +{ + test(NAN); + test(+INFINITY); + test(-INFINITY); + test(0x1p127f); + test(0x7fffffp-149f); + + for (float n = -0.000000001; n <= 1; n = nextafterf(n, 2)) + test(n); +} @@ -2,13 +2,16 @@ // SPDX-License-Identifier: MIT #version 330 core layout (location = 0) in vec3 pos; -layout (location = 1) in vec3 color; +layout (location = 1) in vec3 normal; layout (location = 2) in vec2 uv; out vec3 vcolor; +uniform mat4 model; +uniform mat4 view; +uniform mat4 proj; void main() { - gl_Position = vec4(pos, 1.0); - vcolor = color; + gl_Position = proj * view * model * vec4(pos, 1.0); + vcolor = normal; } diff --git a/vertex.h b/vertex.h new file mode 100644 index 0000000..7f58ee9 --- /dev/null +++ b/vertex.h @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2018 Tomasz Kramkowski <tk@the-tk.com> + * SPDX-License-Identifier: MIT + */ +#ifndef VERTEX_H +#define VERTEX_H + +#include "linmath.h" + +struct vertex { + vec3 pos; + vec3 norm; + vec2 uv; +}; + +#endif // VERTEX_H |