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 "Clipper.hpp"
16
17#include "Polygon.hpp"
18#include "Renderer.hpp"
19#include "Debug.hpp"
20
21namespace sw
22{
23	Clipper::Clipper(bool symmetricNormalizedDepth)
24	{
25		n = symmetricNormalizedDepth ? -1.0f : 0.0f;
26	}
27
28	Clipper::~Clipper()
29	{
30	}
31
32	unsigned int Clipper::computeClipFlags(const float4 &v)
33	{
34		return ((v.x > v.w)     ? CLIP_RIGHT  : 0) |
35		       ((v.y > v.w)     ? CLIP_TOP    : 0) |
36		       ((v.z > v.w)     ? CLIP_FAR    : 0) |
37		       ((v.x < -v.w)    ? CLIP_LEFT   : 0) |
38		       ((v.y < -v.w)    ? CLIP_BOTTOM : 0) |
39		       ((v.z < n * v.w) ? CLIP_NEAR   : 0) |
40		       Clipper::CLIP_FINITE;   // FIXME: xyz finite
41	}
42
43	bool Clipper::clip(Polygon &polygon, int clipFlagsOr, const DrawCall &draw)
44	{
45		if(clipFlagsOr & CLIP_FRUSTUM)
46		{
47			if(clipFlagsOr & CLIP_NEAR)   clipNear(polygon);
48			if(polygon.n >= 3) {
49			if(clipFlagsOr & CLIP_FAR)    clipFar(polygon);
50			if(polygon.n >= 3) {
51			if(clipFlagsOr & CLIP_LEFT)   clipLeft(polygon);
52			if(polygon.n >= 3) {
53			if(clipFlagsOr & CLIP_RIGHT)  clipRight(polygon);
54			if(polygon.n >= 3) {
55			if(clipFlagsOr & CLIP_TOP)    clipTop(polygon);
56			if(polygon.n >= 3) {
57			if(clipFlagsOr & CLIP_BOTTOM) clipBottom(polygon);
58			}}}}}
59		}
60
61		if(clipFlagsOr & CLIP_USER)
62		{
63			DrawData &data = *draw.data;
64
65			if(polygon.n >= 3) {
66			if(draw.clipFlags & CLIP_PLANE0) clipPlane(polygon, data.clipPlane[0]);
67			if(polygon.n >= 3) {
68			if(draw.clipFlags & CLIP_PLANE1) clipPlane(polygon, data.clipPlane[1]);
69			if(polygon.n >= 3) {
70			if(draw.clipFlags & CLIP_PLANE2) clipPlane(polygon, data.clipPlane[2]);
71			if(polygon.n >= 3) {
72			if(draw.clipFlags & CLIP_PLANE3) clipPlane(polygon, data.clipPlane[3]);
73			if(polygon.n >= 3) {
74			if(draw.clipFlags & CLIP_PLANE4) clipPlane(polygon, data.clipPlane[4]);
75			if(polygon.n >= 3) {
76			if(draw.clipFlags & CLIP_PLANE5) clipPlane(polygon, data.clipPlane[5]);
77			}}}}}}
78		}
79
80		return polygon.n >= 3;
81	}
82
83	void Clipper::clipNear(Polygon &polygon)
84	{
85		const float4 **V = polygon.P[polygon.i];
86		const float4 **T = polygon.P[polygon.i + 1];
87
88		int t = 0;
89
90		for(int i = 0; i < polygon.n; i++)
91		{
92			int j = i == polygon.n - 1 ? 0 : i + 1;
93
94			float di = V[i]->z - n * V[i]->w;
95			float dj = V[j]->z - n * V[j]->w;
96
97			if(di >= 0)
98			{
99				T[t++] = V[i];
100
101				if(dj < 0)
102				{
103					clipEdge(polygon.B[polygon.b], *V[i], *V[j], di, dj);
104					T[t++] = &polygon.B[polygon.b++];
105				}
106			}
107			else
108			{
109				if(dj > 0)
110				{
111					clipEdge(polygon.B[polygon.b], *V[j], *V[i], dj, di);
112					T[t++] = &polygon.B[polygon.b++];
113				}
114			}
115		}
116
117		polygon.n = t;
118		polygon.i += 1;
119	}
120
121	void Clipper::clipFar(Polygon &polygon)
122	{
123		const float4 **V = polygon.P[polygon.i];
124		const float4 **T = polygon.P[polygon.i + 1];
125
126		int t = 0;
127
128		for(int i = 0; i < polygon.n; i++)
129		{
130			int j = i == polygon.n - 1 ? 0 : i + 1;
131
132			float di = V[i]->w - V[i]->z;
133			float dj = V[j]->w - V[j]->z;
134
135			if(di >= 0)
136			{
137				T[t++] = V[i];
138
139				if(dj < 0)
140				{
141					clipEdge(polygon.B[polygon.b], *V[i], *V[j], di, dj);
142					T[t++] = &polygon.B[polygon.b++];
143				}
144			}
145			else
146			{
147				if(dj > 0)
148				{
149					clipEdge(polygon.B[polygon.b], *V[j], *V[i], dj, di);
150					T[t++] = &polygon.B[polygon.b++];
151				}
152			}
153		}
154
155		polygon.n = t;
156		polygon.i += 1;
157	}
158
159	void Clipper::clipLeft(Polygon &polygon)
160	{
161		const float4 **V = polygon.P[polygon.i];
162		const float4 **T = polygon.P[polygon.i + 1];
163
164		int t = 0;
165
166		for(int i = 0; i < polygon.n; i++)
167		{
168			int j = i == polygon.n - 1 ? 0 : i + 1;
169
170			float di = V[i]->w + V[i]->x;
171			float dj = V[j]->w + V[j]->x;
172
173			if(di >= 0)
174			{
175				T[t++] = V[i];
176
177				if(dj < 0)
178				{
179					clipEdge(polygon.B[polygon.b], *V[i], *V[j], di, dj);
180					T[t++] = &polygon.B[polygon.b++];
181				}
182			}
183			else
184			{
185				if(dj > 0)
186				{
187					clipEdge(polygon.B[polygon.b], *V[j], *V[i], dj, di);
188					T[t++] = &polygon.B[polygon.b++];
189				}
190			}
191		}
192
193		polygon.n = t;
194		polygon.i += 1;
195	}
196
197	void Clipper::clipRight(Polygon &polygon)
198	{
199		const float4 **V = polygon.P[polygon.i];
200		const float4 **T = polygon.P[polygon.i + 1];
201
202		int t = 0;
203
204		for(int i = 0; i < polygon.n; i++)
205		{
206			int j = i == polygon.n - 1 ? 0 : i + 1;
207
208			float di = V[i]->w - V[i]->x;
209			float dj = V[j]->w - V[j]->x;
210
211			if(di >= 0)
212			{
213				T[t++] = V[i];
214
215				if(dj < 0)
216				{
217					clipEdge(polygon.B[polygon.b], *V[i], *V[j], di, dj);
218					T[t++] = &polygon.B[polygon.b++];
219				}
220			}
221			else
222			{
223				if(dj > 0)
224				{
225					clipEdge(polygon.B[polygon.b], *V[j], *V[i], dj, di);
226					T[t++] = &polygon.B[polygon.b++];
227				}
228			}
229		}
230
231		polygon.n = t;
232		polygon.i += 1;
233	}
234
235	void Clipper::clipTop(Polygon &polygon)
236	{
237		const float4 **V = polygon.P[polygon.i];
238		const float4 **T = polygon.P[polygon.i + 1];
239
240		int t = 0;
241
242		for(int i = 0; i < polygon.n; i++)
243		{
244			int j = i == polygon.n - 1 ? 0 : i + 1;
245
246			float di = V[i]->w - V[i]->y;
247			float dj = V[j]->w - V[j]->y;
248
249			if(di >= 0)
250			{
251				T[t++] = V[i];
252
253				if(dj < 0)
254				{
255					clipEdge(polygon.B[polygon.b], *V[i], *V[j], di, dj);
256					T[t++] = &polygon.B[polygon.b++];
257				}
258			}
259			else
260			{
261				if(dj > 0)
262				{
263					clipEdge(polygon.B[polygon.b], *V[j], *V[i], dj, di);
264					T[t++] = &polygon.B[polygon.b++];
265				}
266			}
267		}
268
269		polygon.n = t;
270		polygon.i += 1;
271	}
272
273	void Clipper::clipBottom(Polygon &polygon)
274	{
275		const float4 **V = polygon.P[polygon.i];
276		const float4 **T = polygon.P[polygon.i + 1];
277
278		int t = 0;
279
280		for(int i = 0; i < polygon.n; i++)
281		{
282			int j = i == polygon.n - 1 ? 0 : i + 1;
283
284			float di = V[i]->w + V[i]->y;
285			float dj = V[j]->w + V[j]->y;
286
287			if(di >= 0)
288			{
289				T[t++] = V[i];
290
291				if(dj < 0)
292				{
293					clipEdge(polygon.B[polygon.b], *V[i], *V[j], di, dj);
294					T[t++] = &polygon.B[polygon.b++];
295				}
296			}
297			else
298			{
299				if(dj > 0)
300				{
301					clipEdge(polygon.B[polygon.b], *V[j], *V[i], dj, di);
302					T[t++] = &polygon.B[polygon.b++];
303				}
304			}
305		}
306
307		polygon.n = t;
308		polygon.i += 1;
309	}
310
311	void Clipper::clipPlane(Polygon &polygon, const Plane &p)
312	{
313		const float4 **V = polygon.P[polygon.i];
314		const float4 **T = polygon.P[polygon.i + 1];
315
316		int t = 0;
317
318		for(int i = 0; i < polygon.n; i++)
319		{
320			int j = i == polygon.n - 1 ? 0 : i + 1;
321
322			float di = p.A * V[i]->x + p.B * V[i]->y + p.C * V[i]->z + p.D * V[i]->w;
323			float dj = p.A * V[j]->x + p.B * V[j]->y + p.C * V[j]->z + p.D * V[j]->w;
324
325			if(di >= 0)
326			{
327				T[t++] = V[i];
328
329				if(dj < 0)
330				{
331					clipEdge(polygon.B[polygon.b], *V[i], *V[j], di, dj);
332					T[t++] = &polygon.B[polygon.b++];
333				}
334			}
335			else
336			{
337				if(dj > 0)
338				{
339					clipEdge(polygon.B[polygon.b], *V[j], *V[i], dj, di);
340					T[t++] = &polygon.B[polygon.b++];
341				}
342			}
343		}
344
345		polygon.n = t;
346		polygon.i += 1;
347	}
348
349	inline void Clipper::clipEdge(float4 &Vo, const float4 &Vi, const float4 &Vj, float di, float dj) const
350	{
351		float D = 1.0f / (dj - di);
352
353		Vo.x = (dj * Vi.x - di * Vj.x) * D;
354		Vo.y = (dj * Vi.y - di * Vj.y) * D;
355		Vo.z = (dj * Vi.z - di * Vj.z) * D;
356		Vo.w = (dj * Vi.w - di * Vj.w) * D;
357	}
358}
359