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