From 0dc41a99ad5a2436d6a1af81b0acf4c9cb01b512 Mon Sep 17 00:00:00 2001 From: Emil Kosz Date: Wed, 4 Jun 2025 19:59:20 +0200 Subject: [PATCH] Prototype clouds, add new entity mesh type --- game/Makefile | 4 +- game/res/textures/clouds.png | Bin 0 -> 31148 bytes game/src/camera.c | 2 +- game/src/chunk/{manager.c => chunkman.c} | 19 ++++-- game/src/chunk/{manager.h => chunkman.h} | 4 +- game/src/chunk/{mesh.c => chunkmesh.c} | 15 +++-- game/src/chunk/{mesh.h => chunkmesh.h} | 3 +- game/src/entity/entity.h | 30 ++++++++- game/src/entity/{manager.c => entman.c} | 74 ++++++++++++++--------- game/src/entity/{manager.h => entman.h} | 5 +- game/src/entity/meshes.c | 51 ++++++++++++++-- game/src/entity/meshes.h | 1 + game/src/entity/templates.c | 14 ++--- game/src/entity/templates.h | 1 + game/src/graphics.c | 3 +- game/src/graphics.h | 4 +- game/src/main.c | 2 +- game/src/resources.c | 6 ++ 18 files changed, 169 insertions(+), 69 deletions(-) create mode 100644 game/res/textures/clouds.png rename game/src/chunk/{manager.c => chunkman.c} (96%) rename game/src/chunk/{manager.h => chunkman.h} (93%) rename game/src/chunk/{mesh.c => chunkmesh.c} (95%) rename game/src/chunk/{mesh.h => chunkmesh.h} (92%) rename game/src/entity/{manager.c => entman.c} (75%) rename game/src/entity/{manager.h => entman.h} (74%) diff --git a/game/Makefile b/game/Makefile index e7cb608..67b93ed 100644 --- a/game/Makefile +++ b/game/Makefile @@ -1,7 +1,7 @@ SRC=src/main.c src/program.c src/resources.c src/camera.c src/chunk/chunk.c \ - src/chunk/mesh.c src/flags.c src/texture.c src/chunk/manager.c \ + src/chunk/chunkmesh.c src/flags.c src/texture.c src/chunk/chunkman.c \ src/event/manager.c src/event/handlers.c src/state.c src/graphics.c \ - src/entity/meshes.c src/entity/manager.c src/entity/templates.c + src/entity/meshes.c src/entity/entman.c src/entity/templates.c OBJ=$(SRC:.c=.o) CFLAGS=-g -pg -Werror -Wextra -Wall `pkg-config --cflags sdl3 sdl3-image cglm gl glib-2.0` diff --git a/game/res/textures/clouds.png b/game/res/textures/clouds.png new file mode 100644 index 0000000000000000000000000000000000000000..53c5dd8acdbe64d82de3d162392d8c63a5803a72 GIT binary patch literal 31148 zcmeAS@N?(olHy`uVBq!ia0y~yU||4Z4mJh`hI(1;W(EcZ#^NA%C&rs6b?QM<>5jgR z3=A9lx&I`xGB7YGBzpw;GB8xBF)%c=FfjaLU|?u?!N5>zz`*b-fq}tl1_Oh5!JJ)z zHVh0344y8IAr-gY+`V4rynU<2g$d37|DWE)f88oDW7=JYHAc^)lcJRxuQF`B^Y5@~ zU0q#W*q?j1-RYd?h`TR$`#RITt)5mQ z4KdSSchp-d^6gt6d+odYZk7dEe^-19|Jbop`X|$a*}tc;UtH@@Rmp#MB>Y!?GZ*R|* z#`Atn#Bt;Qf48qsV*8qW*3w-s&c6DrP5my00#1fp?#-bLhj&*#uhl*Cw zjLhxXts214@XI7{*B6_=)&HyZR@v_@b&>sIBl|DA%45R$^P8(aRAw4{+08QHvqa9u zI)!htf2!wM?`2|G@X*!a+WU1!8FCuj-z5BhZu49+UipX3?2gqRYuFeZKA&c2Held8 zXgmM^eanPzvwk=qS+w{5?hmq)Q$q{R)o6Asly8r}!m{aEYlW-5!`%tRqDk4uc2#gY zd^iv|hoM)JLFV5TT!$#2?F~*ZOmvok$Iqz_rl|i>Us<&G0wafws>Y= zY1qlV;3jK>6K9D1izwD?CW}9d`y06%mN!YR%ve{UGj(=b8;8WK3#$d}8T1$q#jyPO zW4L=l|G(Jk`h99_e0#4k9=OvI$L6fh5GHcTe>$Hm_bxRyHn#Kf5AN`AUO4*rRr8CE zgByR}<_)u%2Fgn93=9iSJ-n~=C8@9Vy54`O1KQkgCeFU4#rp5|=L;ton1v5~-K

iumCTo?s%PZ+*nu7BM) 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 literal 0 HcmV?d00001 diff --git a/game/src/camera.c b/game/src/camera.c index e3c7e42..5321479 100644 --- a/game/src/camera.c +++ b/game/src/camera.c @@ -33,5 +33,5 @@ camera_get_view (mat4 dest) void camera_get_projection (float aspect, mat4 dest) { - glm_perspective (glm_rad (90), aspect, 0.1, 1000.0, dest); + glm_perspective (glm_rad (70), aspect, 0.01, 5000.0, dest); } diff --git a/game/src/chunk/manager.c b/game/src/chunk/chunkman.c similarity index 96% rename from game/src/chunk/manager.c rename to game/src/chunk/chunkman.c index 2486c20..140897a 100644 --- a/game/src/chunk/manager.c +++ b/game/src/chunk/chunkman.c @@ -1,4 +1,4 @@ -#include "manager.h" +#include "chunkman.h" /* TODO: perhaps render the chunks in a circle, not a square, around the player? */ @@ -6,6 +6,8 @@ static GHashTable *chunks; static GHashTable *chunk_meshes; +static bool bound = false; + guint chunkman_ivec2_hash (gconstpointer key) { @@ -55,7 +57,6 @@ chunkman_get_height_at (float x, float z) return 0.0; } - // Pozycja lokalna w chunku float lx = x - cx * CHUNK_DIM; float lz = z - cz * CHUNK_DIM; @@ -86,7 +87,7 @@ chunkman_get_height_at (float x, float z) else h11 = c ? c_get_height (c, 0, 0) : h00; - // Interpolacja + // Bilinear interpolation. float h0 = h00 * (1 - tx) + h10 * tx; float h1 = h01 * (1 - tx) + h11 * tx; float height = h0 * (1 - tz) + h1 * tz; @@ -146,11 +147,19 @@ chunkman_render (vec3 camera_position, int program) ChunkMesh *mesh = chunkman_get_ChunkMesh_at (x, z); if (mesh != NULL) { + if (!bound) + { + ChunkMesh_bind (mesh); + bound = true; + } + program_set_vec3 (program, "chunk_position", x * CHUNK_DIM, 0.0, z * CHUNK_DIM); ChunkMesh_render (mesh); } } - } + } + + bound = false; } Chunk * @@ -190,7 +199,7 @@ chunkman_generate_Chunk_at (int cx, int cz) tree->position[0] = x + xoffset; tree->position[1] = chunk->heightmap [INDEX (x, z)]; tree->position[2] = z + zoffset; - tree->rotation = rand () % 180; + tree->rotation[1] = rand () % 180; ENTADD (tree); } diff --git a/game/src/chunk/manager.h b/game/src/chunk/chunkman.h similarity index 93% rename from game/src/chunk/manager.h rename to game/src/chunk/chunkman.h index 8698643..9ef9708 100644 --- a/game/src/chunk/manager.h +++ b/game/src/chunk/chunkman.h @@ -4,9 +4,9 @@ #include #include "chunk.h" -#include "mesh.h" +#include "chunkmesh.h" #include "../program.h" -#include "../entity/manager.h" +#include "../entity/entman.h" #include "../entity/templates.h" #define RENDER_DISTANCE 3 diff --git a/game/src/chunk/mesh.c b/game/src/chunk/chunkmesh.c similarity index 95% rename from game/src/chunk/mesh.c rename to game/src/chunk/chunkmesh.c index 0827834..c642dec 100644 --- a/game/src/chunk/mesh.c +++ b/game/src/chunk/chunkmesh.c @@ -1,4 +1,4 @@ -#include "mesh.h" +#include "chunkmesh.h" /* No need to bind the elements buffer all the time; it's the same for every single ChunkMesh. */ @@ -84,9 +84,6 @@ ChunkMesh_build (Chunk *chunk, Chunk *nr, Chunk *nd, Chunk *nc) glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, mesh->ebo); glBufferData (GL_ELEMENT_ARRAY_BUFFER, sizeof (unsigned int) * CHUNK_SIZE * 6, indices, GL_STATIC_DRAW); - - glBindBuffer (GL_ARRAY_BUFFER, 0); - glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0); free (positions); free (materials); @@ -95,6 +92,14 @@ ChunkMesh_build (Chunk *chunk, Chunk *nr, Chunk *nd, Chunk *nc) return mesh; } +void +ChunkMesh_bind (ChunkMesh *mesh) +/* The EBO is the same for all chunk meshes, so we can bind it just + once before we render them all. */ +{ + glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, mesh->ebo); +} + void ChunkMesh_render (ChunkMesh *mesh) { @@ -105,8 +110,6 @@ ChunkMesh_render (ChunkMesh *mesh) glBindBuffer (GL_ARRAY_BUFFER, mesh->mbo); glEnableVertexAttribArray (1); glVertexAttribPointer (1, 4, GL_FLOAT, GL_FALSE, sizeof (float) * 4, 0); - - glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, mesh->ebo); if (flags_get ("wireframe_enabled")) { diff --git a/game/src/chunk/mesh.h b/game/src/chunk/chunkmesh.h similarity index 92% rename from game/src/chunk/mesh.h rename to game/src/chunk/chunkmesh.h index ca38d9d..0772f88 100644 --- a/game/src/chunk/mesh.h +++ b/game/src/chunk/chunkmesh.h @@ -18,6 +18,7 @@ typedef struct ChunkMesh unsigned int ebo; } ChunkMesh; -/* Rename to ChunkMesh_build */ + ChunkMesh *ChunkMesh_build (Chunk *chunk, Chunk *nr, Chunk *nd, Chunk *nc); +void ChunkMesh_bind (ChunkMesh *mesh); void ChunkMesh_render (ChunkMesh *mesh); diff --git a/game/src/entity/entity.h b/game/src/entity/entity.h index e98a5a9..527acd3 100644 --- a/game/src/entity/entity.h +++ b/game/src/entity/entity.h @@ -7,17 +7,41 @@ typedef struct Entity { - enum { MESH_QUAD2, MESH_QUAD_X } mesh_type; + enum { MESH_QUAD1, MESH_QUAD2, MESH_QUAD_X } mesh_type; enum { ORIGIN_CENTER, ORIGIN_BOTTOM } origin; enum { RENDER_NORMAL, RENDER_BILLBOARD_Y, RENDER_BILLBOARD } render_type; bool visible; + bool dont_cull; void *userdata; void (*on_tick) (struct Entity *self); vec3 position; - float rotation; + vec3 rotation; vec3 scale; - char *texture; + /* Use RESTEX to get the int. */ + unsigned int texture; } Entity; + +static inline void +entity_compute_aabb (Entity *e, vec3 out_min, vec3 out_max) +{ + vec3 half = { 0.5f * e->scale[0], 0.5f * e->scale[1], 0.5f * e->scale[2] }; + + if (e->origin == ORIGIN_BOTTOM) + { + out_min[0] = e->position[0] - half[0]; + out_min[1] = e->position[1]; + out_min[2] = e->position[2] - half[2]; + + out_max[0] = e->position[0] + half[0]; + out_max[1] = e->position[1] + e->scale[1]; + out_max[2] = e->position[2] + half[2]; + } + else + { + glm_vec3_sub (e->position, half, out_min); + glm_vec3_add (e->position, half, out_max); + } +} diff --git a/game/src/entity/manager.c b/game/src/entity/entman.c similarity index 75% rename from game/src/entity/manager.c rename to game/src/entity/entman.c index 014a53a..62486d9 100644 --- a/game/src/entity/manager.c +++ b/game/src/entity/entman.c @@ -1,14 +1,13 @@ -#include "manager.h" +#include "entman.h" extern vec3 camera_position; Entity *player_entity; static GSequence *entities; -static EntityMesh mesh_quad2, mesh_quad_x; +static EntityMesh mesh_quad1, mesh_quad2, mesh_quad_x; static unsigned int last_type = -1; - -#define CULL_FRUSTUM 0 +static unsigned int last_texture = -1; void character_on_tick (Entity *entity) @@ -20,6 +19,7 @@ void entman_init () { entities = g_sequence_new (NULL); + mesh_quad1 = EntityMesh_make_quad1 (); mesh_quad2 = EntityMesh_make_quad2 (); mesh_quad_x = EntityMesh_make_quad_x (); @@ -28,12 +28,25 @@ entman_init () .origin = ORIGIN_BOTTOM, .visible = false, .position = { 0.0 }, - .rotation = 0.0, .scale = { 1.0, 1.8, 1.0 }, .on_tick = character_on_tick }; ENTADD (player_entity); + + Entity *sky = malloc (sizeof (Entity)); + *sky = (Entity) { + .mesh_type = MESH_QUAD1, + .origin = ORIGIN_CENTER, + .visible = true, + .dont_cull = true, + .position = { 0.0, 200.0, 0.0 }, + .scale = { 5000.0, 5000.0, 5000.0 }, + .rotation = { 90.0 }, + .texture = RESTEX ("clouds") + }; + + ENTADD (sky); } void @@ -65,7 +78,8 @@ entman_render_internal (gpointer data, gpointer userdata) return; } - if (glm_vec3_distance (camera_position, entity->position) > ENTITY_RENDER_DISTANCE) + if (glm_vec3_distance (camera_position, entity->position) > ENTITY_RENDER_DISTANCE + && !entity->dont_cull) { return; } @@ -73,8 +87,7 @@ entman_render_internal (gpointer data, gpointer userdata) /* TODO: Fix this up. It still isn't perfect, when you look up, sometimes the entities get culled. */ - #if CULL_FRUSTUM - +#if FRUSTUM_CULL vec4 planes[6]; mat4 proj, view_proj; @@ -82,29 +95,26 @@ entman_render_internal (gpointer data, gpointer userdata) glm_mat4_mul (proj, *view, view_proj); glm_frustum_planes (view_proj, planes); - vec3 aabb[2] = { - { -entity->scale[0] + entity->position[0], - -entity->scale[1] + entity->position[1] + (entity->origin == ORIGIN_BOTTOM ? entity->scale[1] : 0), - -entity->scale[2] + entity->position[2] }, - { +entity->scale[0] + entity->position[0], - +entity->scale[1] + entity->position[1] + (entity->origin == ORIGIN_BOTTOM ? entity->scale[1] : 0), - +entity->scale[2] + entity->position[2] }, - }; + vec3 aabb[2]; + entity_compute_aabb (entity, aabb[0], aabb[1]); if (!glm_aabb_frustum (aabb, planes)) { return; } - - #endif +#endif EntityMesh to_render; + unsigned int render_type = entity->render_type; switch (entity->mesh_type) { case MESH_QUAD_X: to_render = mesh_quad_x; break; + case MESH_QUAD1: + to_render = mesh_quad1; + break; default: to_render = mesh_quad2; break; @@ -112,7 +122,7 @@ entman_render_internal (gpointer data, gpointer userdata) mat4 model = GLM_MAT4_IDENTITY_INIT; - switch (entity->render_type) + switch (render_type) { case RENDER_BILLBOARD: mat4 inv_view; @@ -145,7 +155,9 @@ entman_render_internal (gpointer data, gpointer userdata) glm_translate (model, entity->position); break; default: - glm_rotate_at (model, entity->position, glm_rad (entity->rotation), (vec3) { 0.0, 1.0, 0.0 }); + glm_rotate_at (model, entity->position, glm_rad (entity->rotation[0]), (vec3) { 1.0, 0.0, 0.0 }); + glm_rotate_at (model, entity->position, glm_rad (entity->rotation[1]), (vec3) { 0.0, 1.0, 0.0 }); + glm_rotate_at (model, entity->position, glm_rad (entity->rotation[2]), (vec3) { 0.0, 0.0, 1.0 }); glm_translate (model, entity->position); break; } @@ -159,10 +171,10 @@ entman_render_internal (gpointer data, gpointer userdata) program_set_mat4 (RESPRG ("default"), "model", model); - if (entity->texture != NULL) + if (entity->texture != last_texture) { glActiveTexture (GL_TEXTURE0); - glBindTexture (GL_TEXTURE_2D, RESTEX (entity->texture)); + glBindTexture (GL_TEXTURE_2D, entity->texture); } if (entity->mesh_type != last_type) @@ -171,6 +183,7 @@ entman_render_internal (gpointer data, gpointer userdata) } last_type = entity->mesh_type; + last_texture = entity->texture; EntityMesh_render (&to_render); } @@ -194,16 +207,19 @@ entman_compare (gconstpointer a, gconstpointer b, gpointer userdata) return 0; } + // Handle MESH_QUAD1 + if (entity1->mesh_type == MESH_QUAD1) + return -1; + if (entity2->mesh_type == MESH_QUAD1) + return 1; + + // Handle MESH_QUAD_X vs MESH_QUAD2 if (entity1->mesh_type == MESH_QUAD_X && entity2->mesh_type == MESH_QUAD2) - { - return -1; - } - + return -1; if (entity1->mesh_type == MESH_QUAD2 && entity2->mesh_type == MESH_QUAD_X) - { - return 1; - } + return 1; + // Default: compare numerically return (int) entity1->mesh_type - (int) entity2->mesh_type; } diff --git a/game/src/entity/manager.h b/game/src/entity/entman.h similarity index 74% rename from game/src/entity/manager.h rename to game/src/entity/entman.h index 2ced55d..d610247 100644 --- a/game/src/entity/manager.h +++ b/game/src/entity/entman.h @@ -8,9 +8,10 @@ #include "../util.h" #include "../resources.h" #include "../state.h" -#include "../chunk/manager.h" +#include "../chunk/chunkman.h" -#define ENTITY_RENDER_DISTANCE (3*CHUNK_DIM/2) +#define ENTITY_RENDER_DISTANCE (RENDER_DISTANCE*CHUNK_DIM) +#define FRUSTUM_CULL 1 #define ENTADD(entity) (entman_add_entity (entity)) diff --git a/game/src/entity/meshes.c b/game/src/entity/meshes.c index 67a9f39..ecb25de 100644 --- a/game/src/entity/meshes.c +++ b/game/src/entity/meshes.c @@ -32,6 +32,51 @@ EntityMesh_render (EntityMesh *mesh) } } +EntityMesh +EntityMesh_make_quad1 () +{ + /* The positions are trivial. */ + float positions[12] = { + -1.0, -1.0, 0.0, + +1.0, -1.0, 0.0, + -1.0, 1.0, 0.0, + +1.0, 1.0, 0.0 + }; + + unsigned int indices[12] = { + 3, 2, 0, 0, 1, 3, + }; + + float uvs[8] = { + 0.0, 1.0, + 1.0, 1.0, + 0.0, 0.0, + 1.0, 0.0, + }; + + EntityMesh mesh; + mesh.indices_len = 6; + glGenBuffers (1, &mesh.pbo); + glGenBuffers (1, &mesh.uvbo); + glGenBuffers (1, &mesh.ebo); + + glBindBuffer (GL_ARRAY_BUFFER, mesh.pbo); + glBufferData (GL_ARRAY_BUFFER, sizeof (float) * 12, positions, GL_STATIC_DRAW); + glEnableVertexAttribArray (0); + glVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE, sizeof (float) * 3, 0); + + glBindBuffer (GL_ARRAY_BUFFER, mesh.uvbo); + glBufferData (GL_ARRAY_BUFFER, sizeof (float) * 8, uvs, GL_STATIC_DRAW); + glEnableVertexAttribArray (1); + glVertexAttribPointer (1, 2, GL_FLOAT, GL_FALSE, sizeof (float) * 2, 0); + + + glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, mesh.ebo); + glBufferData (GL_ELEMENT_ARRAY_BUFFER, sizeof (unsigned int) * mesh.indices_len, indices, GL_STATIC_DRAW); + + return mesh; +} + EntityMesh EntityMesh_make_quad2 () { @@ -75,9 +120,6 @@ EntityMesh_make_quad2 () glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, mesh.ebo); glBufferData (GL_ELEMENT_ARRAY_BUFFER, sizeof (unsigned int) * mesh.indices_len, indices, GL_STATIC_DRAW); - glBindBuffer (GL_ARRAY_BUFFER, 0); - glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0); - return mesh; } @@ -135,8 +177,5 @@ EntityMesh_make_quad_x () glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, mesh.ebo); glBufferData (GL_ELEMENT_ARRAY_BUFFER, sizeof (unsigned int) * mesh.indices_len, indices, GL_STATIC_DRAW); - glBindBuffer (GL_ARRAY_BUFFER, 0); - glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0); - return mesh; } diff --git a/game/src/entity/meshes.h b/game/src/entity/meshes.h index 0959c8d..4cd03e1 100644 --- a/game/src/entity/meshes.h +++ b/game/src/entity/meshes.h @@ -15,5 +15,6 @@ typedef struct EntityMesh void EntityMesh_bind (EntityMesh *mesh); void EntityMesh_render (EntityMesh *mesh); +EntityMesh EntityMesh_make_quad1 (); EntityMesh EntityMesh_make_quad2 (); EntityMesh EntityMesh_make_quad_x (); diff --git a/game/src/entity/templates.c b/game/src/entity/templates.c index 2b3e142..0e67b66 100644 --- a/game/src/entity/templates.c +++ b/game/src/entity/templates.c @@ -24,24 +24,24 @@ ent_templates_init () .mesh_type = MESH_QUAD_X, .visible = true, .origin = ORIGIN_BOTTOM, - .position = { 0.0, 0.0, 0.0 }, + .position = { 0.0 }, .scale = { 3.0, 8.0, 3.0 }, - .rotation = 0.0, - .texture = "tree0" + .rotation = { 0.0 }, + .texture = RESTEX ("tree0") }; ent_templates_add ("tree", tree); Entity *grass = malloc (sizeof (Entity)); *grass = (Entity) { - .mesh_type = MESH_QUAD2, + .mesh_type = MESH_QUAD1, .render_type = RENDER_BILLBOARD_Y, .visible = true, .origin = ORIGIN_BOTTOM, - .position = { 0.0, 0.0, 0.0 }, + .position = { 0.0 }, .scale = { 1.0, 0.5, 1.0 }, - .rotation = 0.0, - .texture = "grass0" + .rotation = { 0.0 }, + .texture = RESTEX ("grass0") }; ent_templates_add ("grass", grass); diff --git a/game/src/entity/templates.h b/game/src/entity/templates.h index d30e2f3..f8fee39 100644 --- a/game/src/entity/templates.h +++ b/game/src/entity/templates.h @@ -6,6 +6,7 @@ #include #include "entity.h" +#include "../resources.h" #define ETEMPLGET(key) (ent_templates_get (key)) diff --git a/game/src/graphics.c b/game/src/graphics.c index 3339a3b..1b207f5 100644 --- a/game/src/graphics.c +++ b/game/src/graphics.c @@ -71,10 +71,9 @@ graphics_render () glBindTexture (GL_TEXTURE_2D, RESTEX ("terrain3")); glActiveTexture (GL_TEXTURE4); glBindTexture (GL_TEXTURE_2D, RESTEX ("terrain4")); - + chunkman_render (camera_position, RESPRG ("chunk")); - /* Set views and projections in all programs. TODO: make this dynamic*/ program_use (RESPRG ("default")); program_set_mat4 (RESPRG ("default"), "projection", projection); program_set_mat4 (RESPRG ("default"), "view", view); diff --git a/game/src/graphics.h b/game/src/graphics.h index 916730a..4ff3a70 100644 --- a/game/src/graphics.h +++ b/game/src/graphics.h @@ -4,8 +4,8 @@ #include #include "util.h" -#include "chunk/manager.h" -#include "entity/manager.h" +#include "chunk/chunkman.h" +#include "entity/entman.h" #include "state.h" #include "resources.h" diff --git a/game/src/main.c b/game/src/main.c index 3d03c24..e08a691 100644 --- a/game/src/main.c +++ b/game/src/main.c @@ -5,7 +5,7 @@ #include "event/manager.h" #include "event/handlers.h" -#include "chunk/manager.h" +#include "chunk/chunkman.h" #include "entity/templates.h" #include "state.h" #include "resources.h" diff --git a/game/src/resources.c b/game/src/resources.c index 7f2b681..c3095fa 100644 --- a/game/src/resources.c +++ b/game/src/resources.c @@ -96,6 +96,12 @@ resources_init () RAT ("terrain4", RLT ("res/textures/asphalt_gravel.png")); RAT ("tree0", RLT ("res/textures/tree.png")); RAT ("grass0", RLT ("res/textures/grass0.png")); + RAT ("clouds", RLT ("res/textures/clouds.png")); + + #undef RAP + #undef RLP + #undef RAT + #undef RLP program_use (RESPRG ("chunk")); program_set_int_array (RESPRG ("chunk"), "materials", 5, (int[5]) { 0, 1, 2, 3, 4 });