Added the RingAdapter class and interfacing ring() function and simplified some math in GLCompiler with it

Fri, 10 Feb 2017 23:06:24 +0200

author
Teemu Piippo <teemu@hecknology.net>
date
Fri, 10 Feb 2017 23:06:24 +0200
changeset 1122
795d1c3554b9
parent 1121
be0b5ad128ea
child 1123
15e46ea3151f

Added the RingAdapter class and interfacing ring() function and simplified some math in GLCompiler with it

src/basics.h file | annotate | diff | comparison | revisions
src/glCompiler.cpp file | annotate | diff | comparison | revisions
--- a/src/basics.h	Thu Feb 09 23:51:42 2017 +0200
+++ b/src/basics.h	Fri Feb 10 23:06:24 2017 +0200
@@ -217,6 +217,75 @@
 double getRadialPoint(int segment, int divisions, double(*func)(double));
 QVector<QLineF> makeCircle(int segments, int divisions, double radius);
 
+/*
+ * Implements a ring adapter over T. This class corrects indices given to the element-operator so that they're within bounds.
+ * The maximum amount can be specified manually.
+ *
+ * Example:
+ *
+ *   int A[] = {10,20,30,40};
+ *   ring(A)[0]  ==     A[0 % 4]    == A[0]
+ *   ring(A)[5]  ==     A[5 % 4]    == A[1]
+ *   ring(A)[-1] == ring(A)[-1 + 4] == A[3]
+ */
+template<typename T>
+class RingAdapter
+{
+private:
+	// The private section must come first because _collection is used in decltype() below.
+	T& _collection;
+	const int _count;
+
+public:
+	RingAdapter(T& collection, int count) :
+	    _collection {collection},
+	    _count {count} {}
+
+	template<typename IndexType>
+	decltype(_collection[IndexType()]) operator[](IndexType index)
+	{
+		if (_count == 0)
+		{
+			// Argh! ...let the collection deal with this case.
+			return _collection[0];
+		}
+		else
+		{
+			index %= _count;
+
+			// Fix negative modulus...
+			if (index < 0)
+				index += _count;
+
+			return _collection[index];
+		}
+	}
+
+	int size() const
+	{
+		return _count;
+	}
+};
+
+/*
+ * Convenience function for RingAdapter so that the template parameter does not have to be provided. The ring amount is assumed
+ * to be the amount of elements in the collection.
+ */
+template<typename T>
+RingAdapter<T> ring(T& collection)
+{
+	return RingAdapter<T> {collection, countof(collection)};
+}
+
+/*
+ * Version of ring() that allows manual specification of the count.
+ */
+template<typename T>
+RingAdapter<T> ring(T& collection, int count)
+{
+	return RingAdapter<T> {collection, count};
+}
+
 //
 // Get the amount of elements in something.
 //
@@ -254,3 +323,9 @@
 {
 	return vector.size();
 }
+
+template<typename T>
+int countof(const RingAdapter<T>& ring)
+{
+	return ring.size();
+}
--- a/src/glCompiler.cpp	Thu Feb 09 23:51:42 2017 +0200
+++ b/src/glCompiler.cpp	Fri Feb 10 23:06:24 2017 +0200
@@ -334,24 +334,26 @@
 void GLCompiler::compilePolygon (LDPolygon& poly, LDObject* topobj, ObjectVBOInfo* objinfo)
 {
 	SurfaceVboType surface;
-	int numverts;
+	int vertexCount;
 
 	switch (poly.num)
 	{
-	case 2:	surface = LinesVbo;				numverts = 2; break;
-	case 3:	surface = TrianglesVbo;			numverts = 3; break;
-	case 4:	surface = QuadsVbo;				numverts = 4; break;
-	case 5:	surface = ConditionalLinesVbo;	numverts = 2; break;
+	case 2:	surface = LinesVbo;				vertexCount = 2; break;
+	case 3:	surface = TrianglesVbo;			vertexCount = 3; break;
+	case 4:	surface = QuadsVbo;				vertexCount = 4; break;
+	case 5:	surface = ConditionalLinesVbo;	vertexCount = 2; break;
 	default: return;
 	}
 
 	// Determine the normals for the polygon.
 	Vertex normals[4];
-	for (int i = 0; i < numverts; ++i)
+	auto vertexRing = ring(poly.vertices, vertexCount);
+
+	for (int i = 0; i < vertexCount; ++i)
 	{
-		const Vertex& v1 = poly.vertices[(i - 1 + numverts) % numverts];
-		const Vertex& v2 = poly.vertices[i];
-		const Vertex& v3 = poly.vertices[(i + 1) % numverts];
+		const Vertex& v1 = vertexRing[i - 1];
+		const Vertex& v2 = vertexRing[i];
+		const Vertex& v3 = vertexRing[i + 1];
 		normals[i] = Vertex::crossProduct(v3 - v2, v1 - v2).normalized();
 	}
 
@@ -361,7 +363,7 @@
 		QVector<GLfloat>& vbodata = objinfo->data[vbonum];
 		const QColor color = getColorForPolygon (poly, topobj, complement);
 
-		for (int vert = 0; vert < numverts; ++vert)
+		for (int vert = 0; vert < vertexCount; ++vert)
 		{
 			if (complement == SurfacesVboComplement)
 			{

mercurial