1 /*
2 * Copyright (C) 1997-2005, R3vis Corporation.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
17 * USA, or visit http://www.gnu.org/copyleft/lgpl.html.
18 *
19 * Original Contributor:
20 * Wes Bethel, R3vis Corporation, Marin County, California
21 * Additional Contributor(s):
22 *
23 * The OpenRM project is located at http://openrm.sourceforge.net/.
24 */
25 /*
26 * $Id: rmcamera.c,v 1.10 2005/09/12 04:02:24 wes Exp $
27 * Version: $Name: OpenRM-1-6-0-2-RC2 $
28 * $Revision: 1.10 $
29 * $Log: rmcamera.c,v $
30 * Revision 1.10 2005/09/12 04:02:24 wes
31 * Minor documentation updates.
32 *
33 * Revision 1.9 2005/02/19 16:22:50 wes
34 * Distro sync and consolidation.
35 *
36 * Revision 1.8 2005/01/23 17:00:22 wes
37 * Copyright updated to 2005.
38 *
39 * Revision 1.7 2004/04/09 14:48:03 wes
40 * Fix some compile warnings about unused variables.
41 *
42 * Revision 1.6 2004/03/30 14:13:31 wes
43 * Fixed declarations and man page docs for several routines.
44 *
45 * Revision 1.5 2004/02/13 00:46:31 wes
46 * Updated inline documentation.
47 *
48 * Revision 1.4 2004/01/16 16:43:24 wes
49 * Updated copyright line for 2004.
50 *
51 * Revision 1.3 2003/06/13 03:08:39 wes
52 * Minor documentation tweak.
53 *
54 * Revision 1.2 2003/02/02 02:07:15 wes
55 * Updated copyright to 2003.
56 *
57 * Revision 1.1.1.1 2003/01/28 02:15:23 wes
58 * Manual rebuild of rm150 repository.
59 *
60 * Revision 1.7 2003/01/16 22:21:17 wes
61 * Updated all source files to reflect new organization of header files:
62 * all header files formerly located in include/rmaux, include/rmi, include/rmv
63 * are now located in include/rm.
64 *
65 * Revision 1.6 2002/08/17 15:07:46 wes
66 * rmCamera3DComputeViewFromGeometry() - updated computation of near/far
67 * clip planes to allow more front-to-back maneuvering space.
68 *
69 * Revision 1.5 2002/04/30 19:28:55 wes
70 * Updated copyright dates.
71 *
72 * Revision 1.4 2001/03/31 17:12:38 wes
73 * v1.4.0-alpha-2 checkin.
74 *
75 * Revision 1.3 2000/08/23 23:24:52 wes
76 * Updated documentation.
77 *
78 * Revision 1.2 2000/04/20 16:29:47 wes
79 * Documentation additions/enhancements, some code rearragement.
80 *
81 * Revision 1.1.1.1 2000/02/28 21:29:40 wes
82 * OpenRM 1.2 Checkin
83 *
84 * Revision 1.1.1.1 2000/02/28 17:18:47 wes
85 * Initial entry - pre-RM120 release, source base for OpenRM 1.2.
86 *
87 */
88
89 #include <rm/rm.h>
90 #include "rmprivat.h"
91
92 /* default camera parameters */
93 extern float RM_DEFAULT_2DCAMERA_XMIN, RM_DEFAULT_2DCAMERA_YMIN, RM_DEFAULT_2DCAMERA_XMAX, RM_DEFAULT_2DCAMERA_YMAX;
94 extern float RM_DEFAULT_2DCAMERA_ASPECT;
95 extern float RM_DEFAULT_3DCAMERA_HITHER, RM_DEFAULT_3DCAMERA_YON, RM_DEFAULT_3DCAMERA_ASPECT, RM_DEFAULT_3DCAMERA_FOV;
96 extern RMenum RM_DEFAULT_3DCAMERA_PROJECTION;
97 extern RMvertex3D RM_DEFAULT_3DCAMERA_EYE, RM_DEFAULT_3DCAMERA_LOOKAT, RM_DEFAULT_3DCAMERA_UP;
98
99 /* PRIVATE declarations */
100 static void private_rmCamera2DComputeMatrix (const RMcamera2D *c, RMmatrix *m);
101
102 /*
103 * ----------------------------------------------------
104 * @Name rmCamera2DNew
105 @pstart
106 RMcamera2D * rmCamera2DNew (void)
107 @pend
108
109 @astart
110 No arguments.
111 @aend
112
113 @dstart
114
115 A default 2D camera is created and a handle to the requested
116 RMcamera2D is returned. If the 2D camera cannot be created, then a
117 NULL pointer is returned.
118
119 @dend
120 * ----------------------------------------------------
121 */
122 RMcamera2D *
rmCamera2DNew(void)123 rmCamera2DNew (void)
124 {
125 RMcamera2D *c;
126
127 if ((c = (RMcamera2D *)malloc(sizeof(RMcamera2D))) == NULL)
128 return(NULL);
129
130 /* defaults */
131 rmCamera2DSetExtents(c, RM_DEFAULT_2DCAMERA_XMIN, RM_DEFAULT_2DCAMERA_YMIN, RM_DEFAULT_2DCAMERA_XMAX, RM_DEFAULT_2DCAMERA_YMAX);
132 rmCamera2DSetAspectRatio(c, RM_DEFAULT_2DCAMERA_ASPECT);
133
134 return(c);
135 }
136
137
138 /*
139 * ----------------------------------------------------
140 * @Name rmCamera2DCopy
141 @pstart
142 RMenum rmCamera2DCopy (RMcamera2D *dst,
143 const RMcamera2D *src)
144 @pend
145
146 @astart
147 RMcamera2D *dst - a handle to an RMcamera2D object to be modified
148 (output).
149
150 const RMcamera2D *src - a handle to an RMcamera2D object that will be
151 copied (input).
152 @aend
153
154 @dstart
155
156 Copies all parameters and attributes from one RMcamera2D object to
157 another. Returns RM_CHILL upon success, or RM_WHACKED upon failure.
158
159 @dend
160 * ----------------------------------------------------
161 */
162 RMenum
rmCamera2DCopy(RMcamera2D * dst,const RMcamera2D * src)163 rmCamera2DCopy (RMcamera2D *dst,
164 const RMcamera2D *src)
165 {
166 if ((RM_ASSERT(dst, "rmCamera2DCopy error: the dst RMcamera2D pointer is NULL") == RM_WHACKED) ||
167 (RM_ASSERT(src, "rmCamera2DCopy error: the src RMcamera2D pointer is NULL") == RM_WHACKED))
168 return(RM_WHACKED);
169
170 memcpy((void *)dst, (void *)src, sizeof(RMcamera2D));
171
172 return(RM_CHILL);
173 }
174
175
176 /*
177 * ----------------------------------------------------
178 * @Name rmCamera2DDelete
179 @pstart
180 void rmCamera2DDelete (RMcamera2D *toDelete)
181 @pend
182
183 @astart
184 RMcamera2D *toDelete - a handle to RMcamera2D object to delete (modified).
185 @aend
186
187 @dstart
188
189 Free the RMcamera2D resources pointed to by c. It is assumed that c
190 points to a valid RMcamera2D previously created with rmCamera2DNew().
191
192 @dend
193 * ----------------------------------------------------
194 */
195 void
rmCamera2DDelete(RMcamera2D * c)196 rmCamera2DDelete (RMcamera2D *c)
197 {
198 if (c != NULL)
199 free(c);
200 }
201
202
203 /*
204 * ----------------------------------------------------
205 * @Name rmDefaultCamera2D
206 @pstart
207 RMenum rmDefaultCamera2D (RMcamera2D *toModify)
208 @pend
209
210 @astart
211 RMcamera2D *toModify - a handle to a caller supplied RMcamera2D
212 object that will be modified by this routine (modified).
213 @aend
214
215 @dstart
216
217 This routine assigns a set of default parameters to an RMcamera2D
218 object. All existing settings of the input RMcamera2D object will be
219 overwritten. Returns RM_CHILL upon success, or RM_WHACKED upon
220 failure.
221
222 The new values written by this routine are:
223
224 1. 2D extents set to: (-1,-1)..(1,1)
225
226 2. Aspect ratio set to 1.0.
227
228 @dend
229 * ----------------------------------------------------
230 */
231 RMenum
rmDefaultCamera2D(RMcamera2D * c)232 rmDefaultCamera2D (RMcamera2D *c)
233 {
234 if (RM_ASSERT(c, "rmDefaultCamera2D error: the input RMcamera2D object is NULL") == RM_WHACKED)
235 return(RM_WHACKED);
236
237 rmCamera2DSetExtents(c, RM_DEFAULT_2DCAMERA_XMIN, RM_DEFAULT_2DCAMERA_YMIN, RM_DEFAULT_2DCAMERA_XMAX, RM_DEFAULT_2DCAMERA_YMAX);
238 rmCamera2DSetAspectRatio(c, RM_DEFAULT_2DCAMERA_ASPECT);
239
240 return(RM_CHILL);
241 }
242
243
244 /*
245 * ----------------------------------------------------
246 * @Name rmCamera2DSetAspectRatio
247 @pstart
248 RMenum rmCamera2DSetAspectRatio (RMcamera2D *toModify,
249 float newAspect)
250
251 @pend
252
253 @astart
254 RMcamera2D *toModify - a handle to the RMcamera2D object that will be
255 modified by this routine.
256
257 float newAspect - a floating point value specifying the new aspect
258 ratio for the RMcamera2D object.
259 @aend
260
261 @dstart
262
263 Use this routine to set the aspect ratio of a 2D camera. Returns
264 RM_CHILL upon success, or RM_WHACKED upon failure.
265
266 The aspect ratio is a fraction that is the width of the field of view
267 divided by the height. It is used to control the stretch and squish
268 of rendering. For example, consider rendering into a window whose
269 width is 400 pixels and height is 300 pixels and using a logically
270 square viewport (0,0..1,1). If the camera aspect ratio is set to 1.0,
271 the resulting image will appear to be stretched along the horizontal
272 axis because the square viewport is being mapped to a rectangular
273 window.
274
275 In this example, we would want to set the aspect ratio to 400/300 to
276 avoid stretching. The aspect ratio is applied at the stage when we
277 compute the view transformation matrix.
278
279 @dend
280 * ----------------------------------------------------
281 */
282 RMenum
rmCamera2DSetAspectRatio(RMcamera2D * toModify,float newAspect)283 rmCamera2DSetAspectRatio (RMcamera2D *toModify,
284 float newAspect)
285 {
286 if (RM_ASSERT(toModify, "rmCamera2DSetAspectRatio error: the input RMcamera2D object is NULL") == RM_WHACKED)
287 return(RM_WHACKED);
288
289 toModify->aspect_ratio = newAspect;
290
291 return(RM_CHILL);
292 }
293
294
295 /*
296 * ----------------------------------------------------
297 * @Name rmCamera2DResetAspectRatio
298 @pstart
299 RMenum rmCamera2DResetAspectRatio (RMcamera2D *toModify,
300 const float *vp,
301 int windowWidth,
302 int windowWeight)
303 @pend
304
305 @astart
306 RMcamera2D *toModify - a handle to the RMcamera2D that will be
307 modified by this routine.
308
309 const float *vp - an array of floating point values of length 4. This
310 is a viewport specification, ordered {xmin, ymin, xmax, ymax}. The
311 viewport coordinates are in the range 0..1, ranging from the lower
312 left corner of the display window (0,0) to the upper right corner
313 (1,1).
314
315 int windowWidth, windowWeight - integer values specifying the size in
316 pixels of the display window. These values are used in computing a
317 new aspect ratio for the RMcamera2D object.
318 @aend
319
320 @dstart
321
322 Given viewport and window geometry, compute an aspect ratio that will
323 cause pixels to "remain square." In other words, an aspect ratio will
324 be computed so that there is no stretch or squish in the rendered
325 image: a square in world coordinates will remain square in the
326 rendered image, regardless of viewport or window geometry.
327
328 Returns RM_CHILL upon success, or RM_WHACKED upon failure.
329
330 @dend
331 * ----------------------------------------------------
332 */
333 RMenum
rmCamera2DResetAspectRatio(RMcamera2D * toModify,const float vp[4],int windowWidth,int windowHeight)334 rmCamera2DResetAspectRatio (RMcamera2D *toModify,
335 const float vp[4],
336 int windowWidth,
337 int windowHeight)
338 {
339 float sx, sy, new_aspect;
340
341 if ((RM_ASSERT(toModify, "rmCamera2DResetAspectRatio error: the input RMcamera2D error is NULL") == RM_WHACKED) ||
342 (RM_ASSERT(vp, "rmCamera2DResetAspectRatio error: the input viewport is NULL")) == RM_WHACKED)
343 return(RM_WHACKED);
344
345 sx = vp[2] - vp[0];
346 sy = vp[3] - vp[1];
347
348 new_aspect = ((float)(windowWidth) * sx) / ((float)(windowHeight) * sy);
349 rmCamera2DSetAspectRatio(toModify, new_aspect);
350
351 return(RM_CHILL);
352 }
353
354
355 /*
356 * ----------------------------------------------------
357 * @Name rmCamera2DGetAspectRatio
358 @pstart
359 RMenum rmCamera2DGetAspectRatio (const RMcamera2D *toQuery,
360 float *retValue)
361 @pend
362
363 @astart
364 const RMcamera2D *toQuery - a handle to the RMcamera2D object that
365 will be queried by this routine.
366
367 float *retValue - a handle to a caller-supplied float. The
368 RMcamera2D's aspect ratio attribute will be copied into this
369 memory location.
370 @aend
371
372 @dstart
373
374 Use this routine to query the aspect ratio of an RMcamera2D object.
375 RM_CHILL is returned upon success, otherwise RM_WHACKED is returned.
376
377 The aspect ratio is a fraction that is the width of the field of view
378 divided by the height. It is used to control the stretch and squish
379 of rendering. For example, consider rendering into a window whose
380 width is 400 pixels and height is 300 pixels and using a logically
381 square viewport (0,0..1,1). If the camera aspect ratio is set to 1.0,
382 the resulting image will appear to be stretched along the horizontal
383 axis because the square viewport is being mapped to a rectangular
384 window.
385
386 In this example, we would want to set the aspect ratio to 400/300 to
387 avoid stretching. The aspect ratio is applied at the stage when we
388 compute the view transformation matrix.
389
390 @dend
391 * ----------------------------------------------------
392 */
393 RMenum
rmCamera2DGetAspectRatio(const RMcamera2D * toQuery,float * retValue)394 rmCamera2DGetAspectRatio (const RMcamera2D *toQuery,
395 float *retValue)
396 {
397 if ((RM_ASSERT(toQuery, "rmCamera2DGetAspectRatio error: the input RMcamera2D object is NULL") == RM_WHACKED) ||
398 (RM_ASSERT(retValue, "rmCamera2DGetAspectRatio error: the return float pointer is NULL.") == RM_WHACKED))
399 return(RM_WHACKED);
400
401 *retValue = toQuery->aspect_ratio;
402
403 return(RM_CHILL);
404 }
405
406
407 /*
408 * ----------------------------------------------------
409 * @Name rmCamera2DSetExtents
410 @pstart
411 RMenum rmCamera2DSetExtents (RMcamera2D *toModify,
412 float xmin,
413 float ymin,
414 float xmax,
415 float ymax)
416
417 @pend
418
419 @astart
420 RMcamera2D *toModify - a handle to an RMcamera2D object that will be
421 modified by this routine.
422
423 float xmin, ymin, xmax, ymax - floating point values that specify the
424 new x/y extents "seen" by the 2D camera. These values are
425 specified in world coordinates.
426 @aend
427
428 @dstart
429
430 Use this routine to specify the extents for a 2D camera. Returns
431 RM_CHILL upon success, or RM_WHACKED upon failure.
432
433 A 2D camera is composed of two parameters in OpenRM: an extents and
434 an aspect ratio. The extents defines a 2D region in world coordinates
435 that will be seen by the 2D camera, these extents are specified with
436 a minimum and maximum coordinate. The aspect ratio defines the
437 relationship between the camera width and height and controls the
438 stretch and squish of rendering, something that is useful if your
439 window is not square.
440
441 @dend
442 * ----------------------------------------------------
443 */
444 RMenum
rmCamera2DSetExtents(RMcamera2D * c,float xmin,float ymin,float xmax,float ymax)445 rmCamera2DSetExtents (RMcamera2D *c,
446 float xmin,
447 float ymin,
448 float xmax,
449 float ymax)
450 {
451 if (RM_ASSERT(c, "rmCamera2DSetExtents error: the input RMcamera2D object is NULL") == RM_WHACKED)
452 return(RM_WHACKED);
453
454 c->xmin = xmin;
455 c->ymin = ymin;
456 c->xmax = xmax;
457 c->ymax = ymax;
458
459 return(RM_CHILL);
460 }
461
462
463 /*
464 * ----------------------------------------------------
465 * @Name rmCamera2DGetExtents
466 @pstart
467 RMenum rmCamera2DGetExtents (const RMcamera2D *toQuery,
468 float *xmin,
469 float *ymin,
470 float *xmax,
471 float *ymax)
472
473 @pend
474
475 @astart
476 const RMcamera2D *toQuery - a handle to an RMcamera2D object that
477 will be queried by this routine.
478
479 float *xmin, *ymin, *xmax, *ymax - pointers to caller-supplied
480 floats. The 2D cameras extents parameters will be written into
481 these memory locations. It is permissible to specify NULL for any
482 or all of these parameters - the corresponding 2D camera extents
483 parameter will not be reported for NULL return parameters.
484 @aend
485
486 @dstart
487
488 Use this routine to query the extents of a 2D camera. Returns
489 RM_CHILL upon success, or RM_WHACKED upon failure.
490
491 A 2D camera is composed of two parameters in OpenRM: an extents and
492 an aspect ratio. The extents defines a 2D region in world coordinates
493 that will be seen by the 2D camera, these extents are specified with
494 a minimum and maximum coordinate. The aspect ratio defines the
495 relationship between the camera width and height and controls the
496 stretch and squish of rendering, something that is useful if your
497 window is not square.
498
499 @dend
500 * ----------------------------------------------------
501 */
502 RMenum
rmCamera2DGetExtents(const RMcamera2D * c,float * xmin,float * ymin,float * xmax,float * ymax)503 rmCamera2DGetExtents (const RMcamera2D *c,
504 float *xmin,
505 float *ymin,
506 float *xmax,
507 float *ymax)
508 {
509 if (RM_ASSERT(c, "rmCamera2DGetExtents error: the input RMcamera2D object is NULL") == RM_WHACKED)
510 return(RM_WHACKED);
511
512 if (xmin != NULL)
513 *xmin = c->xmin;
514
515 if (ymin != NULL)
516 *ymin = c->ymin;
517
518 if (xmax != NULL)
519 *xmax = c->xmax;
520
521 if (ymax != NULL)
522 *ymax = c->ymax;
523
524 return(RM_CHILL);
525 }
526
527
528 /*
529 * ----------------------------------------------------
530 * @Name rmCamera2DComputeViewMatrix
531 @pstart
532 RMenum rmCamera2DComputeViewMatrix (const RMcamera2D *camera,
533 RMmatrix *matrixReturn)
534 @pend
535
536 @astart
537 const RMcamera2D *camera - a handle to an RMcamera2D object (input).
538
539 RMmatrix *matrixReturn - a handle to a caller-supplied RMmatrix
540 object (result).
541 @aend
542
543 @dstart
544
545 Computes the view matrix defined by the 2D input camera, copying the
546 result into caller supplied memory. Upon success, RM_CHILL is
547 returned. Upon failure, RM_WHACKED is returned, and matrixReturn
548 remains undisturbed.
549
550 Note that the 2D camera does not produce a projection matrix, unlike
551 the 3D camera.
552
553 @dend
554 * ----------------------------------------------------
555 */
556 RMenum
rmCamera2DComputeViewMatrix(const RMcamera2D * c,RMmatrix * m)557 rmCamera2DComputeViewMatrix (const RMcamera2D *c,
558 RMmatrix *m)
559 {
560 if ((RM_ASSERT(c, "rmCamera2DComputeViewMatrix error: the input RMcamera2D object is NULL") == RM_WHACKED) ||
561 (RM_ASSERT(m, "rmCamera2DComputeViewMatrix error: the return view RMmatrix object is NULL") == RM_WHACKED))
562 return(RM_WHACKED);
563
564 private_rmCamera2DComputeMatrix(c, m);
565
566 return(RM_CHILL);
567 }
568
569
570 /*
571 * ----------------------------------------------------
572 * @Name rmCamera2DComputeViewFromGeometry
573 @pstart
574 RMenum rmCamera2DComputeViewFromGeometry (RMcamera2D *toModify,
575 const RMnode *source)
576 @pend
577
578 @astart
579 RMcamera2D *toModify - a handle to an RMcamera2D object that will be
580 modified by this routine.
581
582 const RMnode *source - a handle to an RMnode.
583 @aend
584
585 @dstart
586
587 Use this routine to automatically compute 2D view parameters from the
588 2D bounding box of scene graph node. Returns RM_CHILL upon success,
589 or RM_WHACKED upon failure.
590
591 The 2D camera's parameters will be set to reflect the min/max extents
592 of the input RMnode's 2D bounding box. The aspect ratio of the 2D
593 camera remains unmodified.
594
595 @dend
596 * ----------------------------------------------------
597 */
598 RMenum
rmCamera2DComputeViewFromGeometry(RMcamera2D * c,const RMnode * r)599 rmCamera2DComputeViewFromGeometry (RMcamera2D *c,
600 const RMnode *r)
601 {
602 RMvertex3D bmin, bmax;
603
604 if ((RM_ASSERT(c, "rmCamera2DComputeViewFromGeometry error: the input RMcamera2D object is NULL") == RM_WHACKED) ||
605 (RM_ASSERT(r, "rmCamera2DComputeViewFromGeometry error: the input RMnode is NULL") == RM_WHACKED))
606 return(RM_WHACKED);
607
608 rmNodeGetBoundingBox (r, &bmin, &bmax);
609 rmCamera2DSetExtents(c, bmin.x, bmin.y, bmax.x, bmax.y);
610
611 return(RM_CHILL);
612 }
613
614
615 /*
616 * ----------------------------------------------------
617 * @Name rmCamera3DNew
618 @pstart
619 RMcamera3D * rmCamera3DNew (void)
620 @pend
621
622 @astart
623 No arguments.
624 @aend
625
626 @dstart
627
628 This routine creates a new RMcamera3D object, initializes it to some
629 default values, and returns a handle to the caller. If there is an error
630 (malloc failure), an error message is displayed with rmError and NULL is
631 returned.
632
633 For initialization, rmDefaultCamera3D is applied to the newly created
634 RMcamera3D object so that all fields are initialized. See the description
635 of rmDefaultCamera3D for particulars about the default values.
636
637 @dend
638 * ----------------------------------------------------
639 */
640 RMcamera3D *
rmCamera3DNew(void)641 rmCamera3DNew (void)
642 {
643 RMcamera3D *c;
644
645 if ((c = (RMcamera3D *)malloc(sizeof(RMcamera3D))) == NULL)
646 {
647 rmError("rmCamera3DNew() error: unable to malloc memory for a new RMcamera3D struct. ");
648 return(NULL);
649 }
650
651 /* defaults */
652 rmDefaultCamera3D(c);
653
654 return(c);
655 }
656
657
658 /*
659 * ----------------------------------------------------
660 * @Name rmCamera3DCopy
661 @pstart
662 RMenum rmCamera3DCopy (RMcamera3D *dst,
663 const RMcamera3D *src)
664 @pend
665
666 @astart
667 RMcamera3D *dst - a handle to an RMcamera3D object to be modified
668 (output).
669
670 const RMcamera3D *src - a handle to an RMcamera3D object that will be
671 copied (input).
672 @aend
673
674 @dstart
675
676 Copies all parameters and attributes from one RMcamera3D object to
677 another. Returns RM_CHILL upon success, or RM_WHACKED upon failure.
678
679 @dend
680 * ----------------------------------------------------
681 */
682 RMenum
rmCamera3DCopy(RMcamera3D * dst,const RMcamera3D * src)683 rmCamera3DCopy (RMcamera3D *dst,
684 const RMcamera3D *src)
685 {
686 if ((RM_ASSERT(dst, "rmCamera3DCopy error: the dst RMcamera3D pointer is NULL") == RM_WHACKED) ||
687 (RM_ASSERT(src, "rmCamera3DCopy error: the src RMcamera3D pointer is NULL") == RM_WHACKED))
688 return(RM_WHACKED);
689
690 memcpy((void *)dst, (void *)src, sizeof(RMcamera3D));
691
692 return(RM_CHILL);
693 }
694
695
696 /*
697 * ----------------------------------------------------
698 * @Name rmCamera3DDelete
699 @pstart
700 void rmCamera3DDelete (RMcamera3D *toDelete)
701 @pend
702
703 @astart
704 RMcamera3D *toDelete - a handle to RMcamera3D object to delete (modified).
705 @aend
706
707 @dstart
708
709 Free the RMcamera3D resources pointed to by c. It is assumed that c
710 points to a valid RMcamera3D previously created with rmCamera3DNew().
711
712 @dend
713 * ----------------------------------------------------
714 */
715 void
rmCamera3DDelete(RMcamera3D * c)716 rmCamera3DDelete (RMcamera3D *c)
717 {
718 if (c != NULL)
719 free((void *)c);
720 }
721
722
723 /*
724 * ----------------------------------------------------
725 * @Name rmDefaultCamera3D
726 @pstart
727 RMenum rmDefaultCamera3D (RMcamera3D *toModify)
728
729 @pend
730
731 @astart
732 RMcamera3D *toModify - a handle to an RMcamera3D object that will be
733 modified by this routine.
734 @aend
735
736 @dstart
737
738 Assigns some default parameters to an RMcamera3D object. Returns
739 RM_CHILL upon success, or RM_WHACKED upon failure.
740
741 The parameters set by this routine are:
742
743 1. Eye point set to (10,10,50). (rmCamera3DSetEye)
744
745 2. Lookat point is the origin, (0,0,0). (rmCamera3DSetAt)
746
747 3. Up vector is (0,1,0) (rmCamera3DSetUp)
748
749 4. Field of view set to 45 degrees (rmCamera3DSetFOV)
750
751 5. Monoscopic camera (rmCamera3DSetStereo)
752
753 6. Perspective projection (rmCamera3DSetProjection)
754
755 7. Front and back clipping planes set to 2.0 and 40.0, respectively.
756 (rmCamera3DSetHither, rmCamera3DSetYon)
757
758 Returns RM_CHILL upon success, or RM_WHACKED if the input RMcamera3D
759 object is NULL.
760
761 @dend
762 * ----------------------------------------------------
763 */
764 RMenum
rmDefaultCamera3D(RMcamera3D * c)765 rmDefaultCamera3D (RMcamera3D *c)
766 {
767 if (RM_ASSERT(c, "rmDefaultCamera3D error: the input RMcamera3D object is NULL") == RM_WHACKED)
768 return(RM_WHACKED);
769
770 /*
771 * assign some default values:
772 * the camera's default position has the
773 * - eye at (10,10,50)
774 * - lookat point is the origin (0,0,0)
775 * - up vector is +y axis
776 * - hither is 2 and yon is 40
777 * - perspective projection
778 * - monoscopic
779 */
780 rmCamera3DSetFOV(c, RM_DEFAULT_3DCAMERA_FOV);
781 rmCamera3DSetAspectRatio(c, RM_DEFAULT_3DCAMERA_ASPECT);
782
783 rmCamera3DSetEye(c, &RM_DEFAULT_3DCAMERA_EYE);
784 rmCamera3DSetAt(c, &RM_DEFAULT_3DCAMERA_LOOKAT);
785 rmCamera3DSetUpVector(c, &RM_DEFAULT_3DCAMERA_UP);
786
787 rmCamera3DSetHither(c, RM_DEFAULT_3DCAMERA_HITHER);
788 rmCamera3DSetYon(c, RM_DEFAULT_3DCAMERA_YON);
789 rmCamera3DSetProjection(c, RM_DEFAULT_3DCAMERA_PROJECTION);
790 rmCamera3DSetStereo(c, RM_FALSE);
791 rmCamera3DSetEyeSeparation (c, 0.0F);
792 rmCamera3DSetFocalDistance (c, 1.0F);
793
794 return(RM_CHILL);
795 }
796
797
798 /*
799 * ----------------------------------------------------
800 * @Name rmCamera3DSetAspectRatio
801 @pstart
802 RMenum rmCamera3DSetAspectRatio (RMcamera3D *toModify,
803 const float newAspect)
804
805 @pend
806
807 @astart
808 RMcamera3D *toModify - a handle to an RMcamera3D object (modified).
809
810 const float newAspect - a floating point value used to specify the
811 new aspect ratio for the RMcamera3D object.
812 @aend
813
814 @dstart
815
816 Use this routine to modify the aspect ratio attribute of an
817 RMcamera3D object. Returns RM_CHILL upon success, or RM_WHACKED upon
818 failure.
819
820 @dend
821 * ----------------------------------------------------
822 */
823 RMenum
rmCamera3DSetAspectRatio(RMcamera3D * toModify,const float newAspect)824 rmCamera3DSetAspectRatio (RMcamera3D *toModify,
825 const float newAspect)
826 {
827 if (RM_ASSERT(toModify, "rmCamera3DSetAspectRatio error: the input RMcamera3D object is NULL") == RM_WHACKED)
828 return(RM_WHACKED);
829
830 toModify->aspect = newAspect;
831
832 return(RM_CHILL);
833 }
834
835
836 /*
837 * ----------------------------------------------------
838 * @Name rmCamera3DResetAspectRatio
839 @pstart
840 RMenum rmCamera3DResetAspectRatio (RMcamera3D *toModify,
841 const float *vp,
842 int windowWidth,
843 int windowHeight)
844
845 @pend
846
847 @astart
848 RMcamera3D *toModify - a handle to the RMcamera3D object that will be
849 modified by this routine.
850
851 const float *vp - an array of floating point values of length 4. This
852 is a viewport specification, ordered {xmin, ymin, xmax, ymax}. The
853 viewport coordinates are in the range 0..1, ranging from the lower
854 left corner of the display window (0,0) to the upper right corner
855 (1,1).
856
857 int windowWidth, windowWeight - integer values specifying the size in
858 pixels of the display window. These values are used in computing a
859 new aspect ratio for the RMcamera3D object.
860 @aend
861
862 @dstart
863
864 Given viewport and window geometry, compute an aspect ratio that will
865 cause pixels to "remain square." In other words, an aspect ratio will
866 be computed so that there is no stretch or squish in the rendered
867 image: a square in world coordinates will remain square in the
868 rendered image, regardless of viewport or window geometry.
869
870 All other camera parameters are ignored and remain unaffected.
871
872 Returns RM_CHILL upon success, or RM_WHACKED upon failure.
873
874 @dend
875 * ----------------------------------------------------
876 */
877 RMenum
rmCamera3DResetAspectRatio(RMcamera3D * toModify,const float * vp,int windowWidth,int windowHeight)878 rmCamera3DResetAspectRatio (RMcamera3D *toModify,
879 const float *vp,
880 int windowWidth,
881 int windowHeight)
882 {
883 float sx, sy;
884 float new_aspect;
885
886 if ((RM_ASSERT(toModify, "rmCamera3DResetAspectRatio error: input RMcamera3D object is NULL.") == RM_WHACKED) ||
887 (RM_ASSERT(vp, "rmCamera3DResetAspectRatio error: input viewport is NULL.") == RM_WHACKED))
888 return(RM_WHACKED);
889
890 sx = vp[2] - vp[0];
891 sy = vp[3] - vp[1];
892
893 new_aspect = ((float)windowWidth * sx) / ((float)windowHeight * sy);
894 rmCamera3DSetAspectRatio(toModify, new_aspect);
895
896 return(RM_CHILL);
897 }
898
899
900 /*
901 * ----------------------------------------------------
902 * @Name rmCamera3DGetAspectRatio
903 @pstart
904 float rmCamera3DGetAspectRatio (const RMcamera3D *toQuery)
905 @pend
906
907 @astart
908 const RMcamera3D *toQuery - a handle to the RMcamera3D object that
909 will be queried by this routine.
910 @aend
911
912 @dstart
913
914 Use this routine to query the aspect ratio of an RMcamera3D object.
915 RM_CHILL is returned upon success, otherwise RM_WHACKED is returned.
916
917 The aspect ratio is a fraction that is the width of the field of view
918 divided by the height. It is used to control the stretch and squish
919 of rendering. For example, consider rendering into a window whose
920 width is 400 pixels and height is 300 pixels and using a logically
921 square viewport (0,0..1,1). If the camera aspect ratio is set to 1.0,
922 the resulting image will appear to be stretched along the horizontal
923 axis because the square viewport is being mapped to a rectangular
924 window.
925
926 In this example, we would want to set the aspect ratio to 400/300 to
927 avoid stretching. The aspect ratio is applied at the stage when we
928 compute the view transformation matrix.
929
930 @dend
931 * ----------------------------------------------------
932 */
933 float
rmCamera3DGetAspectRatio(const RMcamera3D * toQuery)934 rmCamera3DGetAspectRatio (const RMcamera3D *toQuery)
935 {
936 if (RM_ASSERT(toQuery, "rmCamera3DGetAspectRatio error: input RMcamera3D pointer is NULL. returning 1.0") == RM_WHACKED)
937 return(1.0F);
938
939 return(toQuery->aspect);
940
941 }
942
943
944 /*
945 * ----------------------------------------------------
946 * @Name rmCamera3DSetProjection
947 @pstart
948 RMenum rmCamera3DSetProjection (RMcamera3D *toModify,
949 RMenum newVal)
950 @pend
951
952 @astart
953 RMcamera3D *toModify - a handle to an RMcamera3D object that will be
954 modified by this routine (modified).
955
956 RMenum newVal - an RMenum value specifying the new projection method
957 for the RMcamera3D object. Should be either
958 RM_PROJECTION_PERSPECTIVE or RM_PROJECTION_ORTHOGRAPHIC.
959 @aend
960
961 @dstart
962
963 Use this routine to assign a projection method to a 3D
964 camera. Returns RM_CHILL upon success, or RM_WHACKED upon failure.
965
966 Perspective projections are used to achieve a "perspective
967 foreshortening" effect. This is how humans see in the real world:
968 objects that are further away appear smaller than similarly-sized
969 objects that are closer. In contrast, in orthographics projections
970 size does not diminish as a function of distance to the viewer. This
971 type of projection is often used in CAD systems because it does not
972 distort angles.
973
974 @dend
975 * ----------------------------------------------------
976 */
977 RMenum
rmCamera3DSetProjection(RMcamera3D * toModify,RMenum newVal)978 rmCamera3DSetProjection (RMcamera3D *toModify,
979 RMenum newVal)
980 {
981 if (RM_ASSERT(toModify, "rmCamera3DSetProjection error: input camera is NULL") == RM_WHACKED)
982 return(RM_WHACKED);
983
984 if ((newVal != RM_PROJECTION_PERSPECTIVE) && (newVal != RM_PROJECTION_ORTHOGRAPHIC))
985 return(RM_WHACKED);
986
987 toModify->projection = newVal;
988
989 return(RM_CHILL);
990 }
991
992
993 /*
994 * ----------------------------------------------------
995 * @Name rmCamera3DGetProjection
996 @pstart
997 RMenum rmCamera3DGetProjection (const RMcamera3D *toQuery)
998 @pend
999
1000 @astart
1001
1002 const RMcamera3D *toQuery - a handle to an RMcamera3D object that
1003 will be queried by this routine (input).
1004 @aend
1005
1006 @dstart
1007
1008 Use this routine to obtain the projection method attribute of the
1009 RMcamera3D object. If successful, either RM_PROJECTION_PERSPECTIVE or
1010 RM_PROJECTION_ORTHOGRAPHIC will be returned to the caller. Otherwise,
1011 upon failure, RM_WHACKED will be returned.
1012
1013 @dend
1014 * ----------------------------------------------------
1015 */
1016 RMenum
rmCamera3DGetProjection(const RMcamera3D * toQuery)1017 rmCamera3DGetProjection (const RMcamera3D *toQuery)
1018 {
1019 if (RM_ASSERT(toQuery, "rmCamera3DGetProjection error: input camera is NULL") == RM_WHACKED)
1020 return(RM_WHACKED);
1021
1022 return(toQuery->projection);
1023 }
1024
1025
1026 /*
1027 * ----------------------------------------------------
1028 * @Name rmCamera3DSetEye
1029 @pstart
1030 RMenum rmCamera3DSetEye (RMcamera3D *toModify,
1031 const RMvertex3D *newEye)
1032
1033 @pend
1034
1035 @astart
1036 RMcamera3D *toModify - a handle to the RMcamera3D object that will be
1037 modified by this routine.
1038
1039 const RMvertex3D *newEye - a handle to an RMvertex3D object.
1040 @aend
1041
1042 @dstart
1043
1044 Use this routine to specify a new eye point for a 3D camera. The eye
1045 point is the location of the viewer, and is specified in world
1046 coordinates. The new eye point is copied from the caller-supplied
1047 RMvertex3D object into the RMcamera3D object.
1048
1049 Returns RM_CHILL upon success, or RM_WHACKED upon failure.
1050
1051 @dend
1052 * ----------------------------------------------------
1053 */
1054 RMenum
rmCamera3DSetEye(RMcamera3D * toModify,const RMvertex3D * newEye)1055 rmCamera3DSetEye (RMcamera3D *toModify,
1056 const RMvertex3D *newEye)
1057 {
1058 if ((RM_ASSERT(toModify, "rmCamera3DSetEye error: input camera is null.") == RM_WHACKED) ||
1059 (RM_ASSERT(newEye, "rmCamera3DSetEye error: input RMvertex3D pointer is null.") == RM_WHACKED))
1060 return(RM_WHACKED);
1061
1062 VCOPY(newEye, &(toModify->eye));
1063
1064 return(RM_CHILL);
1065 }
1066
1067
1068 /*
1069 * ----------------------------------------------------
1070 * @Name rmCamera3DGetEye
1071 @pstart
1072 RMenum rmCamera3DGetEye (const RMcamera3D *toQuery,
1073 RMvertex3D *returnEye)
1074
1075 @pend
1076
1077 @astart
1078
1079 const RMcamera3D *toQuery - a handle to an RMcamera3D object to be
1080 queried (input).
1081
1082 RMvertex3D *returnEye - a handle to a caller-supplied RMvertex3D
1083 object (modified).
1084 @aend
1085
1086 @dstart
1087
1088 Use this routine to obtain the 3D eye position of an RMcamera3D
1089 object.
1090
1091 Returns RM_CHILL upon success, or RM_WHACKED upon failure.
1092
1093 @dend
1094 * ----------------------------------------------------
1095 */
1096 RMenum
rmCamera3DGetEye(const RMcamera3D * toQuery,RMvertex3D * returnEye)1097 rmCamera3DGetEye (const RMcamera3D *toQuery,
1098 RMvertex3D *returnEye)
1099 {
1100 if ((RM_ASSERT(toQuery, "rmCamera3DGetEye error: input camera is null.") == RM_WHACKED) ||
1101 (RM_ASSERT(returnEye, "rmCamera3DGetEye error: input RMvertex3D pointer is null.") == RM_WHACKED))
1102 return(RM_WHACKED);
1103
1104 VCOPY(&(toQuery->eye), returnEye);
1105
1106 return(RM_CHILL);
1107 }
1108
1109
1110 /*
1111 * ----------------------------------------------------
1112 * @Name rmCamera3DSetAt
1113 @pstart
1114 RMenum rmCamera3DSetAt (RMcamera3D *toModify,
1115 const RMvertex3D *newAt)
1116
1117 @pend
1118
1119 @astart
1120 RMcamera3D *toModify - a handle to an RMcamera3D object (modified).
1121
1122 const RMvertex3D *newAt - a handle to an RMvertex3D object containing
1123 the new look-at point (input).
1124 @aend
1125
1126 @dstart
1127
1128 Use this routine to set the look-at point of a 3D camera. The
1129 contents of the caller-supplied newAt RMvertex3D object is copied
1130 into the RMcamera3D object's look-at point attribute.
1131
1132 Returns RM_CHILL upon success, or RM_WHACKED upon failure.
1133
1134 @dend
1135 * ----------------------------------------------------
1136 */
1137 RMenum
rmCamera3DSetAt(RMcamera3D * toModify,const RMvertex3D * newAt)1138 rmCamera3DSetAt (RMcamera3D *toModify,
1139 const RMvertex3D *newAt)
1140 {
1141 if ((RM_ASSERT(toModify, "rmCamera3DSetAt error: input camera is null.") == RM_WHACKED) ||
1142 (RM_ASSERT(newAt, "rmCamera3DSetAt error: input RMvertex3D pointer is null.") == RM_WHACKED))
1143 return(RM_WHACKED);
1144
1145 VCOPY(newAt, &(toModify->at));
1146
1147 return(RM_CHILL);
1148 }
1149
1150
1151 /*
1152 * ----------------------------------------------------
1153 * @Name rmCamera3DGetAt
1154 @pstart
1155 RMenum rmCamera3DGetAt (const RMcamera3D *toQuery,
1156 RMvertex3D *returnAt)
1157
1158 @pend
1159
1160 @astart
1161 const RMcamera3D *toQuery - a handle to an RMcamera3D object to be
1162 queried (input).
1163
1164 RMvertex3D *returnAt - a handle to an RMvertex3D object that will
1165 contain the RMcamera3D's look-at point upon return (modified).
1166
1167 @aend
1168
1169 @dstart
1170
1171 Use this routine to obtain the look-at point of a 3D camera. The
1172 RMcamera3D's look-at point is copied into the caller-supplied object.
1173
1174 Returns RM_CHILL upon success, or RM_WHACKED upon failure.
1175
1176 @dend
1177 * ----------------------------------------------------
1178 */
1179 RMenum
rmCamera3DGetAt(const RMcamera3D * toQuery,RMvertex3D * returnAt)1180 rmCamera3DGetAt (const RMcamera3D *toQuery,
1181 RMvertex3D *returnAt)
1182 {
1183 if ((RM_ASSERT(toQuery, "rmCamera3DGetAt error: input camera is null.") == RM_WHACKED) ||
1184 (RM_ASSERT(returnAt, "rmCamera3DGetAt error: input RMvertex3D pointer is null.") == RM_WHACKED))
1185 return(RM_WHACKED);
1186
1187 VCOPY(&(toQuery->at), returnAt);
1188
1189 return(RM_CHILL);
1190 }
1191
1192
1193 /*
1194 * ----------------------------------------------------
1195 * @Name rmCamera3DSetUpVector
1196 @pstart
1197 RMenum rmCamera3DSetUpVector (RMcamera3D *toModify,
1198 const RMvertex3D *newUpVector)
1199
1200 @pend
1201
1202 @astart
1203 RMcamera3D *toModify - a handle to the RMcamera3D object to be
1204 modified (result).
1205
1206 const RMvertex3D *newUpVector - a handle to an RMvertex3D object
1207 supplying the new up vector (input).
1208 @aend
1209
1210 @dstart
1211
1212 Use this routine to set the Up vector attribute of an RMcamera3D
1213 object. The contents of the caller-supplied newUpVector is copied to
1214 the RMcamera3D object's up vector attribute.
1215
1216 Returns RM_CHILL upon success, or RM_WHACKED upon failure.
1217
1218 @dend
1219 * ----------------------------------------------------
1220 */
1221 RMenum
rmCamera3DSetUpVector(RMcamera3D * toModify,const RMvertex3D * newUpVector)1222 rmCamera3DSetUpVector (RMcamera3D *toModify,
1223 const RMvertex3D *newUpVector)
1224 {
1225 if ((RM_ASSERT(toModify, "rmCamera3DSetUpVector error: input RMcamera3D pointer is NULL.") == RM_WHACKED) ||
1226 (RM_ASSERT(newUpVector, "rmCamera3DSetUpVector error: input RMvertex3D pointer is NULL") == RM_WHACKED))
1227 return(RM_WHACKED);
1228
1229 VCOPY(newUpVector, &(toModify->up));
1230
1231 return(RM_CHILL);
1232 }
1233
1234
1235 /*
1236 * ----------------------------------------------------
1237 * @Name rmCamera3DGetUpVector
1238 @pstart
1239 RMenum rmCamera3DGetUpVector (const RMcamera3D *toQuery,
1240 RMvertex3D *returnUpVector)
1241
1242 @pend
1243
1244 @astart
1245 const RMcamera3D *toQuery - a handle to the RMcamera3D object to
1246 query (input).
1247
1248 RMvertex3D *returnUpVector - a handle to an RMvertex3D object
1249 supplied by the caller (modified).
1250 @aend
1251
1252 @dstart
1253
1254 Use this routine to query the Up vector attribute of an RMcamera3D
1255 object. The RMcamera3D object's up vector is copied into the
1256 caller-supplied memory.
1257
1258 Returns RM_CHILL upon success, or RM_WHACKED upon failure.
1259
1260 @dend
1261 * ----------------------------------------------------
1262 */
1263 RMenum
rmCamera3DGetUpVector(const RMcamera3D * toQuery,RMvertex3D * returnUpVector)1264 rmCamera3DGetUpVector (const RMcamera3D *toQuery,
1265 RMvertex3D *returnUpVector)
1266 {
1267 if ((RM_ASSERT(toQuery, "rmCamera3DGetUpVector error: input RMcamera3D pointer is NULL.") == RM_WHACKED) ||
1268 (RM_ASSERT(returnUpVector, "rmCamera3DGetUpVector error: input RMvertex3D pointer is NULL") == RM_WHACKED))
1269 return(RM_WHACKED);
1270
1271 VCOPY(&(toQuery->up), returnUpVector);
1272
1273 return(RM_CHILL);
1274 }
1275
1276
1277 /*
1278 * ----------------------------------------------------
1279 * @Name rmCamera3DSetFOV
1280 @pstart
1281 RMenum rmCamera3DSetFOV (RMcamera3D *toModify,
1282 float newFOV)
1283 @pend
1284
1285 @astart
1286 RMcamera3D *toModify - a handle to an RMcamera3D object that will be
1287 modified by this routine (modified).
1288
1289 float newFOV - a floating point value, the new FOV parameter (input).
1290 @aend
1291
1292 @dstart
1293
1294 Use this routine to set the FOV parameter at a 3D camera object. If
1295 successful, RM_CHILL is returned, otherwise, RM_WHACKED is returned.
1296
1297 FOV in OpenRM refers to the horizontal field of view, not the
1298 vertical field of view. Increasing the FOV in a 3D camera will cause
1299 more of the scene to be visible along the horizontal axis.
1300
1301 @dend
1302 * ----------------------------------------------------
1303 */
1304 RMenum
rmCamera3DSetFOV(RMcamera3D * toModify,float newFOV)1305 rmCamera3DSetFOV (RMcamera3D *toModify,
1306 float newFOV)
1307 {
1308 if (RM_ASSERT(toModify, "rmCamera3DSetFOV error: input camera is NULL.") == RM_WHACKED)
1309 return(RM_WHACKED);
1310
1311 toModify->fov = newFOV; /* range check?? */
1312
1313 return(RM_CHILL);
1314 }
1315
1316
1317 /*
1318 * ----------------------------------------------------
1319 * @Name rmCamera3DGetFOV
1320 @pstart
1321 float rmCamera3DGetFOV (const RMcamera3D *toQuery)
1322 @pend
1323
1324 @astart
1325 const RMcamera3D *toQuery - a handle to an RMcamera3D object that
1326 will be queried (input).
1327 @aend
1328
1329 @dstart
1330
1331 Use this routine to obtain the FOV parameter from a 3D camera object.
1332 A floating point value is returned to the caller.
1333
1334 FOV in OpenRM refers to the horizontal field of view, not the
1335 vertical field of view. Increasing the FOV in a 3D camera will cause
1336 more of the scene to be visible along the horizontal axis.
1337
1338 @dend
1339 * ----------------------------------------------------
1340 */
1341 float
rmCamera3DGetFOV(const RMcamera3D * toQuery)1342 rmCamera3DGetFOV (const RMcamera3D *toQuery)
1343 {
1344 if (RM_ASSERT(toQuery, "rmCamera3DGetFOV error: input camera is NULL. Returning 0.0F.") == RM_WHACKED)
1345 return(0.0F);
1346
1347 return(toQuery->fov);
1348 }
1349
1350
1351 /*
1352 * ----------------------------------------------------
1353 * @Name rmCamera3DSetHither
1354 @pstart
1355 RMenum rmCamera3DSetHither (RMcamera3D *toModify,
1356 float newHither)
1357 @pend
1358
1359 @astart
1360 RMcamera3D *toModify - a handle to the RMcamera3D object (modified).
1361
1362 float newHither - a floating point value containing the new front
1363 clip plane value (input).
1364 @aend
1365
1366 @dstart
1367
1368 Used to set the value of the front clip plane attribute of the
1369 RMcamera3D object. The front clip plane value is a distance, in world
1370 coordinates, from the eye point to the front clip plane. Returns
1371 RM_CHILL upon success, or RM_WHACKED upon failure.
1372
1373 @dend
1374 * ----------------------------------------------------
1375 */
1376 RMenum
rmCamera3DSetHither(RMcamera3D * toModify,float newHither)1377 rmCamera3DSetHither (RMcamera3D *toModify,
1378 float newHither)
1379 {
1380 if (RM_ASSERT(toModify, "rmCamera3DSetHither error: input camera is NULL") == RM_WHACKED)
1381 return(RM_WHACKED);
1382
1383 toModify->hither = newHither;
1384
1385 return(RM_CHILL);
1386 }
1387
1388
1389 /*
1390 * ----------------------------------------------------
1391 * @Name rmCamera3DGetHither
1392 @pstart
1393 float rmCamera3DGetHither (const RMcamera3D *toQuery)
1394 @pend
1395
1396 @astart
1397 const RMcamera3D *toQuery - a handle to the RMcamera3D object to be
1398 queried (input).
1399 @aend
1400
1401 @dstart
1402
1403 Returns to the caller the value of the front clip plane attribute of
1404 the RMcamera3D object. The front clip plane value is a distance, in
1405 world coordinates, from the eye point to the front clip plane.
1406
1407 @dend
1408 * ----------------------------------------------------
1409 */
1410 float
rmCamera3DGetHither(const RMcamera3D * toQuery)1411 rmCamera3DGetHither (const RMcamera3D *toQuery)
1412 {
1413 if (RM_ASSERT(toQuery, "rmCamera3DGetHither error: input camera is NULL, returning 0.0F") == RM_WHACKED)
1414 return(0.0F);
1415
1416 return(toQuery->hither);
1417 }
1418
1419
1420 /*
1421 * ----------------------------------------------------
1422 * @Name rmCamera3DSetYon
1423 @pstart
1424 RMenum rmCamera3DSetYon (RMcamera3D *toModify,
1425 float newYon)
1426 @pend
1427
1428 @astart
1429 RMcamera3D *toModify - a handle to the RMcamera3D object (modified).
1430
1431 float newYon - a floating point value containing the new back clip
1432 plane value (input).
1433 @aend
1434
1435 @dstart
1436
1437 Used to set the value of the back clip plane attribute of the
1438 RMcamera3D object. The back clip plane value is a distance, in world
1439 coordinates, from the eye point to the back clip plane. Returns
1440 RM_CHILL upon success, or RM_WHACKED upon failure.
1441
1442 @dend
1443 * ----------------------------------------------------
1444 */
1445 RMenum
rmCamera3DSetYon(RMcamera3D * toModify,float newYon)1446 rmCamera3DSetYon(RMcamera3D *toModify,
1447 float newYon)
1448 {
1449 if (RM_ASSERT(toModify,"rmCamera3DSetYon error: input RMcamera3D pointer is NULL") == RM_WHACKED)
1450 return(RM_WHACKED);
1451
1452 toModify->yon = newYon;
1453
1454 return(RM_CHILL);
1455 }
1456
1457
1458 /*
1459 * ----------------------------------------------------
1460 * @Name rmCamera3DGetYon
1461 @pstart
1462 float rmCamera3DGetYon(const RMcamera3D *toQuery)
1463 @pend
1464
1465 @astart
1466
1467 const RMcamera3D *toQuery - a handle to the RMcamera3D object to be
1468 queried (input).
1469 @aend
1470
1471 @dstart
1472
1473 Returns to the caller the value of the clip plane attribute of the
1474 RMcamera3D object. The back clip plane value is a distance, in world
1475 coordinates, from the eye point to the back clip plane.
1476
1477 @dend
1478 * ----------------------------------------------------
1479 */
1480 float
rmCamera3DGetYon(const RMcamera3D * toQuery)1481 rmCamera3DGetYon (const RMcamera3D *toQuery)
1482 {
1483 if (RM_ASSERT(toQuery, "rmCamera3DGetYon error: input RMcamera3D pointer is NULL. Returning 0.0F") == RM_WHACKED)
1484 return(0.0F);
1485
1486 return(toQuery->yon);
1487 }
1488
1489
1490 /*
1491 * ----------------------------------------------------
1492 * @Name rmCamera3DSetStereo
1493 @pstart
1494 RMenum rmCamera3DSetStereo (RMcamera3D *toModify,
1495 RMenum newBoolValue)
1496 @pend
1497
1498 @astart
1499 RMcamera3D *toModify - a handle to an RMcamera3D object (modified).
1500
1501 RMenum newBoolValue - a boolean value, either RM_TRUE or RM_FALSE
1502 (input).
1503 @aend
1504
1505 @dstart
1506
1507 Use this routine to set the stereo attribute of a 3D camera. Returns
1508 RM_CHILL upon success or RM_WHACKED upon failure.
1509
1510 A stereo 3D camera in OpenRM defines a binocular viewing geometry.
1511 The binocular viewing geometry is a function of eye separation
1512 (rmCamera3DSetEyeSeparation) and focal length
1513 (rmCamera3DSetFocalDistance).
1514
1515 When the 3D camera is set to be a stereo camera with this routine,
1516 the confluence of multipass rendering control and stereo 3D camera
1517 parameters are used to internally compute left- and right-eye views
1518 used for rendering. If the 3D camera's "is stereo" attribute is set
1519 to RM_FALSE, a monocular view will be used during a stereo multipass
1520 rendering.
1521
1522 @dend
1523 * ----------------------------------------------------
1524 */
1525 RMenum
rmCamera3DSetStereo(RMcamera3D * c,RMenum rm_bool)1526 rmCamera3DSetStereo (RMcamera3D *c,
1527 RMenum rm_bool)
1528 {
1529 if (RM_ASSERT(c, "rmCamera3DSetStereo error: input RMcamera3D object is NULL. ") == RM_WHACKED)
1530 return(RM_WHACKED);
1531
1532 if ((rm_bool != RM_TRUE) && (rm_bool != RM_FALSE))
1533 return(RM_WHACKED);
1534 else
1535 c->isStereo = rm_bool;
1536
1537 return(RM_CHILL);
1538 }
1539
1540
1541 /*
1542 * ----------------------------------------------------
1543 * @Name rmCamera3DGetStereo
1544 @pstart
1545 RMenum rmCamera3DGetStereo (const RMcamera3D *toQuery)
1546 @pend
1547
1548 @astart
1549 const RMcamera3D *toQuery - a handle to an RMcamera3D object that
1550 will be queried by this routine (input).
1551 @aend
1552
1553 @dstart
1554
1555 Use this routine to obtain the stereo attribute of a 3D
1556 camera. Returns RM_WHACKED upon failure, otherwise returns RM_TRUE or
1557 RM_FALSE.
1558
1559 A stereo 3D camera in OpenRM defines a binocular viewing geometry.
1560 The binocular viewing geometry is a function of eye separation
1561 (rmCamera3DSetEyeSeparation) and focal length
1562 (rmCamera3DSetFocalDistance).
1563
1564 When the 3D camera is set to be a stereo camera with this routine,
1565 the confluence of multipass rendering control and stereo 3D camera
1566 parameters are used to internally compute left- and right-eye views
1567 used for rendering. If the 3D camera's "is stereo" attribute is set
1568 to RM_FALSE, a monocular view will be used during a stereo multipass
1569 rendering.
1570
1571 @dend
1572 * ----------------------------------------------------
1573 */
1574 RMenum
rmCamera3DGetStereo(const RMcamera3D * c)1575 rmCamera3DGetStereo (const RMcamera3D *c)
1576 {
1577 if (RM_ASSERT(c, "rmCamera3DGetStereo error: input RMcamera3D object is NULL. Returning RM_WHACKED.") == RM_WHACKED)
1578 return(RM_WHACKED);
1579
1580 return(c->isStereo);
1581 }
1582
1583
1584 /*
1585 * ----------------------------------------------------
1586 * @Name rmCamera3DSetEyeSeparation
1587 @pstart
1588 RMenum rmCamera3DSetEyeSeparation (RMcamera3D *toModify, float newVal)
1589 @pend
1590
1591 @astart
1592 RMcamera3D *toModify - a handle to an RMcamera3D object (modified).
1593
1594 float newVal - a floating point value specifying the interocular
1595 displacement in degrees (input).
1596 @aend
1597
1598 @dstart
1599
1600 Use this routine to modify the interocular separation parameter of a
1601 stereo 3D camera. Returns RM_WHACKED upon failure, otherwise returns
1602 RM_CHILL.
1603
1604 A stereo 3D camera in OpenRM defines a binocular viewing geometry.
1605 The binocular viewing geometry is a function of eye separation
1606 (rmCamera3DSetEyeSeparation) and focal length
1607 (rmCamera3DSetFocalDistance).
1608
1609 The stereo camera's binocular geometry, specifically the interocular
1610 distance, is computed using the 3D camera's eye point, the look-at
1611 point, the focal length and the interocular distance. The "real" look
1612 at point of a 3D stereo camera is computed as the product of the
1613 focal length with the (unitized) eye/look-at vector. The left and
1614 right eyes both look at the "real" stereo look-at point (not the one
1615 specified by rmCamera3DSetAt). The apex of the triangle formed by the
1616 left and right eyes and the "real" stereo look at point will have an
1617 angular measure of X degrees, where X is specified as the parameter
1618 to the routine rmCamera3DSetEyeSeparation. We have found that values
1619 in the range 2.5-3.5 degrees work well for most viewers.
1620
1621 @dend
1622 * ----------------------------------------------------
1623 */
1624 RMenum
rmCamera3DSetEyeSeparation(RMcamera3D * c,float newval)1625 rmCamera3DSetEyeSeparation (RMcamera3D *c,
1626 float newval)
1627 {
1628 if (RM_ASSERT(c, "rmCamera3DSetEyeSeparation error: input RMcamera3D points is NULL. ") == RM_WHACKED)
1629 return(RM_WHACKED);
1630
1631 c->degrees_eye_separation = newval;
1632
1633 return(RM_CHILL);
1634 }
1635
1636
1637 /*
1638 * ----------------------------------------------------
1639 * @Name rmCamera3DGetEyeSeparation
1640 @pstart
1641 RMenum rmCamera3DGetEyeSeparation (RMcamera3D *toQuery)
1642 @pend
1643
1644 @astart
1645
1646 const RMcamera3D *toQuery - a handle to an RMcamera3D object that
1647 will be queried by this routine (input).
1648
1649 @aend
1650
1651 @dstart
1652
1653 Use this routine to query the interocular separation parameter of a
1654 stereo 3D camera. Returns a floating point value representing the 3D
1655 stereo camera's interocular distance parameter.
1656
1657 A stereo 3D camera in OpenRM defines a binocular viewing geometry.
1658 The binocular viewing geometry is a function of eye separation
1659 (rmCamera3DSetEyeSeparation) and focal length
1660 (rmCamera3DSetFocalDistance).
1661
1662 The stereo camera's binocular geometry, specifically the interocular
1663 distance, is computed using the 3D camera's eye point, the look-at
1664 point, the focal length and the interocular distance. The "real" look
1665 at point of a 3D stereo camera is computed as the product of the
1666 focal length with the (unitized) eye/look-at vector. The left and
1667 right eyes both look at the "real" stereo look-at point (not the one
1668 specified by rmCamera3DSetAt). The apex of the triangle formed by the
1669 left and right eyes and the "real" stereo look at point will have an
1670 angular measure of X degrees, where X is specified as the parameter
1671 to the routine rmCamera3DSetEyeSeparation. We have found that values
1672 in the range 2.5-3.5 degrees work well for most viewers.
1673
1674 @dend
1675 * ----------------------------------------------------
1676 */
1677 float
rmCamera3DGetEyeSeparation(const RMcamera3D * toQuery)1678 rmCamera3DGetEyeSeparation (const RMcamera3D *toQuery)
1679 {
1680 if (RM_ASSERT(toQuery, "rmCamera3DGetEyeSeparation error: input RMcamera3D points is NULL. Returning 1.0F.") == RM_WHACKED)
1681 return(1.0F);
1682
1683 return(toQuery->degrees_eye_separation);
1684 }
1685
1686
1687 /*
1688 * ----------------------------------------------------
1689 * @Name rmCamera3DSetFocalDistance
1690 @pstart
1691 RMenum rmCamera3DSetFocalDistance (RMcamera3D *toModify, float newVal)
1692 @pend
1693
1694 @astart
1695 RMcamera3D *toModify - a handle to an RMcamera3D object (modified).
1696
1697 float newVal - a floating point value specifying new focal distance
1698 length (input).
1699 @aend
1700
1701 @dstart
1702
1703 Use this routine to modify the focal distance parameter of a stereo
1704 3D camera. Returns RM_WHACKED upon failure, otherwise returns
1705 RM_CHILL.
1706
1707 A stereo 3D camera in OpenRM defines a binocular viewing geometry.
1708 The binocular viewing geometry is a function of eye separation
1709 (rmCamera3DSetEyeSeparation) and focal length
1710 (rmCamera3DSetFocalDistance).
1711
1712 In a binocular view model, the left and right eyes look at a point
1713 somewhere in space. This point is computed from the 3D stereo camera
1714 parameters: eye point (rmCamera3DSetEye), the look-at point
1715 (rmCamera3DSetAt) and the focal distance
1716 (rmCamera3DSetFocalDistance). The point is computed as the eye point
1717 plus the focal distance times the eye-at vector.
1718
1719 A value of 1.0 for the focal distance places the stereo look-at point
1720 at the look-at point specified by rmCamera3DSetAt. A value of, say,
1721 0.707, places the stereo look at point in front of the 3D camera's
1722 look-at point, and a value of, say, 1.414, places the stereo look-at
1723 point somewhere behind the 3D camera's look at point.
1724
1725 Manipulation of the focal distance and the interocular separation
1726 parameters can have a profound effect upon the perceived stereo view.
1727
1728 @dend
1729 * ----------------------------------------------------
1730 */
1731 RMenum
rmCamera3DSetFocalDistance(RMcamera3D * toModify,float newval)1732 rmCamera3DSetFocalDistance (RMcamera3D *toModify,
1733 float newval)
1734 {
1735 if (RM_ASSERT(toModify, "rmCamera3DSetFocalDistance error: input RMcamera3D is NULL") == RM_WHACKED)
1736 return(RM_WHACKED);
1737
1738 toModify->focalDistance = newval;
1739
1740 return(RM_CHILL);
1741 }
1742
1743
1744 /*
1745 * ----------------------------------------------------
1746 * @Name rmCamera3DGetFocalDistance
1747 @pstart
1748 RMenum rmCamera3DGetFocalDistance (const RMcamera3D *toQuery)
1749 @pend
1750
1751 @astart
1752 const RMcamera3D *toQuery - a handle to an RMcamera3D object that
1753 will be queried by this routine (input).
1754 @aend
1755
1756 @dstart
1757
1758 Use this routine to query the focal distance parameter of a stereo 3D
1759 camera. A floating point value is returned by this routine.
1760
1761 A stereo 3D camera in OpenRM defines a binocular viewing geometry.
1762 The binocular viewing geometry is a function of eye separation
1763 (rmCamera3DSetEyeSeparation) and focal length
1764 (rmCamera3DSetFocalDistance).
1765
1766 In a binocular view model, the left and right eyes look at a point
1767 somewhere in space. This point is computed from the 3D stereo camera
1768 parameters: eye point (rmCamera3DSetEye), the look-at point
1769 (rmCamera3DSetAt) and the focal distance
1770 (rmCamera3DSetFocalDistance). The point is computed as the eye point
1771 plus the focal distance times the eye-at vector.
1772
1773 A value of 1.0 for the focal distance places the stereo look-at point
1774 at the look-at point specified by rmCamera3DSetAt. A value of, say,
1775 0.707, places the stereo look at point in front of the 3D camera's
1776 look-at point, and a value of, say, 1.414, places the stereo look-at
1777 point somewhere behind the 3D camera's look at point.
1778
1779 Manipulation of the focal distance and the interocular separation
1780 parameters can have a profound effect upon the perceived stereo view.
1781
1782 @dend
1783 * ----------------------------------------------------
1784 */
1785 float
rmCamera3DGetFocalDistance(const RMcamera3D * c)1786 rmCamera3DGetFocalDistance (const RMcamera3D *c)
1787 {
1788 if (RM_ASSERT(c, "rmCamera3DGetFocalDistance error: input RMcamera3D is NULL. Returning 1.0F") == RM_WHACKED)
1789 return(1.0F);
1790
1791 return(c->focalDistance);
1792 }
1793
1794
1795 /*
1796 * ----------------------------------------------------
1797 * @Name rmCamera3DComputeViewMatrix
1798 @pstart
1799 RMenum rmCamera3DComputeViewMatrix (const RMcamera3D *source,
1800 RMmatrix *viewReturn,
1801 RMmatrix *projectionReturn)
1802 @pend
1803
1804 @astart
1805 const RMcamera3D *source - a handle to an RMcamera3D object (input).
1806
1807 RMmatrix *viewReturn - a handle to an RMmatrix object (result).
1808
1809 RMmatrix *projectionReturn - a handle to an RMmatrix object (result).
1810 @aend
1811
1812 @dstart
1813
1814 Computes a view and projection matrix from an RMcamera3D object,
1815 returning the computed matrices in the "viewReturn" and
1816 "projectionReturn" parameters, respectively. RM_CHILL is returned
1817 upon success, or RM_WHACKED upon failure. Failure can occur if either
1818 of the input parameters is NULL, or if there is some type of fatal
1819 numerical error caused by bogus 3D camera parameters. These latter
1820 problems are detected and reported via rmError().
1821
1822 The view matrix represents the affine transformation that transforms
1823 from world coordinates into "eye coordinates," assuming a monocular
1824 view. The same matrix is returned regardless of whether or not the
1825 input camera is a stereo or mono camera.
1826
1827 The projection matrix represents the transformation from eye space
1828 coordinates to NDC coordinates. If the camera uses perspective
1829 projection, that transformation will be present in the
1830 projectionReturn matrix.
1831
1832 @dend
1833 * ----------------------------------------------------
1834 */
1835 RMenum
rmCamera3DComputeViewMatrix(const RMcamera3D * c,RMmatrix * m,RMmatrix * p)1836 rmCamera3DComputeViewMatrix (const RMcamera3D *c,
1837 RMmatrix *m,
1838 RMmatrix *p)
1839 {
1840 if ((RM_ASSERT(c, "rmCamera3DComputeViewMatrix error: the input RMcamera3D object is NULL") == RM_WHACKED) ||
1841 (RM_ASSERT(m, "rmCamera3DComputeViewMatrix error: the return view RMmatrix object is NULL") == RM_WHACKED) ||
1842 (RM_ASSERT(p, "rmCamera3DComputeViewMatrix error: the return projection RMmatrix object is NULL") == RM_WHACKED))
1843 return(RM_WHACKED);
1844
1845 private_rmComputeViewMatrix(c, m, p);
1846
1847 return(RM_CHILL);
1848 }
1849
1850
1851 /*
1852 * ----------------------------------------------------
1853 * @Name rmCamera3DComputeViewFromGeometry
1854 @pstart
1855 RMenum rmCamera3DComputeViewFromGeometry (RMcamera3D *toModify,
1856 const RMnode *source,
1857 int windowWidth,
1858 int windowHeight)
1859
1860 @pend
1861
1862 @astart
1863 RMcamera3D *toModify - a handle to the RMcamera3D object (modified).
1864
1865 const RMnode *source - a handle to an RMnode. the bounding box of
1866 this RMnode will be used in computing 3D camera parameters
1867 (input).
1868
1869 int windowWidth, windowHeight - int values specifying the width and
1870 height in pixels of the display window. These values are used in
1871 computing an aspect ratio for the camera (input).
1872 @aend
1873
1874 @dstart
1875
1876 This routine computes and assigns 3D camera parameters such that a
1877 volume defined by the bounding box attribute of the input RMnode will
1878 be visible, regardless of box orientation. If present, the scale matrix
1879 transformation attribute of the RMnode will be used to enlarge or shrink
1880 the bounding box parameter of the RMnode for the purposes of computing
1881 new camera parameters.
1882
1883 The 3D camera must be a valid RMcamera3D object allocated by the
1884 caller. This routine merely computes new values for an existing
1885 camera using the bounding box of an RMnode. It neither creates nor
1886 destroys an RMcamera3D.
1887
1888 The 3D camera's FOV parameter is used as part of the computation, and
1889 will not be overwritten by this routine. All stereo parameters, if
1890 any, are ignored and remain unmodified by this routine.
1891
1892 The new 3D camera parameters are computed thus:
1893
1894 1. The 3D camera's look-at point will be the center of the RMnode's
1895 bounding box.
1896
1897 2. The 3D camera's new eye position is the same as the new look-at
1898 point, but offset along the Z axis a distance D. The distance D is
1899 computed as boxsize/tan(FOV/2) where boxsize is the distance from
1900 the bounding box's min vertex to the box's max vertex. The basic
1901 idea is to move the eye point away from the look-at point a
1902 distance which is sufficient for the entire box to be visible,
1903 given the requested FOV.
1904
1905 3. The near and far clip planes are set to a distance F which is
1906 computed as D-boxsize*1.4 and D+boxsize*1.4, respectively, where D
1907 is the same D computed in (2). Again, the point is to have the
1908 entire bounding box within the view frustum regardless of
1909 orientation.
1910
1911 Note: 8/16/02 - changed computation of near/far to D-boxsize*2.0,
1912 D+boxsize*5.0, respectively. This gives more room to maneuver before
1913 the object gets clipped.
1914
1915 4. The aspect ratio for the 3D camera is set using the input values
1916 windowWidth and WindowHeight.
1917
1918 @dend
1919 * ----------------------------------------------------
1920 */
1921 RMenum
rmCamera3DComputeViewFromGeometry(RMcamera3D * c,const RMnode * r,int w,int h)1922 rmCamera3DComputeViewFromGeometry (RMcamera3D *c, /* input and output */
1923 const RMnode *r, /* input, has geometry & stuff */
1924 int w, /* image width, for aspect ratio */
1925 int h) /* image height, for aspect ratio */
1926 {
1927 float new_hither, new_yon;
1928 float vp[] = {0.0, 0.0, 1.0, 1.0};
1929 double d, d2, boxsize;
1930 RMvertex3D new_at;
1931 RMvertex3D new_eye;
1932 RMvertex3D new_up;
1933 RMvertex3D bmin, bmax;
1934 const RMnode *root;
1935 RMmatrix scale, C, minusC;
1936 extern double sqrt(double);
1937
1938 if ((RM_ASSERT(c, "rmCamera3DComputeViewFromGeometry error: the input RMcamera3D object is NULL") == RM_WHACKED) ||
1939 (RM_ASSERT(r, "rmCamera3DComputeViewFromGeometry error: the input RMnode is NULL") == RM_WHACKED))
1940 return(RM_WHACKED);
1941
1942 root = r;
1943 rmNodeGetBoundingBox(root, &bmin, &bmax);
1944
1945 /* get the scale matrix */
1946 if (rmNodeGetScaleMatrix(r, &scale) == RM_WHACKED)
1947 rmMatrixIdentity(&scale);
1948
1949 /* multiply the bounding box with the scale matrix */
1950 {
1951 RMvertex3D center;
1952 RMmatrix composite;
1953
1954 rmNodeGetCenter(r, ¢er);
1955 rmMatrixIdentity(&C);
1956 rmMatrixIdentity(&minusC);
1957
1958 C.m[3][0] = center.x;
1959 C.m[3][1] = center.y;
1960 C.m[3][2] = center.z;
1961
1962 minusC.m[3][0] = -1.0 * center.x;
1963 minusC.m[3][1] = -1.0 * center.y;
1964 minusC.m[3][2] = -1.0 * center.z;
1965
1966 rmMatrixIdentity(&composite);
1967 rmMatrixMultiply(&minusC, &composite, &composite);
1968 rmMatrixMultiply(&composite, &scale, &composite);
1969 rmMatrixMultiply(&composite, &C, &composite);
1970
1971 rmPointMatrixTransform(&bmin, &composite, &bmin);
1972 rmPointMatrixTransform(&bmax, &composite, &bmax);
1973 }
1974
1975 /* we're going to assume that the bounding boxes are all sync'ed up. */
1976 new_up.x = new_up.z = 0.0;
1977 new_up.y = 1.0;
1978
1979 /* the new "at" point will be a point at the x/y center of the
1980 front face of the bounding box. */
1981
1982 new_at.x = bmin.x + ((bmax.x - bmin.x) * 0.5);
1983 new_at.y = bmin.y + ((bmax.y - bmin.y) * 0.5);
1984 /* new_at.z = bmax.z; */
1985 new_at.z = bmin.z + ((bmax.z - bmin.z) * 0.5);
1986
1987 /* compute the length of the diagonal of the box */
1988 d = ((bmax.x - bmin.x) * (bmax.x - bmin.x)) + ((bmax.y - bmin.y) * (bmax.y - bmin.y)) + ((bmax.z - bmin.z) * (bmax.z - bmin.z));
1989 boxsize = sqrt(d);
1990 boxsize *= 0.5;
1991
1992 /* the new eye point will lie some distance along the +z axis
1993 * away from the new at point. "some distance" is defined as a
1994 * distance which is "far enough" away so that the front face of
1995 * the bounding box will lie within FOV degrees of view.
1996 */
1997
1998 d = boxsize;
1999
2000 d2 = RM_DEGREES_TO_RADIANS(c->fov);
2001 d2 *= 0.5;
2002 d2 = tan(d2);
2003
2004 d = boxsize / d2;
2005 d2 = d;
2006
2007 /* the choices for hither and yon are somewhat arbitrary. what we
2008 * want is a choice of hither/yon that will permit the entire
2009 * object to be displayed w/o clipping regardless of orientation. so,
2010 * we need to look at the maximum dimension of the box. also, such
2011 * a goal may not be achievable under some conditions. for example, when
2012 * the requested fov is > 90, then the eye starts getting closer to
2013 * the box rather than further away from it. oh well...
2014 *
2015 * hither/yon are a function of the boxsize. these are set so that
2016 * the entire bbox will always be visible. possible error conditions
2017 * include the case of d being < boxsize.
2018 */
2019 if (d < boxsize * 2.0)
2020 fprintf(stderr," error: we're about to set the front clip plane behind the eye. \n");
2021
2022 new_hither = d - (boxsize * 2.0);
2023 new_yon = d + (boxsize * 5.0F);
2024
2025 rmCamera3DResetAspectRatio(c, vp, w, h);
2026
2027 new_eye.x = new_at.x;
2028 new_eye.y = new_at.y;
2029 new_eye.z = new_at.z + (d2 * 1.1);
2030
2031 rmCamera3DSetEye(c, &new_eye);
2032 rmCamera3DSetAt(c, &new_at);
2033 rmCamera3DSetUpVector(c, &new_up);
2034 rmCamera3DSetHither(c, new_hither);
2035 rmCamera3DSetYon(c, new_yon);
2036
2037 return(RM_CHILL);
2038 }
2039
2040
2041 /* PRIVATE */
2042 static void
private_rmCamera2DComputeMatrix(const RMcamera2D * c,RMmatrix * m)2043 private_rmCamera2DComputeMatrix (const RMcamera2D *c,
2044 RMmatrix *m)
2045 {
2046 float x, y, z;
2047 float tx, ty, tz;
2048 float cwidth, center, cxmax, cxmin;
2049 double left ,right, top, bottom;
2050 RMmatrix P;
2051
2052 rmMatrixIdentity(&P);
2053
2054 cwidth = c->xmax - c->xmin;
2055 center = ((c->xmax - c->xmin) * 0.5F) + c->xmin;
2056 cxmax = center + (cwidth * 0.5F) * c->aspect_ratio;
2057 cxmin = center - (cwidth * 0.5F) * c->aspect_ratio;
2058
2059 left = cxmin;
2060 right = cxmax;
2061 bottom = c->ymin;
2062 top = c->ymax;
2063
2064 x = 2.0 / (right - left);
2065 y = 2.0 / (top - bottom);
2066 z = 1.0;
2067 tx = -(right + left) / (right -left);
2068 ty = -(top + bottom) / (top - bottom);
2069 tz = 0.;
2070
2071 P.m[3][0] = tx;
2072 P.m[3][1] = ty;
2073 P.m[3][2] = tz;
2074
2075 P.m[0][0] = x;
2076 P.m[1][1] = y;
2077 P.m[2][2] = z;
2078
2079 *m = P;
2080 }
2081
2082
2083 /* PRIVATE */
2084 void
private_rmComputeViewMatrix(const RMcamera3D * c,RMmatrix * m,RMmatrix * proj)2085 private_rmComputeViewMatrix (const RMcamera3D *c,
2086 RMmatrix *m,
2087 RMmatrix *proj)
2088 {
2089 /* compute both the view and projection matrices */
2090 RMmatrix R, T, TR, P;
2091 RMvertex3D z, y, x;
2092
2093 /* Make the translation matrix */
2094 rmMatrixIdentity(&T);
2095 T.m[3][0] = -1.0 * c->eye.x;
2096 T.m[3][1] = -1.0 * c->eye.y;
2097 T.m[3][2] = -1.0 * c->eye.z;
2098
2099 /* Make rotation matrix */
2100 rmMatrixIdentity(&R);
2101
2102 /* Z vector */
2103 rmVertex3DDiff(&(c->eye), &(c->at),&z);
2104 rmVertex3DNormalize(&z);
2105
2106 y = c->up;
2107 rmVertex3DNormalize(&y);
2108
2109 /* X vector = Y cross Z */
2110 rmVertex3DCross(&y, &z, &x);
2111
2112 /* Recompute Y = Z cross X */
2113 rmVertex3DCross(&z, &x, &y);
2114
2115 /* cross product gives area of parallelogram, which is < 1.0 for
2116 non-perpendicular unit-length vectors; so normalize x, y here */
2117
2118 /* this might be transposed */
2119 R.m[0][0] = x.x;
2120 R.m[1][0] = x.y;
2121 R.m[2][0] = x.z;
2122
2123 R.m[0][1] = y.x;
2124 R.m[1][1] = y.y;
2125 R.m[2][1] = y.z;
2126
2127 R.m[0][2] = z.x;
2128 R.m[1][2] = z.y;
2129 R.m[2][2] = z.z;
2130
2131 /* concatenate the translational and rotational pieces together */
2132 rmMatrixMultiply(&T, &R, &TR);
2133
2134 /* build the projection matrix */
2135 rmMatrixIdentity(&P);
2136
2137 if (rmCamera3DGetProjection(c) == RM_PROJECTION_PERSPECTIVE)
2138 {
2139 double fovy, aspect, znear, zfar;
2140 double xmin, xmax, ymin, ymax;
2141 double x, y, a, b, C, d;
2142 double left, right, bottom, top, nearval, farval;
2143
2144 fovy = c->fov;
2145 aspect = c->aspect;
2146 znear = c->hither;
2147 zfar = c->yon;
2148
2149 ymax = znear * tan(fovy * RM_PI / 360.0);
2150 ymin = -ymax;
2151
2152 xmin = ymin * aspect;
2153 xmax = ymax * aspect;
2154
2155 left = xmin;
2156 right = xmax;
2157 bottom = ymin;
2158 top = ymax;
2159 nearval = znear;
2160 farval = zfar;
2161
2162 x = (2.0 * nearval) / (right - left);
2163 y = (2.0 * nearval) / (top - bottom);
2164 a = (right + left) / (right - left);
2165 b = (top + bottom) / (top - bottom);
2166 C = -(farval + nearval) / ( farval - nearval);
2167 d = -(2.0 * farval * nearval) / (nearval - farval); /* error? */
2168
2169 P.m[0][0] = x;
2170 P.m[2][0] = a;
2171 P.m[1][1] = y;
2172 P.m[2][1] = b;
2173 P.m[2][2] = C;
2174 P.m[2][3] = -1.0;
2175 P.m[3][2] = -d;
2176 P.m[3][3] = 1.0; /* should be 0, but OGL puts a 1 there */
2177 }
2178 else /* RM_PROJECTION_ORTHOGONAL */
2179 {
2180 float x, y, z;
2181 float tx, ty, tz;
2182 double width, height;
2183 double sfov, mag;
2184 double left, right, top, bottom, hither, yon;
2185 RMvertex3D eye_at;
2186
2187 /* set the width of the view volume to be proportional to
2188 * the field-of-view angle. we do this a little differently
2189 * than OpenGL, using the FOV to specify the horizontal field
2190 * of view, rather than the vertical field of view.
2191 */
2192 sfov = sin((double)c->fov);
2193
2194 eye_at.x = c->eye.x - c->at.x;
2195 eye_at.y = c->eye.y - c->at.y;
2196 eye_at.z = c->eye.z - c->at.z;
2197
2198 mag = rmVertex3DMag(&eye_at);
2199 width = mag * sfov;
2200
2201 height = width / c->aspect;
2202
2203 left = -width;
2204 right = width;
2205 bottom = -height;
2206 top = height;
2207 hither = c->hither;
2208 yon = c->yon;
2209
2210 x = 2.0 / (right - left);
2211 y = 2.0 / (top - bottom);
2212 z = -2.0 / (yon - hither);
2213 tx = -(right + left) / (right - left);
2214 ty = -(top + bottom) / (top - bottom);
2215 tz = -(yon + hither) / (yon - hither);
2216
2217 P.m[3][0] = tx;
2218 P.m[3][1] = ty;
2219 P.m[3][2] = tz;
2220
2221 P.m[0][0] = x;
2222 P.m[1][1] = y;
2223 P.m[2][2] = z;
2224 }
2225 *proj = P;
2226 *m = TR;
2227 }
2228 /* EOF */
2229