]> git.tdb.fi Git - libs/gl.git/blob - source/matrix.cpp
Field of view is an angle too
[libs/gl.git] / source / matrix.cpp
1 #include <algorithm>
2 #include <cmath>
3 #include <msp/geometry/affinetransformation.h>
4 #include "error.h"
5 #include "matrix.h"
6
7 using namespace std;
8
9 namespace Msp {
10 namespace GL {
11
12 Matrix::Matrix():
13         Base(Base::identity())
14 { }
15
16 Matrix::Matrix(const float *m):
17         Base(LinAl::SquareMatrix<float, 4>(m))
18 { }
19
20 Matrix::Matrix(const double *m):
21         Base(m)
22 { }
23
24 Matrix::Matrix(const LinAl::Matrix<double, 4, 4> &other):
25         Base(other)
26 { }
27
28 void Matrix::multiply(const Matrix &other)
29 {
30         *this = *this*other;
31 }
32
33 void Matrix::translate(const Vector3 &t)
34 {
35         multiply(translation(t));
36 }
37
38 void Matrix::rotate(const Angle &a, const Vector3 &x)
39 {
40         multiply(rotation(a, x));
41 }
42
43 void Matrix::scale(const Vector3 &s)
44 {
45         multiply(scaling(s));
46 }
47
48 Matrix Matrix::operator*(const Matrix &other) const
49 {
50         return static_cast<const Base &>(*this)*static_cast<const Base &>(other);
51 }
52
53 Matrix &Matrix::operator*=(const Matrix &other)
54 {
55         multiply(other);
56         return *this;
57 }
58
59 Vector4 Matrix::operator*(const Vector4 &vec) const
60 {
61         return static_cast<const Base &>(*this)*LinAl::Vector<double, 4>(vec);
62 }
63
64 Vector3 Matrix::operator*(const Vector3 &vec) const
65 {
66         return Vector3((*this)*Vector4(vec, 1.0f));
67 }
68
69 double Matrix::operator[](unsigned i) const
70 {
71         if(i>=16)
72                 throw out_of_range("Matrix::operator[]");
73         return operator()(i%4, i/4);
74 }
75
76 Matrix Matrix::translation(const Vector3 &t)
77 {
78         return Geometry::AffineTransformation<double, 3>::translation(t).get_matrix();
79 }
80
81 Matrix Matrix::rotation(const Angle &a, const Vector3 &x)
82 {
83         return Geometry::AffineTransformation<double, 3>::rotation(a, x).get_matrix();
84 }
85
86 Matrix Matrix::scaling(const Vector3 &s)
87 {
88         return Geometry::AffineTransformation<double, 3>::scaling(s).get_matrix();
89 }
90
91 Matrix Matrix::ortho(double l, double r, double b, double t, double n, double f)
92 {
93         if(l==r || b==t || n==f)
94                 throw invalid_argument("Matrix::ortho");
95
96         Matrix result;
97         result(0, 0) = 2/(r-l);
98         result(1, 1) = 2/(t-b);
99         result(2, 2) = -2/(f-n);
100         result(0, 3) = -(r+l)/(r-l);
101         result(1, 3) = -(t+b)/(t-b);
102         result(2, 3) = -(f+n)/(f-n);
103         return result;
104 }
105
106 Matrix Matrix::ortho_centered(double w, double h)
107 {
108         return ortho(-w/2, w/2, -h/2, h/2, -1, 1);
109 }
110
111 Matrix Matrix::ortho_bottomleft(double w, double h)
112 {
113         return ortho(0, w, 0, h, -1, 1);
114 }
115
116 Matrix Matrix::ortho_topleft(double w, double h)
117 {
118         return ortho(0, w, h, 0, -1, 1);
119 }
120
121 Matrix Matrix::frustum(double l, double r, double b, double t, double n, double f)
122 {
123         if(l==r || b==t || n<=0 || f<=n)
124                 throw invalid_argument("Matrix::frustum");
125
126         Matrix result;
127         result(0, 0) = 2*n/(r-l);
128         result(1, 1) = 2*n/(t-b);
129         result(0, 2) = (r+l)/(r-l);
130         result(1, 2) = (t+b)/(t-b);
131         result(2, 2) = -(f+n)/(f-n);
132         result(3, 2) = -1;
133         result(2, 3) = -2*f*n/(f-n);
134         result(3 ,3) = 0;
135         return result;
136 }
137
138 Matrix Matrix::frustum_centered(double w, double h, double n, double f)
139 {
140         return frustum(-w/2, w/2, -h/2, h/2, n, f);
141 }
142
143 Matrix Matrix::perspective(const Angle &h, double a, double n, double f)
144 {
145         double hh = tan(h/2.0)*n;
146         return frustum(-hh*a, hh*a, -hh, hh, n, f);
147 }
148
149
150 GLenum MatrixStack::current_mode = GL_MODELVIEW;
151
152 MatrixStack::MatrixStack(GLenum m):
153         mode(m)
154 {
155         matrices.reserve(mode==GL_MODELVIEW ? 32 : 4);
156         matrices.push_back(Matrix());
157 }
158
159 MatrixStack::MatrixStack():
160         mode(0)
161 {
162         matrices.reserve(32);
163         matrices.push_back(Matrix());
164 }
165
166 const Matrix &MatrixStack::top() const
167 {
168         return matrices.back();
169 }
170
171 void MatrixStack::load(const Matrix &m)
172 {
173         matrices.back() = m;
174         update();
175 }
176
177 void MatrixStack::multiply(const Matrix &m)
178 {
179         matrices.back() *= m;
180         update();
181 }
182
183 void MatrixStack::push()
184 {
185         matrices.push_back(top());
186 }
187
188 void MatrixStack::pop()
189 {
190         if(matrices.size()==1)
191                 throw stack_underflow("MatrixStack::pop()");
192
193         matrices.pop_back();
194         update();
195 }
196
197 void MatrixStack::update()
198 {
199         if(!mode)
200                 return;
201
202         if(mode!=current_mode)
203         {
204                 glMatrixMode(mode);
205                 current_mode = mode;
206         }
207
208         glLoadMatrixd(matrices.back().data());
209 }
210
211 MatrixStack &MatrixStack::operator=(const Matrix &m)
212 {
213         load(m);
214         return *this;
215 }
216
217 MatrixStack &MatrixStack::operator*=(const Matrix &m)
218 {
219         multiply(m);
220         return *this;
221 }
222
223 MatrixStack &MatrixStack::modelview()
224 {
225         static MatrixStack ms(GL_MODELVIEW);
226         return ms;
227 }
228
229 MatrixStack &MatrixStack::projection()
230 {
231         static MatrixStack ms(GL_PROJECTION);
232         return ms;
233 }
234
235 } // namespace GL
236 } // namespace Msp