a4e6257aecd11b35f42b14d2c5c0553f8747df91
[simavr] / examples / shared / libc3 / src / c3camera.c
1 /*
2         c3camera.c
3
4         Copyright 2008-2012 Michel Pollet <buserror@gmail.com>
5         Copyright (c) 1998 Paul Rademacher
6
7         This file is part of libc3.
8
9         libc3 is free software: you can redistribute it and/or modify
10         it under the terms of the GNU General Public License as published by
11         the Free Software Foundation, either version 3 of the License, or
12         (at your option) any later version.
13
14         libc3 is distributed in the hope that it will be useful,
15         but WITHOUT ANY WARRANTY; without even the implied warranty of
16         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17         GNU General Public License for more details.
18
19         You should have received a copy of the GNU General Public License
20         along with libc3.  If not, see <http://www.gnu.org/licenses/>.
21  */
22
23 #include <string.h>
24 #include "c3camera.h"
25
26
27 void
28 c3cam_set_distance(
29                 c3cam_p c,
30                 const c3f new_distance)
31 {
32     if ( new_distance <= 0.0 )  /* Distance has to be positive */
33         return;
34
35     /* We find the current forward vector */
36 //    forward = lookat - eye;
37     c->forward = c3vec3_normalize(c3vec3_sub(c->lookat, c->eye));
38
39     /* Set distance */
40     c->distance = new_distance;
41
42     /* Find new eye point */
43     c->eye = c3vec3_sub(c->lookat, c3vec3_mulf(c->forward, c->distance));
44     c3cam_update(c);
45 }
46
47 void
48 c3cam_set_upv(
49                 c3cam_p c,
50                 const c3vec3 new_up)
51 {
52     c->up = new_up;
53     c3cam_update(c);
54 }
55
56 void
57 c3cam_set_upf(
58                 c3cam_p c,
59                 const c3f x,
60                 const c3f y,
61                 const c3f z)
62 {
63         c3cam_set_upv(c, c3vec3f(x,y,z));
64 }
65
66 void
67 c3cam_set_eyev(
68                 c3cam_p c,
69                 const c3vec3 new_eye)
70 {
71     c->eye = new_eye;
72     c3cam_update(c);
73 }
74
75 void
76 c3cam_set_eyef(
77                 c3cam_p c,
78                 const c3f x,
79                 const c3f y,
80                 const c3f z)
81 {
82         c3cam_set_eyev(c, c3vec3f(x,y,z));
83 }
84
85 void
86 c3cam_set_lookatv(
87                 c3cam_p c,
88                 const c3vec3 new_lookat)
89 {
90     c->lookat = new_lookat;
91     c3cam_update(c);
92 }
93
94 void
95 c3cam_set_lookatf(
96                 c3cam_p c,
97                 const c3f x,
98                 const c3f y,
99                 const c3f z)
100 {
101         c3cam_set_lookatv(c, c3vec3f(x,y,z));
102 }
103
104
105 void
106 c3cam_roll(
107                 c3cam_p c,
108                 const c3f angle)
109 {
110     c3mat4 rot = rotation3D(c->forward, angle );
111     c->up = c3mat4_mulv3(&rot, c->up);
112     c3cam_update(c);
113 }
114
115 void
116 c3cam_eye_yaw(
117                 c3cam_p c,
118                 const c3f angle)
119 {
120     c3vec3 eye_pt = c3vec3_sub(c->eye, c->lookat); /* eye w/lookat at center */
121     c3mat4 rot    = rotation3D( c->up, angle );
122
123     eye_pt = c3mat4_mulv3(&rot, eye_pt);
124     c->eye    = c3vec3_add(c->lookat, eye_pt);
125
126     c3cam_update(c);
127 }
128
129 void
130 c3cam_eye_yaw_abs(
131                 c3cam_p c,
132                 const c3f angle,
133                 const c3vec3 axis)
134 {
135     c3vec3 eye_pt = c3vec3_sub(c->eye, c->lookat); /* eye w/lookat at center */
136     c3mat4 rot      = rotation3D( axis, angle );
137
138     eye_pt = c3mat4_mulv3(&rot, eye_pt);
139     c->eye    = c3vec3_add(c->lookat, eye_pt);
140
141     c->up = c3mat4_mulv3(&rot, c->up);
142
143     c3cam_update(c);
144 }
145
146
147 void
148 c3cam_eye_pitch(
149                 c3cam_p c,
150                 const c3f angle)
151 {
152     c3vec3 eye_pt = c3vec3_sub(c->eye, c->lookat); /* eye w/lookat at center */
153     c3mat4 rot    = rotation3D( c->side, angle );
154
155     eye_pt = c3mat4_mulv3(&rot, eye_pt);
156     c->eye    = c3vec3_add(c->lookat, eye_pt);
157
158     c->up = c3mat4_mulv3(&rot, c->up);
159
160     c3cam_update(c);
161 }
162
163 void
164 c3cam_lookat_yaw(
165                 c3cam_p c,
166                 const c3f angle)
167 {
168     c3vec3 lookat_pt = c3vec3_sub(c->lookat, c->eye); /* lookat w/eye at center */
169     c3mat4 rot = rotation3D( c->up, -angle );
170
171     lookat_pt = c3mat4_mulv3(&rot, lookat_pt);
172     c->lookat = c3vec3_add(c->eye, lookat_pt);
173
174     c3cam_update(c);
175 }
176
177 void
178 c3cam_lookat_pitch(
179                 c3cam_p c,
180                 const c3f angle)
181 {
182     c3vec3 lookat_pt = c3vec3_sub(c->lookat, c->eye); /* lookat w/eye at center */
183     c3mat4 rot = rotation3D( c->side, -angle );
184
185     lookat_pt = c3mat4_mulv3(&rot, lookat_pt);
186     c->lookat = c3vec3_add(c->eye, lookat_pt);
187
188     c->up = c3mat4_mulv3(&rot, c->up);
189
190     c3cam_update(c);
191 }
192
193 void
194 c3cam_reset_up_axis(
195                 c3cam_p c,
196                 const int axis_num)
197 {
198     c3vec3 eye_pt = c3vec3_sub(c->lookat, c->eye); /* eye w/lookat at center */
199     c3f eye_distance = c3vec3_length(eye_pt);
200     c->eye.n[axis_num] = c->lookat.n[axis_num];
201     /* Bring eye to same level as lookat */
202
203     c3vec3 vector = c3vec3_sub(c->eye, c->lookat);
204     vector = c3vec3_normalize(vector);
205     vector = c3vec3_mulf(vector, eye_distance);
206
207     c->eye = c3vec3_add(c->lookat, vector);
208     c->up = c3vec3f( 0.0, 0.0, 0.0 );
209     c->up.n[axis_num] = 1.0;
210
211     c3cam_update(c);
212 }
213
214 void
215 c3cam_reset_up(
216                 c3cam_p c)
217 {
218         c3cam_reset_up_axis(c, VY ); /* Resets to the Y axis */
219 }
220
221 void
222 c3cam_movef(
223                 c3cam_p c,
224                 const c3f side_move,
225                 const c3f up_move,
226                 const c3f forw_move)
227 {
228     c->eye    = c3vec3_add(c->eye, c3vec3_mulf(c->forward,              forw_move));
229     c->eye    = c3vec3_add(c->eye, c3vec3_mulf(c->side,                 side_move));
230     c->eye    = c3vec3_add(c->eye, c3vec3_mulf(c->up,                   up_move));
231     c->lookat = c3vec3_add(c->lookat, c3vec3_mulf(c->forward,   forw_move));
232     c->lookat = c3vec3_add(c->lookat, c3vec3_mulf(c->side,              side_move));
233     c->lookat = c3vec3_add(c->lookat, c3vec3_mulf(c->up,                up_move));
234     c3cam_update(c);
235 }
236
237 void
238 c3cam_movev(
239                 c3cam_p c,
240                 const c3vec3 v) /* A vector version of the above command */
241 {
242         c3cam_movef(c, v.n[VX], v.n[VY], v.n[VZ] );
243 }
244
245 void
246 c3cam_move_by_eye(
247                 c3cam_p c,
248                 const c3vec3 new_eye)
249 {
250     c3vec3 diff = c3vec3_sub(new_eye, c->eye);
251
252     c->lookat = c3vec3_add(c->lookat, diff);
253     c->eye    = c3vec3_add(c->eye, diff);
254
255     c3cam_update(c);
256 }
257
258 void
259 c3cam_move_by_lookat(
260                 c3cam_p c,
261                 const c3vec3 new_lookat)
262 {
263     c3vec3 diff = c3vec3_sub(new_lookat, c->lookat);
264
265     c->lookat = c3vec3_add(c->lookat, diff);
266     c->eye    = c3vec3_add(c->eye, diff);
267
268     c3cam_update(c);
269 }
270
271 void
272 c3cam_move_abs(
273                 c3cam_p c,
274                 const c3vec3 v)
275 {
276     c->lookat = c3vec3_add(c->lookat, v);
277     c->eye    = c3vec3_add(c->eye, v);
278
279     c3cam_update(c);
280 }
281
282 void
283 c3cam_rot_about_eye(
284                 c3cam_p c,
285                 const c3mat4p rot)
286 {
287     c3vec3  view = c3vec3_sub(c->lookat, c->eye);
288
289     view = c3mat4_mulv3(rot, view);
290     c->up   = c3mat4_mulv3(rot, c->up);
291
292     c->lookat = c3vec3_add(c->eye, view);
293
294     c3cam_update(c);
295 }
296
297 void
298 c3cam_rot_about_lookat(
299                 c3cam_p c,
300                 const c3mat4p rot)
301 {
302     // NOT QUITE RIGHT YET
303
304     c3vec3 view = c3vec3_sub(c->eye, c->lookat);
305
306     view = c3mat4_mulv3(rot, view);
307     c->up   = c3mat4_mulv3(rot, c->up);
308
309     c->eye = c3vec3_add(c->lookat, view);
310
311     c3cam_update(c);
312 }
313
314 void
315 c3cam_update_matrix(
316                 c3cam_p c)
317 {
318     c3cam_update(c);
319
320     c3mat4 m1 = translation3D(c3vec3_minus(c->eye));
321     c3mat4 m2 = c3mat4_vec4(
322                 c3vec4f(c->side.n[VX],  c->up.n[VX],    c->forward.n[VX],       0.0),
323                 c3vec4f(c->side.n[VY],  c->up.n[VY],    c->forward.n[VY],       0.0),
324                 c3vec4f(c->side.n[VZ],  c->up.n[VZ],    c->forward.n[VZ],       0.0),
325                 c3vec4f(0.0,                    0.0,                    0.0,                            1.0));
326     c->mtx = c3mat4_mul(&m1, &m2);
327 }
328
329 void
330 c3cam_reset(
331                 c3cam_p c)
332 {
333         memset(c, 0, sizeof(*c));
334     c->up = c3vec3f( 0.0, 1.0, 0.0 );
335     c->eye = c3vec3f(0.0, 0.0, 10.0);
336     c->lookat = c3vec3f(0.0,0.0,0.0);
337     c->fov = 50.0f;
338     c->mtx = identity3D();
339
340     c3cam_update(c);
341 }
342
343 c3cam_p
344 c3cam_new()
345 {
346         c3cam_p c = malloc(sizeof(*c));
347         memset(c, 0, sizeof(*c));
348         c3cam_reset(c);
349         return c;
350 }
351
352 void
353 c3cam_init(
354                 c3cam_p c)
355 {
356         memset(c, 0, sizeof(*c));
357         c3cam_reset(c);
358 }
359
360 void
361 c3cam_update(
362                 c3cam_p c)
363 {
364         /* get proper side and forward vectors, and distance  */
365         c->forward = c3vec3_minus(c3vec3_sub(c->lookat, c->eye));
366         c->distance = c3vec3_length(c->forward);
367         c->forward = c3vec3_divf(c->forward, c->distance);
368
369         c->side = c3vec3_cross(c->up, c->forward);
370         c->up = c3vec3_cross(c->forward, c->side);
371
372         c->forward = c3vec3_normalize(c->forward);
373         c->up = c3vec3_normalize(c->up);
374         c->side = c3vec3_normalize(c->side);
375 }