Prototype clouds, add new entity mesh type

This commit is contained in:
2025-06-04 19:59:20 +02:00
parent 04bbee09dd
commit 0dc41a99ad
18 changed files with 169 additions and 69 deletions
+2 -2
View File
@@ -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`
Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

+1 -1
View File
@@ -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);
}
@@ -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);
}
@@ -4,9 +4,9 @@
#include <glib-2.0/glib.h>
#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
@@ -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"))
{
@@ -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);
+27 -3
View File
@@ -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);
}
}
@@ -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;
}
@@ -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))
+45 -6
View File
@@ -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;
}
+1
View File
@@ -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 ();
+7 -7
View File
@@ -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);
+1
View File
@@ -6,6 +6,7 @@
#include <cglm/cglm.h>
#include "entity.h"
#include "../resources.h"
#define ETEMPLGET(key) (ent_templates_get (key))
+1 -2
View File
@@ -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);
+2 -2
View File
@@ -4,8 +4,8 @@
#include <SDL3/SDL_opengles2.h>
#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"
+1 -1
View File
@@ -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"
+6
View File
@@ -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 });