commit af0e98b
uint
·
2026-07-23 15:33:38 +0000 UTC
parent eabd47d
add camera movement
5 files changed,
+174,
-18
+39,
-0
1@@ -0,0 +1,39 @@
2+#ifndef CLIENT_CAMERA_H
3+#define CLIENT_CAMERA_H
4+
5+#include "mgmath.h"
6+
7+typedef struct {
8+ MGVec3 pos;
9+
10+ float yaw;
11+ float pitch;
12+
13+ float fov;
14+ float near; /* near plane */
15+ float far; /* far plane */
16+} MGCamera;
17+
18+/* initialise camera at `pos` */
19+void camera_init(MGCamera* cam, MGVec3 pos);
20+
21+/* move camera by offset */
22+void camera_move(MGCamera* cam, MGVec3 offset);
23+
24+/* rotate camera by pitch and yaw deltas */
25+void camera_rotate(MGCamera* cam, float dyaw, float dpitch);
26+
27+/* get cameras forward direction */
28+MGVec3 camera_get_forward(const MGCamera* cam);
29+
30+/* get cameras right direction */
31+MGVec3 camera_get_right(const MGCamera* cam);
32+
33+/* get cameras view matrix */
34+MGMat4 camera_get_view(const MGCamera* cam);
35+
36+/* get cameras projection matrix */
37+MGMat4 camera_get_proj(const MGCamera* cam, float aspect);
38+
39+#endif /* CLIENT_CAMERA_H */
40+
+10,
-10
1@@ -3,10 +3,12 @@
2
3 #include "mgmath.h"
4 #include "util.h"
5+#include "client/camera.h"
6 #include "renderer/renderer.h"
7 #include "renderer/test_block.h"
8
9 static MGMesh block = MGMESH_INVALID;
10+static MGCamera cam;
11
12 void test_scene_create(void)
13 {
14@@ -14,6 +16,10 @@ void test_scene_create(void)
15
16 if (block == MGMESH_INVALID)
17 mg_die(MG_ERR_REN_CREATE, "Failed to create test block mesh");
18+
19+ camera_init(&cam, MG_V3(3.0f, 3.0f, 3.0f));
20+ cam.yaw = MG_AngleDeg(-140.0f);
21+ cam.pitch = MG_AngleDeg(-20.0f);
22 }
23
24 void test_scene_draw(MGContext* ctx)
25@@ -21,7 +27,6 @@ void test_scene_draw(MGContext* ctx)
26 MGMat4 proj;
27 MGMat4 view;
28 MGMat4 model;
29- MGMat4 view_model;
30 MGMat4 mvp;
31 i32 width;
32 i32 height;
33@@ -34,16 +39,11 @@ void test_scene_draw(MGContext* ctx)
34
35 aspect = (float)width / (float)height;
36
37- proj = MG_Perspective_RH_NO(MG_AngleDeg(70.0f), aspect, 0.1f, 100.0f);
38- view = MG_LookAt_RH(
39- MG_V3(2.5f, 2.0f, 3.0f),
40- MG_V3(0.5f, 0.5f, 0.5f),
41- MG_V3(0.0f, 1.0f, 0.0f)
42- );
43-
44+ proj = camera_get_proj(&cam, aspect);
45+ view = camera_get_view(&cam);
46 model = MG_M4D(1.0f);
47- view_model = MG_MulM4(view, model);
48- mvp = MG_MulM4(proj, view_model);
49+
50+ mvp = MG_MulM4(proj, MG_MulM4(view, model));
51
52 renderer_mesh_draw(block, &mvp);
53 }
+1,
-0
1@@ -13,6 +13,7 @@ math_dep = cc.find_library('m', required: false)
2 sources = [
3 'source/main.c',
4 'source/util.c',
5+ 'source/client/camera.c',
6 'source/platform/platform.c',
7 ]
8
+73,
-0
1@@ -0,0 +1,73 @@
2+#include "client/camera.h"
3+#include "mgmath.h"
4+
5+#define MAX_PITCH (MG_AngleDeg(89.0f)) /* < 90 so no div by 0s */
6+
7+void camera_init(MGCamera* cam, MGVec3 pos)
8+{
9+ /* TODO: maybe some immediate mode ui could be nice? */
10+ /* IMGUI imgui Immediate */
11+ cam->pos = pos;
12+ cam->yaw = 0.0f;
13+ cam->pitch = 0.0f;
14+ cam->fov = 70.0f;
15+ cam->near = 0.1f;
16+ cam->far = 100.0f;
17+}
18+
19+void camera_move(MGCamera* cam, MGVec3 offset)
20+{
21+ MGVec3 forward = camera_get_forward(cam);
22+ MGVec3 right = camera_get_right(cam);
23+ MGVec3 movement = MG_V3(0.0f, 0.0f, 0.0f);
24+
25+ /* ignore pitch so we don't go to where we look */
26+ forward.y = 0.0f;
27+ forward = MG_NormV3(forward);
28+
29+ movement = MG_AddV3(movement, MG_MulV3F(forward, offset.z));
30+ movement = MG_AddV3(movement, MG_MulV3F(right, offset.x));
31+
32+ movement.y += offset.y;
33+ cam->pos = MG_AddV3(cam->pos, movement);
34+}
35+
36+void camera_rotate(MGCamera* cam, float dyaw, float dpitch)
37+{
38+ cam->yaw += dyaw;
39+ cam->pitch += dpitch;
40+
41+ if (cam->pitch > MAX_PITCH)
42+ cam->pitch = MAX_PITCH;
43+
44+ if (cam->pitch < -MAX_PITCH)
45+ cam->pitch = -MAX_PITCH;
46+}
47+
48+MGVec3 camera_get_forward(const MGCamera* cam)
49+{
50+ MGVec3 forward;
51+ float pcos = MG_CosF(cam->pitch);
52+
53+ forward.x = pcos * MG_SinF(cam->yaw);
54+ forward.y = MG_SinF(cam->pitch);
55+ forward.z = -pcos * MG_CosF(cam->yaw);
56+ return MG_NormV3(forward);
57+}
58+
59+MGVec3 camera_get_right(const MGCamera* cam)
60+{
61+ return MG_NormV3(MG_Cross(camera_get_forward(cam), MG_V3(0.0f, 1.0f, 0.0f)));
62+}
63+
64+MGMat4 camera_get_view(const MGCamera* cam)
65+{
66+ MGVec3 target = MG_AddV3(cam->pos, camera_get_forward(cam));
67+ return MG_LookAt_RH(cam->pos, target, MG_V3(0.0f, 1.0f, 0.0f));
68+}
69+
70+MGMat4 camera_get_proj(const MGCamera* cam, float aspect)
71+{
72+ return MG_Perspective_RH_NO(cam->fov, aspect, cam->near, cam->far);
73+}
74+
+51,
-8
1@@ -1,24 +1,67 @@
2+#include <SDL2/SDL.h>
3+
4+#include "SDL_keyboard.h"
5+#include "SDL_timer.h"
6 #include "util.h"
7 #include "platform/platform.h"
8 #include "renderer/renderer.h"
9 #include "renderer/test_scene.h"
10
11-int main(void)
12+static MGContext ctx = {
13+ NULL, {NULL},
14+ "Magnolia",
15+ 0, 0, 1024, 768,
16+};
17+
18+static void input(void)
19 {
20- MGContext ctx = {
21- NULL, /* window */
22- {NULL}, /* video-be */
23- "Magnolia", /* title */
24- 0, 0, /* x, y */
25- 1024, 768, /* w, h */
26- };
27+ static u32 last;
28+
29+ const u8* keys = SDL_GetKeyboardState(NULL);
30+ MGVec3 move = MG_V3(0.0f, 0.0f, 0.0f);
31+ u32 now = SDL_GetTicks();
32+ float sensitivity = 0.0025f; /* arbritrary sensitivity */
33+ float dt;
34+ i32 mx;
35+ i32 my;
36+
37+ if (!last) {
38+ last = now;
39+ return;
40+ }
41
42+ dt = (float)(now - last) / 1000.0f;
43+ last = now;
44+
45+ if (keys[SDL_SCANCODE_W])
46+ move.z += 1.0f;
47+ if (keys[SDL_SCANCODE_A])
48+ move.x -= 1.0f;
49+ if (keys[SDL_SCANCODE_S])
50+ move.z -= 1.0f;
51+ if (keys[SDL_SCANCODE_D])
52+ move.x += 1.0f;
53+ if (keys[SDL_SCANCODE_SPACE])
54+ move.y += 1.0f;
55+ if (keys[SDL_SCANCODE_LCTRL])
56+ move.y -= 1.0f;
57+
58+ move = MG_MulV3F(move, 4.0f * dt); /* arbritrary movement speed */
59+ camera_move(&cam, move);
60+ SDL_GetRelativeMouseState(&mx, &my);
61+ camera_rotate(&cam, mx * sensitivity, -my*sensitivity);
62+}
63+
64+int main(void)
65+{
66 platform_init(&ctx);
67 platform_window_create(&ctx);
68 renderer_create(&ctx);
69 test_scene_create();
70+ SDL_SetRelativeMouseMode(SDL_TRUE);
71
72 while (platform_poll(&ctx)) {
73+ input();
74 renderer_begin();
75
76 /* ... */