forked from guillaumeblanc/ozz-animation
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcamera.h
134 lines (124 loc) · 4.06 KB
/
camera.h
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
127
128
129
130
131
132
133
134
#pragma once
/*
Quick'n'dirty Maya-style camera. Include after HandmadeMath.h
and sokol_app.h
*/
#include <string.h>
#include <math.h>
#include <assert.h>
#define CAMERA_DEFAULT_MIN_DIST (2.0f)
#define CAMERA_DEFAULT_MAX_DIST (30.0f)
#define CAMERA_DEFAULT_MIN_LAT (-85.0f)
#define CAMERA_DEFAULT_MAX_LAT (85.0f)
#define CAMERA_DEFAULT_DIST (5.0f)
#define CAMERA_DEFAULT_ASPECT (60.0f)
#define CAMERA_DEFAULT_NEARZ (0.01f)
#define CAMERA_DEFAULT_FARZ (100.0f)
typedef struct {
float min_dist;
float max_dist;
float min_lat;
float max_lat;
float distance;
float latitude;
float longitude;
float aspect;
float nearz;
float farz;
hmm_vec3 center;
} camera_desc_t;
typedef struct {
float min_dist;
float max_dist;
float min_lat;
float max_lat;
float distance;
float latitude;
float longitude;
float aspect;
float nearz;
float farz;
hmm_vec3 center;
hmm_vec3 eye_pos;
hmm_mat4 view;
hmm_mat4 proj;
hmm_mat4 view_proj;
} camera_t;
static float _cam_def(float val, float def) {
return ((val == 0.0f) ? def:val);
}
/* initialize to default parameters */
static void cam_init(camera_t* cam, const camera_desc_t* desc) {
assert(cam && desc);
memset(cam, 0, sizeof(camera_t));
cam->min_dist = _cam_def(desc->min_dist, CAMERA_DEFAULT_MIN_DIST);
cam->max_dist = _cam_def(desc->max_dist, CAMERA_DEFAULT_MAX_DIST);
cam->min_lat = _cam_def(desc->min_lat, CAMERA_DEFAULT_MIN_LAT);
cam->max_lat = _cam_def(desc->max_lat, CAMERA_DEFAULT_MAX_LAT);
cam->distance = _cam_def(desc->distance, CAMERA_DEFAULT_DIST);
cam->center = desc->center;
cam->latitude = desc->latitude;
cam->longitude = desc->longitude;
cam->aspect = _cam_def(desc->aspect, CAMERA_DEFAULT_ASPECT);
cam->nearz = _cam_def(desc->nearz, CAMERA_DEFAULT_NEARZ);
cam->farz = _cam_def(desc->farz, CAMERA_DEFAULT_FARZ);
}
/* feed mouse movement */
static void cam_orbit(camera_t* cam, float dx, float dy) {
assert(cam);
cam->longitude -= dx;
if (cam->longitude < 0.0f) {
cam->longitude += 360.0f;
}
if (cam->longitude > 360.0f) {
cam->longitude -= 360.0f;
}
cam->latitude = HMM_Clamp(cam->min_lat, cam->latitude + dy, cam->max_lat);
}
/* feed zoom (mouse wheel) input */
static void cam_zoom(camera_t* cam, float d) {
assert(cam);
cam->distance = HMM_Clamp(cam->min_dist, cam->distance + d, cam->max_dist);
}
static hmm_vec3 _cam_euclidean(float latitude, float longitude) {
const float lat = HMM_ToRadians(latitude);
const float lng = HMM_ToRadians(longitude);
return HMM_Vec3(cosf(lat) * sinf(lng), sinf(lat), cosf(lat) * cosf(lng));
}
/* update the view, proj and view_proj matrix */
static void cam_update(camera_t* cam, int fb_width, int fb_height) {
assert(cam);
assert((fb_width > 0) && (fb_height > 0));
const float w = (float) fb_width;
const float h = (float) fb_height;
cam->eye_pos = HMM_AddVec3(cam->center, HMM_MultiplyVec3f(_cam_euclidean(cam->latitude, cam->longitude), cam->distance));
cam->view = HMM_LookAt(cam->eye_pos, cam->center, HMM_Vec3(0.0f, 1.0f, 0.0f));
cam->proj = HMM_Perspective(cam->aspect, w/h, cam->nearz, cam->farz);
cam->view_proj = HMM_MultiplyMat4(cam->proj, cam->view);
}
/* handle sokol-app input events */
static void cam_handle_event(camera_t* cam, const sapp_event* ev) {
assert(cam);
switch (ev->type) {
case SAPP_EVENTTYPE_MOUSE_DOWN:
if (ev->mouse_button == SAPP_MOUSEBUTTON_LEFT) {
sapp_lock_mouse(true);
}
break;
case SAPP_EVENTTYPE_MOUSE_UP:
if (ev->mouse_button == SAPP_MOUSEBUTTON_LEFT) {
sapp_lock_mouse(false);
}
break;
case SAPP_EVENTTYPE_MOUSE_SCROLL:
cam_zoom(cam, ev->scroll_y * 0.5f);
break;
case SAPP_EVENTTYPE_MOUSE_MOVE:
if (sapp_mouse_locked()) {
cam_orbit(cam, ev->mouse_dx * 0.25f, ev->mouse_dy * 0.25f);
}
break;
default:
break;
}
}