polyadvent

A game engine from scratch in C
git clone git://jb55.com/polyadvent
Log | Files | Refs | README

commit 5444b48a0c2bced7eb200b56e274ad7de79fe000
parent 1a35612b18f3291266b0c4e84095c7e98d503cc9
Author: William Casarin <jb55@jb55.com>
Date:   Sun, 26 Sep 2021 12:38:22 -0700

shader var overhaul

Diffstat:
MMakefile | 31++++++++++++-------------------
Mdefault.nix | 2+-
Metc/shaders/chess-piece.v.glsl | 4++--
Metc/shaders/main.f.glsl | 2+-
Metc/shaders/standard_vtxos.glsl | 4++--
Metc/shaders/ui.v.glsl | 3+--
Metc/shaders/uniforms.glsl | 8+++-----
Mmain.c | 13++++++-------
Msrc/chess.c | 446+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
Msrc/chess.h | 3++-
Msrc/common.h | 6++++--
Msrc/dae.c | 2+-
Asrc/data_id.h | 92+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/debug.c | 20+++++++++++++++++---
Msrc/debug.h | 3++-
Msrc/delaunay.c | 12++++++------
Msrc/entity.c | 11++---------
Msrc/entity.h | 33+++++++++++++++++++--------------
Msrc/fbo.c | 2--
Msrc/file.c | 2--
Msrc/game.c | 15++++-----------
Msrc/game.h | 4+---
Msrc/geometry.c | 308++++++++++++++++++++++++++++++++++++++++---------------------------------------
Msrc/geometry.h | 5++---
Msrc/gpu.c | 16++++++++++++++++
Msrc/gpu.h | 1+
Asrc/hash.h | 20++++++++++++++++++++
Msrc/hires.c | 2+-
Msrc/input.c | 13+++++--------
Msrc/input.h | 13+++++--------
Msrc/mdl.c | 9++++-----
Msrc/mdl.h | 5++---
Msrc/model.c | 126++++++++++++++++++++++++++++++++++++-------------------------------------------
Msrc/model.h | 2+-
Msrc/node.c | 5++++-
Msrc/node.h | 2+-
Msrc/orbit_util.c | 14+++++++++-----
Msrc/poisson.c | 2--
Msrc/quickhull.c | 4++--
Msrc/render.h | 9++++-----
Msrc/resource.c | 276++++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/resource.h | 1+
Msrc/scene.c | 1-
Msrc/shader.c | 692++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
Msrc/shader.h | 82++++++++++++++++++++++++++++++++++---------------------------------------------
Msrc/skybox.c | 34++++++++++++++++++----------------
Msrc/skybox.h | 11++++-------
Msrc/terrain.c | 185++++++++++++++++++++++++++-----------------------------------------------------
Msrc/terrain.h | 5++---
Msrc/terrain_collision.c | 7++-----
Msrc/test_game.c | 594+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Msrc/test_game.h | 41++++++++++++++++++++++++++++++++---------
Msrc/ui.c | 75+++++++++++++++++++++++++++++++++++++--------------------------------------
Msrc/ui.h | 21+++++++++------------
Msrc/update.c | 22----------------------
Msrc/vbo.h | 12++++++++++++
Atest/test_data_id.c | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtools/compile-model.c | 2+-
58 files changed, 1915 insertions(+), 1483 deletions(-)

diff --git a/Makefile b/Makefile @@ -7,24 +7,17 @@ DEFS= -DGLFW_INCLUDE_NONE -DDEBUG # CFLAGS = $(DEFS) -ggdb -O0 -I src -Wall -Wextra -std=c99 \ -BASE_CFLAGS = $(DEFS) -O2 -g -I src -Wall -Werror -Wextra -std=c99 \ - -DSTBI_ONLY_TGA \ - -Wno-unused-function \ - -Wno-unused-parameter \ - -Wno-unused-variable \ - -Wmissing-field-initializers \ - -Wno-cast-align \ - -Wno-padded \ - $(shell pkg-config --cflags sdl2 gl) - -CFLAGS = $(BASE_CFLAGS) -EM_CFLAGS = $(BASE_CFLAGS) -s STANDALONE_WASM -mbulk-memory - -LDFLAGS = $(shell pkg-config --libs sdl2 gl) -lm +CFLAGS = $(DEFS) -O1 -g -I src -Wall -Werror -Wextra -std=c99 \ + -Wno-unused-function \ + -Wno-unused-parameter \ + -Wno-unused-variable \ + -Wmissing-field-initializers \ + -Wno-cast-align \ + -Wno-padded +LDFLAGS = -lSDL2 -lGL -lm SRC=src SRCS=$(wildcard $(SRC)/*.c) -HEADERS=$(wildcard $(SRC)/*.h) PLYS=$(wildcard data/models/*.ply) MODELS=$(PLYS:.ply=.mdl) @@ -74,14 +67,14 @@ $(BIN): main.o $(OBJS) @echo "link $@" @$(CC) $(CFLAGS) $^ $(LDFLAGS) -o $@ -$(BIN).wasm: main.c $(SRCS) - emcc $(EM_CFLAGS) $^ -s WASM=1 -s ERROR_ON_UNDEFINED_SYMBOLS=0 -o $@ - install: $(BIN) install -d $(PREFIX)/bin install $(BIN) $(PREFIX)/bin +TAGS: + etags $(SRCS) + tags: ctags $(SRCS) $(HEADERS) -.PHONY: TAGS tags +.PHONY: TAGS diff --git a/default.nix b/default.nix @@ -14,7 +14,7 @@ stdenv.mkDerivation rec { makeFlags = "PREFIX=$(out)"; - nativeBuildInputs = with pkgs; [ tinycc pkg-config gdb emscripten binaryen wabt ]; + nativeBuildInputs = with pkgs; [ tinycc pkg-config gdb ]; buildInputs = with pkgs; [ SDL2 mesa libglvnd ] ++ (with xorg; [ libX11 libxcb libXau libXdmcp libXext libXcursor diff --git a/etc/shaders/chess-piece.v.glsl b/etc/shaders/chess-piece.v.glsl @@ -6,7 +6,7 @@ in vec3 normal; #include uniforms.glsl -uniform bool is_white; +uniform int is_white; out shader_data { #include shadervars.glsl @@ -14,7 +14,7 @@ out shader_data { void main() { - vec3 color = is_white ? vec3(0.9, 0.9, 0.9) : vec3(0.3, 0.3, 0.3); + vec3 color = is_white == 1 ? vec3(0.9, 0.9, 0.9) : vec3(0.3, 0.3, 0.3); #include standard_vtxos.glsl gl_Position = mvp * v4_pos; } diff --git a/etc/shaders/main.f.glsl b/etc/shaders/main.f.glsl @@ -41,7 +41,7 @@ void main() { // vec3 color = reflect_env(vertex.color); vec3 color = pbr(vertex.color, normalize(V), vertex.normal); - if (fog_on) { + if (fog_on == 1) { vec3 fog = apply_fog(color, vertex.position, length(V), camera_position, V); color = fog; } diff --git a/etc/shaders/standard_vtxos.glsl b/etc/shaders/standard_vtxos.glsl @@ -2,8 +2,8 @@ vec4 v4_pos = vec4(position, 1.0); // data_out.normal = normal; // data_out.position = position; -data_out.normal = mat3(transpose(inverse(model))) * normal; -data_out.position = vec3(model * v4_pos); +data_out.normal = mat3(transpose(inverse(model_view))) * normal; +data_out.position = vec3(model_view * v4_pos); data_out.color_smooth = data_out.color = color; data_out.shadow_coord = depth_mvp * v4_pos; // TODO: move shadow coord calc from frag to here diff --git a/etc/shaders/ui.v.glsl b/etc/shaders/ui.v.glsl @@ -1,7 +1,6 @@ #include profile in vec3 position; -in vec3 color; in vec2 tex_coords; out vec3 v_color; @@ -18,5 +17,5 @@ void main() gl_Position = mvp * v4_pos; v_tex_coords = tex_coords; - v_color = color + v4_pos.xyz; + v_color = v4_pos.xyz; } diff --git a/etc/shaders/uniforms.glsl b/etc/shaders/uniforms.glsl @@ -1,15 +1,13 @@ +precision highp int; // uniform bool diffuse_on; -uniform bool fog_on; +uniform int fog_on; uniform float sky_intensity; uniform float light_intensity; uniform mat4 depth_mvp; -// uniform mat4 depth_vp; -uniform mat4 model; uniform mat4 mvp; +uniform mat4 model_view; uniform mat4 normal_matrix; -// uniform float time; -// uniform float ambient_str; uniform vec3 sun_color; uniform vec3 camera_position; uniform vec3 light_dir; diff --git a/main.c b/main.c @@ -19,12 +19,10 @@ #include "update.h" #include "util.h" #include "window.h" - #include "test_game.h" +//#include "rogue/rogue.h" - -#include <stdio.h> #include <assert.h> #include <time.h> @@ -46,16 +44,16 @@ int main(void) /* SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); */ int width = 640; - int hello; int height = 480; - game_init(&engine, width, height); - init_test_game(&test_game, &engine.gpu, width, height); + game_init(&engine, width, height); + //rogue_game_init(&rogue_game); + init_test_game(&engine, &test_game); //reset_scene(&engine); default_scene(&test_game); //pbr_scene(&test_game); - //chess_scene(&game); + chess_scene(&engine, &test_game); check_gl(); double last = hires_time_in_seconds(); @@ -77,6 +75,7 @@ int main(void) // render our game frame here test_game_frame(&engine, &test_game); + //rogue_frame(&engine, rogue_game); /* Swap front and back buffers */ SDL_GL_SwapWindow(engine.window); diff --git a/src/chess.c b/src/chess.c @@ -1,233 +1,321 @@ #include "chess.h" #include "node.h" +#include "gpu.h" +#include "shader.h" +#include "hash.h" +#include "test_game.h" -// v1------v0 -// | | -// | | -// | | -// v2------v3 +// v1------v0 +// | | +// | | +// | | +// v2------v3 static GLuint quad_indices[] = {0, 1, 2, 0, 2, 3}; static GLfloat quad_normals[] = { - 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, // front + 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, // front }; static GLfloat quad_vertices[] = { - 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, -0.5,-0.5, 0.5, 0.5,-0.5, 0.5, // v0-v1-v2-v3 front + 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, -0.5,-0.5, 0.5, 0.5,-0.5, 0.5, // v0-v1-v2-v3 front }; - static GLfloat quad_uvs[] = - { - 1.0, 1.0, // v0 - 0.0, 1.0, // v1 - 0.0, 0.0, // v2 - 1.0, 0.0, // v3 - }; + { + 1.0, 1.0, // v0 + 0.0, 1.0, // v1 + 0.0, 0.0, // v2 + 1.0, 0.0, // v3 + }; #define CELL_SIZE 10.0 +struct chess_piece { + int is_white; +}; + +#define CP_LENS(field, typ) { #field, offsetof(struct chess_piece, field), DATA_ID_##typ } +static struct lens chess_piece_lenses[] = { + CP_LENS(is_white, INT), +}; + void make_grid(float *verts, float vert_capacity, - u32 *indices, float index_capacity, - float *normals, float normal_capacity, - float *colors, float color_capacity, - int width, int height) + u32 *indices, float index_capacity, + float *normals, float normal_capacity, + float *colors, float color_capacity, + int width, int height) { - int c = 0; - for (int x = 0; x < width; x++) { - for (int y = 0; y < height; y++, c++) { - int grid_ind = y * height + x; - int vind = grid_ind * ARRAY_SIZE(quad_vertices); - int iind = grid_ind * ARRAY_SIZE(quad_indices); - int i = 0; - - for (i = 0; i < 4; i++) { - int nv = i*3; - assert(vind+2+nv < vert_capacity); - assert(vind+2+nv < color_capacity); - assert(vind+2+nv < normal_capacity); - verts[vind+0+nv] = (quad_vertices[0+nv] + x) * CELL_SIZE; - verts[vind+1+nv] = (quad_vertices[1+nv] + y) * CELL_SIZE; - verts[vind+2+nv] = quad_vertices[2+nv]; - - // recenter - verts[vind+0+nv] -= (width * CELL_SIZE)/2.0 - 0.5 * CELL_SIZE; - verts[vind+1+nv] -= (height * CELL_SIZE)/2.0 - 0.5 * CELL_SIZE; - verts[vind+2+nv] -= 0.5; - - normals[vind+0+nv] = quad_normals[0+nv]; - normals[vind+1+nv] = quad_normals[1+nv]; - normals[vind+2+nv] = quad_normals[2+nv]; - - float checkers = (x ^ y) & 1; - colors[vind+0+nv] = checkers; - colors[vind+1+nv] = checkers; - colors[vind+2+nv] = checkers; - } - - for (i = 0; i < 2; i++) { - int nv = i*3; - assert(iind+2+nv < index_capacity); - indices[iind+0+nv] = quad_indices[0+nv] + 4*c; - indices[iind+1+nv] = quad_indices[1+nv] + 4*c; - indices[iind+2+nv] = quad_indices[2+nv] + 4*c; - } - } - } + int c = 0; + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++, c++) { + int grid_ind = y * height + x; + int vind = grid_ind * ARRAY_SIZE(quad_vertices); + int iind = grid_ind * ARRAY_SIZE(quad_indices); + int i = 0; + + for (i = 0; i < 4; i++) { + int nv = i*3; + assert(vind+2+nv < vert_capacity); + assert(vind+2+nv < color_capacity); + assert(vind+2+nv < normal_capacity); + verts[vind+0+nv] = (quad_vertices[0+nv] + x) * CELL_SIZE; + verts[vind+1+nv] = (quad_vertices[1+nv] + y) * CELL_SIZE; + verts[vind+2+nv] = quad_vertices[2+nv]; + + // recenter + verts[vind+0+nv] -= (width * CELL_SIZE)/2.0 - 0.5 * CELL_SIZE; + verts[vind+1+nv] -= (height * CELL_SIZE)/2.0 - 0.5 * CELL_SIZE; + verts[vind+2+nv] -= 0.5; + + normals[vind+0+nv] = quad_normals[0+nv]; + normals[vind+1+nv] = quad_normals[1+nv]; + normals[vind+2+nv] = quad_normals[2+nv]; + + float checkers = (x ^ y) & 1; + colors[vind+0+nv] = checkers; + colors[vind+1+nv] = checkers; + colors[vind+2+nv] = checkers; + } + + for (i = 0; i < 2; i++) { + int nv = i*3; + assert(iind+2+nv < index_capacity); + indices[iind+0+nv] = quad_indices[0+nv] + 4*c; + indices[iind+1+nv] = quad_indices[1+nv] + 4*c; + indices[iind+2+nv] = quad_indices[2+nv] + 4*c; + } + } + } } static void make_chessboard_geom(geometry_id *id) { - struct make_geometry mkgeom; - init_make_geometry(&mkgeom); - - static float verts[12*8*8]; // array_size(quad) 12 * 8 * 8 - static float colors[12*8*8]; // array_size(quad) 12 * 8 * 8 - static float normals[12*8*8]; // array_size(quad) 12 * 8 * 8 - static u32 indices[6*8*8]; // array_size(quad) 6 * 8 * 8 - - make_grid(verts, ARRAY_SIZE(verts), - indices, ARRAY_SIZE(indices), - normals, ARRAY_SIZE(normals), - colors, ARRAY_SIZE(colors), - 8, 8); - - mkgeom.indices = indices; - mkgeom.vertices = verts; - mkgeom.normals = normals; - mkgeom.colors = colors; - mkgeom.num_indices = ARRAY_SIZE(indices); - mkgeom.num_verts = ARRAY_SIZE(verts)/3; - mkgeom.num_uv_components = 0; - - init_id(id); - struct geometry *geom = new_geometry(id); - make_buffer_geometry(&mkgeom, geom); - check_gl(); + struct make_geometry mkgeom; + init_make_geometry(&mkgeom); + + static float verts[12*8*8]; // array_size(quad) 12 * 8 * 8 + static float colors[12*8*8]; // array_size(quad) 12 * 8 * 8 + static float normals[12*8*8]; // array_size(quad) 12 * 8 * 8 + static u32 indices[6*8*8]; // array_size(quad) 6 * 8 * 8 + + make_grid(verts, ARRAY_SIZE(verts), + indices, ARRAY_SIZE(indices), + normals, ARRAY_SIZE(normals), + colors, ARRAY_SIZE(colors), + 8, 8); + + mkgeom.indices = indices; + mkgeom.vertices = verts; + mkgeom.normals = normals; + mkgeom.colors = colors; + mkgeom.num_indices = ARRAY_SIZE(indices); + mkgeom.num_verts = ARRAY_SIZE(verts)/3; + mkgeom.num_uv_components = 0; + + init_id(id); + struct geometry *geom = new_geometry(id); + make_buffer_geometry(&mkgeom, geom); + check_gl(); } static void position_piece(struct entity *piece, int x, int y) { - assert(x < 8); - assert(y < 8); + assert(x < 8); + assert(y < 8); - struct node *node = get_node(&piece->node_id); - struct model *model = get_model(&piece->model_id); - struct geometry *geom = get_geometry(&model->geom_id); - assert(node); + struct node *node = get_node(&piece->node_id); + struct model *model = get_model(&piece->model_id); + struct geometry *geom = get_geometry(&model->geom_id); + assert(node); - // reset to a1 - node->pos[0] = -3.5 * CELL_SIZE; - node->pos[1] = -3.5 * CELL_SIZE; - node->pos[2] = 0.0; + // reset to a1 + node->pos[0] = -3.5 * CELL_SIZE; + node->pos[1] = -3.5 * CELL_SIZE; + node->pos[2] = 0.0; - node->pos[0] += x * CELL_SIZE; - node->pos[1] += y * CELL_SIZE; + node->pos[0] += x * CELL_SIZE; + node->pos[1] += y * CELL_SIZE; } static void setup_pieces(node_id *chessboard) { - struct model *pirate_officer; - get_model_by_name("pirate_officer", &pirate_officer); - - // make pawn model - struct model_id pawn_model_id; - init_id(&pawn_model_id.id); - struct model *pawn_model = new_model(&pawn_model_id); - pawn_model->geom_id = pirate_officer->geom_id; - pawn_model->shader = CHESS_PIECE_PROGRAM; - - // pawns - for (int i = 0; i < 16; i++) { - struct entity *pawn = new_entity(NULL); - struct node *pawn_node = get_node(&pawn->node_id); - pawn->model_id = pawn_model_id; - pawn->flags |= ENT_IS_WHITE | ENT_CASTS_SHADOWS; - - node_scale(pawn_node, 5.0); - if (i >= 8) { - pawn->flags &= ~ENT_IS_WHITE; - node_rotate(pawn_node, V3(0.0,0.0,135.0)); - } - node_attach(&pawn->node_id, chessboard); - - position_piece(pawn, i % 8, i < 8 ? 1 : 6); - } - - for (int i = 0; i < 4; i++) { - // rooks - struct entity *rook = new_entity(NULL); - struct model *rook_model; - struct node *rook_node = get_node(&rook->node_id); - rook->model_id = get_model_by_name("tower", &rook_model); - rook->flags |= ENT_CASTS_SHADOWS | ENT_IS_WHITE; - rook_model->shader = CHESS_PIECE_PROGRAM; - node_attach(&rook->node_id, chessboard); - /* node_rotate(rook_node, V3(0.0,0.0,20.0)); */ - if (i >= 2) { - rook->flags &= ~ENT_IS_WHITE; - node_rotate(rook_node, V3(0.0,0.0,135.0)); - } - position_piece(rook, i % 2 ? 0 : 7, i < 2 ? 0 : 7); - node_scale(rook_node, 0.25); - } + struct model *pirate_officer, *pawn_model, *tower_model, *rook_model; + struct model_id pawn_model_id, rook_model_id; + u32 ent_type; + + ent_type = hash_str("chess-piece"); + debug("chess piece ent_type %d\n", ent_type); + + get_model_by_name("pirate_officer", &pirate_officer); + get_model_by_name("tower", &tower_model); + + // make pawn model + init_id(&pawn_model_id.id); + init_id(&rook_model_id.id); + + pawn_model = new_model(&pawn_model_id); + pawn_model->geom_id = pirate_officer->geom_id; + pawn_model->shader = CHESS_PIECE_PROGRAM; + pawn_model->name = "pawn"; + + rook_model = new_model(&rook_model_id); + rook_model->geom_id = tower_model->geom_id; + rook_model->shader = CHESS_PIECE_PROGRAM; + rook_model->name = "rook"; + + // pawns + for (int i = 0; i < 16; i++) { + struct entity *ent = new_entity(NULL); + struct node *pawn_node = get_node(&ent->node_id); + struct chess_piece *pawn = (struct chess_piece*)ent->data; + + ent->type = ent_type; + ent->model_id = pawn_model_id; + ent->flags |= ENT_CASTS_SHADOWS; + + node_set_label(pawn_node, "pawn"); + + pawn->is_white = 1; + + node_scale(pawn_node, 5.0); + + if (i >= 8) { + pawn->is_white = 0; + node_rotate(pawn_node, V3(0.0,0.0,135.0)); + } + + node_attach(&ent->node_id, chessboard); + + position_piece(ent, i % 8, i < 8 ? 1 : 6); + } + + for (int i = 0; i < 4; i++) { + // rooks + struct entity *ent = new_entity(NULL); + struct chess_piece *rook = (struct chess_piece*)ent->data; + struct node *rook_node = get_node(&ent->node_id); + ent->type = ent_type; + ent->model_id = rook_model_id; + ent->flags |= ENT_CASTS_SHADOWS; + rook->is_white = true; + + node_attach(&ent->node_id, chessboard); + /* node_rotate(rook_node, V3(0.0,0.0,20.0)); */ + if (i >= 2) { + rook->is_white = false; + node_rotate(rook_node, V3(0.0,0.0,135.0)); + } + position_piece(ent, i % 2 ? 0 : 7, i < 2 ? 0 : 7); + node_scale(rook_node, 0.25); + } + + +} + +static struct structure_binding *get_chess_piece_bindings(int *count) +{ + static struct structure_binding bindings[2]; + + bindings[0].lenses = get_common_lenses(); + bindings[0].num_lenses = get_common_lenses_length(); + assert(bindings[0].num_lenses > 1); + + bindings[1].lenses = chess_piece_lenses; + bindings[1].num_lenses = ARRAY_SIZE(chess_piece_lenses); + + *count = 2; + + return bindings; } +static struct gpu_program *make_chess_program(struct gpu *gpu) +{ + struct gpu_program *program, *default_program; + struct shader *fragment, chess_piece_vertex; + struct structure_binding *bindings; + int num_bindings; + int ok; + + ok = make_shader(GL_VERTEX_SHADER, SHADER("chess-piece.v.glsl"), &chess_piece_vertex); + rtassert(ok, "chess-piece vertex shader"); + check_gl(); + + default_program = get_gpu_program_by_name(gpu, "vertex-color"); + rtassert(default_program, "failed to get default program"); + check_gl(); + + fragment = get_program_shader(default_program, GL_FRAGMENT_SHADER); + rtassert(fragment, "failed to get default fragment shader"); + + bindings = get_chess_piece_bindings(&num_bindings); + + program = &gpu->programs[CHESS_PIECE_PROGRAM]; + ok = make_program("chess-piece", &chess_piece_vertex, fragment, program, + bindings, num_bindings); + rtassert(ok, "chess-piece program"); + check_gl(); + + return program; +} -void chess_scene(struct test_game *game) +void chess_scene(struct game *engine, struct test_game *game) { - struct entity *ent = new_entity(NULL); - struct node *node = get_node(&ent->node_id); assert(node); - struct entity *player = get_entity(&game->player_id); + struct gpu_program *piece_program; + struct entity *ent = new_entity(NULL); + struct node *node = get_node(&ent->node_id); assert(node); + struct entity *player = get_entity(&game->player_id); + struct shader chess_piece_vertex; - ent->model_id = get_model_by_name("icosphere", NULL); - node_set_label(node, "sphere"); + ent->model_id = get_model_by_name("icosphere", NULL); + node_set_label(node, "sphere"); - // - // setup chessboard - // - geometry_id chessboard_geom; - make_chessboard_geom(&chessboard_geom); + // + // setup chessboard + // + geometry_id chessboard_geom; + make_chessboard_geom(&chessboard_geom); - struct model_id chessboard_model_id; - init_id(&chessboard_model_id.id); + struct model_id chessboard_model_id; + init_id(&chessboard_model_id.id); - struct model *chessboard_model = new_model(&chessboard_model_id); - chessboard_model->shader = DEFAULT_PROGRAM; - chessboard_model->geom_id = chessboard_geom; + struct model *chessboard_model = new_model(&chessboard_model_id); + chessboard_model->name = "chessboard"; + chessboard_model->shader = 0; + chessboard_model->geom_id = chessboard_geom; - player->model_id = chessboard_model_id; - player->flags &= ~ENT_CASTS_SHADOWS; + player->model_id = chessboard_model_id; + player->flags &= ~ENT_CASTS_SHADOWS; - // - // setup camera - // - struct spherical *coords = &game->orbit_camera.coords; - coords->radius = 72.0; - coords->inclination = 0.5; - coords->azimuth = -7.86; + // + // setup camera + // + struct spherical *coords = &game->orbit_camera.coords; + coords->radius = 72.0; + coords->inclination = 0.5; + coords->azimuth = -7.86; - struct node *pnode = get_node(&player->node_id); - node_translate(pnode, V3(240.0, 252.0, 373.0)); - pnode->orientation[2] = -0.005; - pnode->orientation[3] = -1.0; + struct node *pnode = get_node(&player->node_id); + node_translate(pnode, V3(240.0, 252.0, 373.0)); + pnode->orientation[2] = -0.005; + pnode->orientation[3] = -1.0; - node_id *cam_id = &game->orbit_camera.node_id; - struct node *cam_node = get_node(cam_id); assert(cam_node); + node_id *cam_id = &game->orbit_camera.node_id; + struct node *cam_node = get_node(cam_id); assert(cam_node); - setup_pieces(&player->node_id); + make_chess_program(&engine->gpu); + setup_pieces(&player->node_id); - node_recalc(pnode); + node_recalc(pnode); - //player 1284.539062 1111.104126 14.273574 + //player 1284.539062 1111.104126 14.273574 - // show terrain - //terrain_ent->flags |= ENT_INVISIBLE; + // show terrain + //terrain_ent->flags |= ENT_INVISIBLE; - // show player - /* player->flags |= ENT_INVISIBLE; */ + // show player + /* player->flags |= ENT_INVISIBLE; */ } diff --git a/src/chess.h b/src/chess.h @@ -3,7 +3,8 @@ #define POLYADVENT_CHESS_H #include "test_game.h" +#include "game.h" -void chess_scene(struct test_game *game); +void chess_scene(struct game *engine, struct test_game *game); #endif /* POLYADVENT_CHESS_H */ diff --git a/src/common.h b/src/common.h @@ -2,6 +2,8 @@ #ifndef POLYADVENT_COMMON_H #define POLYADVENT_COMMON_H +#include <inttypes.h> + typedef int bool; #define false 0 #define true 1 @@ -22,8 +24,8 @@ typedef signed short s16; typedef unsigned int u32; typedef signed int s32; -typedef unsigned long long u64; -typedef signed long long s64; +typedef uint64_t u64; +typedef int64_t s64; struct point { double x, y; diff --git a/src/dae.c b/src/dae.c @@ -351,7 +351,7 @@ void dae_attr(struct xmlparser *x, const char *t, size_t tl, } else if (data->state == PARSING_NODE && streq(a, "name")) { - strncpy(data->current_name, v, sizeof(data->current_name)-1); + strncpy(data->current_name, v, sizeof(data->current_name)); } else if (data->state == PARSING_NODE && streq(a, "type") diff --git a/src/data_id.h b/src/data_id.h @@ -0,0 +1,92 @@ +#pragma once + +#include "resource.h" +#include <stddef.h> +#include <assert.h> +#include <string.h> + +enum data_id_type { + DATA_ID_RESOURCE = 1, + DATA_ID_RAWPTR, +}; + +enum data_id_datatype { + DATA_ID_FLOAT = 1, + DATA_ID_INT, + DATA_ID_VEC2, + DATA_ID_VEC3, + DATA_ID_VEC3P, + DATA_ID_MAT3, + DATA_ID_MAT4, + DATA_ID_MAT4P, +}; + +struct lens { + const char *name; + int offset; + enum data_id_datatype type; +}; + +static inline int data_id_get_ptr_data(void *ptr, enum data_id_datatype typ, void *out) +{ + assert(out); + assert(ptr); + switch (typ) { + case DATA_ID_FLOAT: + break; + case DATA_ID_INT: + *((int*)out) = *(int*)ptr; + break; + case DATA_ID_VEC2: + case DATA_ID_VEC3: + case DATA_ID_MAT3: + case DATA_ID_MAT4: + assert(0); + break; + case DATA_ID_MAT4P: + case DATA_ID_VEC3P: + *((float**)out) = *(float**)ptr; + break; + default: + assert(0); + } + + return 1; +} + + +static inline void *get_lens_offset_ptr(struct lens *lens, void *structure) +{ + return (void*)((unsigned char*)structure + lens->offset); +} + +static inline float *get_lens_ptr(struct lens *lens, void *structure) +{ + assert(lens->type == DATA_ID_MAT4P || lens->type == DATA_ID_VEC3P); + float **p = (float**)get_lens_offset_ptr(lens, structure); + return *p; +} + +static inline float *get_lens_float_array(struct lens *lens, void *structure) +{ + assert(lens->type == DATA_ID_MAT4 || + lens->type == DATA_ID_VEC3 || + lens->type == DATA_ID_VEC2 || + lens->type == DATA_ID_MAT3); + void *p = get_lens_offset_ptr(lens, structure); + return (float*)p; +} + +static inline float get_lens_float(struct lens *lens, void *structure) +{ + assert(lens->type == DATA_ID_FLOAT); + void *p = get_lens_offset_ptr(lens, structure); + return *(float*)p; +} + +static inline int get_lens_int(struct lens *lens, void *structure) +{ + assert(lens->type == DATA_ID_INT); + void *p = get_lens_offset_ptr(lens, structure); + return *(int*)p; +} diff --git a/src/debug.c b/src/debug.c @@ -3,7 +3,21 @@ #include <stdlib.h> #include <stdio.h> -void show_info_log(GLuint shader) { +void show_program_info_log(int program) +{ + GLint msgLen = 0; + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &msgLen); + + // The maxLength includes the NULL character + char *buffer = malloc(msgLen); + glGetProgramInfoLog(program, msgLen, &msgLen, buffer); + + printf("program error: (%d) %.*s\n", msgLen, msgLen, buffer); + + free(buffer); +} + +void show_shader_info_log(GLuint shader) { GLint msgLen = 0; glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &msgLen); @@ -11,9 +25,9 @@ void show_info_log(GLuint shader) { char *buffer = malloc(msgLen); glGetShaderInfoLog(shader, msgLen, &msgLen, buffer); - printf("shader error: (%d) %.*s\n", msgLen, msgLen, buffer); + printf("shader error: (%d) %.*s\n", msgLen, msgLen, buffer); - free(buffer); + free(buffer); } diff --git a/src/debug.h b/src/debug.h @@ -6,7 +6,8 @@ #include <stdio.h> -void show_info_log(GLuint shader); +void show_shader_info_log(GLuint shader); +void show_program_info_log(int program); // rtassert exists in release builds, use sparingly #define rtassert(cond, msg) if (!cond) { \ diff --git a/src/delaunay.c b/src/delaunay.c @@ -513,11 +513,11 @@ static halfedge_t* del_valid_left( halfedge_t* b ) v = b->next->pair->vertex; /* pair(next(next(halfedge)) point */ - if( v!=u && classify_point_seg(g, d, u) == ON_LEFT ) + if( classify_point_seg(g, d, u) == ON_LEFT ) { /* 3 points aren't colinear */ /* as long as the 4 points belong to the same circle, do the cleaning */ - //assert( v != u && "1: floating point precision error"); + assert( v != u && "1: floating point precision error"); while( v != d && v != g && in_circle(g, d, u, v) == INSIDE ) { c = b->next; @@ -528,7 +528,7 @@ static halfedge_t* del_valid_left( halfedge_t* b ) v = b->next->pair->vertex; } - //assert( v != u && "2: floating point precision error"); + assert( v != u && "2: floating point precision error"); if( v != d && v != g && in_circle(g, d, u, v) == ON_CIRCLE ) { du = du->prev; @@ -559,9 +559,9 @@ static halfedge_t* del_valid_right( halfedge_t *b ) v = b->prev->pair->vertex; - if( v!=u && classify_point_seg(lv, rv, u) == ON_LEFT ) + if( classify_point_seg(lv, rv, u) == ON_LEFT ) { - //assert( v != u && "1: floating point precision error"); + assert( v != u && "1: floating point precision error"); while( v != lv && v != rv && in_circle(lv, rv, u, v) == INSIDE ) { c = b->prev; @@ -572,7 +572,7 @@ static halfedge_t* del_valid_right( halfedge_t *b ) v = b->prev->pair->vertex; } - //assert( v != u && "1: floating point precision error"); + assert( v != u && "1: floating point precision error"); if( v != lv && v != rv && in_circle(lv, rv, u, v) == ON_CIRCLE ) { du = du->next; diff --git a/src/entity.c b/src/entity.c @@ -20,12 +20,10 @@ struct entity *get_all_entities(u32 *count, entity_id **ids) { } struct entity *init_entity(struct entity *ent, node_id *id) { - node_id new_id; init_id(&ent->model_id.id); if (id == NULL) { - init_id(&new_id); - new_node(&new_id); - ent->node_id = new_id; + init_id(&ent->node_id); + new_node(&ent->node_id); /* debug("init_entity with new node_id %llu\n", new_id.uuid); */ } else { @@ -43,11 +41,6 @@ static inline struct entity *new_uninitialized_entity(entity_id *id) { return new_resource(&esys, id); } -struct entity *new_entity_(entity_id *id) { - return new_entity_with_node(id, NULL); -} - - struct entity *new_entity_with_node(entity_id *id, node_id *node) { diff --git a/src/entity.h b/src/entity.h @@ -9,21 +9,23 @@ #include <assert.h> #define MAX_ENTITIES 10048 +#define ENTITY_DATA_SIZE 128 enum entity_flags { - ENT_IS_PLAYER = 1 << 0, - ENT_INVISIBLE = 1 << 1, - ENT_CASTS_SHADOWS = 1 << 2, - ENT_ON_GROUND = 1 << 3, - ENT_IS_WHITE = 1 << 4, + ENT_IS_PLAYER = 1 << 0, + ENT_INVISIBLE = 1 << 1, + ENT_CASTS_SHADOWS = 1 << 2, + ENT_ON_GROUND = 1 << 3, }; struct entity { - node_id node_id; - struct model_id model_id; - u32 flags; - float velocity[3]; - float accel[3]; + node_id node_id; + struct model_id model_id; + u32 flags; + u32 type; + float velocity[3]; // move into entity components + float accel[3]; + u8 data[ENTITY_DATA_SIZE]; }; typedef struct resource_id entity_id; @@ -36,16 +38,19 @@ void init_entity_system(); struct entity *get_entity(entity_id *); const char *entity_label(struct entity *); struct entity *get_all_entities(u32 *count, entity_id **ids); -struct entity *new_entity_(entity_id *); struct entity *new_entity_with_node(entity_id *, node_id *); struct entity *new_debug_entity(entity_id *, float *pos); void destroy_entity_system(); +static inline struct entity *new_entity_(entity_id *id) { + return new_entity_with_node(id, NULL); +} + static inline struct entity *new_entity(entity_id *id) { - if (id) - assert((int)id->index == -1 && "error: " __FILE__ ":" STRIZE(__LINE__) " missing init_id or already initialized"); - return new_entity_(id); + if (id) + assert((int)id->index == -1 && "error: " __FILE__ ":" STRIZE(__LINE__) " missing init_id or already initialized"); + return new_entity_(id); } #endif /* ENTITY_H */ diff --git a/src/fbo.c b/src/fbo.c @@ -3,8 +3,6 @@ #include "fbo.h" #include "util.h" -#include <stdio.h> - void create_fbo(struct fbo *fbo, int width, int height) { glGenFramebuffers(1, &fbo->handle); glBindFramebuffer(GL_FRAMEBUFFER, fbo->handle); diff --git a/src/file.c b/src/file.c @@ -2,10 +2,8 @@ #include <stdio.h> #include <stdlib.h> #include "file.h" -#include "debug.h" #include <sys/stat.h> -#include <string.h> time_t file_mtime(const char *filename) { // TODO: windows file_mtime diff --git a/src/game.c b/src/game.c @@ -30,7 +30,7 @@ bool was_key_pressed_this_frame(struct game *game, int scancode) return is_key_down_on_frame(&game->input, scancode, game->frame); } -bool was_button_pressed_this_frame(struct game *game, int button) +bool was_button_pressed_this_frame(struct game *game, SDL_GameControllerButton button) { return is_button_down_on_frame(&game->input, button, game->frame); } @@ -43,7 +43,7 @@ static void init_user_settings(struct user_settings *settings) { static void init_sdl(SDL_Window **window, int width, int height) { - SDL_Init( 0); + SDL_Init( SDL_INIT_JOYSTICK ); /* SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); */ @@ -65,11 +65,9 @@ void init_misc(struct game *game) { game->gpu.num_programs = 0; //debug("creating ui...\n"); - //create_ui(&game->ui, width, height, &res->programs[UI_PROGRAM]); //check_gl(); } -/* void init_controller(struct input *input) { SDL_GameControllerAddMappingsFromFile("data/gamecontrollerdb.txt"); @@ -92,8 +90,6 @@ void init_controller(struct input *input) { } } -*/ - void game_init(struct game *game, int width, int height) { game->width = width; game->height = height; @@ -103,23 +99,20 @@ void game_init(struct game *game, int width, int height) { init_gl(); debug("init entities...\n"); init_entity_system(); - debug("init geom...\n"); init_geometry_manager(); - debug("init modelman...\n"); init_model_manager(); - debug("init nodeman...\n"); init_node_manager(); - debug("init user settings...\n"); init_user_settings(&game->user_settings); check_gl(); game->wireframe = 0; - debug("init input...\n"); init_input(&game->input); + init_controller(&game->input); //init_controller(&game->input); debug("init misc...\n"); init_misc(game); + printf("gpu programs %d\n", game->gpu.num_programs); } diff --git a/src/game.h b/src/game.h @@ -16,8 +16,6 @@ #include "ui.h" #include "gpu.h" -#include <stdio.h> - #define PLAYER_HEIGHT 1.73 /* @@ -48,7 +46,7 @@ void game_init(struct game *game, int width, int height); void quit_game(struct game *game); void should_update(struct game *game); bool was_key_pressed_this_frame(struct game *game, int scancode); -bool was_button_pressed_this_frame(struct game *game, int button); +bool was_button_pressed_this_frame(struct game *game, SDL_GameControllerButton button); int is_free_camera(struct game *game); #endif /* PA_GAME_H */ diff --git a/src/geometry.c b/src/geometry.c @@ -9,204 +9,210 @@ struct resource_manager geom_manager; void destroy_buffer_geometry(geometry_id *geom_id) { - struct geometry *geom = get_geometry(geom_id); - gpu_addr buffers[MAX_VERTEX_ATTRS]; - - for (int i = 0; i < MAX_VERTEX_ATTRS; i++) - buffers[i] = geom->vbos[i].handle; - /* void glDeleteVertexArrays(GLsizei n, const GLuint *arrays); */ - /* glDisableVertexAttribArray(geom->buffer.vertex_buffer.handle); */ - /* check_gl(); */ - /* glDisableVertexAttribArray(geom->buffer.normal_buffer.handle); */ - /* check_gl(); */ - /* glDisableVertexAttribArray(geom->buffer.index_buffer.handle); */ - /* check_gl(); */ - check_gl(); - glDeleteBuffers(ARRAY_SIZE(buffers), buffers); - check_gl(); - - - geom->has_vbos = 0; + struct geometry *geom = get_geometry(geom_id); + gpu_addr buffers[MAX_VERTEX_ATTRS]; + + for (int i = 0; i < MAX_VERTEX_ATTRS; i++) + buffers[i] = geom->vbos[i].handle; + /* void glDeleteVertexArrays(GLsizei n, const GLuint *arrays); */ + /* glDisableVertexAttribArray(geom->buffer.vertex_buffer.handle); */ + /* check_gl(); */ + /* glDisableVertexAttribArray(geom->buffer.normal_buffer.handle); */ + /* check_gl(); */ + /* glDisableVertexAttribArray(geom->buffer.index_buffer.handle); */ + /* check_gl(); */ + check_gl(); + glDeleteBuffers(ARRAY_SIZE(buffers), buffers); + check_gl(); + + + geom->has_vbos = 0; } -void bind_geometry(struct geometry *geom, gpu_addr *vertex_attrs) { - struct vbo *vbo; - for (int i = 0; i < MAX_VERTEX_ATTRS; i++) { - vbo = &geom->vbos[i]; - if (vbo->handle && vertex_attrs[i] != 0xFFFFFFFF) { - bind_vbo(vbo, vertex_attrs[i], vbo->component_type); - check_gl(); - } - } +void bind_geometry(struct geometry *geom, struct gpu_program *program) { + struct vbo *vbo; + for (int i = 0; i < MAX_VERTEX_ATTRS; i++) { + if (i != va_index && !(program->active_attributes & (1 << i))) { + continue; + } + vbo = &geom->vbos[i]; + assert(program->vertex_attrs[i] != 0xFFFFFFFF); + if (vbo->handle) { + bind_vbo(vbo, program->vertex_attrs[i], + vbo->component_type); + check_gl(); + } else { + printf("%s: %s attribute not bound\n", + program->name, + vertex_attr_str(i)); + assert(0); + } + } } -void render_geometry(struct geometry *geom, gpu_addr *vertex_attrs, - struct gpu_program *program) +void render_geometry(struct geometry *geom, struct gpu_program *program) { - int type = GL_TRIANGLES; - bind_geometry(geom, vertex_attrs); - if (geom->num_indices) { - glDrawElements(type, - geom->num_indices, /* count */ - GL_UNSIGNED_INT, /* type */ - (void*)0 /* element array buffer offset */ - ); - //printf("render_geometry %d %s\n", geom->num_indices, program->name); - check_gl(); - } - else { - /* printf("nverts %d\n", geom->num_verts); */ - glDrawArrays(type, 0, geom->num_verts); - check_gl(); - } + int type = GL_TRIANGLES; + bind_geometry(geom, program); + if (geom->num_indices) { + glDrawElements(type, + geom->num_indices, /* count */ + GL_UNSIGNED_INT, /* type */ + (void*)0 /* element array buffer offset */ + ); + //printf("render_geometry %d %s\n", geom->num_indices, program->name); + check_gl(); + } + else { + /* printf("nverts %d\n", geom->num_verts); */ + glDrawArrays(type, 0, geom->num_verts); + check_gl(); + } } void init_make_geometry(struct make_geometry *mkgeom) { - *mkgeom = (struct make_geometry){ - .colors = NULL, - .normals = NULL, - .indices = NULL, - .vertices = NULL, - .tex_coords = NULL, - .joint_ids = NULL, - .joint_weights = NULL, - .num_uv_components = 2, - .num_verts = 0, - .num_indices = 0, - }; + *mkgeom = (struct make_geometry){ + .colors = NULL, + .normals = NULL, + .indices = NULL, + .vertices = NULL, + .tex_coords = NULL, + .joint_ids = NULL, + .joint_weights = NULL, + .num_uv_components = 2, + .num_verts = 0, + .num_indices = 0, + }; } void init_geometry(struct geometry *geom) { - geom->has_vbos = 0; + geom->has_vbos = 0; - for (int i = 0; i < MAX_VERTEX_ATTRS; i++) - init_vbo(&geom->vbos[i]); + for (int i = 0; i < MAX_VERTEX_ATTRS; i++) + init_vbo(&geom->vbos[i]); - geom->num_uv_components = 2; + geom->num_uv_components = 2; } void make_buffer_geometry(struct make_geometry *mkgeom, struct geometry *geom) { - init_geometry(geom); - - // VBOs - geom->num_uv_components = mkgeom->num_uv_components; - geom->num_verts = mkgeom->num_verts; - geom->num_indices = mkgeom->num_indices; - - assert(mkgeom->num_verts); - assert(mkgeom->vertices); - /* assert(geom->normals); */ - /* assert(geom->indices); */ - /* assert(geom->num_indices >= 1); */ - - /* printf("making vertex buffer\n"); */ - make_float_vertex_buffer(&geom->vbos[va_position], - mkgeom->vertices, - mk_num_elements(mkgeom->num_verts), - mk_components(3) - ); - - /* printf("making normal buffer\n"); */ - // cube normals - if (mkgeom->normals) { - make_float_vertex_buffer(&geom->vbos[va_normal], - mkgeom->normals, - mk_num_elements(mkgeom->num_verts), - mk_components(3) - ); - } - if (mkgeom->joint_ids) { - make_int_vertex_buffer(&geom->vbos[va_joint_ids], - mkgeom->joint_ids, - mk_num_elements(mkgeom->num_verts), - mk_components(3) - ); - } - - // vertex colors - if (mkgeom->colors) { - make_float_vertex_buffer(&geom->vbos[va_color], - mkgeom->colors, - mk_num_elements(mkgeom->num_verts), - mk_components(3) - ); - } - - if (mkgeom->tex_coords != NULL) { - assert(geom->num_uv_components); - - make_uv_buffer(&geom->vbos[va_tex_coord], - mkgeom->tex_coords, - mk_num_elements(geom->num_verts), - mk_components(geom->num_uv_components) - ); - } - - /* printf("making index buffer\n"); */ - // cube indices - if (mkgeom->indices) - make_index_buffer(&geom->vbos[va_index], - mkgeom->indices, - mk_num_elements(mkgeom->num_indices) - ); - - geom->has_vbos = 1; + init_geometry(geom); + + // VBOs + geom->num_uv_components = mkgeom->num_uv_components; + geom->num_verts = mkgeom->num_verts; + geom->num_indices = mkgeom->num_indices; + + assert(mkgeom->num_verts); + assert(mkgeom->vertices); + /* assert(geom->normals); */ + /* assert(geom->indices); */ + /* assert(geom->num_indices >= 1); */ + + /* printf("making vertex buffer\n"); */ + make_float_vertex_buffer(&geom->vbos[va_position], + mkgeom->vertices, + mk_num_elements(mkgeom->num_verts), + mk_components(3)); + + /* printf("making normal buffer\n"); */ + // cube normals + if (mkgeom->normals) { + make_float_vertex_buffer(&geom->vbos[va_normal], + mkgeom->normals, + mk_num_elements(mkgeom->num_verts), + mk_components(3)); + } + if (mkgeom->joint_ids) { + assert(0); + make_int_vertex_buffer(&geom->vbos[va_joint_ids], + mkgeom->joint_ids, + mk_num_elements(mkgeom->num_verts), + mk_components(3)); + } + + // vertex colors + if (mkgeom->colors) { + make_float_vertex_buffer(&geom->vbos[va_color], + mkgeom->colors, + mk_num_elements(mkgeom->num_verts), + mk_components(3)); + } + + if (mkgeom->tex_coords != NULL) { + assert(geom->num_uv_components); + + make_uv_buffer(&geom->vbos[va_tex_coord], + mkgeom->tex_coords, + mk_num_elements(geom->num_verts), + mk_components(geom->num_uv_components) + ); + } + + /* printf("making index buffer\n"); */ + // cube indices + if (mkgeom->indices) + make_index_buffer(&geom->vbos[va_index], + mkgeom->indices, + mk_num_elements(mkgeom->num_indices) + ); + + geom->has_vbos = 1; } void geometry_centroid(struct geometry *geom, float *dest) { - vec3_subtract(geom->max, geom->min, dest); - vec3_scale(dest, 0.5, dest); + vec3_subtract(geom->max, geom->min, dest); + vec3_scale(dest, 0.5, dest); }; void init_geometry_manager() { - init_resource_manager(&geom_manager, sizeof(struct geometry), - DEF_NUM_GEOMETRY, MAX_GEOMETRY, "geometry"); + init_resource_manager(&geom_manager, sizeof(struct geometry), + DEF_NUM_GEOMETRY, MAX_GEOMETRY, "geometry"); } struct geometry *get_geometry(geometry_id *geom_id) { - return get_resource(&geom_manager, geom_id); + return get_resource(&geom_manager, geom_id); } struct geometry *new_geometry(geometry_id *geom_id) { - struct geometry *geom = new_resource(&geom_manager, geom_id); - /* debug("new geometry %llu\n", geom_id->uuid); */ - return geom; + struct geometry *geom = new_resource(&geom_manager, geom_id); + /* debug("new geometry %llu\n", geom_id->uuid); */ + return geom; } struct geometry *get_all_geometry(u32 *count, geometry_id **ids) { - return get_all_resources(&geom_manager, count, ids); + return get_all_resources(&geom_manager, count, ids); } void destroy_geometry(geometry_id *geom_id) { - struct geometry *geom = get_geometry(geom_id); assert(geom); - struct vbo *vbo; + struct geometry *geom = get_geometry(geom_id); assert(geom); + struct vbo *vbo; - for (int i = 0; i < MAX_VERTEX_ATTRS; i++) { - vbo = &geom->vbos[i]; - if (vbo->handle) - glDeleteBuffers(1, &vbo->handle); - } + for (int i = 0; i < MAX_VERTEX_ATTRS; i++) { + vbo = &geom->vbos[i]; + if (vbo->handle) + glDeleteBuffers(1, &vbo->handle); + } - destroy_resource(&geom_manager, geom_id); + destroy_resource(&geom_manager, geom_id); } void free_make_geometry(struct make_geometry *mkgeom) { - if (mkgeom->vertices) - free(mkgeom->vertices); + if (mkgeom->vertices) + free(mkgeom->vertices); - if (mkgeom->normals) - free(mkgeom->normals); + if (mkgeom->normals) + free(mkgeom->normals); - if (mkgeom->colors) - free(mkgeom->colors); + if (mkgeom->colors) + free(mkgeom->colors); - if (mkgeom->indices) - free(mkgeom->indices); + if (mkgeom->indices) + free(mkgeom->indices); } diff --git a/src/geometry.h b/src/geometry.h @@ -47,9 +47,8 @@ struct geometry_manager { int num_geometry; }; -void render_geometry(struct geometry *geom, gpu_addr *vertex_attrs, - struct gpu_program *current_program); -void bind_geometry(struct geometry *geom, gpu_addr *vertex_attrs); +void render_geometry(struct geometry *geom, struct gpu_program *current_program); +void bind_geometry(struct geometry *geom, struct gpu_program *program); void init_geometry(struct geometry *geom); void init_make_geometry(struct make_geometry *mkgeom); void free_make_geometry(struct make_geometry *mkgeom); diff --git a/src/gpu.c b/src/gpu.c @@ -21,3 +21,19 @@ int try_reload_shaders(struct gpu *gpu) { return ret; } +struct gpu_program *get_gpu_program_by_name(struct gpu *gpu, const char *name) +{ + int i; + struct gpu_program *program; + + printf("num_programs %d\n", gpu->num_programs); + + for (i = 0; i < gpu->num_programs; i++) { + program = &gpu->programs[i]; + if (!strcmp(program->name, name)) + return program; + } + + return NULL; +} + diff --git a/src/gpu.h b/src/gpu.h @@ -10,3 +10,4 @@ struct gpu { }; int try_reload_shaders(struct gpu *gpu); +struct gpu_program *get_gpu_program_by_name(struct gpu *gpu, const char *name); diff --git a/src/hash.h b/src/hash.h @@ -0,0 +1,20 @@ + +// TODO: move hash to it's own file +#define FNV_32_PRIME ((u32)0x01000193) + +static inline unsigned int hash_str(const char *str) +{ + unsigned char *s = (unsigned char *)str; /* unsigned string */ + unsigned int hval = 0; + + /* + * FNV-1a hash each octet in the buffer + */ + while (*s) { + hval ^= (u32)*s++; + hval *= FNV_32_PRIME; + } + + /* return our new hash value */ + return hval; +} diff --git a/src/hires.c b/src/hires.c @@ -1,7 +1,7 @@ #include <time.h> #include "common.h" -#include <SDL.h> +#include <SDL2/SDL.h> double hires_time_in_seconds() { double ticks_per_sec = (double)SDL_GetPerformanceFrequency(); diff --git a/src/input.c b/src/input.c @@ -29,7 +29,7 @@ static void key_up(struct input *input, int scancode, u64 current_frame) { static void button_up(struct input *input, SDL_JoyButtonEvent *event, u64 current_frame) { - if (event->button >= MAX_CONTROLLER_BUTTONS) return; + if (event->button >= SDL_CONTROLLER_BUTTON_MAX) return; /* printf("button up %d\n", event->button); */ struct input_edge *edge = &input->button_edge_states[event->button]; @@ -39,7 +39,7 @@ static void button_up(struct input *input, SDL_JoyButtonEvent *event, u64 curren static void button_down(struct input *input, SDL_JoyButtonEvent *event, u64 current_frame) { - if (event->button >= MAX_CONTROLLER_BUTTONS) return; + if (event->button >= SDL_CONTROLLER_BUTTON_MAX) return; printf("button down %d\n", event->button); struct input_edge *edge = &input->button_edge_states[event->button]; @@ -152,7 +152,7 @@ void init_input(struct input *input) { input->last_my = 0; input->resized_height = 0; input->resized_width = 0; - //input->controller = 0; + input->controller = 0; assert(input->keystates); } @@ -163,7 +163,7 @@ bool is_key_down_on_frame(struct input *input, u8 scancode, u64 frame) { return edge->down_frame == frame && edge->is_down; } -bool is_button_down_on_frame(struct input *input, int button, u64 frame) +bool is_button_down_on_frame(struct input *input, SDL_GameControllerButton button, u64 frame) { struct input_edge *edge = &input->button_edge_states[button]; return edge->down_frame == frame && edge->is_down; @@ -183,14 +183,11 @@ int input_is_dragging(struct input *input, int mouse_button) { return input->mbuttons[mouse_button-1]; } -bool is_button_down(struct input *input, int button) +bool is_button_down(struct input *input, SDL_GameControllerButton button) { - return false; - /* if (!input->controller) { return false; } return SDL_GameControllerGetButton(input->controller, button) == 1; - */ } diff --git a/src/input.h b/src/input.h @@ -3,7 +3,7 @@ #ifndef POLYADVENT_INPUT_H #define POLYADVENT_INPUT_H -#include <SDL.h> +#include <SDL2/SDL.h> #include "common.h" /* enum key_state { */ @@ -23,7 +23,6 @@ #define MAX_AXIS_VALUE 32767 #define MIN_AXIS_VALUE -32767 #define MAX_CONTROLLERS -#define MAX_CONTROLLER_BUTTONS 15 struct input_edge { int is_down; @@ -31,13 +30,11 @@ struct input_edge { u64 up_frame; }; - - struct input { /* enum key_state keys[0x7F-0x1F]; */ u8 const *keystates; SDL_Keymod modifiers; - //SDL_GameController *controller; + SDL_GameController *controller; int mx, my, last_mx, last_my; int axis[MAX_AXIS]; int axis_min_input; @@ -53,14 +50,14 @@ struct input { /* u8 frame_down_keys[KEY_BUFFER_SIZE]; */ /* u8 frame_up_keys[KEY_BUFFER_SIZE]; */ struct input_edge key_edge_states[SDL_NUM_SCANCODES]; - struct input_edge button_edge_states[MAX_CONTROLLER_BUTTONS]; + struct input_edge button_edge_states[SDL_CONTROLLER_BUTTON_MAX]; }; int input_is_dragging(struct input *input, int mouse_button); -bool is_button_down(struct input *input, int button); +bool is_button_down(struct input *input, SDL_GameControllerButton button); bool is_key_down_on_frame(struct input *input, u8 scancode, u64 frame); -bool is_button_down_on_frame(struct input *input, int button, u64 frame); +bool is_button_down_on_frame(struct input *input, SDL_GameControllerButton button, u64 frame); void init_input(struct input *input); void input_reset(struct input *input); diff --git a/src/mdl.c b/src/mdl.c @@ -41,7 +41,7 @@ void init_mdl_geometry(struct mdl_geometry *lgeom) vec3_set(V3(0,0,0), lgeom->max); } -void save_mdl_fd(FILE *out, struct mdl_geometry *lgeom) +void save_mdl_fd(FILE *out, struct model *model, struct mdl_geometry *lgeom) { struct make_geometry *mkgeom = &lgeom->mkgeom; assert(mkgeom->vertices); @@ -140,7 +140,7 @@ static inline int read_int(FILE *stream) return val; } -#define MAX_MDL_ARRAY 1280000 // only enforced at dev time for sanity +#define MAX_MDL_ARRAY 128000 // only enforced at dev time for sanity static inline int read_nfloats(FILE *stream, int n, float *floats) { @@ -184,7 +184,6 @@ void load_mdl_fd(FILE *in, struct model *model, struct mdl_geometry *lgeom) switch (tag) { case MDL_POSITION: mkgeom->num_verts = read_floats(in, &mkgeom->vertices) / 3; - printf("mdl verts %d\n", mkgeom->num_verts); break; case MDL_NORMAL: @@ -236,11 +235,11 @@ void load_mdl_fd(FILE *in, struct model *model, struct mdl_geometry *lgeom) } } -void save_mdl(const char *filename, struct mdl_geometry *lgeom) +void save_mdl(const char *filename, struct model *model, struct mdl_geometry *lgeom) { FILE *out = fopen(filename, "wb"); assert(out); - save_mdl_fd(out, lgeom); + save_mdl_fd(out, model, lgeom); fclose(out); } diff --git a/src/mdl.h b/src/mdl.h @@ -4,7 +4,6 @@ #include "geometry.h" #include "model.h" - #include <stdio.h> enum mdl_tag { @@ -27,8 +26,8 @@ struct mdl_geometry { }; -void save_mdl(const char *filename, struct mdl_geometry *geom); -void save_mdl_fd(FILE *out, struct mdl_geometry *geom); +void save_mdl(const char *filename, struct model *model, struct mdl_geometry *geom); +void save_mdl_fd(FILE *out, struct model *model, struct mdl_geometry *geom); void load_mdl(const char *filename, struct model *model, struct mdl_geometry *geom); void load_mdl_fd(FILE *in, struct model *model, struct mdl_geometry *geom); diff --git a/src/model.c b/src/model.c @@ -3,6 +3,7 @@ #include "ply.h" #include "resource.h" #include "debug.h" +#include "hash.h" #include "util.h" #include <assert.h> @@ -11,102 +12,87 @@ static struct resource_manager dyn_modelman; struct model *init_model(struct model *model) { - init_id(&model->geom_id); - model->shader = DEFAULT_PROGRAM; - model->texture = 0; - model->nposes = 0; - for (u16 i = 0; i < ARRAY_SIZE(model->poses); i++) { - init_pose(model->poses); - } - return model; + init_id(&model->geom_id); + model->shader = 0; + model->texture = 0; + model->nposes = 0; + for (u16 i = 0; i < ARRAY_SIZE(model->poses); i++) { + init_pose(model->poses); + } + return model; } struct model *get_all_models(u32 *count, struct model_id **ids) { - return get_all_resources(&dyn_modelman, count, (struct resource_id **)ids); + return get_all_resources(&dyn_modelman, count, (struct resource_id **)ids); } static inline struct model *new_uninitialized_model(struct model_id *id) { - return new_resource(&dyn_modelman, &id->id); + return new_resource(&dyn_modelman, &id->id); } -static struct model *new_model_resource(struct model_id *model_id) +struct model *new_model(struct model_id *model_id) { - struct model *model = new_uninitialized_model(model_id); - /* debug("new model %llu\n", model_id->dyn_model_id.uuid); */ - init_id(&model->geom_id); - new_geometry(&model->geom_id); - return model; + struct model *model = new_uninitialized_model(model_id); + /* debug("new model %llu\n", model_id->dyn_model_id.uuid); */ + init_model(model); + init_id(&model->geom_id); + new_geometry(&model->geom_id); + return model; } void init_model_manager() { - init_resource_manager(&dyn_modelman, sizeof(struct model), - DEF_DYNAMIC_MODELS, MAX_DYNAMIC_MODELS, "model"); + init_resource_manager(&dyn_modelman, sizeof(struct model), + DEF_DYNAMIC_MODELS, MAX_DYNAMIC_MODELS, "model"); } -struct model *new_model(struct model_id *id) -{ - return new_model_resource(id); -} - struct model *get_model(struct model_id *model_id) { - return get_resource(&dyn_modelman, &model_id->id); -} - -// TODO: move hash to it's own file -#define FNV_32_PRIME ((u32)0x01000193) - -static u32 hash_str(const char *str) -{ - u8 *s = (u8 *)str; /* unsigned string */ - u32 hval = 0; - - /* - * FNV-1a hash each octet in the buffer - */ - while (*s) { - hval ^= (u32)*s++; - hval *= FNV_32_PRIME; - } - - /* return our new hash value */ - return hval; + return get_resource(&dyn_modelman, &model_id->id); } static struct model *load_model(const char *name, struct model_id *mid) { - static char path[128] = {0}; + static char path[128] = {0}; + + struct model *model = new_model(mid); + struct geometry *geom = get_geometry(&model->geom_id); + struct mdl_geometry lgeom; - struct model *model = new_model_resource(mid); - struct geometry *geom = get_geometry(&model->geom_id); - struct mdl_geometry lgeom; + init_mdl_geometry(&lgeom); + init_geometry(geom); - init_mdl_geometry(&lgeom); - init_geometry(geom); + model->name = name; + model->name_hash = hash_str(name); - model->name = name; - model->name_hash = hash_str(name); + assert(!geom->has_vbos); + + /* + if (geom->has_vbos) { + debug("model %s already loaded\n", name); + return model; + } + */ - if (geom->has_vbos) { - debug("model %s already loaded\n", name); - return model; - } + // Load mesh + debug("loading %s model uuid %" PRIu64 " with geom_id %" PRIu64 "\n", name, + mid->id.uuid, model->geom_id.uuid); - // Load mesh - debug("loading %s model with geom_id\n", name); + snprintf(path, 128, "data/models/%s.mdl", name); + load_mdl(path, model, &lgeom); - snprintf(path, 128, "data/models/%s.mdl", name); - load_mdl(path, model, &lgeom); + vec3_copy(lgeom.min, geom->min); + vec3_copy(lgeom.max, geom->max); - vec3_copy(lgeom.min, geom->min); - vec3_copy(lgeom.max, geom->max); + printf("%s min:%f,%f,%f max:%f,%f,%f\n", name, + geom->min[0], geom->min[1], geom->min[2], + geom->max[0], geom->max[1], geom->max[2]); - make_buffer_geometry(&lgeom.mkgeom, geom); - free_make_geometry(&lgeom.mkgeom); + make_buffer_geometry(&lgeom.mkgeom, geom); + free_make_geometry(&lgeom.mkgeom); - return model; + return model; } struct model_id get_model_by_name(const char *name, struct model **found) @@ -129,6 +115,10 @@ struct model_id get_model_by_name(const char *name, struct model **found) if (model->name_hash == name_hash) { if (found) *found = model; + /* + printf("found %s:%s model_id:%"PRIu64" geom_id:%"PRIu64"\n", + name, model->name, ids[i].id.uuid, model->geom_id.uuid); + */ return ids[i]; } } @@ -142,10 +132,10 @@ struct model_id get_model_by_name(const char *name, struct model **found) void destroy_model(struct model_id *model_id) { - struct model *model = get_model(model_id); + struct model *model = get_model(model_id); - destroy_geometry(&model->geom_id); - destroy_resource(&dyn_modelman, &model_id->id); + destroy_geometry(&model->geom_id); + destroy_resource(&dyn_modelman, &model_id->id); } diff --git a/src/model.h b/src/model.h @@ -20,7 +20,7 @@ struct model_id { struct model { /* geometry_id geom_id; */ geometry_id geom_id; - enum program_type shader; + int shader; struct pose poses[MAX_POSES]; // TODO: separate animated_model buffer? int nposes; u32 texture; diff --git a/src/node.c b/src/node.c @@ -32,7 +32,7 @@ void destroy_node(node_id *id) { #ifdef DEBUG struct node *node = get_node(id); - debug("destroying node %llu %s\n", id->uuid, node->label); + debug("destroying node %" PRIu64 " %s\n", id->uuid, node->label); #endif destroy_resource(&node_manager, id); @@ -216,6 +216,9 @@ void node_attach(struct resource_id *node_id, struct resource_id *to_id) struct node *to = get_node(to_id); assert(node); + if (to->n_children > MAX_NODE_CHILDREN) { + debug("to->n_children %d\n", to->n_children); + } assert(to && to->n_children <= MAX_NODE_CHILDREN); node->parent_id = *to_id; diff --git a/src/node.h b/src/node.h @@ -4,7 +4,7 @@ #include "resource.h" -#define MAX_NODE_CHILDREN 20 +#define MAX_NODE_CHILDREN 32 enum node_flags { NODE_IGNORE_RECALC = 1 << 0 diff --git a/src/orbit_util.c b/src/orbit_util.c @@ -1,6 +1,7 @@ #include "orbit.h" #include "input.h" +#include "debug.h" #include "entity.h" void orbit_update_from_mouse(struct orbit *camera, struct input *input, @@ -8,17 +9,20 @@ void orbit_update_from_mouse(struct orbit *camera, struct input *input, float dt) { float target[3]; - struct node *target_node = get_node(&player->node_id); - struct node *cam_node = get_node(&camera->node_id); - struct model *pmodel = get_model(&player->model_id); assert(pmodel); - struct geometry *player_geom = get_geometry(&pmodel->geom_id); assert(player_geom); + struct node *target_node = get_node(&player->node_id); + struct node *cam_node = get_node(&camera->node_id); + struct model *pmodel = get_model(&player->model_id); + assert(pmodel); + + struct geometry *player_geom = get_geometry(&pmodel->geom_id); + assert(player_geom); assert(target_node); assert(cam_node); node_recalc(target_node); vec3_copy(node_world(target_node), target); - assert(player_geom->max[2] != 0); + //assert(player_geom->max[2] != 0); vec3_add(target, V3(0.0, 0.0, player_geom->max[2]), target); /* vec3_add(target, V3(0.0, 0.0, 10.0), target); */ diff --git a/src/poisson.c b/src/poisson.c @@ -5,8 +5,6 @@ #include "common.h" #include "poisson.h" -#include <stdio.h> - struct grid_info { double size; diff --git a/src/quickhull.c b/src/quickhull.c @@ -998,7 +998,7 @@ qh_face_t* qh__build_tetrahedron(qh_context_t* context, float epsilon) qh_vertex_t* v; qh_face_t* dface = NULL; - if (vertices[0] == (long)i || vertices[1] == (long)i || vertices[2] == (long)i) { + if (vertices[0] == i || vertices[1] == i || vertices[2] == i) { continue; } @@ -1014,7 +1014,7 @@ qh_face_t* qh__build_tetrahedron(qh_context_t* context, float epsilon) for (int j = 0; j < 3; ++j) { qh_half_edge_t* e = context->edges + dface->edges[j]; - if ((long)i == e->to_vertex) { + if (i == e->to_vertex) { valid = 0; break; } diff --git a/src/render.h b/src/render.h @@ -21,28 +21,27 @@ void wireframe_mode_on(); void wireframe_mode_off(); static inline void uniform_3f(struct gpu_program *program, - enum uniform_id id, const float *v3) + int id, const float *v3) { glUniform3f(program->uniforms[id].location, v3[0], v3[1], v3[2]); check_gl(); } -static inline void uniform_1i(struct gpu_program *program, - enum uniform_id id, int i) +static inline void uniform_1i(struct gpu_program *program, int id, int i) { glUniform1i(program->uniforms[id].location, i); check_gl(); } static inline void uniform_m4f(struct gpu_program *program, - enum uniform_id id, float *m) + int id, float *m) { glUniformMatrix4fv(program->uniforms[id].location, 1, 0, m); check_gl(); } static inline void uniform_1f(struct gpu_program *program, - enum uniform_id id, float f) + int id, float f) { glUniform1f(program->uniforms[id].location, f); check_gl(); diff --git a/src/resource.c b/src/resource.c @@ -11,217 +11,217 @@ static u64 resource_uuids = 0; static inline void *index_resource_(u8 *res, u32 elem_size, int i) { - assert(res); - return res + (i * elem_size); + assert(res); + return res + (i * elem_size); } static inline void *index_resource(struct resource_manager *r, int i) { - return index_resource_(r->resources, r->elem_size, i); + return index_resource_(r->resources, r->elem_size, i); } void *get_all_resources(struct resource_manager *r, u32 *count, struct resource_id **ids) { - if (count != 0) - *count = r->resource_count; + if (count != 0) + *count = r->resource_count; - if (ids != 0) - *ids = r->ids; + if (ids != 0) + *ids = r->ids; - return r->resources; + return r->resources; } void init_id(struct resource_id *id) { - id->index = -1; - id->generation = -1; - id->uuid = -1; + id->index = -1; + id->generation = -1; + id->uuid = -1; } void null_id(struct resource_id *id) { - id->generation = 0; - id->uuid = -1; - id->index = -1; + id->generation = 0; + id->uuid = -1; + id->index = -1; } void init_resource_manager(struct resource_manager *r, u32 elem_size, - u32 initial_elements, u32 max_elements, - const char *name) + u32 initial_elements, u32 max_elements, + const char *name) { - r->generation = 1; - r->resource_count = 0; - r->elem_size = elem_size; - r->max_capacity = max_elements; - r->current_capacity = initial_elements; - r->name = name; + r->generation = 1; + r->resource_count = 0; + r->elem_size = elem_size; + r->max_capacity = max_elements; + r->current_capacity = initial_elements; + r->name = name; - assert(initial_elements != 0); + assert(initial_elements != 0); - r->resources = calloc(r->current_capacity, elem_size); - r->ids = calloc(r->current_capacity, sizeof(struct resource_id)); + r->resources = calloc(r->current_capacity, elem_size); + r->ids = calloc(r->current_capacity, sizeof(struct resource_id)); } void destroy_resource_manager(struct resource_manager *r) { - free(r->ids); - free(r->resources); + free(r->ids); + free(r->resources); } static int refresh_id(struct resource_manager *r, struct resource_id *id, - struct resource_id *new) + struct resource_id *new) { - // rollover is ok - /* assert(->generation <= esys.generation); */ - if (id->generation != r->generation) { - /* debug("id %llu gen %d != res gen %d, refreshing\n", */ - /* id->uuid, id->generation, r->generation); */ - // try to find uuid in new memory layout - for (u32 i = 0; i < r->resource_count; i++) { - struct resource_id *newer_id = &r->ids[i]; - if (newer_id->uuid == id->uuid) { - /* debug("found %llu, ind %d -> %d\n", new_id->uuid, new_id->index, new->index); */ - new->index = newer_id->index; - new->generation = r->generation; - return REFRESHED_ID; - } - } - - // entity was deleted - return RESOURCE_DELETED; - } - - // doesn't need refreshed - return REFRESH_NOT_NEEDED; + // rollover is ok + /* assert(->generation <= esys.generation); */ + if (id->generation != r->generation) { + /* debug("id %llu gen %d != res gen %d, refreshing\n", */ + /* id->uuid, id->generation, r->generation); */ + // try to find uuid in new memory layout + for (u32 i = 0; i < r->resource_count; i++) { + struct resource_id *newer_id = &r->ids[i]; + if (newer_id->uuid == id->uuid) { + /* debug("found %llu, ind %d -> %d\n", new_id->uuid, new_id->index, new->index); */ + new->index = newer_id->index; + new->generation = r->generation; + return REFRESHED_ID; + } + } + + // entity was deleted + return RESOURCE_DELETED; + } + + // doesn't need refreshed + return REFRESH_NOT_NEEDED; } -int is_resource_destroyed(struct resource_id *id) { - return id->generation == 0; +int is_resource_destroyed(struct resource_manager *r, struct resource_id *id) { + return refresh_id(r, id, id) == RESOURCE_DELETED; } static void new_id(struct resource_manager *r, struct resource_id *id) { - id->index = r->resource_count; - id->uuid = ++resource_uuids; - id->generation = r->generation; - assert(id->generation); + id->index = r->resource_count; + id->uuid = ++resource_uuids; + id->generation = r->generation; + assert(id->generation); } static void resize(struct resource_manager *r) { - debug("resizing %s resources, count %d+1 > current capacity %d\n", - r->name, r->resource_count, r->current_capacity); - void *new_mem; - u32 new_size = r->resource_count * 1.5; - if (new_size >= r->max_capacity) - new_size = r->max_capacity; - - /* debug("resizing new_size %d\n", new_size); */ - - new_mem = realloc(r->resources, (new_size+1) * r->elem_size); - if (!new_mem) { - // yikes, out of memory, bail - assert(new_mem); - return; - } - - r->resources = new_mem; - new_mem = realloc(r->ids, sizeof(struct resource_id) * (new_size+1)); - - if (!new_mem) { - // yikes, out of memory, bail - assert(new_mem); - return; - } - r->current_capacity = new_size; - r->ids = new_mem; + debug("resizing %s resources, count %d+1 > current capacity %d\n", + r->name, r->resource_count, r->current_capacity); + void *new_mem; + u32 new_size = r->resource_count * 1.5; + if (new_size >= r->max_capacity) + new_size = r->max_capacity; + + /* debug("resizing new_size %d\n", new_size); */ + + new_mem = realloc(r->resources, (new_size+1) * r->elem_size); + if (!new_mem) { + // yikes, out of memory, bail + assert(new_mem); + return; + } + + r->resources = new_mem; + new_mem = realloc(r->ids, sizeof(struct resource_id) * (new_size+1)); + + if (!new_mem) { + // yikes, out of memory, bail + assert(new_mem); + return; + } + r->current_capacity = new_size; + r->ids = new_mem; } void print_id(struct resource_id *id, int nl) { - printf("id(u:%llu i:%d g:%d)%s", - id->uuid, id->index, id->generation, nl?"\n":""); + printf("id(u:%" PRIu64 " i:%d g:%d)%s", + id->uuid, id->index, id->generation, nl?"\n":""); } void *new_resource(struct resource_manager *r, struct resource_id *id) { - assert(id); - assert(id->index == 0xFFFFFFFF && "res_id is uninitialized"); + assert(id); + assert(id->index == 0xFFFFFFFF && "res_id is uninitialized"); - struct resource_id *fresh_id; + struct resource_id *fresh_id; - if (r->resource_count + 1 > r->max_capacity) { - printf("new_resource: count %d > max cap %d\n", r->resource_count, r->max_capacity); - return NULL; - } + if (r->resource_count + 1 > r->max_capacity) { + printf("new_resource: count %d > max cap %d\n", r->resource_count, r->max_capacity); + return NULL; + } - if (r->resource_count + 1 > r->current_capacity) - resize(r); + if (r->resource_count + 1 > r->current_capacity) + resize(r); - fresh_id = &r->ids[r->resource_count]; - new_id(r, fresh_id); - *id = *fresh_id; + fresh_id = &r->ids[r->resource_count]; + new_id(r, fresh_id); + *id = *fresh_id; - return index_resource(r, r->resource_count++); + return index_resource(r, r->resource_count++); } void *get_resource(struct resource_manager *r, struct resource_id *id) { - assert((int64_t)id->generation != -1 && "id intialized but not allocated (needs new_ call)"); + assert((int64_t)id->generation != -1 && "id intialized but not allocated (needs new_ call)"); - if (id->generation == 0) { - /* unusual("getting already deleted resource %llu\n", id->uuid); */ - return NULL; - } + if (id->generation == 0) { + /* unusual("getting already deleted resource %llu\n", id->uuid); */ + return NULL; + } - enum refresh_status res = refresh_id(r, id, id); + enum refresh_status res = refresh_id(r, id, id); - if (res == RESOURCE_DELETED) { - /* unusual("getting deleted %s resource %llu\n", r->name, id->uuid); */ - return NULL; - } + if (res == RESOURCE_DELETED) { + /* unusual("getting deleted %s resource %llu\n", r->name, id->uuid); */ + return NULL; + } - return index_resource(r, id->index); + return index_resource(r, id->index); } void destroy_resource(struct resource_manager *r, struct resource_id *id) { - if (is_resource_destroyed(id)) { - unusual("trying to destroy resource %llu which was already destroyed\n", id->uuid); - return; - } + if (is_resource_destroyed(r, id)) { + unusual("trying to destroy resource %" PRIu64 " which was already destroyed\n", id->uuid); + return; + } - enum refresh_status res = refresh_id(r, id, id); + enum refresh_status res = refresh_id(r, id, id); - // entity already deleted - /* debug("refresh res %d uuid %llu gen %d index %d\n", res, */ - /* id->uuid, id->generation, id->index); */ + // entity already deleted + /* debug("refresh res %d uuid %llu gen %d index %d\n", res, */ + /* id->uuid, id->generation, id->index); */ - if (res == RESOURCE_DELETED) { - unusual("trying to destroy resource %llu which was already destroyed (2)\n", id->uuid); - id->generation = 0; - return; - } + if (res == RESOURCE_DELETED) { + unusual("trying to destroy resource %" PRIu64 " which was already destroyed (2)\n", id->uuid); + id->generation = 0; + return; + } - /* debug("destroying %s resource %llu ind %d res_count %d\n", */ - /* r->name, id->uuid, id->index, r->resource_count); */ + /* debug("destroying %s resource %llu ind %d res_count %d\n", */ + /* r->name, id->uuid, id->index, r->resource_count); */ - r->resource_count--; - r->generation++; + r->resource_count--; + r->generation++; - if (r->resource_count > 0) { - assert((int)r->resource_count - (int)id->index >= 0); + if (r->resource_count > 0) { + assert((int)r->resource_count - (int)id->index >= 0); - // TODO: we're copying OOB here - memmove(index_resource(r, id->index), - index_resource(r, id->index+1), - r->elem_size * (r->resource_count - id->index)); + // TODO: we're copying OOB here + memmove(index_resource(r, id->index), + index_resource(r, id->index+1), + r->elem_size * (r->resource_count - id->index)); - memmove(&r->ids[id->index], - &r->ids[id->index+1], - sizeof(struct resource_id) * (r->resource_count - id->index)); - } + memmove(&r->ids[id->index], + &r->ids[id->index+1], + sizeof(struct resource_id) * (r->resource_count - id->index)); + } - for (u32 i = id->index; i < r->resource_count; i++) { - r->ids[i].index--; - } + for (u32 i = id->index; i < r->resource_count; i++) { + r->ids[i].index--; + } } diff --git a/src/resource.h b/src/resource.h @@ -39,6 +39,7 @@ void destroy_resource_manager(struct resource_manager *); void *new_resource(struct resource_manager *, struct resource_id *id); void print_id(struct resource_id *, int nl); void null_id(struct resource_id *id); +int is_resource_destroyed(struct resource_manager *r, struct resource_id *id); void init_resource_manager(struct resource_manager *r, u32 elem_size, u32 initial_elements, u32 max_elements, const char *name); diff --git a/src/scene.c b/src/scene.c @@ -1 +0,0 @@ - diff --git a/src/shader.c b/src/shader.c @@ -20,319 +20,537 @@ static char *line_buff[MAX_LINES]; static u32 line_lens[MAX_LINES]; static char *cached_file_contents(const char *filename) { - size_t len; - for (int i = 0; i < file_buf_count; i++) { - if (memcmp(file_names[i], filename, file_name_lens[i]) == 0) { - return file_buffers[i]; - } - } - - return (char*)file_contents(filename, &len); + size_t len; + for (int i = 0; i < file_buf_count; i++) { + if (memcmp(file_names[i], filename, file_name_lens[i]) == 0) { + return file_buffers[i]; + } + } + + return (char*)file_contents(filename, &len); } static char *strsep(char **stringp, const char *delim) { - if (*stringp == NULL) { return NULL; } - char *token_start = *stringp; - *stringp = strpbrk(token_start, delim); - if (*stringp) - (*stringp)++; - return token_start; + if (*stringp == NULL) { return NULL; } + char *token_start = *stringp; + *stringp = strpbrk(token_start, delim); + if (*stringp) + (*stringp)++; + return token_start; } static char **resolve_imports(char *contents, int *nlines, int level) { - char *line; - int nline = 0; - char *resolved_contents; - char fname_buf[32] = {0}; - - while ((line = strsep(&contents, "\n"))) { - nline++; - int line_len = contents - line; - int size = sizeof("#include"); - if (memcmp(line, "#include ", size) == 0) { - char *filename = line + size; - int file_name_len = line_len - size - 1; - snprintf(fname_buf, 32, SHADER("%.*s"), file_name_len, filename); - file_name_lens[file_buf_count] = file_name_len; - file_names[file_buf_count] = filename; - - /* printf("got include %.*s at line %d level %d ind %d\n", */ - /* file_name_len, filename, nline, level, file_buf_count); */ - - // TODO (perf): cache file contents based on filename - resolved_contents = cached_file_contents(fname_buf); - file_buffers[file_buf_count] = resolved_contents; - file_buf_count++; - resolve_imports(resolved_contents, nlines, level + 1); - } - else { - line_buff[*nlines] = line; - line_lens[*nlines] = line_len; - (*nlines)++; - /* printf("%d %.*s", *nlines, line_len, line); */ - } - } - - return line_buff; + char *line; + int nline = 0; + char *resolved_contents; + char fname_buf[32] = {0}; + + while ((line = strsep(&contents, "\n"))) { + nline++; + int line_len = contents - line; + int size = sizeof("#include"); + if (memcmp(line, "#include ", size) == 0) { + char *filename = line + size; + int file_name_len = line_len - size - 1; + snprintf(fname_buf, 32, SHADER("%.*s"), file_name_len, filename); + file_name_lens[file_buf_count] = file_name_len; + file_names[file_buf_count] = filename; + + /* printf("got include %.*s at line %d level %d ind %d\n", */ + /* file_name_len, filename, nline, level, file_buf_count); */ + + // TODO (perf): cache file contents based on filename + resolved_contents = cached_file_contents(fname_buf); + file_buffers[file_buf_count] = resolved_contents; + file_buf_count++; + resolve_imports(resolved_contents, nlines, level + 1); + } + else { + line_buff[*nlines] = line; + line_lens[*nlines] = line_len; + (*nlines)++; + /* printf("%d %.*s", *nlines, line_len, line); */ + } + } + + return line_buff; } -struct shader *get_program_shader(struct gpu_program *program, GLenum type) { - struct shader *shader; - for (int i = 0; i < program->n_shaders; i++) { - shader = &program->shaders[i]; - if (shader->type == type) - return shader; - } +struct shader *get_program_shader(struct gpu_program *program, GLenum type) +{ + struct shader *shader; + for (int i = 0; i < program->n_shaders; i++) { + shader = &program->shaders[i]; + if (shader->type == type) + return shader; + } - return NULL; + return NULL; } - int make_shader(GLenum type, const char *filename, struct shader *shader) { - size_t length; - int nlines = 0; - GLchar *source = (GLchar *)file_contents(filename, &length); - if (!source) - return 0; + size_t length; + int nlines = 0; + GLchar *source = (GLchar *)file_contents(filename, &length); + if (!source) + return 0; - assert(file_buf_count == 0); - char **lines = resolve_imports(source, &nlines, 0); + assert(file_buf_count == 0); + char **lines = resolve_imports(source, &nlines, 0); + + GLint shader_ok; + + shader->n_includes = 0; + shader->filename = filename; + shader->type = type; + shader->handle = glCreateShader(type); + + glShaderSource(shader->handle, nlines, (const char**)lines, + (const int*)line_lens); - GLint shader_ok; + // shader dependency stuff + for (int i = 0; i < file_buf_count; ++i) { + assert(i < MAX_SHADER_INCLUDES); + char *p = shader->includes[shader->n_includes]; + int name_len = file_name_lens[i]; + /* printf("%.*s name len %d\n", name_len, file_names[i], name_len); */ + snprintf(p, MAX_INCLUDE_FNAME_LEN, SHADER("%.*s"), name_len, file_names[i]); + assert(name_len < MAX_INCLUDE_FNAME_LEN); + shader->include_mtimes[shader->n_includes] = file_mtime(p); + /* printf("'%s' included in '%s'\n", p, shader->filename); */ + shader->n_includes++; + free(file_buffers[i]); + } + free(source); - shader->n_includes = 0; - shader->filename = filename; - shader->type = type; - shader->handle = glCreateShader(type); + file_buf_count = 0; - glShaderSource(shader->handle, nlines, (const char**)lines, - (const int*)line_lens); + glCompileShader(shader->handle); + glGetShaderiv(shader->handle, GL_COMPILE_STATUS, &shader_ok); - // shader dependency stuff - for (int i = 0; i < file_buf_count; ++i) { - assert(i < MAX_SHADER_INCLUDES); - char *p = shader->includes[shader->n_includes]; - int name_len = file_name_lens[i]; - /* printf("%.*s name len %d\n", name_len, file_names[i], name_len); */ - snprintf(p, MAX_INCLUDE_FNAME_LEN, SHADER("%.*s"), name_len, file_names[i]); - assert(name_len < MAX_INCLUDE_FNAME_LEN); - shader->include_mtimes[shader->n_includes] = file_mtime(p); - /* printf("'%s' included in '%s'\n", p, shader->filename); */ - shader->n_includes++; - free(file_buffers[i]); - } - free(source); - - file_buf_count = 0; - - glCompileShader(shader->handle); - - glGetShaderiv(shader->handle, GL_COMPILE_STATUS, &shader_ok); - - if (!shader_ok) { - fprintf(stderr, "Failed to compile %s:\n", filename); - show_info_log(shader->handle); - glDeleteShader(shader->handle); - return 0; - } - - shader->load_mtime = - file_mtime(shader->filename); - - return 1; + if (!shader_ok) { + fprintf(stderr, "Failed to compile %s:\n", filename); + show_shader_info_log(shader->handle); + glDeleteShader(shader->handle); + return 0; + } + + shader->load_mtime = file_mtime(shader->filename); + + return 1; } #define N_SHADERS 3 void init_gpu_program(struct gpu_program *program) { - memset(program, 0, sizeof(*program)); + memset(program, 0, sizeof(*program)); } -void add_attribute(struct gpu_program *program, const char *name, - enum vertex_attr attr) +void link_attribute(struct gpu_program *program, const char *name, + enum vertex_attr attr) { - program->vertex_attrs[attr] = - (gpu_addr)glGetAttribLocation(program->handle, name); - check_gl(); + program->vertex_attrs[attr] = + (gpu_addr)glGetAttribLocation(program->handle, name); + program->active_attributes |= 1 << attr; + check_gl(); } -void add_uniform(struct gpu_program *program, - const char *name, - enum uniform_id id) +static inline struct lens *get_uniform_lens(struct gpu_program *program, + int binding_id, int lens_id) { - struct uniform *var = &program->uniforms[id]; - var->name = name; - var->id = id; - var->location = glGetUniformLocation(program->handle, var->name); - if (var->location == -1) { - debug("warn: could not find uniform location: %s in program %s\n", - var->name, program->name); - } - /* assert(var->location != -1); */ - check_gl(); + struct structure_binding *binding = + &program->bindings[binding_id]; + + return &binding->lenses[lens_id]; } -void find_program_uniforms(struct gpu_program *program, - struct gpu_program *programs) +void add_uniform(struct gpu_program *program, + int id, + int binding_id, + int lens_id) { - // Program variables - add_uniform(program, "camera_position", UNIFORM_CAMERA_POSITION); - add_uniform(program, "depth_mvp", UNIFORM_DEPTH_MVP); - add_uniform(program, "light_intensity", UNIFORM_LIGHT_INTENSITY); - add_uniform(program, "sky_intensity", UNIFORM_SKY_INTENSITY); - add_uniform(program, "time", UNIFORM_TIME); - add_uniform(program, "light_dir", UNIFORM_LIGHT_DIR); - add_uniform(program, "sun_color", UNIFORM_SUN_COLOR); - add_uniform(program, "fog_on", UNIFORM_FOG_ON); - add_uniform(program, "model", UNIFORM_MODEL); - add_uniform(program, "mvp", UNIFORM_MVP); - add_uniform(program, "normal_matrix", UNIFORM_NORMAL_MATRIX); - - // Attributes - add_attribute(program, "normal", va_normal); - add_attribute(program, "position", va_position); - add_attribute(program, "color", va_color); - - // chess stuff - if (program == &programs[CHESS_PIECE_PROGRAM]) { - add_uniform(program, "is_white", - UNIFORM_IS_WHITE); - } + struct uniform *var = &program->uniforms[id]; + struct lens *lens = get_uniform_lens(program, binding_id, lens_id); + + var->location = glGetUniformLocation(program->handle, lens->name); + var->id = id; + var->binding_id = binding_id; + var->lens_id = lens_id; + + if (var->location == -1) { + debug("warn: could not find uniform location: %s in program %s\n", + lens->name, program->name); + } + /* assert(var->location != -1); */ + check_gl(); } -void find_uniforms(struct gpu_program *programs) +static GLenum datatype_to_gl_type(enum data_id_datatype type) { - for (int i = 0; i < NUM_PROGRAMS; ++i) { - struct gpu_program *program = &programs[i]; - if (program == NULL) { - debug("program %d is NULL\n", i); - continue; - } + switch (type) { + case DATA_ID_INT: return GL_INT; + case DATA_ID_FLOAT: return GL_FLOAT; + case DATA_ID_VEC2: return GL_FLOAT_VEC2; + case DATA_ID_VEC3: return GL_FLOAT_VEC3; + case DATA_ID_VEC3P: return GL_FLOAT_VEC3; + case DATA_ID_MAT3: return GL_FLOAT_MAT3; + case DATA_ID_MAT4: return GL_FLOAT_MAT4; + case DATA_ID_MAT4P: return GL_FLOAT_MAT4; + } - if (program->name == NULL) { - debug("program %d name is NULL, not initialized?\n", i); - continue; - } + return -1; +} - find_program_uniforms(program, programs); - } +static const char *gl_type_str(GLenum type) +{ + switch (type) { + case GL_BYTE: return "byte"; + case GL_UNSIGNED_BYTE: return "ubyte"; + case GL_SHORT: return "short"; + case GL_UNSIGNED_SHORT: return "ushort"; + case GL_INT: return "int"; + case GL_UNSIGNED_INT: return "uint"; + case GL_FLOAT: return "float"; + case GL_FLOAT_VEC2: return "float_vec2"; + case GL_FLOAT_VEC3: return "float_vec3"; + case GL_FLOAT_MAT3: return "float_mat3"; + case GL_FLOAT_MAT4: return "float_mat4"; + case GL_DOUBLE: return "double"; + case GL_TEXTURE_2D: return "texture2d"; + case GL_TEXTURE_3D: return "texture3d"; + case GL_SAMPLER_2D: return "sampler2d"; + case GL_SAMPLER_CUBE: return "samplerCube"; + default: return "unknown"; + } +} +int vertex_attr_from_name(const char *name, enum vertex_attr *attr) +{ + if (!strcmp(name, "position")) { + *attr = va_position; + return 1; + } else if (!strcmp(name, "color")) { + *attr = va_color; + return 1; + } else if (!strcmp(name, "normal")) { + *attr = va_normal; + return 1; + } else if (!strcmp(name, "index")) { + *attr = va_index; + return 1; + } else if (!strncmp(name, "tex_coord", 9)) { + *attr = va_tex_coord; + return 1; + } + return 0; } -#ifdef DEBUG -int reload_program(struct gpu_program *program, - struct gpu_program *programs) { - int ok; +void create_attribute_bindings(struct gpu_program *program) +{ + int i, size, length, count = 0; + char name[64]; + GLenum type; + enum vertex_attr attr; - int n_shaders = program->n_shaders; - struct gpu_program new_program; - struct shader new_shaders[n_shaders]; - struct shader *new_shaders_p[n_shaders]; + glGetProgramiv(program->handle, GL_ACTIVE_ATTRIBUTES, &count); + program->active_attributes = 0; - init_gpu_program(&new_program); + for (i = 0; i < count; i++) { + glGetActiveAttrib(program->handle, (GLuint)i, sizeof(name), + &length, &size, &type, name); - int changes[n_shaders]; + if (!vertex_attr_from_name(name, &attr)) { + printf("unknown vertex attribute: '%s'\n", name); + rtassert(0, ""); + } - for (int i = 0; i < n_shaders; i++) { - changes[i] = 0; - struct shader *shader = &program->shaders[i]; - new_shaders_p[i] = shader; + debug("%s: linking %s to %d\n", program->name, name, attr); + link_attribute(program, name, attr); + } +} - time_t mtime = file_mtime(shader->filename); - int changed = mtime != shader->load_mtime; +void create_uniform_bindings(struct gpu_program *program, + struct structure_binding *bindings, + int num_bindings) +{ + int i, binding_id, lens_id, size, length, count = 0, unis = 0; + GLenum type, lens_type; + struct lens *lens; + struct structure_binding *binding; + unsigned char *p; + char name[64]; + + program->bindings = bindings; + program->num_bindings = num_bindings; + + glGetProgramiv(program->handle, GL_ACTIVE_UNIFORMS, &count); + + for (i = 0; i < count; i++) { + glGetActiveUniform(program->handle, (GLuint)i, sizeof(name), + &length, &size, &type, name); + + debug("%s: var '%s' :: %s\n", program->name, name, + gl_type_str(type)); + // TODO: bind sampler uniforms + if (type == GL_SAMPLER_2D || type == GL_SAMPLER_CUBE) { + debug("create_uniform_bindings: skipping %s :: %s\n", + name, gl_type_str(type)); + continue; + } + + for (binding_id = 0; binding_id < num_bindings; binding_id++) { + binding = &bindings[binding_id]; + for (lens_id = 0; lens_id < binding->num_lenses; lens_id++) { + lens = &binding->lenses[lens_id]; + if (!strcmp(name, lens->name)) { + lens_type = datatype_to_gl_type(lens->type); + if (type != lens_type) { + printf("shader var type mismatch: %s shader(%s) != struct(%s)\n", + name, + gl_type_str(type), + gl_type_str(lens_type)); + assert(0); + } + assert(type == datatype_to_gl_type(lens->type)); + add_uniform(program, unis++, binding_id, lens_id); + goto cont; + } + } + } + + printf("bind_uniforms: could not bind uniform '%s' in %s\n", + name, program->name); + assert(0); + cont: + ; + } - for (int j = 0; j < shader->n_includes; ++j) { - time_t include_mtime = shader->include_mtimes[j]; - time_t new_mtime = file_mtime(shader->includes[j]); - changed |= include_mtime != new_mtime; - } + program->num_uniforms = unis; +} - changes[i] = changed; +static void bind_uniform_lens(struct lens *lens, int location, void *structure) +{ + float f; + float *fs; + int i; + + switch (lens->type) { + case DATA_ID_FLOAT: + f = get_lens_float(lens, structure); + glUniform1f(location, f); + check_gl(); + break; + + case DATA_ID_INT: + i = get_lens_int(lens, structure); + glUniform1i(location, i); + check_gl(); + break; + + case DATA_ID_VEC2: + fs = get_lens_float_array(lens, structure); + glUniform2f(location, fs[0], fs[1]); + check_gl(); + break; + + case DATA_ID_VEC3: + fs = get_lens_float_array(lens, structure); + glUniform3f(location, fs[0], fs[1], fs[2]); + check_gl(); + break; + + case DATA_ID_VEC3P: + fs = get_lens_ptr(lens, structure); + glUniform3f(location, fs[0], fs[1], fs[2]); + check_gl(); + break; + + case DATA_ID_MAT3: + fs = get_lens_float_array(lens, structure); + glUniformMatrix3fv(location, 1, 0, fs); + check_gl(); + break; + + case DATA_ID_MAT4P: + fs = get_lens_ptr(lens, structure); + glUniformMatrix4fv(location, 1, 0, fs); + check_gl(); + break; + + case DATA_ID_MAT4: + fs = get_lens_float_array(lens, structure); + glUniformMatrix4fv(location, 1, 0, fs); + check_gl(); + break; + } +} - if (changed) { - /* printf("making shader %s\n", shader->filename); */ - ok = make_shader(shader->type, shader->filename, &new_shaders[i]); - if (!ok) { - // clean up all the new shaders we've created so far - for (int k = 0; k < i; k++) - glDeleteShader(new_shaders[k].handle); - return 0; - } - new_shaders_p[i] = &new_shaders[i]; - } - } +void bind_uniforms(struct gpu_program *program, void **structures, int num_structs) +{ + int i; + struct uniform *uniform; + struct lens *lens; + struct structure_binding *binding; + void *structure; + void *data; + + if (num_structs < program->num_bindings) { + debug("%s: num_structs(%d) < program->num_bindings(%d)\n", + program->name, num_structs, program->num_bindings); + } + assert(num_structs >= program->num_bindings); + + assert(program->name); + /* + debug("bind_uniforms: %s num_uniforms %d\n", + program->name, program->num_uniforms); + */ + for (i = 0; i < program->num_uniforms; i++) { + uniform = &program->uniforms[i]; + binding = &program->bindings[uniform->binding_id]; + lens = &binding->lenses[uniform->lens_id]; + /* + debug("%s: binding %d %s binding_id:%d lens_id:%d\n", + program->name, i, + lens->name, uniform->binding_id, + uniform->lens_id); + */ + structure = structures[uniform->binding_id]; + bind_uniform_lens(lens, uniform->location, structure); + } +} - int any_changes = 0; - for (int i = 0; i < n_shaders; i++) - any_changes |= changes[i]; +static void link_uniform(struct gpu_program *program, struct uniform *u) +{ + struct lens *lens = get_uniform_lens(program, u->binding_id, u->lens_id); + u->location = glGetUniformLocation(program->handle, lens->name); + if (u->location == -1) { + debug("warn: could not find uniform location: %s in program %s\n", + lens->name, program->name); + } + /* assert(u->location != -1); */ + check_gl(); +} - if (!any_changes) { - return 2; - } +int reload_program(struct gpu_program *program, struct gpu_program *programs) +{ + int ok; - ok = make_program_from_shaders(program->name, new_shaders_p, - n_shaders, &new_program); + int n_shaders = program->n_shaders; + struct gpu_program new_program; + struct shader new_shaders[n_shaders]; + struct shader *new_shaders_p[n_shaders]; + + init_gpu_program(&new_program); + + int changes[n_shaders]; + + for (int i = 0; i < n_shaders; i++) { + changes[i] = 0; + struct shader *shader = &program->shaders[i]; + new_shaders_p[i] = shader; + + time_t mtime = file_mtime(shader->filename); + int changed = mtime != shader->load_mtime; + + for (int j = 0; j < shader->n_includes; ++j) { + time_t include_mtime = shader->include_mtimes[j]; + time_t new_mtime = file_mtime(shader->includes[j]); + changed |= include_mtime != new_mtime; + } + + changes[i] = changed; + + if (changed) { + /* printf("making shader %s\n", shader->filename); */ + ok = make_shader(shader->type, shader->filename, &new_shaders[i]); + if (!ok) { + // clean up all the new shaders we've created so far + for (int k = 0; k < i; k++) + glDeleteShader(new_shaders[k].handle); + return 0; + } + new_shaders_p[i] = &new_shaders[i]; + } + } + + int any_changes = 0; + for (int i = 0; i < n_shaders; i++) + any_changes |= changes[i]; - if (!ok) { - for (int i = 0; i < n_shaders; i++) { - glDeleteShader(program->shaders[i].handle); - } - return 0; - } + if (!any_changes) { + return 2; + } - *program = new_program; + ok = make_program_from_shaders(program->name, new_shaders_p, + n_shaders, &new_program, + program->bindings, + program->num_bindings); + + if (!ok) { + for (int i = 0; i < n_shaders; i++) { + glDeleteShader(program->shaders[i].handle); + } + return 0; + } - find_program_uniforms(program, programs); - return 1; + *program = new_program; + return 1; } -#endif int -make_program(const char *name, - struct shader *vertex, - struct shader *fragment, - struct gpu_program *program) +make_program(const char *name, struct shader *vertex, struct shader *fragment, + struct gpu_program *program, struct structure_binding *bindings, + int num_bindings) { - struct shader *shaders[] = { vertex, fragment }; - return make_program_from_shaders(name, shaders, 2, program); + struct shader *shaders[] = { vertex, fragment }; + return make_program_from_shaders(name, shaders, 2, program, bindings, + num_bindings); } int make_program_from_shaders(const char *name, struct shader **shaders, - int n_shaders, struct gpu_program *program) + int n_shaders, struct gpu_program *program, + struct structure_binding *bindings, + int num_bindings) { GLint program_ok; // TODO: relax these constraints program->handle = glCreateProgram(); - check_gl(); - program->n_shaders = n_shaders; - program->name = name; - - assert(n_shaders <= MAX_SHADERS); - for (int i = 0; i < n_shaders; i++) { - struct shader *shader = shaders[i]; - program->shaders[i] = *shader; - /* printf("attaching shader %s\n", shader->filename); */ - /* for (int j = 0; j < shader->n_includes; ++j) { */ - /* printf("attaching shader %s dep %s \n", shader->filename, */ - /* shader->includes[j]); */ - /* } */ - glAttachShader(program->handle, shader->handle); - check_gl(); - } + check_gl(); + program->n_shaders = n_shaders; + program->name = name; + + assert(n_shaders <= MAX_SHADERS); + for (int i = 0; i < n_shaders; i++) { + struct shader *shader = shaders[i]; + program->shaders[i] = *shader; + /* printf("attaching shader %s\n", shader->filename); */ + /* for (int j = 0; j < shader->n_includes; ++j) { */ + /* printf("attaching shader %s dep %s \n", shader->filename, */ + /* shader->includes[j]); */ + /* } */ + glAttachShader(program->handle, shader->handle); + check_gl(); + } glLinkProgram(program->handle); - check_gl(); + check_gl(); glGetProgramiv(program->handle, GL_LINK_STATUS, &program_ok); if (!program_ok) { fprintf(stderr, "Failed to link shader program:\n"); - show_info_log(program->handle); + show_program_info_log(program->handle); glDeleteProgram(program->handle); return 0; } + if (num_bindings > 0) + create_uniform_bindings(program, bindings, num_bindings); + + create_attribute_bindings(program); + return 1; } diff --git a/src/shader.h b/src/shader.h @@ -4,88 +4,76 @@ #include <time.h> #include "gl.h" #include "vbo.h" +#include "data_id.h" #define SHADER(f) "etc/shaders/" f #define MAX_SHADER_INCLUDES 16 #define MAX_INCLUDE_FNAME_LEN 64 #define MAX_SHADERS 5 +#define MAX_UNIFORMS 64 +#define MAX_SHADER_STRUCTS 4 + +/* structure binding */ +struct structure_binding { + struct lens *lenses; + int num_lenses; +}; struct shader { GLenum type; GLuint handle; - int n_includes; + int n_includes; const char *filename; - char includes[MAX_SHADER_INCLUDES][MAX_INCLUDE_FNAME_LEN]; - time_t include_mtimes[MAX_SHADER_INCLUDES]; + char includes[MAX_SHADER_INCLUDES][MAX_INCLUDE_FNAME_LEN]; + time_t include_mtimes[MAX_SHADER_INCLUDES]; time_t load_mtime; }; -enum program_type { - DEFAULT_PROGRAM, - TERRAIN_PROGRAM, - UI_PROGRAM, - SKYBOX_PROGRAM, - CHESS_PIECE_PROGRAM, - NUM_PROGRAMS, -}; - - -enum uniform_id { - UNIFORM_AMBIENT_STR, - UNIFORM_CAMERA_POSITION, - UNIFORM_DEPTH_MVP, - UNIFORM_DEPTH_VP, - UNIFORM_DIFFUSE_ON, - UNIFORM_FOG_ON, - UNIFORM_LIGHT_DIR, - UNIFORM_LIGHT_INTENSITY, - UNIFORM_MODEL, - UNIFORM_MODEL_VIEW, - UNIFORM_MVP, - UNIFORM_NORMAL_MATRIX, - UNIFORM_SKY_INTENSITY, - UNIFORM_SUN_COLOR, - UNIFORM_TIME, - UNIFORM_VIEW_PROJ, - UNIFORM_IS_WHITE, - MAX_UNIFORMS -}; - struct uniform { - enum uniform_id id; - const char *name; - int location; + int id; + int location; + int binding_id; + int lens_id; }; struct gpu_program { struct shader shaders[MAX_SHADERS]; - struct uniform uniforms[MAX_UNIFORMS]; + struct uniform uniforms[MAX_UNIFORMS]; + struct structure_binding *bindings; + int num_bindings; gpu_addr vertex_attrs[MAX_VERTEX_ATTRS]; - int n_shaders; + int n_shaders; + int num_uniforms; + int active_attributes; GLuint handle; - const char *name; + const char *name; }; -void add_uniform(struct gpu_program *program, const char *name, enum uniform_id id); -void add_attribute(struct gpu_program *program, const char *name, enum vertex_attr attr); +void add_uniform(struct gpu_program *program, int id, int binding_id, int lens_id); + +void create_shader_bindings(struct gpu_program *program, struct structure_binding *bindings, int num_bindings); #define NO_GEOM_SHADER NULL int reload_program(struct gpu_program *program, struct gpu_program *programs); int make_shader(GLenum type, const char *filename, struct shader *shader); -void find_uniforms(struct gpu_program *programs); -void find_program_uniforms(struct gpu_program *program, - struct gpu_program *programs); +void bind_uniforms(struct gpu_program *program, void **structures, int num_structs); + void init_gpu_program(struct gpu_program *program); int make_program_from_shaders(const char *name, struct shader **shaders, int n_shaders, - struct gpu_program *program); + struct gpu_program *program, + struct structure_binding *bindings, + int n_bindings + ); struct shader *get_program_shader(struct gpu_program *program, GLenum type); -int make_program(const char *name, struct shader *vertex, struct shader *fragment, struct gpu_program *program); +int make_program(const char *name, struct shader *vertex, struct shader *fragment, + struct gpu_program *program, struct structure_binding *bindings, + int n_bindings); #endif /* POLYADVENT_SHADER_H */ diff --git a/src/skybox.c b/src/skybox.c @@ -3,8 +3,6 @@ #include "util.h" #include "texture.h" -#include <stdio.h> - static GLfloat skybox_vertices[] = { 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0,-1.0, 1.0, 1.0,-1.0, 1.0, // v0-v1-v2-v3 top 1.0, 1.0,-1.0, 1.0, 1.0, 1.0, 1.0,-1.0, 1.0, 1.0,-1.0,-1.0, // v5-v0-v3-v4 right @@ -35,6 +33,16 @@ static u32 skybox_indices[] = { }; +#define SKY_LENS(field, typ) { #field, offsetof(struct skybox, field), DATA_ID_##typ } +static struct lens skybox_lenses[] = { + SKY_LENS(mvp, MAT4P), +}; +#undef SKY_LENS + +static struct structure_binding skybox_bindings[] = { + { skybox_lenses, ARRAY_SIZE(skybox_lenses) } +}; + void create_skybox(struct skybox *skybox, struct gpu_program *program) { struct shader vertex, frag; struct shader *shaders[] = {&vertex, &frag}; @@ -60,6 +68,7 @@ void create_skybox(struct skybox *skybox, struct gpu_program *program) { struct model *model = new_model(&skybox->model_id); assert(model); struct geometry *geom = get_geometry(&model->geom_id); assert(geom); + model->name = "skybox"; make_buffer_geometry(&mkgeom, geom); static const char *faces[6] = { @@ -82,25 +91,16 @@ void create_skybox(struct skybox *skybox, struct gpu_program *program) { /* }; */ model->texture = create_cubemap(faces); - printf("cubemap texture %d\n", model->texture); make_shader(GL_VERTEX_SHADER, SHADER("skybox.v.glsl"), &vertex); check_gl(); make_shader(GL_FRAGMENT_SHADER, SHADER("skybox.f.glsl"), &frag); check_gl(); - ok = make_program("skybox", &vertex, &frag, skybox->program); + ok = make_program("skybox", &vertex, &frag, skybox->program, + skybox_bindings, ARRAY_SIZE(skybox_bindings)); assert(ok); check_gl(); - - skybox->uniforms.mvp = - glGetUniformLocation(skybox->program->handle, "mvp"); - - skybox->attrs[va_position] = (gpu_addr) - glGetAttribLocation(skybox->program->handle, "position"); - - skybox->attrs[va_tex_coord] = (gpu_addr) - glGetAttribLocation(skybox->program->handle, "tex_coord"); } @@ -108,6 +108,9 @@ void render_skybox(struct skybox *skybox, mat4 *camera) { struct model *model = get_model(&skybox->model_id); assert(model); struct geometry *geom = get_geometry(&model->geom_id); assert(geom); + void *structures[] = { skybox }; + + skybox->mvp = camera; glDepthFunc(GL_LEQUAL); glDepthMask(GL_FALSE); @@ -116,13 +119,12 @@ void render_skybox(struct skybox *skybox, mat4 *camera) { glUseProgram(skybox->program->handle); check_gl(); - glUniformMatrix4fv(skybox->uniforms.mvp, 1, 0, camera); - check_gl(); + bind_uniforms(skybox->program, structures, ARRAY_SIZE(structures)); glBindTexture(GL_TEXTURE_CUBE_MAP, model->texture); check_gl(); - render_geometry(geom, skybox->attrs, skybox->program); + render_geometry(geom, skybox->program); check_gl(); glDepthMask(GL_TRUE); diff --git a/src/skybox.h b/src/skybox.h @@ -8,13 +8,10 @@ #include "mat4.h" struct skybox { - struct gpu_program *program; - struct model_id model_id; - gpu_addr attrs[MAX_VERTEX_ATTRS]; - struct node node; - struct { - int mvp; - } uniforms; + struct gpu_program *program; + struct model_id model_id; + struct node node; + float *mvp; }; void create_skybox(struct skybox *skybox, struct gpu_program *program); diff --git a/src/terrain.c b/src/terrain.c @@ -1,4 +1,5 @@ + #include "terrain.h" #include "util.h" #include "delaunay.h" @@ -6,9 +7,6 @@ #include "vec3.h" #include "perlin.h" #include "poisson.h" -#include "mdl.h" - -static const double pdist = 24.0; static const float plane_verts[] = { -1,-1,0, -1,1,0, 1,1,0, 1,-1,0 @@ -55,13 +53,6 @@ void reset_terrain(struct terrain *terrain, float size) { assert(ent); } -double offset_fn(struct terrain* terrain, double x, double y) { - struct perlin_settings *perlin = &terrain->settings; - double ox = perlin->ox; - double oy = perlin->oy; - return old_noisy_boi(terrain, ox+x, oy+y); -} - void init_terrain(struct terrain *terrain, float size) { init_id(&terrain->entity_id); @@ -70,9 +61,7 @@ void init_terrain(struct terrain *terrain, float size) { struct model *model = new_model(&ent->model_id); assert(model); /* struct model *model = init_model(&ent->model_id); assert(model); */ - assert(terrain->entity_id.index == 0); - - model->shader = TERRAIN_PROGRAM; + model->shader = 1; node_set_label(node, "terrain"); ent->flags &= ~ENT_CASTS_SHADOWS; @@ -80,22 +69,18 @@ void init_terrain(struct terrain *terrain, float size) { /* node->pos[2] = 20.0; */ reset_terrain(terrain, size); +} - terrain->fn = offset_fn; - terrain->cell_size = pdist; - terrain->n_cells = round(size / terrain->cell_size) + 1; - debug("n_cells %d\n", terrain->n_cells); - - struct terrain_cell *grid = - calloc(terrain->n_cells * terrain->n_cells, sizeof(struct terrain_cell)); - - terrain->grid = grid; - +double offset_fn(struct terrain* terrain, double x, double y) { + struct perlin_settings *perlin = &terrain->settings; + double ox = perlin->ox; + double oy = perlin->oy; + return old_noisy_boi(terrain, ox+x, oy+y); } void gen_terrain_samples(struct terrain *terrain, float scale, const double pdist) { - debug("generating terrain samples...\n"); + debug("generating terrain samples\n"); if (terrain->samples) free(terrain->samples); @@ -105,12 +90,9 @@ void gen_terrain_samples(struct terrain *terrain, float scale, const double pdis /* struct point *samples = */ /* uniform_samples(n_samples, game->terrain.size); */ - struct point *samples = poisson_disk_samples(pdist, terrain->size, 30, &n_samples); - debug("done generating terrain samples\n"); - /* remap_samples(samples, n_samples, game->terrain.size); */ /* draw_samples(samples, pdist, n_samples, game->terrain.size); */ @@ -123,6 +105,7 @@ void gen_terrain_samples(struct terrain *terrain, float scale, const double pdis static inline struct terrain_cell *index_terrain_cell(struct terrain *terrain, int x, int y) { if (x < 0 || y < 0 || x >= terrain->n_cells || y >= terrain->n_cells) { + assert(!"terrain oob"); return NULL; } @@ -133,11 +116,10 @@ static inline struct terrain_cell *query_terrain_cell(struct terrain *terrain, float x, float y, int *grid_x, int *grid_y) { - if (x < 0) return NULL; - if(y < 0) return NULL; - if(x >= terrain->size) return NULL; - if(y >= terrain->size) return NULL; - + assert(x >= 0); + assert(y >= 0); + assert(x < terrain->size); + assert(y < terrain->size); *grid_x = grid_index(terrain, x); *grid_y = grid_index(terrain, y); @@ -147,7 +129,7 @@ static inline struct terrain_cell *query_terrain_cell(struct terrain *terrain, void query_terrain_grid(struct terrain *terrain, float x, float y, struct terrain_cell *cells[9]) { - int grid_x = 0, grid_y = 0; + int grid_x, grid_y; // middle cells[4] = query_terrain_cell(terrain, x, y, &grid_x, &grid_y); @@ -218,94 +200,45 @@ static double distance_to_closest_edge(double size, double x, double y) { return min(top, min(left, min(right, bottom))); } -static void compute_bounding(float *vertices, int num_verts, vec3 *min, vec3 *max) -{ - int i; - for (i = 0; i < num_verts; i++) { - } -} - -void create_terrain_collision(struct terrain *terrain) -{ - double x, y; - int n; - u32 i; - - for (i = 0; i < (u32)terrain->n_verts; i++) { - n = i*3; - /* double dx, dy; */ - - x = terrain->verts[n+0]; - y = terrain->verts[n+1]; - - int grid_x = x / terrain->cell_size; - int grid_y = y / terrain->cell_size; - - // clamp height at edge - printf("%f %f %f %d grid_x %d grid_y %f cell_size\n", - x, y, terrain->verts[n+2], - grid_x, grid_y, terrain->cell_size); - - struct terrain_cell *cell = - index_terrain_cell(terrain, grid_x, grid_y); - - insert_grid_vertex(cell, n); - } -} - - -void load_terrain(struct terrain *terrain) -{ - int seed; - - assert(terrain->size > 0); - struct mdl_geometry terrain_mdl; - init_mdl_geometry(&terrain_mdl); - load_mdl("terrain.mdl", NULL, &terrain_mdl); - - struct entity *ent = get_entity(&terrain->entity_id); assert(ent); - struct model *model = get_model(&ent->model_id); assert(model); - struct geometry *geom = get_geometry(&model->geom_id); assert(geom); - - assert(terrain_mdl.mkgeom.joint_weights == 0); - - make_buffer_geometry(&terrain_mdl.mkgeom, geom); - - terrain->verts = terrain_mdl.mkgeom.vertices; - terrain->n_verts = terrain_mdl.mkgeom.num_verts; - - //struct vert_tris *vert_tris = calloc(terrain->n_verts, sizeof(struct vert_tris)); - //terrain->vtris = vert_tris; - - //create_terrain_collision(terrain); -} - void create_terrain(struct terrain *terrain, float scale, int seed) { u32 i; - int n; - double x, y, z; const double size = terrain->size; + static const double pdist = 24.0; terrain->settings.seed = seed; float tmp1[3], tmp2[3]; if (!terrain->n_samples) { gen_terrain_samples(terrain, scale, pdist); - //save_samples(terrain->samples, seed, terrain->n_samples); + /* save_samples(terrain->samples, seed, terrain->n_samples); */ } assert(terrain->n_samples > 0); del_point2d_t *points = calloc(terrain->n_samples, sizeof(*points)); float *verts = calloc(terrain->n_samples * 3, sizeof(*verts)); + terrain->cell_size = pdist; + terrain->n_cells = round(size / terrain->cell_size) + 1; + debug("n_cells %d\n", terrain->n_cells); + + struct terrain_cell *grid = + calloc(terrain->n_cells * terrain->n_cells, sizeof(struct terrain_cell)); + + terrain->grid = grid; + + /* float *normals = calloc(terrain->n_samples * 3, sizeof(*verts)); */ + + terrain->fn = offset_fn; + // n random samples from our noise function for (i = 0; i < (u32)terrain->n_samples; i++) { - n = i*3; + int n = i*3; + double x, y; + /* double dx, dy; */ + x = terrain->samples[i].x; y = terrain->samples[i].y; double z = terrain->fn(terrain, x, y); - double d = distance_to_closest_edge(size, x, y); - z *= (d / (size/2.0)) * 2.0; points[i].x = x; points[i].y = y; @@ -313,17 +246,28 @@ void create_terrain(struct terrain *terrain, float scale, int seed) { verts[n] = (float)x; verts[n+1] = (float)y; + int grid_x = verts[n] / terrain->cell_size; + int grid_y = verts[n+1] / terrain->cell_size; + + // clamp height at edge + + double d = distance_to_closest_edge(size, x, y); + z *= (d / (size/2.0)) * 2.0; + + struct terrain_cell *cell = + index_terrain_cell(terrain, grid_x, grid_y); + + assert(cell); + + insert_grid_vertex(cell, n); + static const double limit = 1.4; if (x < limit || x > size-limit || y < limit || y > size-limit) - verts[n+2] = 0; + verts[n+2] = 0; else - verts[n+2] = (float)z; + verts[n+2] = (float)z; } - /* float *normals = calloc(terrain->n_samples * 3, sizeof(*verts)); */ - - // n random samples from our noise function - delaunay2d_t *del = delaunay2d_from(points, terrain->n_samples); tri_delaunay2d_t *tri = tri_delaunay2d_from(del); @@ -388,27 +332,20 @@ void create_terrain(struct terrain *terrain, float scale, int seed) { struct entity *ent = get_entity(&terrain->entity_id); assert(ent); - struct mdl_geometry terrain_mdl; - init_mdl_geometry(&terrain_mdl); - - struct make_geometry *mkgeom = &terrain_mdl.mkgeom; + struct make_geometry mkgeom; + init_make_geometry(&mkgeom); - mkgeom->num_verts = num_verts; - mkgeom->vertices = (float*)del_verts; - mkgeom->normals = (float*)del_norms; - mkgeom->indices = (u32*)del_indices; - mkgeom->num_indices = num_verts; + mkgeom.num_verts = num_verts; + mkgeom.vertices = (float*)del_verts; + mkgeom.normals = (float*)del_norms; + mkgeom.indices = (u32*)del_indices; + mkgeom.num_indices = num_verts; struct model *model = get_model(&ent->model_id); assert(model); struct geometry *geom = get_geometry(&model->geom_id); assert(geom); - assert(mkgeom->joint_weights == 0); - - make_buffer_geometry(mkgeom, geom); - - compute_bounding(mkgeom->vertices, mkgeom->num_verts, terrain_mdl.min, - terrain_mdl.max); - save_mdl("terrain.mdl", &terrain_mdl); + assert(mkgeom.joint_weights == 0); + make_buffer_geometry(&mkgeom, geom); delaunay2d_release(del); tri_delaunay2d_release(tri); @@ -423,8 +360,6 @@ void create_terrain(struct terrain *terrain, float scale, int seed) { terrain->verts = verts; terrain->n_verts = num_verts; - create_terrain_collision(terrain); - // we might need norms in memory eventually as well ? free(del_norms); free(del_indices); diff --git a/src/terrain.h b/src/terrain.h @@ -7,8 +7,8 @@ #include "model.h" #include "debug.h" -#define MAX_CELL_VERTS 16 -#define MAX_VERT_TRIS 32 +#define MAX_CELL_VERTS 4 +#define MAX_VERT_TRIS 20 struct point; @@ -68,7 +68,6 @@ void gen_terrain_samples(struct terrain *terrain, float scale, const double pdis void init_terrain(struct terrain *terrain, float size); void reset_terrain(struct terrain *terrain, float size); void create_terrain(struct terrain *terrain, float scale, int seed); -void load_terrain(struct terrain *terrain); void destroy_terrain(struct terrain *terrain); void query_terrain_grid(struct terrain *terrain, float x, float y, struct terrain_cell *cells[9]); diff --git a/src/terrain_collision.c b/src/terrain_collision.c @@ -1,7 +1,6 @@ #include "terrain_collision.h" - -#include <float.h> +#include <stdint.h> struct grid_query { struct terrain_cell *cell; @@ -23,8 +22,6 @@ static void get_closest_verts(struct terrain *terrain, { for (int i = 0; i < 9; i++) { struct terrain_cell *cell = cells[i]; - if (!cell) - continue; for (int j = 0; j < cell->vert_count; j++) { vec3 *vpos = &terrain->verts[cell->verts_index[j]]; float d = vec3_distsq(pos, vpos); @@ -170,7 +167,7 @@ struct tri *collide_terrain(struct terrain *terrain, float *pos, float *move, fl struct terrain_cell *cells[9] = {0}; struct grid_query queries[3]; for (int i = 0; i < 3; i++) { - queries[i].distance = FLT_MAX; + queries[i].distance = 3.402823e+38; queries[i].cell = NULL; queries[i].cell_vert_index = -1; } diff --git a/src/test_game.c b/src/test_game.c @@ -6,9 +6,11 @@ #include "game.h" #include "node.h" #include "render.h" +#include "shader.h" #include "quat.h" #include "movement.h" #include "gpu.h" +#include "util.h" #include "terrain_collision.h" #include "orbit_util.h" #include "mat_util.h" @@ -21,8 +23,33 @@ static const float bias_matrix[] = { 0.5, 0.5, 0.5, 1.0 }; +#define CU_LENS(field, typ) { #field, offsetof(struct common_uniforms, field), DATA_ID_##typ } +static struct lens common_lenses[] = { + CU_LENS(fog_on, INT), + CU_LENS(sky_intensity, FLOAT), + CU_LENS(light_intensity, FLOAT), + CU_LENS(depth_mvp, MAT4), + CU_LENS(mvp, MAT4), + CU_LENS(model_view, MAT4), + CU_LENS(normal_matrix, MAT4), + CU_LENS(sun_color, VEC3), + CU_LENS(camera_position, VEC3P), + CU_LENS(light_dir, VEC3), +}; +#undef CU_LENS + +struct lens *get_common_lenses() +{ + return common_lenses; +} + +int get_common_lenses_length() +{ + return ARRAY_SIZE(common_lenses); +} + static void resize_fbos(struct entity *player, struct fbo *shadow_buffer, - float *m4_ortho, int width, int height) + float *m4_ortho, int width, int height) { if (shadow_buffer->handle) { // TODO: remove once delete_fbo deletes attachments @@ -37,15 +64,15 @@ static void resize_fbos(struct entity *player, struct fbo *shadow_buffer, struct model *model = get_model(&player->model_id); assert(model); struct geometry *geom = get_geometry(&model->geom_id); assert(geom); - float left = geom->min[0] - factor; + float left = geom->min[0] - factor; float right = geom->max[0] + factor; float bottom = geom->min[1] - factor; - float top = geom->max[1] + factor; + float top = geom->max[1] + factor; - /* float left = -factor; */ - /* float right = factor; */ + /* float left = -factor; */ + /* float right = factor; */ /* float bottom = factor; */ - /* float top = -factor; */ + /* float top = -factor; */ const float near = -50.0; const float far = 50.0; @@ -55,7 +82,7 @@ static void resize_fbos(struct entity *player, struct fbo *shadow_buffer, create_fbo(shadow_buffer, width, height ); /* fbo_attach_renderbuffer(&res->shadow_buffer, GL_DEPTH24_STENCIL8, */ - /* GL_DEPTH_STENCIL_ATTACHMENT); */ + /* GL_DEPTH_STENCIL_ATTACHMENT); */ /* fbo_attach_color_texture(&res->shadow_buffer); */ fbo_attach_depth_texture(shadow_buffer); @@ -63,7 +90,7 @@ static void resize_fbos(struct entity *player, struct fbo *shadow_buffer, check_fbo(shadow_buffer); /* fbo_attach_texture(&res->shadow_buffer, GL_DEPTH_COMPONENT16, */ - /* GL_DEPTH_COMPONENT, GL_DEPTH_ATTACHMENT); */ + /* GL_DEPTH_COMPONENT, GL_DEPTH_ATTACHMENT); */ } @@ -80,217 +107,225 @@ static struct entity *get_terrain_entity(struct terrain *t) { } static void player_movement(struct game *engine, struct entity *player) { - /* if (player->flags & ENT_ON_GROUND) */ - /* entity_movement(game, player); */ + /* if (player->flags & ENT_ON_GROUND) */ + /* entity_movement(game, player); */ struct node *node = get_node(&player->node_id); movement(engine, node, 2.0); } static void camera_keep_above_ground(struct terrain *terrain, - struct node *camera) { - if (get_entity(&terrain->entity_id)->flags & ENT_INVISIBLE) - return; - float move[3]; - float *camworld = node_world(camera); - float pen = 0.0; - static const float penlim = 1.0; - struct tri *tri = collide_terrain(terrain, camworld, move, &pen); - - if (!tri) - return; - - if (pen < penlim) { - float dir[3], above[3]; - vec3_normalize(move, dir); - vec3_scale(dir, pen < 0 ? penlim : -penlim, above); - vec3_add(camworld, move, camworld); - vec3_add(camworld, above, camworld); - /* vec3_add(move, above, move); */ - /* vec3_add(camworld, move, camworld); */ - } + struct node *camera) { + if (get_entity(&terrain->entity_id)->flags & ENT_INVISIBLE) + return; + float move[3]; + float *camworld = node_world(camera); + float pen = 0.0; + static const float penlim = 1.0; + struct tri *tri = collide_terrain(terrain, camworld, move, &pen); + + if (!tri) + return; + + if (pen < penlim) { + float dir[3], above[3]; + vec3_normalize(move, dir); + vec3_scale(dir, pen < 0 ? penlim : -penlim, above); + vec3_add(camworld, move, camworld); + vec3_add(camworld, above, camworld); + /* vec3_add(move, above, move); */ + /* vec3_add(camworld, move, camworld); */ + } } static void entity_movement(struct game *game, struct entity *ent) { - static const float move_accel = 1.0f; - static const float max_speed = 10.0f; - struct node *node = get_node(&ent->node_id); + static const float move_accel = 1.0f; + static const float max_speed = 10.0f; + struct node *node = get_node(&ent->node_id); - float vel[3]; + float vel[3]; - float amt = 10.0 * game->dt; + float amt = 10.0 * game->dt; - if (game->input.keystates[SDL_SCANCODE_W]) { - vec3_forward(ent->velocity, node->orientation, V3(0,amt,0), vel); - if (vec3_lengthsq(vel) <= max_speed*max_speed) - vec3_copy(vel, ent->velocity); - } + if (game->input.keystates[SDL_SCANCODE_W]) { + vec3_forward(ent->velocity, node->orientation, V3(0,amt,0), vel); + if (vec3_lengthsq(vel) <= max_speed*max_speed) + vec3_copy(vel, ent->velocity); + } } static void player_terrain_collision(struct terrain *terrain, struct node *node) { - // player movement - static vec3 last_pos[3] = {0}; + // player movement + static vec3 last_pos[3] = {0}; - if (!vec3_approxeq(node->pos, last_pos)) { - float player_z = node->pos[2]; + if (!vec3_approxeq(node->pos, last_pos)) { + float player_z = node->pos[2]; - float terrain_z = - terrain->fn(terrain, node->pos[0], node->pos[1]); + float terrain_z = + terrain->fn(terrain, node->pos[0], node->pos[1]); - float inset = - min(0.0, player_z - terrain_z); + float inset = + min(0.0, player_z - terrain_z); - if (inset <= 0) - node_translate(node, V3(0.0, 0.0, -inset)); - } + if (inset <= 0) + node_translate(node, V3(0.0, 0.0, -inset)); + } } // TODO: match based on some real concept of time static void day_night_cycle(float time, struct test_game *res) { - float val = time * 0.0001; - float intensity = 1.0;//max(0.0, vec3_dot(res->light_dir, V3(0.0, 0.0, 1.0))); */ - struct entity *player = get_player(res); - struct node *pnode = get_node(&player->node_id); - assert(pnode); - struct node *suncam = get_node(&res->sun_camera_id); - assert(suncam); + float val = time * 0.0001; + float intensity = 1.0;//max(0.0, vec3_dot(res->light_dir, V3(0.0, 0.0, 1.0))); */ + struct entity *player = get_player(res); + struct node *pnode = get_node(&player->node_id); + assert(pnode); + struct node *suncam = get_node(&res->sun_camera_id); + assert(suncam); + struct common_uniforms *cvars = &res->common_vars; - float light_pos[3]; + float light_pos[3]; - float g = 0.6; - float b = 0.4; - res->sun_color[0] = 1.0; - res->sun_color[1] = g+intensity*(1.0-g); - res->sun_color[2] = b+intensity*(1.0-b); + float g = 0.6; + float b = 0.4; + cvars->sun_color[0] = 1.0; + cvars->sun_color[1] = g+intensity*(1.0-g); + cvars->sun_color[2] = b+intensity*(1.0-b); - /* res->sun_color[0] = 1.0; */ - /* res->sun_color[1] = 1.0; */ - /* res->sun_color[2] = 1.0; */ + /* res->sun_color[0] = 1.0; */ + /* res->sun_color[1] = 1.0; */ + /* res->sun_color[2] = 1.0; */ - /* vec3_scale(res->sun_color, res->light_intensity, gtmp); */ + /* vec3_scale(res->sun_color, res->light_intensity, gtmp); */ - /* float intensity = angle <= 0.5 */ - /* ? clamp(roots, darkest, 1.0) */ - /* : clamp(-roots * 0.4, darkest, 0.5); */ + /* float intensity = angle <= 0.5 */ + /* ? clamp(roots, darkest, 1.0) */ + /* : clamp(-roots * 0.4, darkest, 0.5); */ - res->light_intensity = intensity; + cvars->light_intensity = intensity; - /* vec3_normalize(res->light_intensity, res->light_intensity); */ + /* vec3_normalize(res->light_intensity, res->light_intensity); */ - res->light_dir[0] = 0.0; - /* res->light_dir[1] = sin(val); */ - /* res->light_dir[2] = cos(val) + 1.0; */ - res->light_dir[1] = 0.8; - res->light_dir[2] = 0.8; + cvars->light_dir[0] = 0.0; + /* res->light_dir[1] = sin(val); */ + /* res->light_dir[2] = cos(val) + 1.0; */ + cvars->light_dir[1] = 0.8; + cvars->light_dir[2] = 0.8; - vec3_normalize(res->light_dir, res->light_dir); + vec3_normalize(cvars->light_dir, cvars->light_dir); - /* printf("intensity %f(%f) n %f light_dir %f %f\n", roots, intensity, */ - /* n, res->light_dir[1], res->light_dir[2]); */ + /* printf("intensity %f(%f) n %f light_dir %f %f\n", roots, intensity, */ + /* n, res->light_dir[1], res->light_dir[2]); */ - vec3_add(pnode->pos, res->light_dir, light_pos); + vec3_add(pnode->pos, cvars->light_dir, light_pos); - /* float target[3]; */ - /* float hh = player->model.geom.max[2] / 2.0; */ - /* vec3_copy(player->node.pos, target); */ - /* target[2] += 2.0; */ + /* float target[3]; */ + /* float hh = player->model.geom.max[2] / 2.0; */ + /* vec3_copy(player->node.pos, target); */ + /* target[2] += 2.0; */ - look_at(light_pos, pnode->pos, V3(0, 0, 1.0), suncam->mat); - /* look_at(light_pos, player->node.pos, V3(0, 0, 1.0), res->sun_camera.mat); */ + look_at(light_pos, pnode->pos, V3(0, 0, 1.0), suncam->mat); + /* look_at(light_pos, player->node.pos, V3(0, 0, 1.0), res->sun_camera.mat); */ } static void player_update(struct game *engine, struct test_game *game, struct entity *player) { - struct orbit *camera = &game->orbit_camera; - struct node *node = get_node(&player->node_id); - struct node *cam_node = get_node(&game->camera_node_id); - assert(node); - assert(cam_node); - - orbit_update_from_mouse(camera, &engine->input,engine->user_settings.mouse_sens, - player, engine->dt); - - camera_keep_above_ground(&game->terrain, cam_node); - - // move player camera toward camera orientation - if (input_is_dragging(&engine->input, SDL_BUTTON_RIGHT)) { - float yaw = game->orbit_camera.coords.azimuth; - quat_axis_angle(V3(0.0, 0.0, 1.0), -yaw - RAD(90), node->orientation); - } - - struct terrain *terrain = &game->terrain; - - player_terrain_collision(terrain, node); - - float move[3]; - float pos[3]; - float pen = 0.0; - vec3_copy(node_world(node), pos); - /* debug("node_world(player) %f %f %f\n", pos[0], pos[1], pos[2]); */ - struct tri *tri = collide_terrain(terrain, pos, move, &pen); - //struct tri *tri = NULL; - /* node_translate(node, move); */ - - if (tri) { - if (vec3_eq(move, V3(0,0,0), 0.1)) { - player->flags |= ENT_ON_GROUND; - } - else if (pen < 0) { - node_translate(node, move); - /* vec3_all(player->velocity, 0); */ - vec3_scale(player->velocity, 0.1, player->velocity); - } - else { - player->flags &= ~ENT_ON_GROUND; - } - } - else { - static int tric = 0; - /* debug("%d no tri\n", tric++); */ - } - - if (player->flags & ENT_ON_GROUND && - (was_key_pressed_this_frame(engine, SDL_SCANCODE_SPACE) /*|| - was_button_pressed_this_frame(engine, SDL_CONTROLLER_BUTTON_X)*/)) { - entity_jump(player, 2.0); - } - - /* debug("player velocity %f %f %f\n", */ - /* player->velocity[0], */ - /* player->velocity[1], */ - /* player->velocity[2]); */ - -// if (player->flags & ENT_AT_REST) + struct orbit *camera = &game->orbit_camera; + struct node *node = get_node(&player->node_id); + struct node *cam_node = get_node(&game->camera_node_id); + assert(node); + assert(cam_node); + + orbit_update_from_mouse(camera, &engine->input, + engine->user_settings.mouse_sens, + player, engine->dt); + + camera_keep_above_ground(&game->terrain, cam_node); + + // move player camera toward camera orientation + if (input_is_dragging(&engine->input, SDL_BUTTON_RIGHT)) { + float yaw = game->orbit_camera.coords.azimuth; + quat_axis_angle(V3(0.0, 0.0, 1.0), -yaw - RAD(90), node->orientation); + } + + struct terrain *terrain = &game->terrain; + + player_terrain_collision(terrain, node); + + float move[3]; + float pos[3]; + float pen = 0.0; + vec3_copy(node_world(node), pos); + /* debug("node_world(player) %f %f %f\n", pos[0], pos[1], pos[2]); */ + struct tri *tri = collide_terrain(terrain, pos, move, &pen); + //struct tri *tri = NULL; + /* node_translate(node, move); */ + + if (tri) { + if (vec3_eq(move, V3(0,0,0), 0.1)) { + player->flags |= ENT_ON_GROUND; + } + else if (pen < 0) { + node_translate(node, move); + /* vec3_all(player->velocity, 0); */ + vec3_scale(player->velocity, 0.1, player->velocity); + } + else { + player->flags &= ~ENT_ON_GROUND; + } + } + else { + static int tric = 0; + /* debug("%d no tri\n", tric++); */ + } + + if (player->flags & ENT_ON_GROUND && + (was_key_pressed_this_frame(engine, SDL_SCANCODE_SPACE) /*|| + was_button_pressed_this_frame(engine, SDL_CONTROLLER_BUTTON_X)*/)) { + entity_jump(player, 2.0); + } + + /* debug("player velocity %f %f %f\n", */ + /* player->velocity[0], */ + /* player->velocity[1], */ + /* player->velocity[2]); */ + +// if (player->flags & ENT_AT_REST) // vec3_scale(player->velocity, 0.00001, player->velocity); - node_translate(node, player->velocity); - node_recalc(node); + node_translate(node, player->velocity); + node_recalc(node); } +enum binding_structs { + COMMON_UNIFORMS, + CHESS_PIECE_UNIFORMS, +}; + +static struct structure_binding uniform_bindings[] = { + [COMMON_UNIFORMS] = + { common_lenses, ARRAY_SIZE(common_lenses) }, +}; void init_test_gl(struct test_game *game, struct gpu *gpu, int width, int height) { - struct shader vertex, terrain_vertex, chess_piece_vertex, terrain_geom, fragment, fragment_smooth; + struct shader vertex, terrain_vertex, terrain_geom, fragment, fragment_smooth; struct shader terrain_teval, terrain_tc; float tmp_matrix[16]; int ok = 0; + gpu->num_programs = NUM_TEST_GAME_PROGRAMS; // Shaders ok = make_shader(GL_VERTEX_SHADER, SHADER("vertex-color.glsl"), - &vertex); + &vertex); rtassert(ok, "vertex-color shader"); ok = make_shader(GL_VERTEX_SHADER, SHADER("terrain.v.glsl"), &terrain_vertex); rtassert(ok, "terrain vertex shader"); check_gl(); - ok = make_shader(GL_VERTEX_SHADER, SHADER("chess-piece.v.glsl"), &chess_piece_vertex); - rtassert(ok, "chess-piece vertex shader"); - check_gl(); - ok = make_shader(GL_FRAGMENT_SHADER, SHADER("main.f.glsl"), &fragment); rtassert(ok, "default fragment shader"); check_gl(); @@ -303,38 +338,35 @@ void init_test_gl(struct test_game *game, struct gpu *gpu, int width, int height game->proj_persp); struct gpu_program *programs = gpu->programs; - struct gpu_program *program; ok = make_program("terrain", &terrain_vertex, &fragment, - &programs[TERRAIN_PROGRAM]); - // TODO: replace rtassert with error reporting/handling + &programs[TERRAIN_PROGRAM], + uniform_bindings, + ARRAY_SIZE(uniform_bindings)); rtassert(ok, "terrain program"); check_gl(); - ok = make_program("vertex-color", &vertex, &fragment, &programs[DEFAULT_PROGRAM]); + ok = make_program("vertex-color", &vertex, &fragment, + &programs[DEFAULT_PROGRAM], + uniform_bindings, + ARRAY_SIZE(uniform_bindings)); rtassert(ok, "vertex-color program"); check_gl(); - - program = &programs[CHESS_PIECE_PROGRAM]; - ok = make_program("chess-piece", &chess_piece_vertex, &fragment, program); - rtassert(ok, "chess-piece program"); - - find_uniforms(programs); } -void init_gpu_programs(struct gpu *gpu) -{ -} +// TODO: add uniforms automatically? +static void render_test_game(struct game *game, struct test_game *res, struct render_config *config) { + float gtmp[3]; + u32 num_entities; -void render_test_game(struct game *game, struct test_game *res, struct render_config *config) { - float gtmp[3]; + struct common_uniforms *cvars = &res->common_vars; - glEnable(GL_DEPTH_TEST); + cvars->sky_intensity = clamp(cvars->light_intensity, 0.2, 1.0); + vec3_scale(cvars->sun_color, cvars->sky_intensity, gtmp); - float sky_intensity = clamp(res->light_intensity, 0.2, 1.0); - vec3_scale(res->sun_color, sky_intensity, gtmp); + glEnable(GL_DEPTH_TEST); glClearColor( gtmp[0], gtmp[1], gtmp[2], 1.0 ); //clear background screen to black /* glClearColor( 0.5294f * adjust, 0.8078f * adjust, 0.9216f * adjust, 1.0f ); //clear background screen to black */ @@ -346,23 +378,19 @@ void render_test_game(struct game *game, struct test_game *res, struct render_co static float view[MAT4_ELEMS] = { 0 }; static float view_proj[MAT4_ELEMS] = { 0 }; static float normal_matrix[MAT4_ELEMS] = { 0 }; - static float model_view[MAT4_ELEMS] = { 0 }; - static float depth_mvp[MAT4_ELEMS] = { 0 }; + mat4_id(id); - mat4_id(model_view); + mat4_id(cvars->model_view); - mat4 *mvp = res->test_mvp; mat4 *projection = config->projection; - mat4 *light = res->light_dir; struct node *camera_node = get_node(&config->camera); assert(camera_node); const mat4 *camera = camera_node->mat; - u32 num_entities; struct entity *entities = - get_all_entities(&num_entities, NULL); + get_all_entities(&num_entities, NULL); struct gpu_program *program = NULL; @@ -370,11 +398,11 @@ void render_test_game(struct game *game, struct test_game *res, struct render_co mat4_multiply(projection, view, view_proj); if (config->is_depth_pass) { - glDisable(GL_CULL_FACE); - mat4_multiply(bias_matrix, view_proj, config->depth_vp); + glDisable(GL_CULL_FACE); + mat4_multiply(bias_matrix, view_proj, config->depth_vp); } else { - glCullFace(GL_BACK); + glCullFace(GL_BACK); } mat4_inverse((float *)camera, view); @@ -386,6 +414,8 @@ void render_test_game(struct game *game, struct test_game *res, struct render_co glBindTexture(GL_TEXTURE_CUBE_MAP, skybox_model->texture); check_gl(); + cvars->camera_position = (float*)&camera[M_X]; + for (u32 i = 0; i < num_entities; ++i) { struct entity *entity = &entities[i]; struct model *model = get_model(&entity->model_id); @@ -394,44 +424,39 @@ void render_test_game(struct game *game, struct test_game *res, struct render_co assert(node); if (entity->flags & ENT_INVISIBLE) - continue; + continue; if (config->is_depth_pass && !(entity->flags & ENT_CASTS_SHADOWS)) - continue; + continue; program = &game->gpu.programs[model->shader]; glUseProgram(program->handle); check_gl(); - uniform_3f(program, UNIFORM_CAMERA_POSITION, &camera[M_X]); - - if (model->shader == CHESS_PIECE_PROGRAM) { - uniform_1i(program, UNIFORM_IS_WHITE, - (entity->flags & ENT_IS_WHITE) == ENT_IS_WHITE); - } + mat4_multiply(view_proj, node->mat, cvars->mvp); + mat4_copy(node->mat, cvars->model_view); + mat4_multiply(config->depth_vp, cvars->model_view, cvars->depth_mvp); - uniform_1i(program, UNIFORM_FOG_ON, res->fog_on); - uniform_3f(program, UNIFORM_LIGHT_DIR, light); - uniform_1f(program, UNIFORM_LIGHT_INTENSITY, res->light_intensity); - uniform_1f(program, UNIFORM_SKY_INTENSITY, sky_intensity); - uniform_3f(program, UNIFORM_SUN_COLOR, res->sun_color); + void *shader_data[] = { + [COMMON_UNIFORMS] = cvars, + [CHESS_PIECE_UNIFORMS] = entity->data, + }; - mat4_multiply(view_proj, node->mat, mvp); - mat4_copy(node->mat, model_view); - mat4_multiply(config->depth_vp, model_view, depth_mvp); - uniform_m4f(program, UNIFORM_DEPTH_MVP, depth_mvp); - uniform_m4f(program, UNIFORM_MVP, mvp); - uniform_m4f(program, UNIFORM_MODEL, node->mat); + bind_uniforms(program, shader_data, ARRAY_SIZE(shader_data)); + check_gl(); + /* recalc_normals(program->uniforms[UNIFORM_NORMAL_MATRIX].location, - model_view, normal_matrix); + model_view, normal_matrix); + check_gl(); + */ struct geometry *geo = get_geometry(&model->geom_id); /* debug("geo node %s\n", node->label); */ assert(geo); - render_geometry(geo, program->vertex_attrs, program); + render_geometry(geo, program); check_gl(); } @@ -451,7 +476,7 @@ void render_test_game(struct game *game, struct test_game *res, struct render_co } if (config->draw_ui) - render_ui(&game->ui, view); + render_ui(&res->ui, view); //player // y tho @@ -472,17 +497,18 @@ void render_test_game(struct game *game, struct test_game *res, struct render_co void update_test_game (struct game *engine, struct test_game *game) { static int toggle_fog = 0; static int needs_terrain_update = 0; - //struct terrain *terrain = &game->terrain; - struct node *root = get_node(&game->root_id); - struct entity *player = get_player(game); - struct node *pnode = get_node(&player->node_id); - struct node *cam_node = get_node(&game->camera_node_id); + //struct terrain *terrain = &game->terrain; + struct node *root = get_node(&game->root_id); + struct entity *player = get_player(game); + struct node *pnode = get_node(&player->node_id); + struct node *cam_node = get_node(&game->camera_node_id); + struct common_uniforms *cvars = &game->common_vars; assert(pnode); assert(cam_node); float *time = &game->time; - float *light = game->light_dir; + float *light = cvars->light_dir; gravity(player, engine->dt); @@ -491,8 +517,8 @@ void update_test_game (struct game *engine, struct test_game *game) { needs_terrain_update = 0; } - /* spherical_dir(game->test_resources.camera.coords, camera_dir); */ - /* vec3_scale(camera_dir, -1, camera_dir); */ + /* spherical_dir(game->test_resources.camera.coords, camera_dir); */ + /* vec3_scale(camera_dir, -1, camera_dir); */ if (engine->input.modifiers & KMOD_ALT && ideq(&game->camera_node_id, &game->free_camera_id)) @@ -510,8 +536,9 @@ void update_test_game (struct game *engine, struct test_game *game) { player_update(engine, game, player); #ifdef DEBUG - if (was_key_pressed_this_frame(engine, SDL_SCANCODE_R)) + if (was_key_pressed_this_frame(engine, SDL_SCANCODE_R)) { try_reload_shaders(&engine->gpu); + } #endif if (was_key_pressed_this_frame(engine, SDL_SCANCODE_F5)) { @@ -538,7 +565,7 @@ void update_test_game (struct game *engine, struct test_game *game) { } if (toggle_fog) { - game->fog_on = !game->fog_on; + cvars->fog_on ^= 1; toggle_fog = 0; } @@ -563,7 +590,7 @@ void test_game_frame(struct game *engine, struct test_game *game) }; struct render_config default_config = { - .draw_ui = 0, + .draw_ui = 1, .is_depth_pass = 0, .camera = game->camera_node_id, .projection = game->proj_persp, @@ -571,7 +598,7 @@ void test_game_frame(struct game *engine, struct test_game *game) }; struct entity *player = get_entity(&game->player_id); - if (engine->input.resized_height) { + if (engine->input.resized_height) { mat4_perspective(60 /* fov */, (float)engine->width / (float)engine->height, 0.1, 10000.0, game->proj_persp); @@ -580,28 +607,27 @@ void test_game_frame(struct game *engine, struct test_game *game) engine->width, engine->height); } - update_test_game(engine, game); + update_test_game(engine, game); - struct fbo *fbo = &game->shadow_buffer; - check_fbo(fbo); - bind_fbo(fbo); - /* glDrawBuffer(GL_NONE); */ + struct fbo *fbo = &game->shadow_buffer; + check_fbo(fbo); + bind_fbo(fbo); + /* glDrawBuffer(GL_NONE); */ - render_test_game(engine, game, &fbo_render_config); - unbind_fbo(&game->shadow_buffer); - render_test_game(engine, game, &default_config); + render_test_game(engine, game, &fbo_render_config); + unbind_fbo(&game->shadow_buffer); + render_test_game(engine, game, &default_config); } -void init_test_game(struct test_game *game, struct gpu *gpu, int width, int height) +void init_test_game(struct game *engine, struct test_game *game) { memset(game, 0, sizeof(*game)); struct terrain *terrain = &game->terrain; struct entity *player; + struct model *model; + struct common_uniforms *cvars = &game->common_vars; - init_test_gl(game, gpu, width, height); - - mat4 *mvp = game->test_mvp; - mat4 *light_dir = game->light_dir; + init_test_gl(game, &engine->gpu, engine->width, engine->height); init_id(&game->root_id); init_id(&game->sun_camera_id); @@ -618,50 +644,46 @@ void init_test_game(struct test_game *game, struct gpu *gpu, int width, int heig //double scale = 0.03; double scale = 0.03; - create_skybox(&game->skybox, &gpu->programs[SKYBOX_PROGRAM]); + create_skybox(&game->skybox, &engine->gpu.programs[SKYBOX_PROGRAM]); + create_ui(&game->ui, engine->width, engine->height, &engine->gpu.programs[UI_PROGRAM]); terrain->settings = (struct perlin_settings){ - .depth = 1, - .freq = scale * 0.08, - .o1 = 2.0, .o1s = 0.5, - .o2 = 4.0, .o2s = 0.25, - .amplitude = 70.0, - .ox = 0, - .oy = 0, - .exp = 5.3, - .scale = scale + .depth = 1, + .freq = scale * 0.08, + .o1 = 2.0, .o1s = 0.5, + .o2 = 4.0, .o2s = 0.25, + .amplitude = 70.0, + .ox = 0, + .oy = 0, + .exp = 5.3, + .scale = scale }; init_terrain(terrain, size); /* terrain->samples = load_samples(&seed, &terrain->n_samples); */ terrain->n_samples = 0; - //create_terrain(terrain, size, game->seed); - load_terrain(terrain); + create_terrain(terrain, size, engine->seed); + //load_terrain(terrain); /* update_terrain(terrain, terrain->cell_size); */ /* get_entity(&terrain->entity_id)->flags |= ENT_INVISIBLE; */ /* node_scale(&game->skybox.node, size/4.0); */ - mat4_id(mvp); + mat4_id(cvars->mvp); - game->time = 0; - game->light_intensity = 0.8; + cvars->light_intensity = 0.8; - light_dir[0] = 0.8; - light_dir[1] = 0.8; - light_dir[2] = 0.8; + cvars->light_dir[0] = 0.8; + cvars->light_dir[1] = 0.8; + cvars->light_dir[2] = 0.8; - game->piece_color[0] = 1.0; - game->piece_color[1] = 1.0; - game->piece_color[2] = 1.0; + cvars->sun_color[0] = 0.5; + cvars->sun_color[1] = 0.6; + cvars->sun_color[2] = 0.7; - game->sun_color[0] = 0.5; - game->sun_color[1] = 0.6; - game->sun_color[2] = 0.7; - - game->fog_on = 0; - game->diffuse_on = 0; + cvars->fog_on = 0; + //cvars->diffuse_on = 0; node_init(root); node_init(sun_camera); @@ -681,6 +703,7 @@ void init_test_game(struct test_game *game, struct gpu *gpu, int width, int heig player->model_id = get_model_by_name("pirate_officer", NULL); assert(!is_null_id(&player->model_id.id)); + node_set_label(pnode, "player"); /* node_rotate(pnode, V3(-5.0,0,0)); */ node_attach(&player->node_id, &game->root_id); @@ -704,7 +727,7 @@ void init_test_game(struct test_game *game, struct gpu *gpu, int width, int heig // FBO STUFF init_fbo(&game->shadow_buffer); - resize_fbos(player, &game->shadow_buffer, game->proj_ortho, width, height); + resize_fbos(player, &game->shadow_buffer, game->proj_ortho, engine->width, engine->height); // FBO STUFF END // TEXTURES @@ -724,11 +747,12 @@ void default_scene(struct test_game *game) { struct entity *tower = new_entity(NULL); struct node *tnode = get_node(&tower->node_id); + struct node *pnode = get_node(&player->node_id); assert(tnode); tower->model_id = get_model_by_name("tower", NULL); node_set_label(tnode, "tower"); - //node_attach(&tower->node_id, &player->node_id); + node_attach(&tower->node_id, &player->node_id); node_translate(tnode, V3(0.0, 50.0, 0.0)); node_recalc(tnode); float z = terrain->fn(terrain, tnode->mat[M_X], tnode->mat[M_Y]); @@ -740,40 +764,40 @@ void default_scene(struct test_game *game) { void entity_test_scene(struct terrain *terrain) { - struct model_id rock_model; - init_id(&rock_model.id); + struct model_id rock_model; + init_id(&rock_model.id); - /* model_id rock_model = get_static_model(model_tower, NULL); */ - struct model *pmodel = new_model(&rock_model); assert(pmodel); - struct geometry *geom = get_geometry(&pmodel->geom_id); assert(geom); - proc_sphere(geom); + /* model_id rock_model = get_static_model(model_tower, NULL); */ + struct model *pmodel = new_model(&rock_model); assert(pmodel); + struct geometry *geom = get_geometry(&pmodel->geom_id); assert(geom); + proc_sphere(geom); - for (int i = 0; i < 200; i++) { - struct entity *ent = new_entity(NULL); - struct node *node = get_node(&ent->node_id); + for (int i = 0; i < 200; i++) { + struct entity *ent = new_entity(NULL); + struct node *node = get_node(&ent->node_id); - ent->model_id = rock_model; + ent->model_id = rock_model; - double x = rand_0to1() * terrain->size; - double y = rand_0to1() * terrain->size; - double z = terrain->fn(terrain, x, y); + double x = rand_0to1() * terrain->size; + double y = rand_0to1() * terrain->size; + double z = terrain->fn(terrain, x, y); - node_scale(node, pow(15.0, rand_0to1())); - node_rotate(node, V3(rand_0to1(),rand_0to1(),rand_0to1())); - node_translate(node, V3(x, y, z)); - node_set_label(node, "rock"); + node_scale(node, pow(15.0, rand_0to1())); + node_rotate(node, V3(rand_0to1(),rand_0to1(),rand_0to1())); + node_translate(node, V3(x, y, z)); + node_set_label(node, "rock"); - node_recalc(node); - } + node_recalc(node); + } } void pbr_scene(struct test_game *game) { - struct entity *ent = new_entity(NULL); - struct node *node = get_node(&ent->node_id); assert(node); - struct entity *player = get_player(game); + struct entity *ent = new_entity(NULL); + struct node *node = get_node(&ent->node_id); assert(node); + struct entity *player = get_player(game); - ent->model_id = get_model_by_name("icosphere", NULL); - node_set_label(node, "sphere"); + ent->model_id = get_model_by_name("icosphere", NULL); + node_set_label(node, "sphere"); } diff --git a/src/test_game.h b/src/test_game.h @@ -10,11 +10,38 @@ #include "gpu.h" #include "game.h" +enum test_game_programs { + DEFAULT_PROGRAM, + TERRAIN_PROGRAM, + UI_PROGRAM, + SKYBOX_PROGRAM, + CHESS_PIECE_PROGRAM, + NUM_TEST_GAME_PROGRAMS, +}; + +struct common_uniforms { +// int diffuse_on; + int fog_on; + float sky_intensity; + float light_intensity; + float depth_mvp[MAT4_ELEMS]; + // mat4 *depth_vp; + float model_view[MAT4_ELEMS]; + float mvp[MAT4_ELEMS]; + float normal_matrix[MAT4_ELEMS]; + // float time; + // float ambient_str; + float sun_color[3]; + float *camera_position; + float light_dir[3]; +}; + struct test_game { struct terrain terrain; struct vbo vertex_buffer, element_buffer, normal_buffer; struct fbo shadow_buffer; + struct common_uniforms common_vars; node_id root_id; entity_id player_id; struct geometry qh_test; @@ -25,26 +52,22 @@ struct test_game { u32 test_cubemap; float time; - bool fog_on, diffuse_on; struct skybox skybox; - float sun_color[3]; - float piece_color[3]; - float test_mvp[MAT4_ELEMS]; - float light_dir[3]; - float light_intensity; + struct ui ui; float proj_persp[MAT4_ELEMS]; float proj_ortho[MAT4_ELEMS]; }; void init_test_gl(struct test_game *game, struct gpu *gpu, int width, int height); -void render_test_game(struct game *engine, struct test_game *game, struct render_config *config); -void init_test_game(struct test_game *game, struct gpu *gpu, int width, int height); +void init_test_game(struct game *engine, struct test_game *game); void test_game_frame(struct game *engine, struct test_game *game); void default_scene(struct test_game *); void entity_test_scene(struct terrain *); void pbr_scene(struct test_game *); -void chess_scene(struct test_game *); +void chess_scene(struct game *, struct test_game *); +struct lens *get_common_lenses(); +int get_common_lenses_length(); diff --git a/src/ui.c b/src/ui.c @@ -5,8 +5,7 @@ #include "geometry.h" #include "util.h" #include "common.h" - -#include <stdio.h> +#include "data_id.h" // v1------v0 @@ -53,29 +52,43 @@ static void create_quad(geometry_id *id) check_gl(); } -void render_ui(struct ui *ui, float *view) { - static float mvp[MAT4_ELEMS]; - glDisable(GL_DEPTH_TEST); - glUseProgram(ui->shader->handle); - check_gl(); - - float uipos[2] = {0.01, 0.01}; - float uisize[2] = {0.4, 0.4}; - mat4_multiply(ui->ortho, view, mvp); - - // setup camera for shader - /* glUniform2f(ui->uipos_uniform, uipos[0] * uisize[0], uipos[1] * uisize[1]); */ - glUniform2f(ui->uniforms.uipos, uipos[0], uipos[1]); - glUniform2f(ui->uniforms.uisize, uisize[0], uisize[1]); - glUniform1i(ui->uniforms.texture, 0); +#define UI_LENS(field, typ) { #field, offsetof(struct ui, field), DATA_ID_##typ } +static struct lens ui_lenses[] = { + UI_LENS(uipos, VEC2), + UI_LENS(uisize, VEC2), + UI_LENS(mvp, MAT4P), + UI_LENS(texture, INT), +}; +#undef UI_LENS - glUniformMatrix4fv(ui->uniforms.mvp, 1, 0, ui->ortho); - check_gl(); +static struct structure_binding ui_bindings[] = { + { ui_lenses, ARRAY_SIZE(ui_lenses) }, +}; - // render quad - render_geometry(get_geometry(&ui->quad_geom_id), ui->attrs, ui->shader); - check_gl(); +void render_ui(struct ui *ui, float *view) { + glDisable(GL_DEPTH_TEST); + glUseProgram(ui->shader->handle); + check_gl(); + + ui->uipos[0] = 0.01; + ui->uipos[1] = 0.01; + ui->uisize[0] = 0.4; + ui->uisize[1] = 0.4; + ui->texture = 0; + + void *structures[] = { ui }; + + assert(ARRAY_SIZE(structures) == ARRAY_SIZE(ui_bindings)); + + ui->mvp = ui->ortho; + //mat4_multiply(ui->ortho, view, ui->mvp); + bind_uniforms(ui->shader, structures, ARRAY_SIZE(structures)); + check_gl(); + + // render quad + render_geometry(get_geometry(&ui->quad_geom_id), ui->shader); + check_gl(); } @@ -90,7 +103,6 @@ void resize_ui(struct ui *ui, int width, int height) { mat4_ortho(left, right, bottom, top, near, far, ui->ortho); } - void create_ui(struct ui *ui, int width, int height, struct gpu_program *shader) { struct shader vertex; struct shader fragment; @@ -108,23 +120,10 @@ void create_ui(struct ui *ui, int width, int height, struct gpu_program *shader) ok = make_shader(GL_FRAGMENT_SHADER, SHADER("ui.f.glsl"), &fragment); assert(ok && "ui fragment shader"); - ok = make_program("ui", &vertex, &fragment, ui->shader); + ok = make_program("ui", &vertex, &fragment, ui->shader, ui_bindings, + ARRAY_SIZE(ui_bindings)); assert(ok && "ui program"); - GLuint program = ui->shader->handle; - - ui->uniforms.mvp = glGetUniformLocation(program, "mvp"); - ui->uniforms.uipos = glGetUniformLocation(program, "uipos"); - ui->uniforms.uisize = glGetUniformLocation(program, "uisize"); - - ui->uniforms.texture = - glGetUniformLocation(program, "screen_texture"); - - /* ui->attrs.normal = (gpu_addr)glGetAttribLocation(program, "normal"); */ - ui->attrs[va_position] = (gpu_addr)glGetAttribLocation(program, "position"); - ui->attrs[va_color] = (gpu_addr)glGetAttribLocation(program, "color"); - ui->attrs[va_tex_coord] = (gpu_addr)glGetAttribLocation(program, "tex_coords"); - check_gl(); resize_ui(ui, width, height); check_gl(); diff --git a/src/ui.h b/src/ui.h @@ -7,18 +7,15 @@ #include "geometry.h" struct ui { - struct gpu_program *shader; - geometry_id quad_geom_id; - gpu_addr attrs[MAX_VERTEX_ATTRS]; - - struct ui_uniforms { - GLint mvp; - GLint uipos; - GLint uisize; - GLint texture; - } uniforms; - - float ortho[MAT4_ELEMS]; + struct gpu_program *shader; + geometry_id quad_geom_id; + + GLint texture; + float uipos[2]; + float uisize[2]; + + float *mvp; + float ortho[MAT4_ELEMS]; }; void create_ui(struct ui *ui, int width, int height, diff --git a/src/update.c b/src/update.c @@ -16,25 +16,3 @@ #include "debug.h" #include <math.h> - -static void remap_samples(struct point *points, int n_samples, - double size) -{ - double middle = size / 2.0; - - for (int i = 0; i < n_samples; ++i) { - struct point *point = &points[i]; - - /* double x = point->x/size; */ - /* double y = point->y/size; */ - double dx = point->x - middle; - double dy = point->y - middle; - double dist = sqrt(dx*dx + dy*dy); - double nx = dx / dist; - double ny = dy / dist; - double factor = -log(dist)*50.0; - point->x += nx * factor; - point->y += ny * factor; - } -} - diff --git a/src/vbo.h b/src/vbo.h @@ -17,6 +17,18 @@ enum vertex_attr { MAX_VERTEX_ATTRS }; +static inline const char *vertex_attr_str(enum vertex_attr addr) +{ + switch(addr) { + case va_position: return "position"; + case va_normal: return "normal"; + case va_color: return "color"; + case va_index: return "index"; + case va_tex_coord: return "tex_coord"; + default: return "unknown"; + } +} + struct vbo { u32 type; int component_type; diff --git a/test/test_data_id.c b/test/test_data_id.c @@ -0,0 +1,63 @@ + +#include "resource.h" +#include "data_id.h" +#include <stdio.h> + +struct test_struct { + struct { + char ca, cb; + int bleh; + } s; + float a; + float mat4[MAT4_ELEMS]; + float b; +}; + +static void test_data_ids() +{ + printf("test_data_ids\n"); + struct resource_manager r; + struct resource_id id; + struct test_struct *ts; + struct data_id a_id, b_id; + float a, b; + int ret; + // 2 item case + init_resource_manager(&r, sizeof(struct test_struct), 1, 2, "test_struct"); + init_id(&id); + + ts = new_resource(&r, &id); + assert(ts); + + new_resource_data_id(&a_id, &r, id, DATA_ID_FLOAT, struct test_struct, a); + new_ptr_data_id(&b_id, &a, DATA_ID_FLOAT); + + ts->a = 1337.0; + ts->b = 123.0; + + assert(get_data_id_float(&a_id, &a)); + + assert(a == 1337.0); + a = 123.0; + + assert(get_data_id_float(&b_id, &b)); + assert(b == 123.0); + + destroy_resource(&r, &id); + ret = get_data_id_float(&a_id, &a); + assert(ret == 0); + assert(is_resource_destroyed(&r, &a_id.res_id.id)); + + b = 0.0; + assert(get_data_id_float(&b_id, &b)); + assert(b == 123.0); + + destroy_resource_manager(&r); +} + +int main(int argc, char *argv[]) +{ + test_data_ids(); + + return 0; +} diff --git a/tools/compile-model.c b/tools/compile-model.c @@ -60,7 +60,7 @@ int main(int argc, char *argv[]) int ok = parse_ply_with_mkgeom(filename, &mdl_geom); assert(ok); - save_mdl(outfile, &mdl_geom); + save_mdl(outfile, &model, &mdl_geom); return 0; }