source: trunk/packages/vizservers/nanovis/Camera.cpp @ 3611

Last change on this file since 3611 was 3611, checked in by ldelgass, 9 years ago

Use nv namespace for classes in nanovis rather than prefixing class names with
Nv (still need to convert shader classes).

  • Property svn:eol-style set to native
File size: 7.1 KB
Line 
1/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/*
3 * Copyright (c) 2004-2013  HUBzero Foundation, LLC
4 *
5 *  Authors:
6 *    Wei Qiao <qiaow@purdue.edu>
7 */
8#include <stdio.h>
9#include <math.h>
10#include <float.h>
11
12#include <GL/glew.h>
13#include <GL/glu.h>
14
15#include <vrmath/Quaternion.h>
16#include <vrmath/Rotation.h>
17#include <vrmath/Matrix4x4d.h>
18#include <vrmath/Vector3f.h>
19#include <vrmath/Vector4f.h>
20
21#include "nanovis.h"
22#include "Camera.h"
23#include "Trace.h"
24
25using namespace nv;
26using namespace vrmath;
27
28static inline double deg2rad(double deg)
29{
30    return ((deg * M_PI) / 180.);
31}
32
33static inline double rad2deg(double rad)
34{
35    return ((rad * 180.) / M_PI);
36}
37
38Camera::Camera(int startx, int starty, int w, int h,
39               float loc_x, float loc_y, float loc_z) :
40    _location(loc_x, loc_y, loc_z),
41    _fov(30.0),
42    _near(0.1),
43    _far(50.0),
44    _width(w),
45    _height(h),
46    _startX(startx),
47    _startY(starty)
48{
49}
50
51void
52Camera::getUpDirMatrix(Matrix4x4d& upMat)
53{
54    switch (NanoVis::updir) {
55    case NanoVis::X_POS: {
56        upMat.makeRotation(0, 0, 1, deg2rad(90));
57        Matrix4x4d tmp;
58        tmp.makeRotation(1, 0, 0, deg2rad(90));
59        upMat.multiply(tmp);
60    }
61        break;
62    case NanoVis::Y_POS:
63        upMat.makeIdentity();
64        break;
65    case NanoVis::Z_POS: {
66        upMat.makeRotation(1, 0, 0, deg2rad(-90));
67        Matrix4x4d tmp;
68        tmp.makeRotation(0, 0, 1, deg2rad(-90));
69        upMat.multiply(tmp);
70    }
71        break;
72    case NanoVis::X_NEG:
73        upMat.makeRotation(0, 0, 1, deg2rad(-90));
74        break;
75    case NanoVis::Y_NEG: {
76        upMat.makeRotation(0, 0, 1, deg2rad(180));
77        Matrix4x4d tmp;
78        tmp.makeRotation(0, 1, 0, deg2rad(-90));
79        upMat.multiply(tmp);
80    }
81        break;
82    case NanoVis::Z_NEG:
83        upMat.makeRotation(1, 0, 0, deg2rad(90));
84        break;
85    }
86}
87
88/**
89 * \brief Reset zoom to include extents
90 */
91void
92Camera::reset(const Vector3f& bboxMin,
93              const Vector3f& bboxMax,
94              bool resetOrientation)
95{
96    TRACE("Enter");
97
98    if (resetOrientation) {
99        _cameraMatrix.makeIdentity();
100    }
101
102    Vector3f center(bboxMin + bboxMax);
103    center.scale(0.5);
104
105    Matrix4x4d mat, upMat;
106    getUpDirMatrix(upMat);
107    mat.makeTranslation(-center);
108    mat.multiply(_cameraMatrix, mat);
109    mat.multiply(upMat);
110
111    Vector3f emin(FLT_MAX, FLT_MAX, FLT_MAX), emax(-FLT_MAX, -FLT_MAX, -FLT_MAX);
112
113    // Transform bounds by camera matrix
114    Vector4f bboxEye[8];
115    bboxEye[0] = Vector4f(bboxMin.x, bboxMin.y, bboxMin.z, 1);
116    bboxEye[1] = Vector4f(bboxMax.x, bboxMin.y, bboxMin.z, 1);
117    bboxEye[2] = Vector4f(bboxMin.x, bboxMax.y, bboxMin.z, 1);
118    bboxEye[3] = Vector4f(bboxMin.x, bboxMin.y, bboxMax.z, 1);
119    bboxEye[4] = Vector4f(bboxMax.x, bboxMax.y, bboxMin.z, 1);
120    bboxEye[5] = Vector4f(bboxMax.x, bboxMin.y, bboxMax.z, 1);
121    bboxEye[6] = Vector4f(bboxMin.x, bboxMax.y, bboxMax.z, 1);
122    bboxEye[7] = Vector4f(bboxMax.x, bboxMax.y, bboxMax.z, 1);
123
124    for (int i = 0; i < 8; i++) {
125        Vector4f eyeVert = mat.transform(bboxEye[i]);
126        if (eyeVert.x < emin.x) emin.x = eyeVert.x;
127        if (eyeVert.x > emax.x) emax.x = eyeVert.x;
128        if (eyeVert.y < emin.y) emin.y = eyeVert.y;
129        if (eyeVert.y > emax.y) emax.y = eyeVert.y;
130        if (eyeVert.z < emin.z) emin.z = eyeVert.z;
131        if (eyeVert.z > emax.z) emax.z = eyeVert.z;
132    }
133
134    TRACE("Eye bounds: (%g,%g,%g) - (%g,%g,%g)",
135          emin.x, emin.y, emin.z,
136          emax.x, emax.y, emax.z);
137
138    double bwidth = emax.x - emin.x;
139    double bheight = emax.y - emin.y;
140    double bdepth = emax.z - emin.z;
141
142    TRACE("bwidth: %g, bheight: %g, bdepth: %g", bwidth, bheight, bdepth);
143
144    double angle = deg2rad(_fov);
145    double distance;
146
147    // Deal with vertical aspect window
148    double winAspect = (double)(_width - _startX)/(double)(_height - _startY);
149    double sceneAspect = 1.0;;
150    if (bheight > 0.0)
151        sceneAspect = bwidth / bheight;
152
153    if (sceneAspect >= winAspect) {
154        angle = 2.0 * atan(tan(angle*0.5)*winAspect);
155        _near = bwidth / (2.0 * tan(angle*0.5));
156    } else {
157        _near = bheight / (2.0 * tan(angle*0.5));
158    }
159
160    distance = _near + bdepth * 0.5;
161    _far = _near + bdepth;
162
163    _location.set(center.x, center.y, center.z + distance);
164
165    TRACE("win aspect: %g scene aspect: %g", winAspect, sceneAspect);
166    TRACE("c: %g,%g,%g, d: %g", center.x, center.y, center.z, distance);
167    TRACE("near: %g, far: %g", _near, _far);
168
169    initialize();
170    resetClippingRange(bboxMin, bboxMax);
171}
172
173void
174Camera::resetClippingRange(const Vector3f& bboxMin, const Vector3f& bboxMax)
175{
176    Vector3f emin(bboxMin.x, bboxMin.y, bboxMin.z), emax(bboxMax.x, bboxMax.y, bboxMax.z);
177
178    Vector3f center(emin + emax);
179    center.scale(0.5);
180
181    // Compute the radius of the enclosing sphere,
182    // which is half the bounding box diagonal
183    Vector3f diagonal(emax - emin);
184    double radius = diagonal.length() * 0.5;
185
186    // If we have just a single point, pick a radius of 1.0
187    radius = (radius == 0) ? 1.0 : radius;
188
189    TRACE("c: %g,%g,%g, r: %g cam z: %g", center.x, center.y, center.z, radius, _location.z);
190
191    _near = _location.z - radius;
192    _far = _location.z + radius;
193
194    if (_near < 0.0) {
195        _near = 0.001;
196    }
197    if (_far < 0.0) {
198        _far = 1.0;
199    }
200
201    TRACE("Resetting camera clipping range to: near: %g, far: %g", _near, _far);
202
203    glMatrixMode(GL_PROJECTION);
204    glLoadIdentity();
205    gluPerspective(_fov,
206                   (GLdouble)(_width - _startX)/(GLdouble)(_height - _startY),
207                   _near, _far);
208    glMatrixMode(GL_MODELVIEW);
209
210    print();
211}
212
213void
214Camera::initialize()
215{
216    TRACE("Enter");
217    print();
218
219    glViewport(_startX, _startY, _width, _height);
220    glMatrixMode(GL_PROJECTION);
221    glLoadIdentity();
222    gluPerspective(_fov,
223                   (GLdouble)(_width - _startX)/(GLdouble)(_height - _startY),
224                   _near, _far);
225
226    glMatrixMode(GL_MODELVIEW);
227    glLoadIdentity();
228
229    glTranslatef(-_location.x, -_location.y, -_location.z);
230    glMultMatrixd((const GLdouble *)_cameraMatrix.get());
231}
232
233void Camera::rotate(double *quat)
234{
235    Quaternion q(quat[0], quat[1], quat[2], quat[3]);
236    Rotation rot;
237    rot.set(q);
238    _cameraMatrix.makeRotation(rot);
239    _cameraMatrix.transpose();
240    TRACE("Set rotation to quat: %g %g %g %g",
241          quat[0], quat[1], quat[2], quat[3]);
242}
243
244void Camera::rotate(float angleX, float angleY, float angleZ)
245{
246    angleX = -angleX;
247    angleY = angleY - 180.;
248
249    _cameraMatrix.makeRotation(1, 0, 0, deg2rad(angleX));
250    Matrix4x4d mat;
251    mat.makeRotation(0, 1, 0, deg2rad(angleY));
252    _cameraMatrix.multiply(mat);
253    mat.makeRotation(0, 0, 1, deg2rad(angleZ));
254    _cameraMatrix.multiply(mat);
255    //_cameraMatrix.transpose();
256
257    TRACE("Set rotation to angles: %g %g %g",
258          angleX, angleY, angleZ);
259}
260
261void Camera::print() const
262{
263    TRACE("x: %d y: %d w: %d h: %d", _startX, _startY, _width, _height);
264    TRACE("loc: %g %g %g",
265          _location.x, _location.y, _location.z);
266    TRACE("Camera matrix: ");
267    _cameraMatrix.print();
268    TRACE("fov: %g near: %g far: %g", _fov, _near, _far);
269}
Note: See TracBrowser for help on using the repository browser.