resolution don't care option, heuristic to avoid multimon sizes
[summerhack] / src / 3dengfx / src / gfx / base_cam.cpp
1 /*
2 This file is part of the graphics core library.
3
4 Copyright (c) 2004, 2005 John Tsiombikas <nuclear@siggraph.org>
5
6 the graphics core library is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 the graphics core library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with the graphics core library; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21 #include "3dengfx_config.h"
22
23 #include "base_cam.hpp"
24
25 #ifdef USING_3DENGFX
26 #include "3dengfx/3denginefx.hpp"
27 #include "fxwt/fxwt.hpp"
28 #endif  // USING_3DENGFX
29
30 FrustumPlane::FrustumPlane() {
31         a = b = c = d = 0;
32 }
33
34 FrustumPlane::FrustumPlane(scalar_t a, scalar_t b, scalar_t c, scalar_t d) {
35         this->a = a;
36         this->b = b;
37         this->c = c;
38         this->d = d;
39 }
40
41 // frustum plane extraction from a projection (or mvp) matrix
42 FrustumPlane::FrustumPlane(const Matrix4x4 &mat, int plane) {
43         int i = plane / 2;
44         int neg = plane % 2;
45
46         a = mat[3][0] + (neg ? -mat[i][0] : mat[i][0]);
47         b = mat[3][1] + (neg ? -mat[i][1] : mat[i][1]);
48         c = mat[3][2] + (neg ? -mat[i][2] : mat[i][2]);
49         d = mat[3][3] + (neg ? -mat[i][3] : mat[i][3]);
50
51         // normalize plane equation
52         scalar_t len = Vector3(a, b, c).length();
53         a /= len;
54         b /= len;
55         c /= len;
56         d /= len;
57 }
58
59 BaseCamera::BaseCamera(const Vector3 &trans, const Quaternion &rot) {
60         set_position(trans);
61         set_rotation(rot);
62         up = Vector3(0, 1, 0);
63         fov = quarter_pi;
64         near_clip = 1.0;
65         far_clip = 10000.0;
66 #ifdef USING_3DENGFX
67         aspect = (float)fxwt::screenx / fxwt::screeny;
68 #else
69         aspect = 1.33333333;
70 #endif
71         flip_view.x = flip_view.y = flip_view.z = false;
72 }
73
74 BaseCamera::~BaseCamera() {}
75
76 void BaseCamera::setup_frustum(const Matrix4x4 &m) {
77         for(int i=0; i<6; i++) {
78                 frustum[i] = FrustumPlane(m, i);
79         }
80 }
81
82 void BaseCamera::set_up_vector(const Vector3 &up) {
83         this->up = up;
84 }
85
86 void BaseCamera::set_fov(scalar_t angle) {
87         fov = angle;
88 }
89
90 scalar_t BaseCamera::get_fov() const {
91         return fov;
92 }
93
94 void BaseCamera::set_aspect(scalar_t aspect) {
95         this->aspect = aspect;
96 }
97
98 scalar_t BaseCamera::get_aspect() const {
99         return aspect;
100 }
101
102 void BaseCamera::set_clipping_planes(scalar_t near_clip, scalar_t far_clip) {
103         this->near_clip = near_clip;
104         this->far_clip = far_clip;
105 }
106
107 void BaseCamera::set_clipping_plane(scalar_t val, ClipPlane which) {
108         if(which == CLIP_NEAR) {
109                 near_clip = val;
110         } else {
111                 far_clip = val;
112         }
113 }
114
115 scalar_t BaseCamera::get_clipping_plane(ClipPlane which) const {
116         return which == CLIP_NEAR ? near_clip : far_clip;
117 }
118
119
120 void BaseCamera::zoom(scalar_t zoom_factor, unsigned long msec) {
121         Vector3 zoom_dir(0, 0, zoom_factor);
122         PRS prs = get_prs(msec);
123
124         zoom_dir.transform(prs.rotation.inverse());
125         translate(zoom_dir, msec);
126 }
127
128 void BaseCamera::pan(const Vector2 &dir, unsigned long msec) {
129         Vector3 i(1, 0, 0), j(0, 1, 0);
130         
131         PRS prs = get_prs(msec);
132         
133         i.transform(prs.rotation.inverse());
134         j.transform(prs.rotation.inverse());
135         
136         translate(i * dir.x);
137         translate(j * dir.y);
138 }
139
140 void BaseCamera::roll(scalar_t angle, unsigned long msec) {
141         Vector3 dir(0, 0, 1);
142         dir.transform(get_prs(msec).rotation);
143
144         Quaternion q(dir, angle);
145         up = Vector3(0, 1, 0);
146         up.transform(q);
147 }
148
149 void BaseCamera::flip(bool x, bool y, bool z) {
150         flip_view.x = x;
151         flip_view.y = y;
152         flip_view.z = z;
153 }
154
155 const FrustumPlane *BaseCamera::get_frustum() const {
156         return frustum;
157 }
158
159 Matrix4x4 BaseCamera::get_projection_matrix() const {
160 #ifdef USING_3DENGFX
161         return create_projection_matrix(fov, aspect, near_clip, far_clip);
162 #else
163         return Matrix4x4::identity_matrix;
164 #endif  // USING_3DENGFX
165 }
166
167 void BaseCamera::activate(unsigned long msec) const {
168 #ifdef USING_3DENGFX
169         set_matrix(XFORM_VIEW, get_camera_matrix(msec));
170
171         Matrix4x4 proj = get_projection_matrix();
172         set_matrix(XFORM_PROJECTION, proj);
173
174         engfx_state::view_mat_camera = (const Camera*)this;
175         const_cast<BaseCamera*>(this)->setup_frustum(proj * engfx_state::view_matrix);
176 #endif  // USING_3DENGFX
177 }