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