1#ifndef _RRPRIMITIVEASSEMBLER_HPP
2#define _RRPRIMITIVEASSEMBLER_HPP
3/*-------------------------------------------------------------------------
4 * drawElements Quality Program Reference Renderer
5 * -----------------------------------------------
6 *
7 * Copyright 2014 The Android Open Source Project
8 *
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 *      http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 *
21 *//*!
22 * \file
23 * \brief Primitive assembler
24 *//*--------------------------------------------------------------------*/
25
26#include "rrDefs.hpp"
27#include "rrVertexPacket.hpp"
28
29namespace rr
30{
31namespace pa
32{
33
34struct Triangle
35{
36	enum
37	{
38		NUM_VERTICES = 3
39	};
40
41	Triangle (void)
42		: v0				(DE_NULL)
43		, v1				(DE_NULL)
44		, v2				(DE_NULL)
45		, provokingIndex	(-1)
46	{
47	}
48
49	Triangle (VertexPacket* v0_, VertexPacket* v1_, VertexPacket* v2_, int provokingIndex_)
50		: v0				(v0_)
51		, v1				(v1_)
52		, v2				(v2_)
53		, provokingIndex	(provokingIndex_)
54	{
55	}
56
57	VertexPacket* getProvokingVertex (void)
58	{
59		switch (provokingIndex)
60		{
61			case 0: return v0;
62			case 1: return v1;
63			case 2: return v2;
64			default:
65				DE_ASSERT(false);
66				return DE_NULL;
67		}
68	}
69
70	VertexPacket*	v0;
71	VertexPacket*	v1;
72	VertexPacket*	v2;
73
74	int				provokingIndex;
75} DE_WARN_UNUSED_TYPE;
76
77struct Triangles
78{
79	template <typename Iterator>
80	static void exec (Iterator outputIterator, VertexPacket* const* vertices, size_t numVertices, rr::ProvokingVertex provokingConvention)
81	{
82		const int provokingOffset = (provokingConvention == rr::PROVOKINGVERTEX_FIRST) ? (0) : (2);
83
84		for (size_t ndx = 0; ndx + 2 < numVertices; ndx += 3)
85			*(outputIterator++) = Triangle(vertices[ndx], vertices[ndx+1], vertices[ndx+2], provokingOffset);
86	}
87
88	static size_t getPrimitiveCount (size_t vertices)
89	{
90		return vertices / 3;
91	}
92} DE_WARN_UNUSED_TYPE;
93
94struct TriangleStrip
95{
96	template <typename Iterator>
97	static void exec (Iterator outputIterator, VertexPacket* const* vertices, size_t numVertices, rr::ProvokingVertex provokingConvention)
98	{
99		if (numVertices < 3)
100		{
101		}
102		else
103		{
104			VertexPacket* vert0 = vertices[0];
105			VertexPacket* vert1 = vertices[1];
106			size_t ndx = 2;
107
108			for (;;)
109			{
110				{
111					if (ndx >= numVertices)
112						break;
113
114					*(outputIterator++) = Triangle(vert0, vert1, vertices[ndx], (provokingConvention == rr::PROVOKINGVERTEX_FIRST) ? (0) : (2));
115					vert0 = vertices[ndx];
116
117					ndx++;
118				}
119
120				{
121					if (ndx >= numVertices)
122						break;
123
124					*(outputIterator++) = Triangle(vert0, vert1, vertices[ndx], (provokingConvention == rr::PROVOKINGVERTEX_FIRST) ? (1) : (2));
125					vert1 = vertices[ndx];
126
127					ndx++;
128				}
129			}
130		}
131	}
132
133	static size_t getPrimitiveCount (size_t vertices)
134	{
135		return (vertices < 3) ? (0) : (vertices - 2);
136	}
137} DE_WARN_UNUSED_TYPE;
138
139struct TriangleFan
140{
141	template <typename Iterator>
142	static void exec (Iterator outputIterator, VertexPacket* const* vertices, size_t numVertices, rr::ProvokingVertex provokingConvention)
143	{
144		if (numVertices == 0)
145		{
146		}
147		else
148		{
149			const int			provokingOffset	= (provokingConvention == rr::PROVOKINGVERTEX_FIRST) ? (1) : (2);
150			VertexPacket* const	first			= vertices[0];
151
152			for (size_t ndx = 1; ndx + 1 < numVertices; ++ndx)
153				*(outputIterator++) = Triangle(first, vertices[ndx], vertices[ndx+1], provokingOffset);
154		}
155	}
156
157	static size_t getPrimitiveCount (size_t vertices)
158	{
159		return (vertices < 3) ? (0) : (vertices - 2);
160	}
161} DE_WARN_UNUSED_TYPE;
162
163struct Line
164{
165	enum
166	{
167		NUM_VERTICES = 2
168	};
169
170	Line (void)
171		: v0				(DE_NULL)
172		, v1				(DE_NULL)
173		, provokingIndex	(-1)
174	{
175	}
176
177	Line (VertexPacket* v0_, VertexPacket* v1_, int provokingIndex_)
178		: v0				(v0_)
179		, v1				(v1_)
180		, provokingIndex	(provokingIndex_)
181	{
182	}
183
184	VertexPacket* getProvokingVertex (void)
185	{
186		switch (provokingIndex)
187		{
188			case 0: return v0;
189			case 1: return v1;
190			default:
191				DE_ASSERT(false);
192				return DE_NULL;
193		}
194	}
195
196	VertexPacket*	v0;
197	VertexPacket*	v1;
198
199	int				provokingIndex;
200} DE_WARN_UNUSED_TYPE;
201
202struct Lines
203{
204	template <typename Iterator>
205	static void exec (Iterator outputIterator, VertexPacket* const* vertices, size_t numVertices, rr::ProvokingVertex provokingConvention)
206	{
207		const int provokingOffset = (provokingConvention == rr::PROVOKINGVERTEX_FIRST) ? (0) : (1);
208
209		for (size_t ndx = 0; ndx + 1 < numVertices; ndx += 2)
210			*(outputIterator++) = Line(vertices[ndx], vertices[ndx+1], provokingOffset);
211	}
212
213	static size_t getPrimitiveCount (size_t vertices)
214	{
215		return vertices / 2;
216	}
217} DE_WARN_UNUSED_TYPE;
218
219struct LineStrip
220{
221	template <typename Iterator>
222	static void exec (Iterator outputIterator, VertexPacket* const* vertices, size_t numVertices, rr::ProvokingVertex provokingConvention)
223	{
224		if (numVertices == 0)
225		{
226		}
227		else
228		{
229			VertexPacket* prev = vertices[0];
230
231			for (size_t ndx = 1; ndx < numVertices; ++ndx)
232			{
233				*(outputIterator++) = Line(prev, vertices[ndx], (provokingConvention == rr::PROVOKINGVERTEX_FIRST) ? (0) : (1));
234				prev = vertices[ndx];
235			}
236		}
237	}
238
239	static size_t getPrimitiveCount (size_t vertices)
240	{
241		return (vertices < 2) ? (0) : (vertices - 1);
242	}
243} DE_WARN_UNUSED_TYPE;
244
245struct LineLoop
246{
247	template <typename Iterator>
248	static void exec (Iterator outputIterator, VertexPacket* const* vertices, size_t numVertices, rr::ProvokingVertex provokingConvention)
249	{
250		if (numVertices < 2)
251		{
252		}
253		else
254		{
255			VertexPacket* prev = vertices[0];
256
257			for (size_t ndx = 1; ndx < numVertices; ++ndx)
258			{
259				*(outputIterator++) = Line(prev, vertices[ndx], (provokingConvention == rr::PROVOKINGVERTEX_FIRST) ? (0) : (1));
260				prev = vertices[ndx];
261			}
262
263			*(outputIterator++) = Line(prev, vertices[0], (provokingConvention == rr::PROVOKINGVERTEX_FIRST) ? (0) : (1));
264		}
265	}
266
267	static size_t getPrimitiveCount (size_t vertices)
268	{
269		return (vertices < 2) ? (0) : (vertices);
270	}
271} DE_WARN_UNUSED_TYPE;
272
273struct Point
274{
275	enum
276	{
277		NUM_VERTICES = 1
278	};
279
280	Point (void)
281		: v0(DE_NULL)
282	{
283	}
284
285	Point (VertexPacket* v0_)
286		: v0(v0_)
287	{
288	}
289
290	VertexPacket* v0;
291} DE_WARN_UNUSED_TYPE;
292
293struct Points
294{
295	template <typename Iterator>
296	static void exec (Iterator outputIterator, VertexPacket* const* vertices, size_t numVertices, rr::ProvokingVertex provokingConvention)
297	{
298		DE_UNREF(provokingConvention);
299
300		for (size_t ndx = 0; ndx < numVertices; ++ndx)
301			*(outputIterator++) = Point(vertices[ndx]);
302	}
303
304	static size_t getPrimitiveCount (size_t vertices)
305	{
306		return (vertices);
307	}
308} DE_WARN_UNUSED_TYPE;
309
310struct LineAdjacency
311{
312	enum
313	{
314		NUM_VERTICES = 4
315	};
316
317	LineAdjacency (void)
318		: v0				(DE_NULL)
319		, v1				(DE_NULL)
320		, v2				(DE_NULL)
321		, v3				(DE_NULL)
322		, provokingIndex	(-1)
323	{
324	}
325
326	LineAdjacency (VertexPacket* v0_, VertexPacket* v1_, VertexPacket* v2_, VertexPacket* v3_, int provokingIndex_)
327		: v0				(v0_)
328		, v1				(v1_)
329		, v2				(v2_)
330		, v3				(v3_)
331		, provokingIndex	(provokingIndex_)
332	{
333	}
334
335	VertexPacket* getProvokingVertex (void)
336	{
337		switch (provokingIndex)
338		{
339			case 1: return v1;
340			case 2: return v2;
341			default:
342				DE_ASSERT(false);
343				return DE_NULL;
344		}
345	}
346
347	VertexPacket*	v0;
348	VertexPacket*	v1;
349	VertexPacket*	v2;
350	VertexPacket*	v3;
351
352	int				provokingIndex;
353} DE_WARN_UNUSED_TYPE;
354
355struct LinesAdjacency
356{
357	template <typename Iterator>
358	static void exec (Iterator outputIterator, VertexPacket* const* vertices, size_t numVertices, rr::ProvokingVertex provokingConvention)
359	{
360		const int provokingOffset = (provokingConvention == rr::PROVOKINGVERTEX_FIRST) ? (1) : (2);
361
362		for (size_t ndx = 0; ndx + 3 < numVertices; ndx += 4)
363			*(outputIterator++) = LineAdjacency(vertices[ndx], vertices[ndx+1], vertices[ndx+2], vertices[ndx+3], provokingOffset);
364	}
365
366	static size_t getPrimitiveCount (size_t vertices)
367	{
368		return vertices / 4;
369	}
370} DE_WARN_UNUSED_TYPE;
371
372struct LineStripAdjacency
373{
374	template <typename Iterator>
375	static void exec (Iterator outputIterator, VertexPacket* const* vertices, size_t numVertices, rr::ProvokingVertex provokingConvention)
376	{
377		const int provokingOffset = (provokingConvention == rr::PROVOKINGVERTEX_FIRST) ? (1) : (2);
378
379		for (size_t ndx = 0; ndx + 3 < numVertices; ++ndx)
380			*(outputIterator++) = LineAdjacency(vertices[ndx], vertices[ndx+1], vertices[ndx+2], vertices[ndx+3], provokingOffset);
381	}
382
383	static size_t getPrimitiveCount (size_t vertices)
384	{
385		return (vertices < 4) ? (0) : (vertices - 3);
386	}
387} DE_WARN_UNUSED_TYPE;
388
389struct TriangleAdjacency
390{
391	enum
392	{
393		NUM_VERTICES = 6
394	};
395
396	TriangleAdjacency (void)
397		: v0				(DE_NULL)
398		, v1				(DE_NULL)
399		, v2				(DE_NULL)
400		, v3				(DE_NULL)
401		, v4				(DE_NULL)
402		, v5				(DE_NULL)
403		, provokingIndex	(-1)
404	{
405	}
406
407	TriangleAdjacency (VertexPacket* v0_, VertexPacket* v1_, VertexPacket* v2_, VertexPacket* v3_, VertexPacket* v4_, VertexPacket* v5_, int provokingIndex_)
408		: v0				(v0_)
409		, v1				(v1_)
410		, v2				(v2_)
411		, v3				(v3_)
412		, v4				(v4_)
413		, v5				(v5_)
414		, provokingIndex	(provokingIndex_)
415	{
416	}
417
418	VertexPacket* getProvokingVertex (void)
419	{
420		switch (provokingIndex)
421		{
422			case 0: return v0;
423			case 2: return v2;
424			case 4: return v4;
425			default:
426				DE_ASSERT(false);
427				return DE_NULL;
428		}
429	}
430
431	VertexPacket*	v0;
432	VertexPacket*	v1;	//!< adjacent
433	VertexPacket*	v2;
434	VertexPacket*	v3;	//!< adjacent
435	VertexPacket*	v4;
436	VertexPacket*	v5;	//!< adjacent
437
438	int				provokingIndex;
439} DE_WARN_UNUSED_TYPE;
440
441struct TrianglesAdjacency
442{
443	template <typename Iterator>
444	static void exec (Iterator outputIterator, VertexPacket* const* vertices, size_t numVertices, rr::ProvokingVertex provokingConvention)
445	{
446		const int provokingOffset = (provokingConvention == rr::PROVOKINGVERTEX_FIRST) ? (0) : (4);
447
448		for (size_t ndx = 0; ndx + 5 < numVertices; ndx += 6)
449			*(outputIterator++) = TriangleAdjacency(vertices[ndx], vertices[ndx+1], vertices[ndx+2], vertices[ndx+3], vertices[ndx+4], vertices[ndx+5], provokingOffset);
450	}
451
452	static size_t getPrimitiveCount (size_t vertices)
453	{
454		return vertices / 6;
455	}
456} DE_WARN_UNUSED_TYPE;
457
458struct TriangleStripAdjacency
459{
460	template <typename Iterator>
461	static void exec (Iterator outputIterator, VertexPacket* const* vertices, size_t numVertices, rr::ProvokingVertex provokingConvention)
462	{
463		if (numVertices < 6)
464		{
465		}
466		else if (numVertices < 8)
467		{
468			*(outputIterator++) = TriangleAdjacency(vertices[0], vertices[1], vertices[2], vertices[5], vertices[4], vertices[3], (provokingConvention == rr::PROVOKINGVERTEX_FIRST) ? (0) : (4));
469		}
470		else
471		{
472			const size_t primitiveCount = getPrimitiveCount(numVertices);
473			size_t i;
474
475			// first
476			*(outputIterator++) = TriangleAdjacency(vertices[0], vertices[1], vertices[2], vertices[6], vertices[4], vertices[3], (provokingConvention == rr::PROVOKINGVERTEX_FIRST) ? (0) : (4));
477
478			// middle
479			for (i = 1; i + 1 < primitiveCount; ++i)
480			{
481				// odd
482				if (i % 2 == 1)
483				{
484					*(outputIterator++) = TriangleAdjacency(vertices[2*i+2], vertices[2*i-2], vertices[2*i+0], vertices[2*i+3], vertices[2*i+4], vertices[2*i+6], (provokingConvention == rr::PROVOKINGVERTEX_FIRST) ? (2) : (4));
485				}
486				// even
487				else
488				{
489					*(outputIterator++) = TriangleAdjacency(vertices[2*i+0], vertices[2*i-2], vertices[2*i+2], vertices[2*i+6], vertices[2*i+4], vertices[2*i+3], (provokingConvention == rr::PROVOKINGVERTEX_FIRST) ? (0) : (4));
490				}
491			}
492
493			// last
494
495			// odd
496			if (i % 2 == 1)
497				*(outputIterator++) = TriangleAdjacency(vertices[2*i+2], vertices[2*i-2], vertices[2*i+0], vertices[2*i+3], vertices[2*i+4], vertices[2*i+5], (provokingConvention == rr::PROVOKINGVERTEX_FIRST) ? (2) : (4));
498			// even
499			else
500				*(outputIterator++) = TriangleAdjacency(vertices[2*i+0], vertices[2*i-2], vertices[2*i+2], vertices[2*i+5], vertices[2*i+4], vertices[2*i+3], (provokingConvention == rr::PROVOKINGVERTEX_FIRST) ? (0) : (4));
501		}
502	}
503
504	static size_t getPrimitiveCount (size_t vertices)
505	{
506		return (vertices < 6) ? 0 : ((vertices - 4) / 2);
507	}
508} DE_WARN_UNUSED_TYPE;
509
510} // pa
511} // rr
512
513#endif // _RRPRIMITIVEASSEMBLER_HPP
514