summaryrefslogtreecommitdiff
path: root/src/extend/camera.c
blob: f34900664a0f3d03c75ff1eae56978ee1d1273a3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include "camera.h"

// A unity editor style camera

void camera_init(Camera* cam, wog_Window* wnd) {
	cam->is_viewdirty = cam->is_projdirty = TRUE;

	// camera local = world
	cam->transform.parent = NULL ;
	cam->transform.localposition = vec3_make(0, 0, 800);
	cam->transform.localscale = vec3_make(1, 1, 1);
	cam->transform.localrotation = quat_make(0, 0, 0);

	cam->near = 1; 
	cam->far = 5500;
	cam->aspect = 600/500.f;
	cam->fov = 60;
	cam->zoom_speed = 4000;

	cam->look_around = FALSE;
	cam->move_around = FALSE;
	cam->rotate_sensitivity.x = 5;
	cam->rotate_sensitivity.y = 5;
	cam->move_sensitivity.x = 150;
	cam->move_sensitivity.y = 100;
	cam->euler.yaw = cam->euler.pitch = cam->euler.roll = 0;

	cam->wnd = wnd;
}

void camera_getmatrix(Camera* cam, Mat4* view, Mat4* proj) {
	camera_getviewmatrix(cam, view);
	camera_getprojmatrix(cam, proj);
}

void camera_getviewmatrix(Camera* cam, Mat4* out) {
	if (!cam->is_viewdirty) {
		if (out)*out = cam->view_matrix;
		return;
	}
	transform_getinvmatrixnoscale(&cam->transform, &cam->view_matrix);
	if(out) *out = cam->view_matrix;
	cam->is_viewdirty = FALSE;
}

void camera_getprojmatrix(Camera* cam, Mat4* out) {
	if (!cam->is_projdirty) {
		if (out)*out = cam->proj_matrix;
		return;
	}
	mat4_setperspective(cam->fov, cam->aspect, cam->near, cam->far, &cam->proj_matrix);
	if(out) *out = cam->proj_matrix;
	cam->is_projdirty = FALSE;
}

static void _onwheelscroll(Camera* cam, int wheel, float dt) {
	Quat rot; transform_getrotation(&cam->transform, &rot);
	Vec3 forward = {0,0,-1};
	quat_applytovec3(&rot, &forward, &forward);
	vec3_scale(&forward, cam->zoom_speed * wheel * dt, &forward);
	vec3_plus(&forward, &cam->transform.localposition, &cam->transform.localposition);
	cam->is_viewdirty = TRUE;
}

static void _onlookaround(Camera* cam,float dt) {
	if(!cam->look_around) return;
	static Quat rot;
	static Euler angle;
	int x, y; 
	wog_getMouse(cam->wnd, &x, &y);
	float dx = cam->mouse_prev.x - x, dy = y - cam->mouse_prev.y;
	angle.x = dy * cam->rotate_sensitivity.y * dt;
	angle.y = dx * cam->rotate_sensitivity.x * dt;
	cam->euler.pitch += angle.x;
	cam->euler.yaw += angle.y;
	//printf("%f    %f\n", cam->euler.pitch, cam->euler.yaw);
	quat_fromeuler(&cam->euler, &cam->transform.localrotation);
	cam->mouse_prev.x = x; cam->mouse_prev.y = y;
	cam->is_viewdirty = TRUE;
}

static void _onmovearound(Camera* cam, float dt) {
	if(!cam->move_around) return ;	
	int x, y;
	wog_getMouse(cam->wnd, &x, &y);
	Vec3 dd = { cam->mouse_prev.x - x, y - cam->mouse_prev.y , 0};
	dd.x *= cam->move_sensitivity.x * dt;
	dd.y *= cam->move_sensitivity.y * dt;
	quat_applytovec3(&cam->transform.localrotation, &dd, &dd);
	//printf("%f   %f   %f\n", dd.x, dd.y, dd.z);
	vec3_plus(&cam->transform.localposition, &dd, &cam->transform.localposition);
	cam->mouse_prev.x = x; cam->mouse_prev.y = y;
	cam->is_viewdirty = TRUE;
}

void camera_onevent(Camera* cam, wog_Event* e, float dt) {
	if(e == NULL) return ;
	if (e->type == WOG_EMOUSEWHEEL) {//zoom in\zoom out
		_onwheelscroll(cam, e->wheel, dt);
	}
	else if (e->type == WOG_EMOUSEBUTTONDOWN) {
		if (!cam->look_around && e->button == WOG_MOUSE_RBUTTON) {
			cam->look_around = TRUE;
			cam->mouse_prev.x = e->pos.x; 
			cam->mouse_prev.y = e->pos.y;
		}
		if (!cam->move_around && e->button == WOG_MOUSE_MIDDLE) {
			cam->move_around = TRUE; 
			cam->mouse_prev.x = e->pos.x;
			cam->mouse_prev.y = e->pos.y;
		}
	}
	else if (e->type == WOG_EMOUSEBUTTONUP) {
		if (e->button == WOG_MOUSE_RBUTTON)
			cam->look_around = FALSE;
		if (e->button == WOG_MOUSE_MIDDLE)
			cam->move_around = FALSE;
	}
}

void camera_onupdate(Camera* cam, float dt) {
	if (cam->look_around)
		_onlookaround(cam, dt);
	if (cam->move_around)
		_onmovearound(cam, dt);
}