diff --git a/game/Makefile b/game/Makefile index cf3ae1a..74766b7 100644 --- a/game/Makefile +++ b/game/Makefile @@ -1,6 +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/event/manager.c src/event/handlers.c src/state.c src/graphics.c + src/event/manager.c src/event/handlers.c src/state.c src/graphics.c \ + src/entity/meshes.c src/entity/manager.c OBJ=$(SRC:.c=.o) CFLAGS=-Werror -Wextra -Wall `pkg-config --cflags sdl3 sdl3-image cglm gl glib-2.0` diff --git a/game/res/shaders/billboard.frag b/game/res/shaders/billboard.frag new file mode 100644 index 0000000..b26a6a5 --- /dev/null +++ b/game/res/shaders/billboard.frag @@ -0,0 +1,8 @@ +#version 100 + +precision mediump float; + +void main () +{ + gl_FragColor = vec4 (1.0, 1.0, 1.0, 1.0); +} diff --git a/game/res/shaders/billboard.vert b/game/res/shaders/billboard.vert new file mode 100644 index 0000000..6b02501 --- /dev/null +++ b/game/res/shaders/billboard.vert @@ -0,0 +1,11 @@ +#version 100 + +attribute vec4 position; + +uniform mat4 view; +uniform mat4 projection; + +void main () +{ + gl_Position = projection * view * position; +} diff --git a/game/res/shaders/default.frag b/game/res/shaders/default.frag index b541df3..18447de 100644 --- a/game/res/shaders/default.frag +++ b/game/res/shaders/default.frag @@ -2,7 +2,16 @@ precision mediump float; +uniform sampler2D texture; + +varying vec2 f_uv; + void main () { - gl_FragColor = vec4 (0.5, 1.0, 0.5, 1.0); + if(texture2D (texture, f_uv).a < 0.1) + { + discard; + } + + gl_FragColor = texture2D (texture, f_uv); } diff --git a/game/res/shaders/default.vert b/game/res/shaders/default.vert index 6b02501..ebe8591 100644 --- a/game/res/shaders/default.vert +++ b/game/res/shaders/default.vert @@ -1,11 +1,15 @@ #version 100 attribute vec4 position; +attribute vec2 uv; uniform mat4 view; uniform mat4 projection; +varying vec2 f_uv; + void main () { + f_uv = uv; gl_Position = projection * view * position; } diff --git a/game/res/textures/tree.png b/game/res/textures/tree.png new file mode 100644 index 0000000..8e867bf Binary files /dev/null and b/game/res/textures/tree.png differ diff --git a/game/src/chunk/manager.c b/game/src/chunk/manager.c index df625f9..e6149b2 100644 --- a/game/src/chunk/manager.c +++ b/game/src/chunk/manager.c @@ -77,7 +77,7 @@ ChunkManager_render (vec3 camera_position, int program) { int cx = 0, cz = 0; cm_world_to_chunk (camera_position[0], camera_position[2], &cx, &cz); - + for (int z = cz - RENDER_DISTANCE; z <= cz + RENDER_DISTANCE; ++z) { for (int x = cx - RENDER_DISTANCE; x <= cx + RENDER_DISTANCE; ++x) diff --git a/game/src/chunk/mesh.c b/game/src/chunk/mesh.c index 2c74a27..d7d51f9 100644 --- a/game/src/chunk/mesh.c +++ b/game/src/chunk/mesh.c @@ -1,5 +1,8 @@ #include "mesh.h" +/* No need to bind the elements buffer all the time; it's the same for + every single ChunkMesh. */ + extern GameFlags game_flags; ChunkMesh * @@ -104,7 +107,7 @@ 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 (game_flags.wireframe_enabled) @@ -115,6 +118,4 @@ ChunkMesh_render (ChunkMesh *mesh) { glDrawElements (GL_TRIANGLES, CHUNK_SIZE * 6, GL_UNSIGNED_INT, 0); } - - glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0); } diff --git a/game/src/entity/entity.h b/game/src/entity/entity.h new file mode 100644 index 0000000..052ec58 --- /dev/null +++ b/game/src/entity/entity.h @@ -0,0 +1,18 @@ +#pragma once + +typedef enum EntityMeshType + { + ENTITY_MESH_BILLBOARD, + ENTITY_MESH_X + } EntityMeshType; + +typedef struct Entity +{ + vec3 position; + vec3 rotation; /* Unused for now. */ + vec3 scale; /* Unused for now. */ + int texture; + EntityMeshType type; +} Entity; + +Entity *Entity_new (vec3 position, int texture, EntityMeshType type); diff --git a/game/src/entity/manager.c b/game/src/entity/manager.c new file mode 100644 index 0000000..4f29f81 --- /dev/null +++ b/game/src/entity/manager.c @@ -0,0 +1,25 @@ +#include "manager.h" + +GSequence *entity_manager; + +EntityMesh mesh_billboard, mesh_x; + +void +EntityManager_init () +{ + entity_manager = g_sequence_new (NULL); + mesh_billboard = EntityMesh_make_billboard (); + mesh_x = EntityMesh_make_x (); +} + +void +EntityManager_tick () +{ + +} + +void +EntityManager_render () +{ + +} diff --git a/game/src/entity/manager.h b/game/src/entity/manager.h new file mode 100644 index 0000000..f7d6001 --- /dev/null +++ b/game/src/entity/manager.h @@ -0,0 +1,15 @@ +#pragma once + +#include +#include + +#include "entity.h" +#include "meshes.h" + +/* TODO: Sort entities by mesh type AS WELL AS distance. Binding + buffers is very performance-sensitive, thus to conserve speed one + type should be rendered in one go, then the other type, etc. */ + +void EntityManager_init (); +void EntityManager_tick (); +void EntityManager_render (); diff --git a/game/src/entity/meshes.c b/game/src/entity/meshes.c new file mode 100644 index 0000000..a4a70a9 --- /dev/null +++ b/game/src/entity/meshes.c @@ -0,0 +1,141 @@ +#include "meshes.h" + +/* TODO: add back faces. */ + +extern GameFlags game_flags; + +void +EntityMesh_bind (EntityMesh *mesh) +{ + glBindBuffer (GL_ARRAY_BUFFER, mesh->pbo); + glEnableVertexAttribArray (0); + glVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE, sizeof (float) * 3, 0); + + glBindBuffer (GL_ARRAY_BUFFER, mesh->uvbo); + glEnableVertexAttribArray (1); + glVertexAttribPointer (1, 2, GL_FLOAT, GL_FALSE, sizeof (float) * 2, 0); + + glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, mesh->ebo); +} + +void +EntityMesh_render (EntityMesh *mesh) +{ + if (game_flags.wireframe_enabled) + { + glDrawElements (GL_LINES, mesh->indices_len, GL_UNSIGNED_INT, 0); + } + else + { + glDrawElements (GL_TRIANGLES, mesh->indices_len, GL_UNSIGNED_INT, 0); + } +} + +EntityMesh +EntityMesh_make_billboard () +{ + /* 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] = { + 0, 2, 3, 3, 1, 0, /* Quad 1 */ + 3, 2, 0, 0, 1, 3, /* Back of quad 1 */ + }; + + float uvs[8] = { + 0.0, 1.0, + 1.0, 1.0, + 0.0, 0.0, + 1.0, 0.0, + }; + + EntityMesh mesh; + mesh.indices_len = 12; + 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); + + glBindBuffer (GL_ARRAY_BUFFER, 0); + glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0); + + return mesh; +} + +EntityMesh +EntityMesh_make_x () +{ + /* The positions are trivial. */ + float positions[24] = { + -1.0, -1.0, 0.0, + +1.0, -1.0, 0.0, + -1.0, 1.0, 0.0, + +1.0, 1.0, 0.0, + + 0.0, -1.0, -1.0, + 0.0, -1.0, 1.0, + 0.0, 1.0, -1.0, + 0.0, 1.0, 1.0 + }; + + unsigned int indices[24] = { + 0, 2, 3, 3, 1, 0, /* Quad 1 */ + 3, 2, 0, 0, 1, 3, /* Back of quad 1 */ + 4, 6, 7, 7, 5, 4, /* Quad 2 */ + 7, 6, 4, 4, 5, 7 /* Back of quad 2 */ + }; + + float uvs[16] = { + 0.0, 1.0, + 1.0, 1.0, + 0.0, 0.0, + 1.0, 0.0, + + 0.0, 1.0, + 1.0, 1.0, + 0.0, 0.0, + 1.0, 0.0 + }; + + EntityMesh mesh; + mesh.indices_len = 24; + glGenBuffers (1, &mesh.pbo); + glGenBuffers (1, &mesh.uvbo); + glGenBuffers (1, &mesh.ebo); + + glBindBuffer (GL_ARRAY_BUFFER, mesh.pbo); + glBufferData (GL_ARRAY_BUFFER, sizeof (float) * 24, 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) * 16, 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); + + 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 new file mode 100644 index 0000000..0bee0ce --- /dev/null +++ b/game/src/entity/meshes.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include + +#include "../flags.h" + +typedef struct EntityMesh +{ + size_t indices_len; + unsigned int pbo; + unsigned int uvbo; + unsigned int ebo; +} EntityMesh; + +void EntityMesh_bind (EntityMesh *mesh); +void EntityMesh_render (EntityMesh *mesh); +EntityMesh EntityMesh_make_billboard (); +EntityMesh EntityMesh_make_x (); diff --git a/game/src/graphics.c b/game/src/graphics.c index 5a65593..ccf445c 100644 --- a/game/src/graphics.c +++ b/game/src/graphics.c @@ -6,6 +6,9 @@ extern ChunkManager chunk_manager; extern GameState game_state; extern Resources resources; +extern EntityMesh mesh_billboard; +extern EntityMesh mesh_x; + void GraphicsContext_init () { @@ -54,12 +57,11 @@ GraphicsContext_render () { glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - program_use (resources.programs[1]); - mat4 projection, view; Camera_get_projection (&game_state.camera, 640.0 / 480.0, projection); Camera_get_view (&game_state.camera, view); + program_use (resources.programs[1]); program_set_mat4 (resources.programs[1], "projection", projection); program_set_mat4 (resources.programs[1], "view", view); @@ -71,8 +73,15 @@ GraphicsContext_render () ChunkManager_render (game_state.camera.position, resources.programs[1]); - glBindTexture (GL_TEXTURE_2D, 0); + program_use (resources.programs[0]); + program_set_mat4 (resources.programs[0], "projection", projection); + program_set_mat4 (resources.programs[0], "view", view); + glActiveTexture (GL_TEXTURE0); + glBindTexture (GL_TEXTURE_2D, resources.textures[5]); + EntityMesh_bind (&mesh_billboard); + EntityMesh_render (&mesh_billboard); + SDL_GL_SwapWindow (gfx.window); } diff --git a/game/src/graphics.h b/game/src/graphics.h index 37daaad..70ec949 100644 --- a/game/src/graphics.h +++ b/game/src/graphics.h @@ -5,6 +5,7 @@ #include "util.h" #include "chunk/manager.h" +#include "entity/manager.h" #include "state.h" #include "resources.h" diff --git a/game/src/main.c b/game/src/main.c index 56d00db..4ca8186 100644 --- a/game/src/main.c +++ b/game/src/main.c @@ -23,6 +23,7 @@ SDL_AppInit (void **appstate, int argc, char **argv) handlers_init (); Resources_init (); ChunkManager_init (); + EntityManager_init (); GameState_init (SDL_GetTicks ()); /* Set some basic game flags for testing. */ game_flags.can_free_look = 1; diff --git a/game/src/resources.c b/game/src/resources.c index 3518d2f..d1205c7 100644 --- a/game/src/resources.c +++ b/game/src/resources.c @@ -85,6 +85,7 @@ Resources_init () Resources_load_texture ("res/textures/grass.png"); Resources_load_texture ("res/textures/rock_cement.png"); Resources_load_texture ("res/textures/asphalt_gravel.png"); + Resources_load_texture ("res/textures/tree.png"); } void diff --git a/game/src/state.c b/game/src/state.c index 63c9562..28ea819 100644 --- a/game/src/state.c +++ b/game/src/state.c @@ -9,6 +9,7 @@ GameState_init (int ticks) { game_state.last_time = ticks; game_state.camera = Camera_default (); + game_state.camera.position[2] = -1.0; } void