1// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "MatrixStack.hpp"
16
17#include "Common/Math.hpp"
18
19namespace sw
20{
21 MatrixStack::MatrixStack(int size)
22 {
23 stack = new Matrix[size];
24 stack[0] = 1;
25
26 top = 0;
27 this->size = size;
28 }
29
30 MatrixStack::~MatrixStack()
31 {
32 delete[] stack;
33 stack = 0;
34 }
35
36 void MatrixStack::identity()
37 {
38 stack[top] = 1;
39 }
40
41 void MatrixStack::load(const Matrix &M)
42 {
43 stack[top] = M;
44 }
45
46 void MatrixStack::load(const float *M)
47 {
48 stack[top] = Matrix(M[0], M[4], M[8], M[12],
49 M[1], M[5], M[9], M[13],
50 M[2], M[6], M[10], M[14],
51 M[3], M[7], M[11], M[15]);
52 }
53
54 void MatrixStack::load(const double *M)
55 {
56 stack[top] = Matrix((float)M[0], (float)M[4], (float)M[8], (float)M[12],
57 (float)M[1], (float)M[5], (float)M[9], (float)M[13],
58 (float)M[2], (float)M[6], (float)M[10], (float)M[14],
59 (float)M[3], (float)M[7], (float)M[11], (float)M[15]);
60 }
61
62 void MatrixStack::translate(float x, float y, float z)
63 {
64 stack[top] *= Matrix::translate(x, y, z);
65 }
66
67 void MatrixStack::translate(double x, double y, double z)
68 {
69 translate((float)x, (float)y, (float)z);
70 }
71
72 void MatrixStack::rotate(float angle, float x, float y, float z)
73 {
74 float n = 1.0f / sqrt(x*x + y*y + z*z);
75
76 x *= n;
77 y *= n;
78 z *= n;
79
80 float theta = angle * 0.0174532925f; // In radians
81 float c = cos(theta);
82 float _c = 1 - c;
83 float s = sin(theta);
84
85 // Rodrigues' rotation formula
86 sw::Matrix rotate(c+x*x*_c, x*y*_c-z*s, x*z*_c+y*s,
87 x*y*_c+z*s, c+y*y*_c, y*z*_c-x*s,
88 x*z*_c-y*s, y*z*_c+x*s, c+z*z*_c);
89
90 stack[top] *= rotate;
91 }
92
93 void MatrixStack::rotate(double angle, double x, double y, double z)
94 {
95 rotate((float)angle, (float)x, (float)y, (float)z);
96 }
97
98 void MatrixStack::scale(float x, float y, float z)
99 {
100 stack[top] *= Matrix::scale(x, y, z);
101 }
102
103 void MatrixStack::scale(double x, double y, double z)
104 {
105 scale((float)x, (float)y, (float)z);
106 }
107
108 void MatrixStack::multiply(const float *M)
109 {
110 stack[top] *= Matrix(M[0], M[4], M[8], M[12],
111 M[1], M[5], M[9], M[13],
112 M[2], M[6], M[10], M[14],
113 M[3], M[7], M[11], M[15]);
114 }
115
116 void MatrixStack::multiply(const double *M)
117 {
118 stack[top] *= Matrix((float)M[0], (float)M[4], (float)M[8], (float)M[12],
119 (float)M[1], (float)M[5], (float)M[9], (float)M[13],
120 (float)M[2], (float)M[6], (float)M[10], (float)M[14],
121 (float)M[3], (float)M[7], (float)M[11], (float)M[15]);
122 }
123
124 void MatrixStack::frustum(float left, float right, float bottom, float top, float zNear, float zFar)
125 {
126 float l = (float)left;
127 float r = (float)right;
128 float b = (float)bottom;
129 float t = (float)top;
130 float n = (float)zNear;
131 float f = (float)zFar;
132
133 float A = (r + l) / (r - l);
134 float B = (t + b) / (t - b);
135 float C = -(f + n) / (f - n);
136 float D = -2 * f * n / (f - n);
137
138 Matrix frustum(2 * n / (r - l), 0, A, 0,
139 0, 2 * n / (t - b), B, 0,
140 0, 0, C, D,
141 0, 0, -1, 0);
142
143 stack[this->top] *= frustum;
144 }
145
146 void MatrixStack::ortho(double left, double right, double bottom, double top, double zNear, double zFar)
147 {
148 float l = (float)left;
149 float r = (float)right;
150 float b = (float)bottom;
151 float t = (float)top;
152 float n = (float)zNear;
153 float f = (float)zFar;
154
155 float tx = -(r + l) / (r - l);
156 float ty = -(t + b) / (t - b);
157 float tz = -(f + n) / (f - n);
158
159 Matrix ortho(2 / (r - l), 0, 0, tx,
160 0, 2 / (t - b), 0, ty,
161 0, 0, -2 / (f - n), tz,
162 0, 0, 0, 1);
163
164 stack[this->top] *= ortho;
165 }
166
167 bool MatrixStack::push()
168 {
169 if(top >= size - 1) return false;
170
171 stack[top + 1] = stack[top];
172 top++;
173
174 return true;
175 }
176
177 bool MatrixStack::pop()
178 {
179 if(top <= 0) return false;
180
181 top--;
182
183 return true;
184 }
185
186 const Matrix &MatrixStack::current()
187 {
188 return stack[top];
189 }
190
191 bool MatrixStack::isIdentity() const
192 {
193 const Matrix &m = stack[top];
194
195 if(m.m[0][0] != 1.0f) return false;
196 if(m.m[0][1] != 0.0f) return false;
197 if(m.m[0][2] != 0.0f) return false;
198 if(m.m[0][3] != 0.0f) return false;
199
200 if(m.m[1][0] != 0.0f) return false;
201 if(m.m[1][1] != 1.0f) return false;
202 if(m.m[1][2] != 0.0f) return false;
203 if(m.m[1][3] != 0.0f) return false;
204
205 if(m.m[2][0] != 0.0f) return false;
206 if(m.m[2][1] != 0.0f) return false;
207 if(m.m[2][2] != 1.0f) return false;
208 if(m.m[2][3] != 0.0f) return false;
209
210 if(m.m[3][0] != 0.0f) return false;
211 if(m.m[3][1] != 0.0f) return false;
212 if(m.m[3][2] != 0.0f) return false;
213 if(m.m[3][3] != 1.0f) return false;
214
215 return true;
216 }
217}
218