From 013718658263796b655ed2eb711042e5b5403362 Mon Sep 17 00:00:00 2001 From: Emil Kosz Date: Sun, 20 Jul 2025 23:16:30 +0200 Subject: [PATCH] Primitive pak loader --- game/res/manifest.cfg | 51 +++++++ game/res/scripts/entity_templates.scm | 28 ++-- game/res/scripts/resources.scm | 19 --- game/src/chunk/chunkman.c | 14 +- game/src/chunk/chunkman.h | 1 + game/src/entity/entity_guile.c | 110 +++++++++++++++ game/src/entity/entity_guile.h | 7 + game/src/entity/entman.c | 4 +- game/src/entity/entman.h | 2 +- game/src/entity/templates.c | 99 +------------ game/src/entity/templates.h | 7 +- game/src/graphics.c | 6 +- game/src/graphics.h | 2 +- game/src/main.c | 11 +- game/src/pak/pak_guile.c | 24 ++++ game/src/pak/pak_guile.h | 7 + game/src/pak/pakman.c | 193 +++++++++++++++++++++++++ game/src/pak/pakman.h | 27 ++++ game/src/resources.c | 196 -------------------------- game/src/resources.h | 20 --- game/src/ui/widget_core.h | 2 +- game/src/ui/widget_render.c | 89 ++++++------ 22 files changed, 508 insertions(+), 411 deletions(-) create mode 100644 game/res/manifest.cfg delete mode 100644 game/res/scripts/resources.scm create mode 100644 game/src/entity/entity_guile.c create mode 100644 game/src/entity/entity_guile.h create mode 100644 game/src/pak/pak_guile.c create mode 100644 game/src/pak/pak_guile.h create mode 100644 game/src/pak/pakman.c create mode 100644 game/src/pak/pakman.h delete mode 100644 game/src/resources.c delete mode 100644 game/src/resources.h diff --git a/game/res/manifest.cfg b/game/res/manifest.cfg new file mode 100644 index 0000000..036543b --- /dev/null +++ b/game/res/manifest.cfg @@ -0,0 +1,51 @@ +[Metadata] +id=base +name=Wschód + +# In this section, all the programs (commonly called "shaders") are +# loaded. These can be referenced from Guile. In this instance, since +# it's a base game package, they are also referenced in the C +# code. Modifying this can fuck up your game big time, so do a backup. +[Programs] +default=res/shaders/default.vert;res/shaders/default.frag +chunk=res/shaders/chunk.vert;res/shaders/chunk.frag +clouds=res/shaders/clouds.vert;res/shaders/clouds.frag +uiwidget=res/shaders/uiwidget.vert;res/shaders/uiwidget.frag +uitext=res/shaders/uitext.vert;res/shaders/uitext.frag +uidummy=res/shaders/uidummy.vert;res/shaders/uidummy.frag + +# In this section we load textures. I think a lot of formats should be +# supported, but RGBA PNG is what I use. All of these can be +# referenced from Guile, and some of these are referenced in C (all +# the terrains, font0 and icons). +[Textures] +font0=res/textures/font_9x20.png +icons=res/textures/icons.png + +terrain0=res/textures/dirt.png +terrain1=res/textures/drygrass.png +terrain2=res/textures/grass.png +terrain3=res/textures/rock_cement.png +terrain4=res/textures/asphalt_gravel.png + +tree0=res/textures/tree.png +grass0=res/textures/grass0.png +clouds=res/textures/clouds.png + +# The heightmap converts white (the highest) and black (the lowest) +# and everything inbetween into floating point values. The texturemap +# just uses all the RGBA channels as texture info (R=1, texture1, G=1, +# texture2, all 0, texture0, &c.). The entity map should base its +# colors on the colors defined in entity_templates.scm. The 0-1 in +# heightmap bitmap is multiplied by `heightmult`, and that's how many +# metres 1 is. +[Map] +heightmult=16 +heightmap=res/map/heightmap.png +texturemap=res/map/texturemap.png +entitymap=res/map/entitymap.png + +# The scripts are loaded and executed after everything above has been +# loaded, so that Guile has some stuff to work with. +[Scripts] +global=res/scripts/ui_styles.scm;res/scripts/ui_composites.scm \ No newline at end of file diff --git a/game/res/scripts/entity_templates.scm b/game/res/scripts/entity_templates.scm index 137da61..ce103ae 100644 --- a/game/res/scripts/entity_templates.scm +++ b/game/res/scripts/entity_templates.scm @@ -1,18 +1,20 @@ (register-entity-template "tree" - #:mesh-type 'quad-x - #:cull-distance 70 ;in % - #:wavy #t - #:scale '(3.0 8.0 3.0) - #:texture (get-texture "tree0") - #:program (get-program "default")) + (entity-new + #:mesh-type 'quad-x + #:cull-distance 70 ;in % + #:wavy #t + #:scale '(3.0 8.0 3.0) + #:texture (pak-texture "base" "tree0") + #:program (pak-program "base" "default"))) (register-entity-template "grass" - #:mesh-type 'quad-1 - #:render-type 'billboard-y - #:cull-distance 20 ;in % - #:wavy #t - #:scale '(1.0 0.5 1.0) - #:texture (get-texture "grass0") - #:program (get-program "default")) + (entity-new + #:mesh-type 'quad-1 + #:render-type 'billboard-y + #:cull-distance 20 ;in % + #:wavy #t + #:scale '(1.0 0.5 1.0) + #:texture (pak-texture "base" "grass0") + #:program (pak-program "base" "default"))) diff --git a/game/res/scripts/resources.scm b/game/res/scripts/resources.scm deleted file mode 100644 index 2d65d0b..0000000 --- a/game/res/scripts/resources.scm +++ /dev/null @@ -1,19 +0,0 @@ -(register-program "default" "res/shaders/default.vert" "res/shaders/default.frag") -(register-program "chunk" "res/shaders/chunk.vert" "res/shaders/chunk.frag") -(register-program "clouds" "res/shaders/clouds.vert" "res/shaders/clouds.frag") -(register-program "uiwidget" "res/shaders/uiwidget.vert" "res/shaders/uiwidget.frag") -(register-program "uitext" "res/shaders/uitext.vert" "res/shaders/uitext.frag") -(register-program "uidummy" "res/shaders/uidummy.vert" "res/shaders/uidummy.frag") - -(register-texture "terrain0" "res/textures/dirt.png") -(register-texture "terrain1" "res/textures/drygrass.png") -(register-texture "terrain2" "res/textures/grass.png") -(register-texture "terrain3" "res/textures/rock_cement.png") -(register-texture "terrain4" "res/textures/asphalt_gravel.png") - -(register-texture "tree0" "res/textures/tree.png") -(register-texture "grass0" "res/textures/grass0.png") -(register-texture "clouds" "res/textures/clouds.png") - -(register-texture "font0" "res/textures/font_9x20.png") -(register-texture "icons" "res/textures/icons.png") diff --git a/game/src/chunk/chunkman.c b/game/src/chunk/chunkman.c index 71b1a1b..8fee647 100644 --- a/game/src/chunk/chunkman.c +++ b/game/src/chunk/chunkman.c @@ -160,13 +160,13 @@ chunkman_render (vec3 position, vec4 planes[6]) int cx = 0, cz = 0; chunkman_world_to_chunk (position[0], position[2], &cx, &cz); - program_use (RESPRG ("chunk")); + program_use (PMPRG ("chunk")); - texture_use (RESTEX ("terrain0"), 0); - texture_use (RESTEX ("terrain1"), 1); - texture_use (RESTEX ("terrain2"), 2); - texture_use (RESTEX ("terrain3"), 3); - texture_use (RESTEX ("terrain4"), 4); + texture_use (PMTEX ("terrain0"), 0); + texture_use (PMTEX ("terrain1"), 1); + texture_use (PMTEX ("terrain2"), 2); + texture_use (PMTEX ("terrain3"), 3); + texture_use (PMTEX ("terrain4"), 4); int render_distance = gvar_get ("render_distance"); int frame_chunks = 0; @@ -202,7 +202,7 @@ chunkman_render (vec3 position, vec4 planes[6]) bound = true; } - program_set_vec3_ind (RESPRG ("chunk"), "chunk_position", x * CHUNK_DIM, 0.0, z * CHUNK_DIM); + program_set_vec3_ind (PMPRG ("chunk"), "chunk_position", x * CHUNK_DIM, 0.0, z * CHUNK_DIM); ChunkMesh_render (mesh, FLAG_GET ("wireframe_enabled")); frame_chunks++; } diff --git a/game/src/chunk/chunkman.h b/game/src/chunk/chunkman.h index 2611a35..cb3b577 100644 --- a/game/src/chunk/chunkman.h +++ b/game/src/chunk/chunkman.h @@ -9,6 +9,7 @@ #include "../entity/entman.h" #include "../graphics.h" #include "../gvar.h" +#include "../pak/pakman.h" #define TERRAIN_HEIGHT 8.0 diff --git a/game/src/entity/entity_guile.c b/game/src/entity/entity_guile.c new file mode 100644 index 0000000..788bb44 --- /dev/null +++ b/game/src/entity/entity_guile.c @@ -0,0 +1,110 @@ +#include "entity_guile.h" + +static int +_symbol_to_mesh_type (SCM sym) +{ + if (scm_is_eq (sym, scm_from_utf8_symbol ("quad-x"))) return MESH_QUAD_X; + if (scm_is_eq (sym, scm_from_utf8_symbol ("quad-2"))) return MESH_QUAD2; + return MESH_QUAD1; +} + +static int +_symbol_to_origin (SCM sym) +{ + if (scm_is_eq (sym, scm_from_utf8_symbol ("bottom"))) return ORIGIN_BOTTOM; + return ORIGIN_CENTER; +} + +static int +_symbol_to_render_type (SCM sym) +{ + if (scm_is_eq (sym, scm_from_utf8_symbol ("billboard-y"))) return RENDER_BILLBOARD_Y; + if (scm_is_eq (sym, scm_from_utf8_symbol ("billboard"))) return RENDER_BILLBOARD; + return RENDER_NORMAL; +} + +static SCM +_scm_entity_new (SCM rest) +{ + Entity *e = Entity_new (); + + while (!scm_is_null (rest)) + { + SCM keyword = scm_car (rest); rest = scm_cdr (rest); + SCM value = scm_car (rest); rest = scm_cdr (rest); + + SCM sym = scm_keyword_to_symbol (keyword); + const char *kw = scm_to_utf8_string (scm_symbol_to_string (sym)); + + if (g_strcmp0 (kw, "mesh-type") == 0) + { + e->mesh_type = _symbol_to_mesh_type (value); + } + + if (g_strcmp0 (kw, "origin") == 0) + { + e->mesh_type = _symbol_to_origin (value); + } + + else if (g_strcmp0 (kw, "render-type") == 0) + { + e->render_type = _symbol_to_render_type (value); + } + + else if (g_strcmp0 (kw, "visible") == 0) + { + e->visible = scm_is_true (value); + } + + else if (g_strcmp0 (kw, "dont-cull") == 0) + { + e->dont_cull = scm_is_true (value); + } + + else if (g_strcmp0 (kw, "cull-distance") == 0) + { + e->cull_distance = scm_to_int (value); + } + + else if (g_strcmp0 (kw, "wavy") == 0) + { + e->wavy = scm_is_true (value); + } + + else if (g_strcmp0 (kw, "scale") == 0) + { + for (int i = 0; i < 3; ++i) + { + e->scale[i] = scm_to_double (scm_list_ref (value, scm_from_int (i))); + } + } + + else if (g_strcmp0 (kw, "texture") == 0) + { + e->texture = scm_to_int (value); + } + + else if (g_strcmp0 (kw, "program") == 0) + { + e->program = scm_to_int (value); + } + } + + return scm_from_pointer (e, NULL); +} + +static SCM +_scm_register_entity_template (SCM name_scm, SCM ent_scm) +{ + char *key = scm_to_utf8_string (name_scm); + Entity *ent = scm_to_pointer (ent_scm); + ent_templates_add (key, ent); + return SCM_UNSPECIFIED; +} + +void +entity_guile_register () +{ + scm_c_define_gsubr ("entity-new", 0, 0, 1, _scm_entity_new); + scm_c_define_gsubr ("register-entity-template", 2, 0, 0, _scm_register_entity_template); +} diff --git a/game/src/entity/entity_guile.h b/game/src/entity/entity_guile.h new file mode 100644 index 0000000..71e1c23 --- /dev/null +++ b/game/src/entity/entity_guile.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +#include "templates.h" + +void entity_guile_register (); diff --git a/game/src/entity/entman.c b/game/src/entity/entman.c index 8f9d128..b8e115a 100644 --- a/game/src/entity/entman.c +++ b/game/src/entity/entman.c @@ -51,8 +51,8 @@ entman_init () glm_vec3_copy ((vec3) { 5000.0, 5000.0, 5000.0 }, sky_entity->scale); glm_vec3_copy ((vec3) { 0.0, 200.0, 0.0 }, sky_entity->position); glm_vec3_copy ((vec3) { 90.0, 0.0, 0.0 }, sky_entity->rotation); - sky_entity->texture = RESTEX ("clouds"); - sky_entity->program = RESPRG ("clouds"); + sky_entity->texture = PMTEX ("clouds"); + sky_entity->program = PMPRG ("clouds"); ENTADD (sky_entity); } diff --git a/game/src/entity/entman.h b/game/src/entity/entman.h index a1dbbfb..d235bc6 100644 --- a/game/src/entity/entman.h +++ b/game/src/entity/entman.h @@ -10,11 +10,11 @@ #include "templates.h" #include "../gl/mesh.h" #include "../util.h" -#include "../resources.h" #include "../state.h" #include "../chunk/chunkman.h" #include "../graphics.h" #include "../gvar.h" +#include "../pak/pakman.h" #define ENTADD(entity) (entman_add_entity (entity)) diff --git a/game/src/entity/templates.c b/game/src/entity/templates.c index 7fc4a34..e362299 100644 --- a/game/src/entity/templates.c +++ b/game/src/entity/templates.c @@ -2,24 +2,9 @@ static GHashTable *templates; -static inline void -ent_templates_add (char *key, Entity *entity) -{ - g_hash_table_insert (templates, key, entity); -} - - -Entity * -ent_templates_get (char *key) -{ - return (Entity *) g_hash_table_lookup (templates, key); -} - -Entity * -ent_templates_clone (char *key) -{ - return g_memdup2 (ent_templates_get (key), sizeof (Entity)); -} +Entity *ent_templates_get (char *key) { return (Entity *) g_hash_table_lookup (templates, key); } +void ent_templates_add (char *key, Entity *entity) { g_hash_table_insert (templates, key, entity); } +Entity *ent_templates_clone (char *key) { return g_memdup2 (ent_templates_get (key), sizeof (Entity)); } void ent_templates_init () @@ -27,81 +12,3 @@ ent_templates_init () templates = g_hash_table_new (g_str_hash, g_str_equal); scm_c_primitive_load ("res/scripts/entity_templates.scm"); } - -static int -symbol_to_mesh_type (SCM sym) -{ - if (scm_is_eq (sym, scm_from_utf8_symbol ("quad-x"))) return MESH_QUAD_X; - if (scm_is_eq (sym, scm_from_utf8_symbol ("quad-1"))) return MESH_QUAD1; - return 0; -} - -static int -symbol_to_render_type (SCM sym) -{ - if (scm_is_eq (sym, scm_from_utf8_symbol ("billboard-y"))) return RENDER_BILLBOARD_Y; - return 0; -} - -static SCM -_scm_register_entity_template (SCM name_scm, SCM rest) -{ - Entity *e = Entity_new (); - const char *key = scm_to_utf8_string (name_scm); - - while (!scm_is_null (rest)) - { - SCM keyword = scm_car (rest); rest = scm_cdr (rest); - SCM value = scm_car (rest); rest = scm_cdr (rest); - - SCM sym = scm_keyword_to_symbol (keyword); - const char *kw = scm_to_utf8_string (scm_symbol_to_string (sym)); - - if (g_strcmp0 (kw, "mesh-type") == 0) - { - e->mesh_type = symbol_to_mesh_type (value); - } - - else if (g_strcmp0 (kw, "render-type") == 0) - { - e->render_type = symbol_to_render_type (value); - } - - else if (g_strcmp0 (kw, "cull-distance") == 0) - { - e->cull_distance = scm_to_int (value); - } - - else if (g_strcmp0 (kw, "wavy") == 0) - { - e->wavy = scm_is_true (value); - } - - else if (g_strcmp0 (kw, "scale") == 0) - { - for (int i = 0; i < 3; ++i) - { - e->scale[i] = scm_to_double (scm_list_ref (value, scm_from_int (i))); - } - } - - else if (g_strcmp0 (kw, "texture") == 0) - { - e->texture = scm_to_int (value); - } - - else if (g_strcmp0 (kw, "program") == 0) - { - e->program = scm_to_int (value); - } - } - - ent_templates_add ((char *) key, e); - return SCM_UNSPECIFIED; -} - -void -ent_templates_guile_register () -{ - scm_c_define_gsubr ("register-entity-template", 1, 0, 1, _scm_register_entity_template); -} diff --git a/game/src/entity/templates.h b/game/src/entity/templates.h index 43ac297..952e315 100644 --- a/game/src/entity/templates.h +++ b/game/src/entity/templates.h @@ -4,12 +4,13 @@ #include #include +#include #include "entity.h" -#include "../resources.h" void ent_templates_init (); -void ent_templates_guile_register (); -Entity *ent_templates_clone (char *key); Entity *ent_templates_get (char *key); +void ent_templates_add (char *key, Entity *entity); +Entity *ent_templates_clone (char *key); + diff --git a/game/src/graphics.c b/game/src/graphics.c index 5f70d7e..8f2c2b7 100644 --- a/game/src/graphics.c +++ b/game/src/graphics.c @@ -68,9 +68,9 @@ graphics_render () camera_get_projection (gvar_get ("window_width") / gvar_get ("window_height"), projection); camera_get_view (view); - resources_programs_set_mat4 ("projection", &projection); - resources_programs_set_mat4 ("view", &view); - resources_programs_set_float ("time", gvar_get ("last_time")); + pakman_all_paks_set_mat4 ("projection", projection); + pakman_all_paks_set_mat4 ("view", view); + pakman_all_paks_set_float ("time", gvar_get ("last_time")); vec4 planes[6]; #if FRUSTUM_CULL diff --git a/game/src/graphics.h b/game/src/graphics.h index 94f11de..cc20af9 100644 --- a/game/src/graphics.h +++ b/game/src/graphics.h @@ -8,9 +8,9 @@ #include "chunk/chunkman.h" #include "entity/entman.h" #include "state.h" -#include "resources.h" #include "util.h" #include "gvar.h" +#include "pak/pakman.h" #define FRUSTUM_CULL 1 diff --git a/game/src/main.c b/game/src/main.c index 5bff043..b3d6a91 100644 --- a/game/src/main.c +++ b/game/src/main.c @@ -5,12 +5,14 @@ #include "event/evtman.h" #include "chunk/chunkman.h" #include "entity/templates.h" +#include "entity/entity_guile.h" #include "ui/uiman.h" #include "ui/widget_guile.h" #include "state.h" -#include "resources.h" #include "graphics.h" #include "gvar.h" +#include "pak/pakman.h" +#include "pak/pak_guile.h" extern vec3 camera_position; @@ -22,13 +24,14 @@ SDL_AppInit (void **appstate, int argc, char **argv) scm_init_guile (); gvar_guile_register (); - resources_guile_register (); widget_guile_register (); - ent_templates_guile_register (); + entity_guile_register (); + pak_guile_register (); gvar_init (); graphics_init (); - resources_init (); + pakman_init (); + pakman_load_pak ("res/"); evtman_init (); uiman_init (); diff --git a/game/src/pak/pak_guile.c b/game/src/pak/pak_guile.c new file mode 100644 index 0000000..e9eb79b --- /dev/null +++ b/game/src/pak/pak_guile.c @@ -0,0 +1,24 @@ +#include "pak_guile.h" + +static SCM +_scm_get_program (SCM pak_scm, SCM key_scm) +{ + const char *pak = scm_to_utf8_string (pak_scm); + const char *key = scm_to_utf8_string (key_scm); + return scm_from_int (pakman_pak_program (pak, key)); +} + +static SCM +_scm_get_texture (SCM pak_scm, SCM key_scm) +{ + const char *pak = scm_to_utf8_string (pak_scm); + const char *key = scm_to_utf8_string (key_scm); + return scm_from_int (pakman_pak_texture (pak, key)); +} + +void +pak_guile_register () +{ + scm_c_define_gsubr ("pak-program", 2, 0, 0, _scm_get_program); + scm_c_define_gsubr ("pak-texture", 2, 0, 0, _scm_get_texture); +} diff --git a/game/src/pak/pak_guile.h b/game/src/pak/pak_guile.h new file mode 100644 index 0000000..b40f388 --- /dev/null +++ b/game/src/pak/pak_guile.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +#include "pakman.h" + +void pak_guile_register (); diff --git a/game/src/pak/pakman.c b/game/src/pak/pakman.c new file mode 100644 index 0000000..cd9a2cd --- /dev/null +++ b/game/src/pak/pakman.c @@ -0,0 +1,193 @@ +#include "pakman.h" + +static GHashTable *paks; + +void +pakman_init () +{ + paks = g_hash_table_new (g_str_hash, g_str_equal); +} + +unsigned int +_pm_load_program (const char *v_path, const char *f_path) +{ + char *v_src; + + if (!g_file_get_contents (v_path, &v_src, NULL, NULL)) + { + g_warning ("File `%s' does not exist.", v_path); + } + + char *f_src; + + if (!g_file_get_contents (f_path, &f_src, NULL, NULL)) + { + g_warning ("File `%s' does not exist.", f_path); + } + + unsigned int program = program_create (v_src, f_src); + g_free (v_src); + g_free (f_src); + return program; +} + +unsigned int +_pm_load_texture (const char *path) +{ + SDL_Surface *surface = IMG_Load (path); + + if (surface == NULL) + { + g_warning ("Failed to load texture from path %s: %s", path, SDL_GetError ()); + return 0; + } + + unsigned int texture = texture_create (surface->w, surface->h, surface->pixels); + return texture; +} + +void +pakman_load_pak (const char *path) +{ + GError *err = NULL; + GKeyFile *key_file = g_key_file_new (); + + char *manifest_path = g_build_filename (path, "manifest.cfg", NULL); + + g_debug ("Loading .pak mainfest from %s...", manifest_path); + + if (!g_key_file_load_from_file (key_file, manifest_path, G_KEY_FILE_NONE, &err)) + { + g_error ("Error loading .pak manifest.cfg: %s", err->message); + return; + } + + PakFile *pak = g_new0 (PakFile, 1); + pak->programs = g_hash_table_new (g_str_hash, g_str_equal); + pak->textures = g_hash_table_new (g_str_hash, g_str_equal); + + char **programs = g_key_file_get_keys (key_file, "Programs", NULL, &err); + + for (char **p = programs; *p != NULL; p++) + { + size_t n_shaders; + char **shaders = g_key_file_get_string_list (key_file, "Programs", *p, &n_shaders, &err); + + if (n_shaders == 2) + { + g_hash_table_insert (pak->programs, g_strdup (*p), GUINT_TO_POINTER (_pm_load_program (shaders[0], shaders[1]))); + } + else + { + g_warning ("Program %s does not have 2 shaders.", *p); + } + } + + char **textures = g_key_file_get_keys (key_file, "Textures", NULL, &err); + + for (char **t = textures; *t != NULL; t++) + { + char *texture = g_key_file_get_string (key_file, "Textures", *t, &err); + g_hash_table_insert (pak->textures, g_strdup (*t), GUINT_TO_POINTER (_pm_load_texture (texture))); + } + + char *id = g_key_file_get_string (key_file, "Metadata", "id", &err); + g_hash_table_insert (paks, g_strdup (id), pak); + + /* Some hacks. */ + program_use (pakman_pak_program (id, "chunk")); + program_set_int_array (pakman_pak_program (id, "chunk"), "materials", 5, (int[5]) { 0, 1, 2, 3, 4 }); + program_use (pakman_pak_program (id, "uiwidget")); + program_set_int (pakman_pak_program (id, "uiwidget"), "background_image", 0); + program_set_int (pakman_pak_program (id, "uiwidget"), "icons", 1); + + g_key_file_free (key_file); +} + +unsigned int +pakman_pak_program (const char *pak, const char *program) +{ + PakFile *p = g_hash_table_lookup (paks, pak); + + if (!p) + { + g_warning ("Pak `%s' not found.", pak); + return 0; + } + + gpointer value = g_hash_table_lookup (p->programs, program); + + if (!value) + { + g_warning ("Program `%s' not found in pak `%s'.", program, pak); + return 0; + } + + return GPOINTER_TO_UINT (value); +} + +unsigned int +pakman_pak_texture (const char *pak, const char *texture) +{ + PakFile *p = g_hash_table_lookup (paks, pak); + + if (!p) + { + g_warning ("Pak `%s' not found.", pak); + return 0; + } + + gpointer value = g_hash_table_lookup (p->textures, texture); + + if (!value) + { + g_warning ("Texture `%s' not found in pak `%s'.", texture, pak); + return 0; + } + + return GPOINTER_TO_UINT (value); +} + +void +pakman_all_paks_set_mat4 (const char *uniform, mat4 value) +{ + GHashTableIter pack_iter; + PakFile *pak; + + g_hash_table_iter_init (&pack_iter, paks); + while (g_hash_table_iter_next (&pack_iter, NULL, (void **) &pak)) + { + GHashTableIter program_iter; + void *program_value; + + g_hash_table_iter_init (&program_iter, pak->programs); + while (g_hash_table_iter_next (&program_iter, NULL, (void **) &program_value)) + { + unsigned int program = GPOINTER_TO_UINT (program_value); + program_use (program); + program_set_mat4 (program, uniform, value); + } + } +} + +void +pakman_all_paks_set_float (const char *uniform, float value) +{ + GHashTableIter pack_iter; + PakFile *pak; + + g_hash_table_iter_init (&pack_iter, paks); + while (g_hash_table_iter_next (&pack_iter, NULL, (void **) &pak)) + { + GHashTableIter program_iter; + void *program_value; + + g_hash_table_iter_init (&program_iter, pak->programs); + while (g_hash_table_iter_next (&program_iter, NULL, (void **) &program_value)) + { + unsigned int program = GPOINTER_TO_UINT (program_value); + program_use (program); + program_set_float (program, uniform, value); + } + } +} diff --git a/game/src/pak/pakman.h b/game/src/pak/pakman.h new file mode 100644 index 0000000..ee75311 --- /dev/null +++ b/game/src/pak/pakman.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include +#include + +#include "../gl/program.h" +#include "../gl/texture.h" +#include "../util.h" + +typedef struct PakFile +{ + GHashTable *programs; + GHashTable *textures; +} PakFile; + +void pakman_init (); +void pakman_load_pak (const char *path); + +unsigned int pakman_pak_program (const char *pak, const char *program); +unsigned int pakman_pak_texture (const char *pak, const char *texture); + +void pakman_all_paks_set_mat4 (const char *uniform, mat4 value); +void pakman_all_paks_set_float (const char *uniform, float value); + +#define PMPRG(program) pakman_pak_program ("base", program) +#define PMTEX(texture) pakman_pak_texture ("base", texture) diff --git a/game/src/resources.c b/game/src/resources.c deleted file mode 100644 index 7cdfe8f..0000000 --- a/game/src/resources.c +++ /dev/null @@ -1,196 +0,0 @@ -#include "resources.h" - -SDL_Surface *resources_cursor; - -static GHashTable *programs; -static GHashTable *textures; - -unsigned int -resources_load_program (const char *v_path, const char *f_path) -{ - char *v_src; - - if (!g_file_get_contents (v_path, &v_src, NULL, NULL)) - { - g_warning ("File `%s' does not exist.", v_path); - } - - char *f_src; - - if (!g_file_get_contents (f_path, &f_src, NULL, NULL)) - { - g_warning ("File `%s' does not exist.", f_path); - } - - unsigned int program = program_create (v_src, f_src); - g_free (v_src); - g_free (f_src); - return program; -} - -unsigned int -resources_load_texture (const char *path) -{ - SDL_Surface *surface = IMG_Load (path); - - if (surface == NULL) - { - g_warning ("Failed to load texture from path %s: %s", path, SDL_GetError ()); - return 0; - } - - unsigned int texture = texture_create (surface->w, surface->h, surface->pixels); - return texture; -} - -static inline void -resources_add_program (char *key, unsigned int program) -{ - if (program) - { - g_hash_table_insert (programs, key, GINT_TO_POINTER (program)); - } -} - -static inline void -resources_add_texture (char *key, unsigned int texture) -{ - if (texture) - { - g_hash_table_insert (textures, key, GINT_TO_POINTER (texture)); - } -} - -unsigned int -resources_get_program (char *key) -{ - if (!g_hash_table_contains (programs, key)) - { - g_warning ("Program `%s' does not exist. Careful!", key); - } - - return GPOINTER_TO_INT (g_hash_table_lookup (programs, key)); -} - -unsigned int -resources_get_texture (char *key) -{ - if (!g_hash_table_contains (textures, key)) - { - g_warning ("Texture `%s' does not exist. Careful!", key); - } - - return GPOINTER_TO_INT (g_hash_table_lookup (textures, key)); -} - -void -res_mat4_internal (gpointer key, gpointer value, gpointer userdata) -{ - UNUSED (key); - unsigned int program = GPOINTER_TO_INT (value); - - struct { - const char *name; - mat4 *mat; - } *data = userdata; - - program_use (program); - program_set_mat4 (program, data->name, *data->mat); -} - -void -res_float_internal (gpointer key, gpointer value, gpointer userdata) -{ - UNUSED (key); - unsigned int program = GPOINTER_TO_INT (value); - - struct { - const char *name; - float val; - } *data = userdata; - - program_use (program); - program_set_float (program, data->name, data->val); -} - -void -resources_programs_set_float (const char *name, float value) -{ - struct { - const char *name; - float val; - } data = { name, value }; - - g_hash_table_foreach (programs, res_float_internal, &data); -} - -void -resources_programs_set_mat4 (const char *name, mat4 *value) -{ - struct { - const char *name; - mat4 *mat; - } data = { name, value }; - - g_hash_table_foreach (programs, res_mat4_internal, &data); -} - -void -resources_init () -{ - programs = g_hash_table_new (g_str_hash, g_str_equal); - textures = g_hash_table_new (g_str_hash, g_str_equal); - - scm_c_primitive_load ("res/scripts/resources.scm"); - - program_use (RESPRG ("chunk")); - program_set_int_array (RESPRG ("chunk"), "materials", 5, (int[5]) { 0, 1, 2, 3, 4 }); - - program_use (RESPRG ("uiwidget")); - program_set_int (RESPRG ("uiwidget"), "background_image", 0); - program_set_int (RESPRG ("uiwidget"), "icons", 1); -} - -static SCM -_scm_register_program (SCM key_scm, SCM vpath_scm, SCM fpath_scm) -{ - const char *key = scm_to_utf8_string (key_scm); - const char *vpath = scm_to_utf8_string (vpath_scm); - const char *fpath = scm_to_utf8_string (fpath_scm); - unsigned int prog = resources_load_program (vpath, fpath); - resources_add_program ((char *) key, prog); - return SCM_UNSPECIFIED; -} - -static SCM -_scm_register_texture (SCM key_scm, SCM path_scm) -{ - const char *key = scm_to_utf8_string (key_scm); - const char *path = scm_to_utf8_string (path_scm); - unsigned int tex = resources_load_texture (path); - resources_add_texture ((char *) key, tex); - return SCM_UNSPECIFIED; -} - -static SCM -_scm_get_program (SCM key_scm) -{ - const char *key = scm_to_utf8_string (key_scm); - return scm_from_int (resources_get_program ((char *) key)); -} - -static SCM -_scm_get_texture (SCM key_scm) -{ - const char *key = scm_to_utf8_string (key_scm); - return scm_from_int (resources_get_texture ((char *) key)); -} - -void -resources_guile_register () -{ - scm_c_define_gsubr ("register-program", 3, 0, 0, _scm_register_program); - scm_c_define_gsubr ("register-texture", 2, 0, 0, _scm_register_texture); - scm_c_define_gsubr ("get-program", 1, 0, 0, _scm_get_program); - scm_c_define_gsubr ("get-texture", 1, 0, 0, _scm_get_texture); -} diff --git a/game/src/resources.h b/game/src/resources.h deleted file mode 100644 index 3a79850..0000000 --- a/game/src/resources.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include "gl/program.h" -#include "gl/texture.h" -#include "util.h" - -#define RESPRG(key) (resources_get_program (key)) -#define RESTEX(key) (resources_get_texture (key)) - -void resources_programs_set_float (const char *name, float value); -void resources_programs_set_mat4 (const char *name, mat4 *mat); -unsigned int resources_get_program (char *key); -unsigned int resources_get_texture (char *key); -void resources_init (); -void resources_guile_register (); diff --git a/game/src/ui/widget_core.h b/game/src/ui/widget_core.h index 097ad62..4847c4a 100644 --- a/game/src/ui/widget_core.h +++ b/game/src/ui/widget_core.h @@ -10,7 +10,7 @@ #include "widget_boilerplate.h" #include "../util.h" -#include "../resources.h" +#include "../pak/pakman.h" #include "../gl/mesh.h" #include "../gl/program.h" diff --git a/game/src/ui/widget_render.c b/game/src/ui/widget_render.c index 98b15a5..91e561a 100644 --- a/game/src/ui/widget_render.c +++ b/game/src/ui/widget_render.c @@ -19,9 +19,9 @@ static inline void _Widget_render_text_line(const char *text, TextAlignment alignment, ivec2 position, ivec2 size, int max_width, const vec4 color, mat4 projection) { - program_use (RESPRG ("uitext")); - program_set_mat4 (RESPRG ("uitext"), "projection", projection); - program_set_vec4 (RESPRG ("uitext"), "color", color); + program_use (PMPRG ("uitext")); + program_set_mat4 (PMPRG ("uitext"), "projection", projection); + program_set_vec4 (PMPRG ("uitext"), "color", color); int nchars = g_utf8_strlen (text, -1); int total_w = nchars * size[0]; @@ -45,12 +45,12 @@ _Widget_render_text_line(const char *text, TextAlignment alignment, ivec2 positi while (*p) { gunichar ch = g_utf8_get_char (p); - program_set_float (RESPRG ("uitext"), "character", ch); + program_set_float (PMPRG ("uitext"), "character", ch); mat3 model; glm_translate2d_make (model, (vec2) { position[0] + xoff, position[1] }); glm_scale2d (model, (vec2) { size[0], size[1] }); - program_set_mat3 (RESPRG ("uitext"), "model", model); + program_set_mat3 (PMPRG ("uitext"), "model", model); SimpleMesh_render (&quad, FALSE); @@ -74,42 +74,41 @@ Widget_render_base (Widget *self, mat4 projection, int window_height) const WidgetStyle *style = self->style; - program_use (RESPRG ("uiwidget")); + program_use (PMPRG ("uiwidget")); texture_use (style->background_image, 0); /* If it doesn't have a texture, it'll be 0 anyway. */ - texture_use (RESTEX ("icons"), 1); + texture_use (PMTEX ("icons"), 1); - - program_set_int (RESPRG ("uiwidget"), "has_background_image", style->background_image != 0); - program_set_int (RESPRG ("uiwidget"), "has_icon", self->icon != ICON_NONE); - program_set_int (RESPRG ("uiwidget"), "has_resize_handle", self->kind == WIDGET_WINDOW); + program_set_int (PMPRG ("uiwidget"), "has_background_image", style->background_image != 0); + program_set_int (PMPRG ("uiwidget"), "has_icon", self->icon != ICON_NONE); + program_set_int (PMPRG ("uiwidget"), "has_resize_handle", self->kind == WIDGET_WINDOW); - program_set_vec2 (RESPRG ("uiwidget"), "widget_size", (vec2) { self->size[0], self->size[1] }); - program_set_float (RESPRG ("uiwidget"), "border_width", style->border_width); - program_set_float (RESPRG ("uiwidget"), "icon_index", self->icon - 1); + program_set_vec2 (PMPRG ("uiwidget"), "widget_size", (vec2) { self->size[0], self->size[1] }); + program_set_float (PMPRG ("uiwidget"), "border_width", style->border_width); + program_set_float (PMPRG ("uiwidget"), "icon_index", self->icon - 1); - program_set_vec4 (RESPRG ("uiwidget"), "background_color", style->background_color); - program_set_vec4 (RESPRG ("uiwidget"), "icon_color", style->icon_color); - program_set_vec4 (RESPRG ("uiwidget"), "border_color", style->border_color); - program_set_vec4 (RESPRG ("uiwidget"), "resize_handle_color", style->resize_handle_color); + program_set_vec4 (PMPRG ("uiwidget"), "background_color", style->background_color); + program_set_vec4 (PMPRG ("uiwidget"), "icon_color", style->icon_color); + program_set_vec4 (PMPRG ("uiwidget"), "border_color", style->border_color); + program_set_vec4 (PMPRG ("uiwidget"), "resize_handle_color", style->resize_handle_color); if (self->clicked) { - program_set_vec4 (RESPRG ("uiwidget"), "background_color", style->background_color_clicked); - program_set_vec4 (RESPRG ("uiwidget"), "icon_color", style->icon_color_clicked); + program_set_vec4 (PMPRG ("uiwidget"), "background_color", style->background_color_clicked); + program_set_vec4 (PMPRG ("uiwidget"), "icon_color", style->icon_color_clicked); } else if (self->hovered) { - program_set_vec4 (RESPRG ("uiwidget"), "background_color", style->background_color_hovered); - program_set_vec4 (RESPRG ("uiwidget"), "icon_color", style->icon_color_hovered); + program_set_vec4 (PMPRG ("uiwidget"), "background_color", style->background_color_hovered); + program_set_vec4 (PMPRG ("uiwidget"), "icon_color", style->icon_color_hovered); } mat3 model; glm_translate2d_make (model, (vec2) { self->position[0], self->position[1] }); glm_scale2d (model, (vec2) { self->size[0], self->size[1] }); - program_set_mat3 (RESPRG ("uiwidget"), "model", model); - program_set_mat4 (RESPRG ("uiwidget"), "projection", projection); + program_set_mat3 (PMPRG ("uiwidget"), "model", model); + program_set_mat4 (PMPRG ("uiwidget"), "projection", projection); /* Before we render, we calculate the scissor box based on the parents. */ @@ -145,7 +144,7 @@ Widget_render_label (Widget *self, mat4 projection, int window_height) ivec2 pos = { self->position[0], self->position[1] }; const WidgetStyle *style = self->style; - texture_use (RESTEX ("font0"), 0); + texture_use (PMTEX ("font0"), 0); _Widget_render_text_line (self->label.text->str, self->label.text_alignment, pos, (ivec2) { char_w, self->size[1] }, self->size[0], self->clicked ? style->text_color_clicked : self->hovered @@ -155,20 +154,20 @@ Widget_render_label (Widget *self, mat4 projection, int window_height) void Widget_render_scrollbar (Widget *self, mat4 projection, int window_height) { - program_use (RESPRG ("uiwidget")); - program_set_int (RESPRG ("uiwidget"), "has_scrollbar", TRUE); + program_use (PMPRG ("uiwidget")); + program_set_int (PMPRG ("uiwidget"), "has_scrollbar", TRUE); const WidgetStyle *style = self->style; - program_set_vec4 (RESPRG ("uiwidget"), "scrollbar_color", style->scrollbar_color); + program_set_vec4 (PMPRG ("uiwidget"), "scrollbar_color", style->scrollbar_color); if (self->clicked) { - program_set_vec4 (RESPRG ("uiwidget"), "scrollbar_color", style->scrollbar_color_clicked); + program_set_vec4 (PMPRG ("uiwidget"), "scrollbar_color", style->scrollbar_color_clicked); } else if (self->hovered) { - program_set_vec4 (RESPRG ("uiwidget"), "scrollbar_color", style->scrollbar_color_hovered); + program_set_vec4 (PMPRG ("uiwidget"), "scrollbar_color", style->scrollbar_color_hovered); } /* Calculate the scrollbar size. */ @@ -182,35 +181,35 @@ Widget_render_scrollbar (Widget *self, mat4 projection, int window_height) int thumb_size_norm = view_size / content_size; int thumb_pos_norm = scroll_pos / content_size; - program_set_vec2 (RESPRG ("uiwidget"), "scrollbar_position", self->scrollbar.horizontal + program_set_vec2 (PMPRG ("uiwidget"), "scrollbar_position", self->scrollbar.horizontal ? (vec2) { thumb_pos_norm, 0.0f } : (vec2) { 0.0f, thumb_pos_norm }); - program_set_vec2 (RESPRG ("uiwidget"), "scrollbar_size", self->scrollbar.horizontal + program_set_vec2 (PMPRG ("uiwidget"), "scrollbar_size", self->scrollbar.horizontal ? (vec2) { thumb_size_norm, 1.0f } : (vec2) { 1.0f, thumb_size_norm }); Widget_render_base (self, projection, window_height); - program_set_int (RESPRG ("uiwidget"), "has_scrollbar", FALSE); + program_set_int (PMPRG ("uiwidget"), "has_scrollbar", FALSE); } void Widget_render_progress (Widget *self, mat4 projection, int window_height) { - program_use (RESPRG ("uiwidget")); - program_set_int (RESPRG ("uiwidget"), "has_progress", TRUE); + program_use (PMPRG ("uiwidget")); + program_set_int (PMPRG ("uiwidget"), "has_progress", TRUE); float bar_size = (*self->progress.ptr - self->progress.min) / (self->progress.max - self->progress.min); bar_size = glm_clamp (bar_size, 0.0, 1.0); - program_set_vec4 (RESPRG ("uiwidget"), "progress_color", self->style->progress_color); + program_set_vec4 (PMPRG ("uiwidget"), "progress_color", self->style->progress_color); - program_set_vec2 (RESPRG ("uiwidget"), "progress_size", self->progress.horizontal + program_set_vec2 (PMPRG ("uiwidget"), "progress_size", self->progress.horizontal ? (vec2) { bar_size, 1.0f } : (vec2) { 1.0f, bar_size }); Widget_render_base (self, projection, window_height); - program_set_int (RESPRG ("uiwidget"), "has_progress", FALSE); + program_set_int (PMPRG ("uiwidget"), "has_progress", FALSE); } void @@ -218,7 +217,7 @@ Widget_render_multiline_text (Widget *self, mat4 projection, int window_height) { Widget_render_base (self, projection, window_height); - texture_use (RESTEX ("font0"), 0); + texture_use (PMTEX ("font0"), 0); int pad = self->layout_padding; int row_h = self->multiline_text.line_height; @@ -240,7 +239,7 @@ Widget_render_entry (Widget *self, mat4 projection, int window_height) { Widget_render_base (self, projection, window_height); - texture_use (RESTEX ("font0"), 0); + texture_use (PMTEX ("font0"), 0); int char_w = self->size[1] * (9.0f / 20.0f); int cursor_in_px = self->entry.cursor_position * char_w; @@ -273,10 +272,10 @@ Widget_render_entry (Widget *self, mat4 projection, int window_height) glm_translate2d_make (model, (vec2) { x, y }); glm_scale2d (model, (vec2) { w, h }); - program_use (RESPRG ("uidummy")); - program_set_mat3 (RESPRG ("uidummy"), "model", model); - program_set_mat4 (RESPRG ("uidummy"), "projection", projection); - program_set_vec4 (RESPRG ("uidummy"), "background_color", self->style->text_color); + program_use (PMPRG ("uidummy")); + program_set_mat3 (PMPRG ("uidummy"), "model", model); + program_set_mat4 (PMPRG ("uidummy"), "projection", projection); + program_set_vec4 (PMPRG ("uidummy"), "background_color", self->style->text_color); SimpleMesh_render (&quad, FALSE); } @@ -288,7 +287,7 @@ Widget_render_window (Widget *self, mat4 projection, int window_height) UNUSED (self, projection, window_height); Widget_render_base (self, projection, window_height); - texture_use (RESTEX ("font0"), 0); + texture_use (PMTEX ("font0"), 0); ivec2 pos = { self->position[0] + self->layout_padding,