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
|
#include <al/lib.h>
#include <al/math.h>
#include "view.h"
#define ZOOM_MAX 100.0
#define ZOOM_MIN 0.02
#define PAN_BOUNDS 35.0
#define X_IN_BOUNDS(view, w, x) \
((x + PAN_BOUNDS <= w) && (PAN_BOUNDS - x <= view->width * view->zoom / view->stretch))
#define Y_IN_BOUNDS(view, h, y) \
((y + PAN_BOUNDS <= h) && (PAN_BOUNDS - y <= view->height * view->zoom * view->stretch))
#define FOV_MIN AL_TO_RADIANS(10.0)
#define FOV_MAX AL_TO_RADIANS(160.0)
#define VIEW_ON_ITS_SIDE(view) \
(view->rotation % CAMU_VIEW_ROTATION_180 == CAMU_VIEW_ROTATION_90)
void camu_view_init(struct camu_view *view, u32 width, u32 height, u8 rotation)
{
view->mode = CAMU_DEFAULT_VIEW;
view->rotation = rotation;
view->width = width;
view->height = height;
view->zindex = 0;
view->stretch = 1.0;
view->fov = AL_TO_RADIANS(CAMU_DEFAULT_FOV);
}
void camu_view_calculate(struct camu_view *view, u32 window_width, u32 window_height)
{
u32 width, height;
if (VIEW_ON_ITS_SIDE(view)) {
width = view->height;
height = view->width;
view->stretch = height / (f64)width;
} else {
width = view->width;
height = view->height;
view->stretch = 1.0;
}
f64 frame_ratio = width / (f64)height;
f64 ratio = window_width / (f64)window_height;
switch (view->mode) {
case CAMU_VIEW_AUTOFIT:
if (frame_ratio > ratio) {
view->zoom = window_width / (f64)width;
} else {
view->zoom = window_height / (f64)height;
}
break;
case CAMU_VIEW_ZOOM:
if (frame_ratio < ratio) {
view->zoom = window_width / (f64)width;
} else {
view->zoom = window_height / (f64)height;
}
break;
default:
return;
}
view->x_offset = (window_width - (width * view->zoom)) / 2.0;
view->y_offset = (window_height - (height * view->zoom)) / 2.0;
}
bool camu_view_pan_simple(struct camu_view *view, u32 window_width, u32 window_height, f64 dx, f64 dy)
{
f64 nx = view->x_offset + dx;
f64 ny = view->y_offset + dy;
bool view_changed = false;
if (X_IN_BOUNDS(view, window_width, nx)) {
view->x_offset = nx;
view_changed = true;
}
if (Y_IN_BOUNDS(view, window_height, ny)) {
view->y_offset = ny;
view_changed = true;
}
return view_changed;
}
bool camu_view_zoom_simple(struct camu_view *view, u32 window_width, u32 window_height, f64 x, f64 y, f64 v)
{
x -= view->x_offset;
y -= view->y_offset;
x /= view->zoom;
y /= view->zoom;
f64 prev_width = window_width * view->zoom;
f64 prev_height = window_height * view->zoom;
f64 x_ratio = x / (f64)window_width;
f64 y_ratio = y / (f64)window_height;
f64 zoom = view->zoom + (v * view->zoom);
if (zoom > ZOOM_MAX || zoom < ZOOM_MIN) return false;
x = view->x_offset - x_ratio * ((window_width * zoom) - prev_width);
y = view->y_offset - y_ratio * ((window_height * zoom) - prev_height);
if (!(X_IN_BOUNDS(view, window_width, x) && Y_IN_BOUNDS(view, window_height, y))) {
return false;
}
view->x_offset = x;
view->y_offset = y;
view->zoom = zoom;
return true;
}
bool camu_view_zoom_fov(struct camu_view *view, f64 v)
{
f64 fov = view->fov - v;
if (fov > FOV_MAX || fov < FOV_MIN) return false;
view->fov = fov;
return true;
}
|