aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author0undefined <oscar@nelin.dk>2026-03-27 20:28:26 +0000
committeronelin <oscar@nelin.dk>2026-05-03 20:01:18 +0000
commit17ab9ae9e5df36c0756c24ebeb83964bb9aabd99 (patch)
tree3404d4a7708d94d0df3b9b746a9dc5ba1cde529d
parent25a214149344ee8f2109525207a20ff156512a2b (diff)
Add player & simple controls
-rw-r--r--state_mainstate/include/states/mainstate.h15
-rw-r--r--state_mainstate/src/mainstate.c102
2 files changed, 88 insertions, 29 deletions
diff --git a/state_mainstate/include/states/mainstate.h b/state_mainstate/include/states/mainstate.h
index 2baa4f2..df6fead 100644
--- a/state_mainstate/include/states/mainstate.h
+++ b/state_mainstate/include/states/mainstate.h
@@ -20,6 +20,18 @@ struct assimp_mesh {
f32* normals;
};
+struct object_physics {
+ vec3 pos;
+ vec3 vel;
+ vec3 acc;
+};
+
+struct entity_info {
+ struct object_physics p;
+ // i16 health
+ // .. etc
+};
+
typedef struct mainstate_state {
/* Resources */
Shader shaders[10];
@@ -28,7 +40,7 @@ typedef struct mainstate_state {
RenderObject objects[10];
u32 world[WORLD_SIZE * CHUNK_SIZE];
i_ctx input_ctx;
- binding_t input_bindings[10];
+ binding_t input_bindings[14];
vec3 cam_dir;
f32 cam_dir_dt;
vec3 cam_pos;
@@ -38,6 +50,7 @@ typedef struct mainstate_state {
f64 fov;
Resources resources;
f64 height;
+ struct entity_info player;
} mainstate_state;
#endif
diff --git a/state_mainstate/src/mainstate.c b/state_mainstate/src/mainstate.c
index 682712c..8f9c39b 100644
--- a/state_mainstate/src/mainstate.c
+++ b/state_mainstate/src/mainstate.c
@@ -27,6 +27,11 @@
#define FOV_INC 20
#endif
+enum FramebufferLayers {
+ FRAMEBUF_UI = 0,
+ FRAMEBUF_CAM = 1,
+};
+
enum GameResources {
MyVertexShader,
MyFragmentShader,
@@ -105,6 +110,7 @@ ShaderBuffer shaderbuf_quad_fullscreen[] = {
// or: a * (1-f) + f*b;
#define FF(_state) ((_state->fov - FOV_MIN) / (FOV_MAX - FOV_MIN))
#define SPEED(_state) (SPEED_MIN + FF(_state) * (SPEED_MAX - SPEED_MIN))
+#define PLAYER_SPEED (12.f)
//#define SPEED(_state) (SPEED_MIN * (1 - FF(_state)) + (FF(_state) * SPEED_MAX))
#define ACCELERATE( x, y, z ) \
@@ -123,6 +129,19 @@ void move_cam_up_stop(mainstate_state *s) { ACCELERATE( 0, -SPEED(s),
void move_cam_dwn(mainstate_state *s) { ACCELERATE( 0, -SPEED(s), 0); }
void move_cam_dwn_stop(mainstate_state *s) { ACCELERATE( 0, +SPEED(s), 0); }
+#undef ACCELERATE
+#define ACCELERATE( x, y, z ) \
+ glm_vec3_add((vec3){x, y, z}, s->player.p.acc, s->player.p.acc)
+void move_player_left(mainstate_state *s) { ACCELERATE(-PLAYER_SPEED, 0, 0); }
+void move_player_left_stop(mainstate_state *s) { ACCELERATE(+PLAYER_SPEED, 0, 0); }
+void move_player_right(mainstate_state *s) { ACCELERATE( PLAYER_SPEED, 0, 0); }
+void move_player_right_stop(mainstate_state *s) { ACCELERATE(-PLAYER_SPEED, 0, 0); }
+void move_player_fwd(mainstate_state *s) { ACCELERATE(0, 0, -PLAYER_SPEED); }
+void move_player_fwd_stop(mainstate_state *s) { ACCELERATE(0, 0, +PLAYER_SPEED); }
+void move_player_bck(mainstate_state *s) { ACCELERATE(0, 0, PLAYER_SPEED); }
+void move_player_bck_stop(mainstate_state *s) { ACCELERATE(0, 0, -PLAYER_SPEED); }
+
+
void window_resize_callback_ui(ivec3* dst, ivec2 src) {
// Map the resolution 1:1
glm_ivec2_copy(src, *dst);
@@ -355,7 +374,6 @@ void mainstate_init(Window *restrict w, mainstate_state *state, void* arg) {
[MySimpleShader_frag] = Declare_Shader("resources/simpl.frag"),
[MySimpleShader] = Declare_ShaderProgram(
simple_shader, sizeof(simple_shader) / sizeof(simple_shader[0])),
-
};
/// Setup the camera
@@ -504,6 +522,12 @@ void mainstate_init(Window *restrict w, mainstate_state *state, void* arg) {
state->input_bindings[ 8] = BindAction(KEY_Q, 0, cam_rotate_l);
state->input_bindings[ 9] = BindAction(KEY_E, 0, cam_rotate_r);
+ state->input_bindings[ 10] = BindState(KEY_LEFT, 0, move_player_left, move_player_left_stop);
+ state->input_bindings[ 11] = BindState(KEY_UP, 0, move_player_fwd, move_player_fwd_stop);
+ state->input_bindings[ 12] = BindState(KEY_DOWN, 0, move_player_bck, move_player_bck_stop);
+ state->input_bindings[ 13] = BindState(KEY_RIGHT, 0, move_player_right, move_player_right_stop);
+
+
state->input_ctx = (i_ctx){
.bindings = (binding_t*)&state->input_bindings,
.len = sizeof(state->input_bindings) / sizeof(binding_t),
@@ -523,39 +547,44 @@ void mainstate_init(Window *restrict w, mainstate_state *state, void* arg) {
// Texture final texture that is presented to screen
BUFFERPARAMETER_SET_PARAMETER(BUFFERPARAMETER_SET_TYPE(0, BufferType_texture), BUFFERPARAMETER_FMT_RGB8),
- // Target texture for intermmediate FB
+ // Target texture and depth buffer for intermmediate FB
BUFFERPARAMETER_SET_PARAMETER(BUFFERPARAMETER_SET_TYPE(0, BufferType_texture), BUFFERPARAMETER_FMT_RGB8),
- // The depth buffer could also be a texture like so:
+ // The depth buffer could either be a texture like so:
// BUFFERPARAMETER_SET_PARAMETER( BUFFERPARAMETER_SET_TYPE(0, BufferType_texture), BUFFERPARAMETER_FMT_DEPTH32),
+ // Or like this
BUFFERPARAMETER_SET_PARAMETER(BUFFERPARAMETER_SET_TYPE(0, BufferType_render), BUFFERPARAMETER_FMT_DEPTH32F),
};
FramebufferParameters p[] = {
- // 16 by 16 is just some bogus values, but they cannot be zero, as they're
+ // 48 by 48 is just some bogus values, but they cannot be zero, as they're
// needed to be set when resetting cameras.
- {.num_textures = 1, .num_renderbuffers = 0, .dimensions = {48, 48, 0}},
- {.num_textures = 1, .num_renderbuffers = 1, .dimensions = {48, 48, 0}},
+ [FRAMEBUF_UI] = {.num_textures = 1, .num_renderbuffers = 0, .dimensions = {48, 48, 0}},
+ [FRAMEBUF_CAM] = {.num_textures = 1, .num_renderbuffers = 1, .dimensions = {48, 48, 0}},
};
// There's a strange duality between using functions to change render_targets,
// and manipulating the datastructures directly.
- window_init_renderstack(w, 2, sizeof(t) / sizeof(t[0]), p, t);
- w->render_targets->camera_reset_callback[0] = &perspective_update_callback_ui;
- w->render_targets->framebuffer_size_callback[0] = &window_resize_callback_ui;
- w->render_targets->camera_reset_callback[1] = &perspective_update_callback;
- w->render_targets->framebuffer_size_callback[1] = &window_resize_callback;
+ window_init_renderstack(w, sizeof(p) / sizeof(p[0]), sizeof(t) / sizeof(t[0]), p, t);
+ w->render_targets->camera_reset_callback[FRAMEBUF_UI] = &perspective_update_callback_ui;
+ w->render_targets->framebuffer_size_callback[FRAMEBUF_UI] = &window_resize_callback_ui;
+ w->render_targets->camera_reset_callback[FRAMEBUF_CAM] = &perspective_update_callback;
+ w->render_targets->framebuffer_size_callback[FRAMEBUF_CAM] = &window_resize_callback;
- r_set_camera(w->render_targets, 0, &UI_Camera);
- r_set_camera(w->render_targets, 1, &state->c);
+ r_set_camera(w->render_targets, FRAMEBUF_UI, &UI_Camera);
+ r_set_camera(w->render_targets, FRAMEBUF_CAM, &state->c);
+ // Create the quad renderobject for the final renderpass, using the (render)
+ // buffer from the FRAMEBUF_CAM. Not really desired that we need indexing into
+ // the rendertargets->buffer.
+ //
// Remember to keep this texture up-to date when resizing! A caveat I'd rather
// have implemented in the engine s.t. I don't need to think about it here.
// I guess it is soon time to define a "scene" structure for DAW.
state->objects[3] = RenderObject_new(
// Shader
get_asset(&state->resources, MyFullscreenShader),
- // Texture
+ // Texture, from FRAMEBUF_CAM (cumulative sum textures & buffers, zero-indexed)
w->render_targets->buffer[1],
// Vertices
shaderbuf_quad_fullscreen,
@@ -601,6 +630,11 @@ void mainstate_init(Window *restrict w, mainstate_state *state, void* arg) {
light_shaderbuf,
sizeof(light_shaderbuf) / sizeof(ShaderBuffer)
);
+
+ // Setup
+ glm_vec3_zero(state->player.p.vel);
+ glm_vec3_zero(state->player.p.acc);
+ glm_vec3_copy((vec3){CHUNK_WIDTH * WORLD_WIDTH / 2.f, CHUNK_HEIGHT / 4.f, CHUNK_LENGTH * WORLD_LENGTH / 2.f}, state->player.p.pos);
}
void* mainstate_free(mainstate_state *_ /* unused */) {
@@ -614,25 +648,37 @@ StateType mainstate_update(Window *restrict w, mainstate_state *state, f64 dt) {
// Convert to seconds
const f32 dsec = (f32)(dt / 1000000.f);
- r_clear_buffer(w->context, w->render_targets, 0);
- r_clear_buffer(w->context, w->render_targets, 1);
+ r_clear_buffer(w->context, w->render_targets, FRAMEBUF_UI);
+ r_clear_buffer(w->context, w->render_targets, FRAMEBUF_CAM);
// Order really shouldn't matter
- draw_model(w, 1, &state->objects[4], (vec4){CHUNK_WIDTH * WORLD_WIDTH / 2.f, CHUNK_HEIGHT / 4.f, CHUNK_LENGTH * WORLD_LENGTH / 2.f, 1});
- draw_model(w, 1, &state->objects[4], (vec4){CHUNK_WIDTH * WORLD_WIDTH / 2.f, CHUNK_HEIGHT / 4.f - 1.f, CHUNK_LENGTH * WORLD_LENGTH / 2.f + 2, 1});
- draw_model(w, 1, &state->objects[4], (vec4){CHUNK_WIDTH * WORLD_WIDTH / 2.f, CHUNK_HEIGHT / 4.f, CHUNK_LENGTH * WORLD_LENGTH / 2.f + 4, 1});
- draw_model(w, 1, &state->objects[4], (vec4){CHUNK_WIDTH * WORLD_WIDTH / 2.f + 2, CHUNK_HEIGHT / 4.f, CHUNK_LENGTH * WORLD_LENGTH / 2.f + 4, 1});
- draw_model(w, 1, &state->objects[4], (vec4){CHUNK_WIDTH * WORLD_WIDTH / 2.f, CHUNK_HEIGHT / 4.f, CHUNK_LENGTH * WORLD_LENGTH / 2.f, 1});
+ vec4 playerpos;
+ {
+ const f32 friction = 1.f / (1.f + (dsec * 32.f));
+ vec3 acc;
+ vec3 vel;
- draw_model(w, 1, &state->terrain.renderobj, (vec4){0, 0, 0, 1});
+ glm_vec3_scale(state->player.p.acc, dsec, acc);
+ glm_vec3_scale(state->player.p.vel, dsec, vel);
- // Light
- draw_model(w, 1, &state->objects[5], (vec4){7, 65, 10, 1});
+ glm_vec3_add(acc, vel, vel);
- // Location should, however
- // Draw UI by their screen XY coordinates, Z is the depth/layering
- draw_model(w, 0, &state->objects[3], (vec4){0.0, 0.0, 0.0, 1});
+ // Add delta speed to speed
+ glm_vec3_add(acc, state->player.p.vel, state->player.p.vel);
+ // Scale by friction
+ glm_vec3_scale(state->player.p.vel, friction, state->player.p.vel);
+ glm_vec3_add(state->player.p.pos, state->player.p.vel, state->player.p.pos);
+ }
+ glm_vec4(state->player.p.pos, 1, playerpos);
+ // Draw player, terrain, and "lightbulb" onto camera texture
+ draw_model(w, FRAMEBUF_CAM, &state->objects[4], playerpos);
+ draw_model(w, FRAMEBUF_CAM, &state->terrain.renderobj, (vec4){0, 0, 0, 1});
+ draw_model(w, FRAMEBUF_CAM, &state->objects[5], (vec4){7, 65, 10, 1});
+
+ // Draw the camera onto the final "ui" layer
+ draw_model(w, FRAMEBUF_UI, &state->objects[3], (vec4){0.0, 0.0, 0.0, 1});
+ // Draw UI by their screen XY coordinates, Z is the depth/layering
{
// Anchor top left
const vec2 padding = {240, 240};
@@ -640,7 +686,7 @@ StateType mainstate_update(Window *restrict w, mainstate_state *state, f64 dt) {
const float window_height = w->windowsize[1];
const float anchor_left = -(window_width - padding[0]);
const float anchor_top = (window_height - padding[1]);
- draw_model(w, 0, &state->objects[2], (vec4){anchor_left, anchor_top, 0.0, 1});
+ draw_model(w, FRAMEBUF_UI, &state->objects[2], (vec4){anchor_left, anchor_top, 0.0, 1});
}
// Move the camera