gitignore: Updated
[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 simavr.
8
9         simavr 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         simavr 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 simavr.  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     c->mtx = c3mat4_vec4(
321                 c3vec4f(c->side.n[VX],  c->up.n[VX],    c->forward.n[VX],       0.0),
322                 c3vec4f(c->side.n[VY],  c->up.n[VY],    c->forward.n[VY],       0.0),
323                 c3vec4f(c->side.n[VZ],  c->up.n[VZ],    c->forward.n[VZ],       0.0),
324                 c3vec4f(0.0,                    0.0,                    0.0,                            1.0));
325 }
326 #if 0
327 void
328 c3cam_load_to_openGL(c3cam_p c)
329 {
330     c3mat4  m;
331
332     make_mtx();
333
334     glMatrixMode( GL_MODELVIEW );
335     glLoadIdentity();
336     glMultMatrixf( (c3f*) &mtx[0][0]);
337     glTranslatef( -eye[VX], -eye[VY], -eye[VZ] );
338 }
339
340 void
341 c3cam_load_to_openGL_noident(c3cam_p c)
342 {
343     c3mat4  m;
344
345     make_mtx();
346
347     glMatrixMode( GL_MODELVIEW );
348     glMultMatrixf( (c3f*) &mtx[0][0]);
349     glTranslatef( -eye[VX], -eye[VY], -eye[VZ] );
350 }
351 #endif
352
353 void
354 c3cam_reset(
355                 c3cam_p c)
356 {
357         memset(c, 0, sizeof(*c));
358     c->up = c3vec3f( 0.0, 1.0, 0.0 );
359     c->eye = c3vec3f(0.0, 0.0, 10.0);
360     c->lookat = c3vec3f(0.0,0.0,0.0);
361
362     c->mtx = identity3D();
363
364     c3cam_update(c);
365 }
366
367 c3cam_t
368 c3cam_new()
369 {
370         c3cam_t c;
371         c3cam_reset(&c);
372         return c;
373 }
374
375 void
376 c3cam_init(
377                 c3cam_p c)
378 {
379         c3cam_reset(c);
380 }
381
382 void
383 c3cam_update(
384                 c3cam_p c)
385 {
386         /* get proper side and forward vectors, and distance  */
387         c->forward = c3vec3_minus(c3vec3_sub(c->lookat, c->eye));
388         c->distance = c3vec3_length(c->forward);
389         c->forward = c3vec3_divf(c->forward, c->distance);
390
391         c->side = c3vec3_cross(c->up, c->forward);
392         c->up = c3vec3_cross(c->forward, c->side);
393
394         c->forward = c3vec3_normalize(c->forward);
395         c->up = c3vec3_normalize(c->up);
396         c->side = c3vec3_normalize(c->side);
397 }
398
399 # if 0
400 void
401 c3cam_dump(c3cam_p c, FILE *output) const
402 {
403     fprintf( output, "Viewmodel: \n" );
404     eye.print(    output, "  eye"    );
405     lookat.print( output, "  lookat" );
406     up.print(     output, "  up"     );
407     side.print(   output, "  side"   );
408     forward.print(output, "  forward");
409     mtx.print(    output, "  mtx"    );
410 }
411 #endif