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 		/* ... */