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