separation to vec.h, generic vector ops, camera class and its usage for spatial rendering

This commit is contained in:
veclav talica 2024-07-29 15:21:39 +03:00
parent 86d135281e
commit ff077c5d0d
12 changed files with 207 additions and 62 deletions

View File

@ -36,16 +36,16 @@ set(SOURCE_FILES
third-party/stb/stb_vorbis.c third-party/stb/stb_vorbis.c
third-party/glad/src/glad.c third-party/glad/src/glad.c
src/config.h
src/context.h
src/context.c
src/main.c src/main.c
src/audio.c src/config.h
src/context.c src/context.h
src/audio.c src/audio.h
src/util.c src/util.h src/util.c src/util.h
src/rendering.c src/rendering.h src/rendering.c src/rendering.h
src/textures.c src/textures.h src/textures.c src/textures.h
src/input.c src/input.h src/input.c src/input.h
src/text.c src/text.h src/text.c src/text.h
src/camera.c src/camera.h
src/game_api.h src/game_api.h
src/game/game.c src/game/game.h src/game/game.c src/game/game.h

27
src/camera.c Normal file
View File

@ -0,0 +1,27 @@
#include "camera.h"
t_matrix4 camera_look_at(const t_camera *const camera) {
/* from cglm */
const t_fvec3 f = m_vec_norm(m_vec_sub(camera->pos, camera->target));
const t_fvec3 r = m_vec_norm(m_vec_cross(f, camera->up));
const t_fvec3 u = m_vec_cross(f, r);
t_matrix4 result;
result.row[0].x = r.x;
result.row[0].y = u.x;
result.row[0].z =-f.x;
result.row[1].x = r.y;
result.row[1].y = u.y;
result.row[1].z =-f.y;
result.row[2].x = r.z;
result.row[2].y = u.z;
result.row[2].z =-f.z;
result.row[3].x =-m_vec_dot(r, camera->pos);
result.row[3].y =-m_vec_dot(u, camera->pos);
result.row[3].z = m_vec_dot(f, camera->pos);
result.row[0].w = result.row[1].w = result.row[2].w = 0.0f;
result.row[3].w = 1.0f;
return result;
}

15
src/camera.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef CAMERA_H
#define CAMERA_H
#include "util.h"
/* first person camera class */
typedef struct camera {
t_fvec3 pos; /* eye position */
t_fvec3 target; /* target point */
t_fvec3 up; /* normalized up vector */
} t_camera;
t_matrix4 camera_look_at(const t_camera *camera);
#endif

View File

@ -11,6 +11,15 @@ static void ingame_tick(struct state *state) {
world_drawdef(scn->world); world_drawdef(scn->world);
player_calc(scn->player); player_calc(scn->player);
static t_camera cam = { .pos = { 0 }, .target = { 0, 0, -1 }, .up = { 0, -1, 0 } };
if (input_is_action_pressed(&ctx.input, "player_left"))
cam.pos.x -= 0.01f;
if (input_is_action_pressed(&ctx.input, "player_right"))
cam.pos.x += 0.01f;
push_camera(&cam);
push_sprite_ex((t_frect){ .x = 32, .y = 64, .w = 64, .h = 64 }, (t_push_sprite_args){ push_sprite_ex((t_frect){ .x = 32, .y = 64, .w = 64, .h = 64 }, (t_push_sprite_args){
.path = "/assets/light.png", .path = "/assets/light.png",
.color = (t_color){255, 0, 0, 255}, }); .color = (t_color){255, 0, 0, 255}, });

View File

@ -13,6 +13,10 @@
#include <tgmath.h> #include <tgmath.h>
/* TODO: have a default initialized one */
static t_matrix4 camera_projection;
void render_queue_clear(void) { void render_queue_clear(void) {
/* since i don't intend to free the queues, */ /* since i don't intend to free the queues, */
/* it's faster and simpler to just "start over" */ /* it's faster and simpler to just "start over" */
@ -160,7 +164,7 @@ void render(void) {
{ {
glMatrixMode(GL_PROJECTION); glMatrixMode(GL_PROJECTION);
glLoadIdentity(); glLoadMatrixf(&camera_projection.row[0].x);
glMatrixMode(GL_MODELVIEW); glMatrixMode(GL_MODELVIEW);
glLoadIdentity(); glLoadIdentity();
@ -168,6 +172,9 @@ void render(void) {
render_space(); render_space();
} }
/* TODO: only do it when transition between spaces is needed */
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
{ {
glMatrixMode(GL_PROJECTION); glMatrixMode(GL_PROJECTION);
glLoadIdentity(); glLoadIdentity();
@ -181,3 +188,8 @@ void render(void) {
SDL_GL_SwapWindow(ctx.window); SDL_GL_SwapWindow(ctx.window);
} }
void push_camera(const t_camera *const camera) {
/* TODO: skip recaulculating if it's the same? */
camera_projection = camera_look_at(camera);
}

View File

@ -2,6 +2,7 @@
#define RENDERING_H #define RENDERING_H
#include "util.h" #include "util.h"
#include "camera.h"
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
@ -63,6 +64,9 @@ void unfurl_triangle(const char *path,
// t_fvec2 scaling, // t_fvec2 scaling,
// t_frect uvs); // t_frect uvs);
/* pushes a camera state to be used for all future unfurl_* commands */
void push_camera(const t_camera *camera);
/* renders the background, then the primitives in all render queues */ /* renders the background, then the primitives in all render queues */
void render(void); void render(void);

View File

@ -3,8 +3,8 @@
#define CIRCLES_H #define CIRCLES_H
#include "../util.h" #include "../util.h"
#include "internal_api.h"
#include "../context.h" #include "../context.h"
#include "internal_api.h"
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
#include <stb_ds.h> #include <stb_ds.h>

View File

@ -7,6 +7,7 @@
#include "../context.h" #include "../context.h"
#include "../util.h" #include "../util.h"
#include "quad_element_buffer.h" #include "quad_element_buffer.h"
#include "internal_api.h"
#include <stb_ds.h> #include <stb_ds.h>

View File

@ -4,6 +4,7 @@
#include "../textures.h" #include "../textures.h"
#include "../context.h" #include "../context.h"
#include "internal_api.h"
#include <stb_ds.h> #include <stb_ds.h>
@ -66,6 +67,8 @@ static void draw_uncolored_space_traingle_batch(struct mesh_batch *batch,
t_rect srcrect = textures_get_srcrect(&ctx.texture_cache, texture_key); t_rect srcrect = textures_get_srcrect(&ctx.texture_cache, texture_key);
t_rect dims = textures_get_dims(&ctx.texture_cache, texture_key); t_rect dims = textures_get_dims(&ctx.texture_cache, texture_key);
/* TODO: fast path for uvs mapped directly on srcrect corners? */
const float wr = (float)srcrect.w / (float)dims.w; const float wr = (float)srcrect.w / (float)dims.w;
const float hr = (float)srcrect.h / (float)dims.h; const float hr = (float)srcrect.h / (float)dims.h;
const float xr = (float)srcrect.x / (float)dims.w; const float xr = (float)srcrect.x / (float)dims.w;

View File

@ -194,21 +194,6 @@ t_fvec2 frect_center(t_frect rect) {
} }
t_fvec2 fvec2_from_vec2(t_vec2 vec) {
return (t_fvec2) {
.x = (float)vec.x,
.y = (float)vec.y,
};
}
t_fvec2 fvec2_from_shvec2(t_shvec2 vec) {
return (t_fvec2) {
.x = (float)vec.x,
.y = (float)vec.y,
};
}
void tick_timer(int *value) { void tick_timer(int *value) {
*value = MAX(*value - 1, 0); *value = MAX(*value - 1, 0);
} }

View File

@ -1,6 +1,7 @@
#ifndef UTIL_H #ifndef UTIL_H
#define UTIL_H #define UTIL_H
#include "vec.h"
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
#include <physfs.h> #include <physfs.h>
@ -78,40 +79,13 @@ _Alignas(4)
} t_color; } t_color;
/* a point in some space (integer) */
typedef struct vec2 {
int x, y;
} t_vec2;
/* a point in some space (floating point) */
typedef struct fvec2 {
_Alignas(8)
float x;
float y;
} t_fvec2;
/* a point in some three dimension space (floating point) */
/* y goes up, x goes to the right */
typedef struct fvec3 {
_Alignas(8)
float x;
float y;
float z;
} t_fvec3;
/* a point in some space (short) */
typedef struct shvec2 {
short x, y;
} t_shvec2;
/* a rectangle with the origin at the upper left (integer) */ /* a rectangle with the origin at the upper left (integer) */
typedef struct rect { typedef struct rect {
int x, y; _Alignas(16)
int w, h; int32_t x;
int32_t y;
int32_t w;
int32_t h;
} t_rect; } t_rect;
@ -135,15 +109,9 @@ t_frect to_frect(t_rect rect);
t_fvec2 frect_center(t_frect rect); t_fvec2 frect_center(t_frect rect);
/* aren't macros to prevent double evaluation with side effects */ typedef struct matrix4 {
/* maybe could be inlined? i hope LTO will resolve this */ t_fvec4 row[4];
t_fvec2 fvec2_from_vec2(t_vec2 vec); } t_matrix4;
t_fvec2 fvec2_from_shvec2(t_shvec2 vec);
#define m_to_fvec2(p_any_vec2) (_Generic((p_any_vec2), \
t_vec2: fvec2_from_vec2, \
t_shvec2: fvec2_from_shvec2 \
)(p_any_vec2))
/* decrements an lvalue (which should be an int), stopping at 0 */ /* decrements an lvalue (which should be an int), stopping at 0 */

121
src/vec.h Normal file
View File

@ -0,0 +1,121 @@
#ifndef VEC_H
#define VEC_H
#include <stdint.h>
#include <math.h>
/* a point in some space (integer) */
typedef struct vec2 {
_Alignas(8)
int32_t x;
int32_t y;
} t_vec2;
/* a point in some space (floating point) */
typedef struct fvec2 {
_Alignas(8)
float x;
float y;
} t_fvec2;
/* a point in some three dimension space (floating point) */
/* y goes up, x goes to the right */
typedef struct fvec3 {
_Alignas(16)
float x;
float y;
float z;
} t_fvec3;
/* a point in some three dimension space (floating point) */
/* y goes up, x goes to the right */
typedef struct fvec4 {
_Alignas(16)
float x;
float y;
float z;
float w;
} t_fvec4;
/* a point in some space (short) */
typedef struct shvec2 {
_Alignas(4)
int16_t x;
int16_t y;
} t_shvec2;
/* aren't macros to prevent double evaluation with side effects */
/* maybe could be inlined? i hope LTO will resolve this */
static inline t_fvec2 fvec2_from_vec2(t_vec2 vec) {
return (t_fvec2) {
.x = (float)vec.x,
.y = (float)vec.y,
};
}
static inline t_fvec2 fvec2_from_shvec2(t_shvec2 vec) {
return (t_fvec2) {
.x = (float)vec.x,
.y = (float)vec.y,
};
}
static inline t_fvec3 fvec3_sub(t_fvec3 a, t_fvec3 b) {
return (t_fvec3) { a.x - b.x, a.y - b.y, a.z - b.z };
}
static inline t_fvec3 fvec3_scale(t_fvec3 a, float s) {
return (t_fvec3) { a.x * s, a.y * s, a.z * s };
}
static inline float fvec3_dot(t_fvec3 a, t_fvec3 b) {
return a.x * b.x + a.x * b.x + a.z * b.z;
}
static inline t_fvec3 fvec3_cross(t_fvec3 a, t_fvec3 b) {
return (t_fvec3) {
a.y * b.z - a.z * b.y,
a.z * b.x - a.x * b.z,
a.x * b.y - a.y * b.x,
};
}
/* TODO: fast_sqrt version? */
static inline t_fvec3 fvec3_norm(t_fvec3 a) {
const float n = sqrtf(fvec3_dot(a, a));
/* TODO: do we need truncating over epsilon as cglm does? */
return fvec3_scale(a, 1.0f / n);
}
#define m_to_fvec2(p_any_vec2) (_Generic((p_any_vec2), \
t_vec2: fvec2_from_vec2, \
t_shvec2: fvec2_from_shvec2 \
)(p_any_vec2))
#define m_vec_sub(p_any_vec0, p_any_vec1) (_Generic((p_any_vec0), \
t_fvec3: fvec3_sub \
)(p_any_vec0, p_any_vec1))
#define m_vec_scale(p_any_vec, p_any_scalar) (_Generic((p_any_vec), \
t_fvec3: fvec3_scale \
)(p_any_vec, p_any_scalar))
#define m_vec_dot(p_any_vec0, p_any_vec1) (_Generic((p_any_vec0), \
t_fvec3: fvec3_dot \
)(p_any_vec0, p_any_vec1))
#define m_vec_cross(p_any_vec0, p_any_vec1) (_Generic((p_any_vec0), \
t_fvec3: fvec3_cross \
)(p_any_vec0, p_any_vec1))
#define m_vec_norm(p_any_vec) (_Generic((p_any_vec), \
t_fvec3: fvec3_norm \
)(p_any_vec))
#endif