Commits

Jason McKesson committed dffd36d

Tot08: Round Gimbals.

  • Participants
  • Parent commits cb1415a

Comments (0)

Files changed (9)

File Documents/Positioning/Tutorial 07.xml

                 the target moves, the camera will follow it perfectly.</para>
             <para>To do this, we use a special coordinate system trick. Instead of storing the
                 relative position of the camera in a normal coordinate system, we instead use a
-                    <glossterm>spherical coordinate system.</glossterm></para>
+                    <glossterm>spherical coordinate system</glossterm>, also known as
+                    <glossterm>polar coordinates</glossterm>.</para>
             <para>Previously, we said that a coordinate system was defined by a series of vectors
                 and an origin point. This was a useful simplification of the possibilities; this is
                 true of any coordinate system that follows the rules of <glossterm>Euclidean
                 </glossdef>
             </glossentry>
             <glossentry>
-                <glossterm>spherical coordinate system</glossterm>
+                <glossterm>spherical coordinate system, polar coordinates</glossterm>
                 <glossdef>
                     <para>A three dimensional coordinate system where the three coordinates are not
                         defined by 3 values multiplied by vectors, but by two angles and a radius.

File Documents/Positioning/Tutorial 08.xml

     <section>
         <?dbhtml filename="Tut08 Gimbal Lock.html"?>
         <title>Gimbal Lock</title>
-        <para>Remember back when we said that n rotation matrix isn't a rotation matrix at all, that
-            it is an orientation matrix? We also said that forgetting this can come back to bite
-            you. Well, here's likely the most common way.</para>
+        <para>Remember a few tutorials back, when we said that a rotation matrix isn't a rotation
+            matrix at all, that it is an orientation matrix? We also said that forgetting this can
+            come back to bite you. Well, here's likely the most common way.</para>
         <para>Normally, when dealing with orienting an object like a plane or spaceship in 3D space,
             you want to orient it based on 3 rotations about the 3 axes. The obvious way to do this
             is with a series of 3 rotations. This means that the program stores 3 angles, and you
         <para>When gimbals are in such a position, you have what is known as <glossterm>gimbal
                 lock</glossterm>; you have locked one of the gimbals to another, and now both cause
             the same effect.</para>
-        <para>How do you fix this problem? There are several possible solutions to the
-            problem.</para>
-        <para>Perhaps the most optimal solution is to simply not use gimbals. After all, if you
-            don't have gimbals, you can't gimbal lock. Instead of storing the orientation as a
-            series of rotations, store the orientation as an <emphasis>orientation.</emphasis> That
-            is, maintain the current orientation as a matrix. When you need to modify the
-            orientation, you apply a transformation to this matrix, storing the result as the new
-            current orientation.</para>
-        <para>This means that every yaw, pitch, and roll applied to the current orientation will be
-            relative to that current orientation. Which is usually exactly what you want. If the
-            user applies a positive yaw, you want that yaw to rotate them relative to where they are
-            current pointing.</para>
-        <para>A downside of this approach, besides the size penalty of having to store a 4x4 matrix
-            rather than 3 floating-point angles, is that floating-point math can lead to errors. If
-            you keep accumulating successive transformations of an object, once every 1/30th of a
-            second for a period of several minutes or hours, these floating-point errors start
-            accumulating. Eventually, the orientation stops being a pure rotation and starts
-            incorporating scale and skewing characteristics.</para>
-        <para>The solution here is to re-orthonormalize the matrix after applying each transform. A
-            transform (space) is said to be <glossterm>orthonormal</glossterm> if the basis vectors
-            are of unit length (no scale) and each axis is perpendicular to all of the
-            others.</para>
-        <para>Unfortunately, re-orthonormalizing a matrix is not a simple operation. You could try
-            to normalize each of the axis vectors with typical vector normalization, but that
-            wouldn't ensure that the matrix was orthonormal. It would remove scaling, but the axes
-            wouldn't be guaranteed to be perpendicular.</para>
-        <para>The proper solution is to use <link
-                xlink:href="http://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation">unit
-                quaternions</link> to store orientations, which can be orthonormalized much more
-            easily. This is beyond the scope of this tutorial, but the Wikipedia article on the
-            subject is a good place to start.</para>
         <section>
             <title>Complex Mesh Space</title>
             <para>The way this tutorial renders each gimbal serves as an object lesson in the use of
     </section>
     <section>
         <title>Quaternions</title>
-        <para/>
+        <para>How do you fix this problem? There are several possible solutions to the
+            problem.</para>
+        <para>Perhaps the most optimal solution is to simply not use gimbals. After all, if you
+            don't have gimbals, you can't gimbal lock. Instead of storing the orientation as a
+            series of rotations, store the orientation as an <emphasis>orientation.</emphasis> That
+            is, maintain the current orientation as a matrix. When you need to modify the
+            orientation, you apply a transformation to this matrix, storing the result as the new
+            current orientation.</para>
+        <para>This means that every yaw, pitch, and roll applied to the current orientation will be
+            relative to that current orientation. Which is usually exactly what you want. If the
+            user applies a positive yaw, you want that yaw to rotate them relative to where they are
+            current pointing.</para>
+        <para>A downside of this approach, besides the size penalty of having to store a 4x4 matrix
+            rather than 3 floating-point angles, is that floating-point math can lead to errors. If
+            you keep accumulating successive transformations of an object, once every 1/30th of a
+            second for a period of several minutes or hours, these floating-point errors start
+            accumulating. Eventually, the orientation stops being a pure rotation and starts
+            incorporating scale and skewing characteristics.</para>
+        <para>The solution here is to re-orthonormalize the matrix after applying each transform. A
+            transform (space) is said to be <glossterm>orthonormal</glossterm> if the basis vectors
+            are of unit length (no scale) and each axis is perpendicular to all of the
+            others.</para>
+        <para>Unfortunately, re-orthonormalizing a matrix is not a simple operation. You could try
+            to normalize each of the axis vectors with typical vector normalization, but that
+            wouldn't ensure that the matrix was orthonormal. It would remove scaling, but the axes
+            wouldn't be guaranteed to be perpendicular.</para>
+        <para>So instead, we need to use a different way of storing an orientation. To do this, we
+            use something called a <glossterm>quaternion.</glossterm></para>
+        <para>A quaternion is (for the purposes of this conversation) a 4-dimensional vector that is
+            treated in a special way. Any change of orientation from one coordinate system to
+            another can be represented by a rotation about some axis by some angle. A quaternion is
+            a way of encoding this angle/axis rotation:</para>
+        <!--TODO: Equation: build XYZW of a quaternion from an angle/axis rotation.-->
+        <para>This will produce a <glossterm>unit quaternion.</glossterm> That is, a quaternion with
+            a length of 1.</para>
+        <section>
+            <title>Quaternion Math</title>
+            <para>Quaternions are equivalent to orientation matrices. You can compose two
+                orientation quaternions using a special operation called <glossterm>quaternion
+                    multiplication</glossterm>.</para>
+            <!--TODO: Equation: two quaternions and the multiplication of them.-->
+            <para>If the two quaternions being multiplied represent orientations, then the product
+                of them is a composite orientation. Just as with matrix multiplication, only
+                specifically for orientations. Like matrix multiplication, quaternion multiplication
+                is associative (<informalequation>
+                    <mathphrase>(a*b) * c = a * (b*c)</mathphrase>
+                </informalequation>), but not commutative (<informalequation>
+                    <mathphrase>a*b != b*a</mathphrase>
+                </informalequation>).</para>
+            <para>The main difference that helps us solve the Gimbal lock problem is that it is easy
+                to keep a quaternion normalized. Simply perform a vector normalization on it after
+                every few multiplications. This enables us to add numerous small rotations together
+                without numerical precision problems showing up.</para>
+            <para>There is one more thing we need to be able to do: convert a quaternion into a
+                rotation matrix. While we could convert a unit quaternion back into angle/axis
+                rotations, it's much preferable to do it directly:</para>
+            <!--TODO: Equation: compute rotation matrix from a quaternion.-->
+        </section>
+        <section>
+            <title>Composition Type</title>
+            <para>So our goal is to compose successive rotations into a final orientation. When we
+                want to increase the pitch, for example, we will take the current orientation and
+                multiply into it a quaternion that represents a pitch rotation of a few degrees. The
+                result becomes the new orientation.</para>
+            <para>But which side do we do the multiplication on? Quaternion multiplication is not
+                commutative, so this will have an affect on the output. Well, it works exactly like
+                matrix math.</para>
+            <para>If you multiply the pitch increase on the left side, then it changes the pitch
+                relative to the current orientation. If you multiply the pitch on the right side, it
+                changes the pitch relative to the initial space of the vertices. Which is usually
+                model space. Since the yaw, pitch, and roll are usually defined relative to the
+                current orientation, that is what we need to do.</para>
+        </section>
     </section>
     <section>
         <title>Camera-Relative Orientation</title>
                 </inlineequation>.</para>
         </section>
     </section>
+    <section>
+        <title>Interpolation</title>
+        <para>One other trick you can do with quaternions is this.</para>
+    </section>
     
     <section>
         <?dbhtml filename="Tut08 In Review.html" ?>

File Tut 08 Getting Oriented/GimbalLock.cpp

 #include <glloader/gl_3_2_comp.h>
 #include <GL/freeglut.h>
 #include "../framework/framework.h"
+#include "../framework/Mesh.h"
+#include "../framework/MatrixStack.h"
 #include <glm/glm.hpp>
 #include <glm/gtc/type_ptr.hpp>
 
 	return 1.0f / tan(fFovRad / 2.0f);
 }
 
-const float fFrustumScale = CalcFrustumScale(45.0f);
+const float fFrustumScale = CalcFrustumScale(20.0f);
 
 void InitializeProgram()
 {
 	cameraToClipMatrixUnif = glGetUniformLocation(theProgram, "cameraToClipMatrix");
 	baseColorUnif = glGetUniformLocation(theProgram, "baseColor");
 
-	float fzNear = 1.0f; float fzFar = 100.0f;
+	float fzNear = 1.0f; float fzFar = 600.0f;
 
 	cameraToClipMatrix[0].x = fFrustumScale;
 	cameraToClipMatrix[1].y = fFrustumScale;
 	glUseProgram(0);
 }
 
-const int numberOfVertices = 24;
-
-#define FULL_COLOR 1.0f, 1.0f, 1.0f, 1.0f
-#define LIGHT_COLOR 0.75f, 0.75f, 0.75f, 1.0f
-#define MID_COLOR 0.5f, 0.5f, 0.5f, 1.0f
-#define DARK_COLOR 	0.3f, 0.3f, 0.3f, 1.0f
-
-
-const float vertexData[] =
-{
-	//Front
-	+0.5f, +0.5f, +0.5f,
-	+0.5f, -0.5f, +0.5f,
-	-0.5f, -0.5f, +0.5f,
-	-0.5f, +0.5f, +0.5f,
-
-	//Top
-	+0.5f, +0.5f, +0.5f,
-	-0.5f, +0.5f, +0.5f,
-	-0.5f, +0.5f, -0.5f,
-	+0.5f, +0.5f, -0.5f,
-
-	//Left
-	+0.5f, +0.5f, +0.5f,
-	+0.5f, +0.5f, -0.5f,
-	+0.5f, -0.5f, -0.5f,
-	+0.5f, -0.5f, +0.5f,
-
-	//Back
-	+0.5f, +0.5f, -0.5f,
-	-0.5f, +0.5f, -0.5f,
-	-0.5f, -0.5f, -0.5f,
-	+0.5f, -0.5f, -0.5f,
-
-	//Bottom
-	+0.5f, -0.5f, +0.5f,
-	+0.5f, -0.5f, -0.5f,
-	-0.5f, -0.5f, -0.5f,
-	-0.5f, -0.5f, +0.5f,
-
-	//Right
-	-0.5f, +0.5f, +0.5f,
-	-0.5f, -0.5f, +0.5f,
-	-0.5f, -0.5f, -0.5f,
-	-0.5f, +0.5f, -0.5f,
-
-
-	FULL_COLOR,
-	FULL_COLOR,
-	FULL_COLOR,
-	FULL_COLOR,
-
-	LIGHT_COLOR,
-	LIGHT_COLOR,
-	LIGHT_COLOR,
-	LIGHT_COLOR,
-
-	MID_COLOR,
-	MID_COLOR,
-	MID_COLOR,
-	MID_COLOR,
-
-	FULL_COLOR,
-	FULL_COLOR,
-	FULL_COLOR,
-	FULL_COLOR,
-
-	LIGHT_COLOR,
-	LIGHT_COLOR,
-	LIGHT_COLOR,
-	LIGHT_COLOR,
-
-	MID_COLOR,
-	MID_COLOR,
-	MID_COLOR,
-	MID_COLOR,
-};
-
-const GLshort indexData[] =
-{
-	0, 1, 2,
-	2, 3, 0,
-
-	4, 5, 6,
-	6, 7, 4,
-
-	8, 9, 10,
-	10, 11, 8,
-
-	12, 13, 14,
-	14, 15, 12,
-
-	16, 17, 18,
-	18, 19, 16,
-
-	20, 21, 22,
-	22, 23, 20,
-};
-
-GLuint vertexBufferObject;
-GLuint indexBufferObject;
-GLuint vao;
-
-void InitializeVAO()
-{
-	glGenBuffers(1, &vertexBufferObject);
-
-	glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject);
-	glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);
-	glBindBuffer(GL_ARRAY_BUFFER, 0);
-
-	glGenBuffers(1, &indexBufferObject);
-
-	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferObject);
-	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indexData), indexData, GL_STATIC_DRAW);
-	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
-
-	glGenVertexArrays(1, &vao);
-	glBindVertexArray(vao);
-
-	size_t colorDataOffset = sizeof(float) * 3 * numberOfVertices;
-	glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject);
-	glEnableVertexAttribArray(positionAttrib);
-	glEnableVertexAttribArray(colorAttrib);
-	glVertexAttribPointer(positionAttrib, 3, GL_FLOAT, GL_FALSE, 0, 0);
-	glVertexAttribPointer(colorAttrib, 4, GL_FLOAT, GL_FALSE, 0, (void*)colorDataOffset);
-	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferObject);
-
-	glBindVertexArray(0);
-}
-
-inline float DegToRad(float fAngDeg)
-{
-	const float fDegToRad = 3.14159f * 2.0f / 360.0f;
-	return fAngDeg * fDegToRad;
-}
-
-inline float Clamp(float fValue, float fMinValue, float fMaxValue)
-{
-	if(fValue < fMinValue)
-		return fMinValue;
-
-	if(fValue > fMaxValue)
-		return fMaxValue;
-
-	return fValue;
-}
-
-glm::mat3 RotateX(float fAngDeg)
-{
-	float fAngRad = DegToRad(fAngDeg);
-	float fCos = cosf(fAngRad);
-	float fSin = sinf(fAngRad);
-
-	glm::mat3 theMat(1.0f);
-	theMat[1].y = fCos; theMat[2].y = -fSin;
-	theMat[1].z = fSin; theMat[2].z = fCos;
-	return theMat;
-}
-
-glm::mat3 RotateY(float fAngDeg)
-{
-	float fAngRad = DegToRad(fAngDeg);
-	float fCos = cosf(fAngRad);
-	float fSin = sinf(fAngRad);
-
-	glm::mat3 theMat(1.0f);
-	theMat[0].x = fCos; theMat[2].x = fSin;
-	theMat[0].z = -fSin; theMat[2].z = fCos;
-	return theMat;
-}
-
-glm::mat3 RotateZ(float fAngDeg)
-{
-	float fAngRad = DegToRad(fAngDeg);
-	float fCos = cosf(fAngRad);
-	float fSin = sinf(fAngRad);
-
-	glm::mat3 theMat(1.0f);
-	theMat[0].x = fCos; theMat[1].x = -fSin;
-	theMat[0].y = fSin; theMat[1].y = fCos;
-	return theMat;
-}
-
-class MatrixStack
-{
-public:
-	MatrixStack()
-		: m_currMat(1.0f)
-	{
-	}
-
-	const glm::mat4 &Top()
-	{
-		return m_currMat;
-	}
-
-	void RotateX(float fAngDeg)
-	{
-		m_currMat = m_currMat * glm::mat4(::RotateX(fAngDeg));
-	}
-
-	void RotateY(float fAngDeg)
-	{
-		m_currMat = m_currMat * glm::mat4(::RotateY(fAngDeg));
-	}
-
-	void RotateZ(float fAngDeg)
-	{
-		m_currMat = m_currMat * glm::mat4(::RotateZ(fAngDeg));
-	}
-
-	void Scale(const glm::vec3 &scaleVec)
-	{
-		glm::mat4 scaleMat(1.0f);
-		scaleMat[0].x = scaleVec.x;
-		scaleMat[1].y = scaleVec.y;
-		scaleMat[2].z = scaleVec.z;
-
-		m_currMat = m_currMat * scaleMat;
-	}
-
-	void Translate(const glm::vec3 &offsetVec)
-	{
-		glm::mat4 translateMat(1.0f);
-		translateMat[3] = glm::vec4(offsetVec, 1.0f);
-
-		m_currMat = m_currMat * translateMat;
-	}
-
-	void Push()
-	{
-		m_matrices.push(m_currMat);
-	}
-
-	void Pop()
-	{
-		m_currMat = m_matrices.top();
-		m_matrices.pop();
-	}
-
-private:
-	glm::mat4 m_currMat;
-	std::stack<glm::mat4> m_matrices;
-};
-
-void DrawGimbalSides(MatrixStack &currMatrix, float fGimbalSidesOffset, float fGimbalSidesScale)
-{
-	//Draw the top
-	{
-		currMatrix.Push();
-		currMatrix.Translate(glm::vec3(0.0f, fGimbalSidesOffset, 0.0f));
-		currMatrix.Scale(glm::vec3(fGimbalSidesScale, 1.0f, 1.0f));
-		glUniformMatrix4fv(modelToCameraMatrixUnif, 1, GL_FALSE, glm::value_ptr(currMatrix.Top()));
-		glDrawElements(GL_TRIANGLES, ARRAY_COUNT(indexData), GL_UNSIGNED_SHORT, 0);
-		currMatrix.Pop();
-	}
-
-	//Draw the bottom
-	{
-		currMatrix.Push();
-		currMatrix.Translate(glm::vec3(0.0f, -fGimbalSidesOffset, 0.0f));
-		currMatrix.Scale(glm::vec3(fGimbalSidesScale, 1.0f, 1.0f));
-		glUniformMatrix4fv(modelToCameraMatrixUnif, 1, GL_FALSE, glm::value_ptr(currMatrix.Top()));
-		glDrawElements(GL_TRIANGLES, ARRAY_COUNT(indexData), GL_UNSIGNED_SHORT, 0);
-		currMatrix.Pop();
-	}
-
-	//Draw the right
-	{
-		currMatrix.Push();
-		currMatrix.Translate(glm::vec3(fGimbalSidesOffset, 0.0f, 0.0f));
-		currMatrix.Scale(glm::vec3(1.0f, fGimbalSidesScale, 1.0f));
-		glUniformMatrix4fv(modelToCameraMatrixUnif, 1, GL_FALSE, glm::value_ptr(currMatrix.Top()));
-		glDrawElements(GL_TRIANGLES, ARRAY_COUNT(indexData), GL_UNSIGNED_SHORT, 0);
-		currMatrix.Pop();
-	}
-
-	//Draw the left
-	{
-		currMatrix.Push();
-		currMatrix.Translate(glm::vec3(-fGimbalSidesOffset, 0.0f, 0.0f));
-		currMatrix.Scale(glm::vec3(1.0f, fGimbalSidesScale, 1.0f));
-		glUniformMatrix4fv(modelToCameraMatrixUnif, 1, GL_FALSE, glm::value_ptr(currMatrix.Top()));
-		glDrawElements(GL_TRIANGLES, ARRAY_COUNT(indexData), GL_UNSIGNED_SHORT, 0);
-		currMatrix.Pop();
-	}
-}
-
-void DrawGimbalAttachments(MatrixStack &currMatrix, float fGimbalAttachOffset)
-{
-	//Draw the right attachment.
-	{
-		currMatrix.Push();
-		currMatrix.Translate(glm::vec3(fGimbalAttachOffset, 0.0f, 0.0f));
-		currMatrix.Scale(glm::vec3(1.0f, 0.5f, 0.5f));
-		glUniformMatrix4fv(modelToCameraMatrixUnif, 1, GL_FALSE, glm::value_ptr(currMatrix.Top()));
-		glDrawElements(GL_TRIANGLES, ARRAY_COUNT(indexData), GL_UNSIGNED_SHORT, 0);
-		currMatrix.Pop();
-	}
-
-	//Draw the left attachment.
-	{
-		currMatrix.Push();
-		currMatrix.Translate(glm::vec3(-fGimbalAttachOffset, 0.0f, 0.0f));
-		currMatrix.Scale(glm::vec3(1.0f, 0.5f, 0.5f));
-		glUniformMatrix4fv(modelToCameraMatrixUnif, 1, GL_FALSE, glm::value_ptr(currMatrix.Top()));
-		glDrawElements(GL_TRIANGLES, ARRAY_COUNT(indexData), GL_UNSIGNED_SHORT, 0);
-		currMatrix.Pop();
-	}
-}
-
-
-void DrawBaseGimbal(MatrixStack &currMatrix, float fSize, glm::vec4 baseColor)
-{
-	//A Gimbal can only be 4 units in size or more.
-	assert(fSize > 4.0f);
-
-	glUseProgram(theProgram);
-	//Set the base color for this object.
-	glUniform4fv(baseColorUnif, 1, glm::value_ptr(baseColor));
-	glBindVertexArray(vao);
-
-	float fGimbalSidesOffset = (fSize / 2.0f) - 1.5f;
-	float fGimbalSidesScale = fSize - 2.0f;
-
-	DrawGimbalSides(currMatrix, fGimbalSidesOffset, fGimbalSidesScale);
-	
-	float fGimbalAttachOffset = (fSize / 2.0f) - 0.5f;
-
-	DrawGimbalAttachments(currMatrix, fGimbalAttachOffset);
-
-	glBindVertexArray(0);
-	glUseProgram(0);
-}
-
 enum GimbalAxis
 {
 	GIMBAL_X_AXIS,
 	GIMBAL_Z_AXIS,
 };
 
-void DrawGimbal(MatrixStack &currMatrix, GimbalAxis eAxis, float fSize, glm::vec4 baseColor)
+Framework::Mesh *g_Gimbals[3] = {NULL, NULL, NULL};
+const char *g_strGimbalNames[3] =
 {
-	currMatrix.Push();
+	"LargeGimbal.xml",
+	"MediumGimbal.xml",
+	"SmallGimbal.xml",
+};
+
+void DrawGimbal(Framework::MatrixStack &currMatrix, GimbalAxis eAxis, float fSize, glm::vec4 baseColor)
+{
+	Framework::MatrixStackPusher pusher(currMatrix);
 
 	switch(eAxis)
 	{
 		break;
 	}
 
-	DrawBaseGimbal(currMatrix, fSize, baseColor);
-	currMatrix.Pop();
+	glUseProgram(theProgram);
+	//Set the base color for this object.
+	glUniform4fv(baseColorUnif, 1, glm::value_ptr(baseColor));
+	glUniformMatrix4fv(modelToCameraMatrixUnif, 1, GL_FALSE, glm::value_ptr(currMatrix.Top()));
+
+	g_Gimbals[eAxis]->Render();
+
+	glUseProgram(0);
 }
 
 //Called after the window and OpenGL are initialized. Called exactly once, before the main loop.
 void init()
 {
 	InitializeProgram();
-	InitializeVAO();
+
+	try
+	{
+		for(int iLoop = 0; iLoop < 3; iLoop++)
+		{
+			g_Gimbals[iLoop] = new Framework::Mesh(g_strGimbalNames[iLoop]);
+		}
+	}
+	catch(std::exception &except)
+	{
+		printf(except.what());
+	}
 
 
 	glEnable(GL_CULL_FACE);
 	glClearDepth(1.0f);
 	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
-	MatrixStack currMatrix;
-	currMatrix.Translate(glm::vec3(0.0f, 0.0f, -60.0f));
+	Framework::MatrixStack currMatrix;
+	currMatrix.Translate(glm::vec3(0.0f, 0.0f, -200.0f));
 	currMatrix.RotateX(g_angles.fAngleX);
 	DrawGimbal(currMatrix, GIMBAL_X_AXIS, 30.0f, glm::vec4(0.4f, 0.4f, 1.0f, 1.0f));
 	currMatrix.RotateY(g_angles.fAngleY);

File Tut 08 Getting Oriented/data/GenGimbals.lua

+require "XmlWriter"
+require "vmath"
+
+local function GenStringFromArray(theArray)
+	local array = {" "}
+	for i, vector in ipairs(theArray) do
+		array[#array + 1] = "        " .. table.concat(vector, " ");
+	end
+	
+	return table.concat(array, "\n");
+end
+
+local iSegCount = ...;
+iSegCount = iSegCount or 40;
+
+local gimbalPoints = {{}, {}, {}};
+local gimbalColors = {{}, {}, {}};
+local gimbalRadii = {28, 24, 20};
+local gimbalConnect = {4, 4, 4};
+local gimbalTriStrips = {{}, {}, {}, {}};
+local gimbalTris = {};
+local gimbalNames = {"Large", "Medium", "Small"};
+
+local iAngle = 3.14159 * 2.0 / iSegCount;
+
+--Compute circle attributes.
+local function AddSegments(SegmentFunc)
+	for iSeg = 1, iSegCount do
+		local iCurrAngle = iSeg * iAngle;
+		local radialDir = vmath.vec2(math.cos(iCurrAngle), math.sin(iCurrAngle));
+		
+		for iGimbal = 1, #gimbalRadii do
+			local vShort = radialDir * (gimbalRadii[iGimbal] - 1.0);
+			local vLong = radialDir * (gimbalRadii[iGimbal] + 1.0);
+			
+			SegmentFunc(iGimbal, vShort, vLong)
+		end
+	end
+end
+
+local halfHeight = 1.0;
+
+local SegmentAdders =
+{
+	function (iGimbal, vShort, vLong)
+		local iLen = #gimbalPoints[iGimbal];
+		gimbalPoints[iGimbal][iLen + 1] = vmath.vec3(vLong[1], vLong[2], halfHeight);
+		gimbalPoints[iGimbal][iLen + 2] = vmath.vec3(vShort[1], vShort[2], halfHeight);
+		gimbalColors[iGimbal][iLen + 1] = vmath.vec4(1.0, 1.0, 1.0, 1.0);
+		gimbalColors[iGimbal][iLen + 2] = vmath.vec4(1.0, 1.0, 1.0, 1.0);
+	end,
+	function (iGimbal, vShort, vLong)
+		local iLen = #gimbalPoints[iGimbal];
+		gimbalPoints[iGimbal][iLen + 1] = vmath.vec3(vShort[1], vShort[2], halfHeight);
+		gimbalPoints[iGimbal][iLen + 2] = vmath.vec3(vShort[1], vShort[2], -halfHeight);
+		gimbalColors[iGimbal][iLen + 1] = vmath.vec4(0.5, 0.5, 0.5, 1.0);
+		gimbalColors[iGimbal][iLen + 2] = vmath.vec4(0.5, 0.5, 0.5, 1.0);
+	end,
+	function (iGimbal, vShort, vLong)
+		local iLen = #gimbalPoints[iGimbal];
+		gimbalPoints[iGimbal][iLen + 1] = vmath.vec3(vShort[1], vShort[2], -halfHeight);
+		gimbalPoints[iGimbal][iLen + 2] = vmath.vec3(vLong[1], vLong[2], -halfHeight);
+		gimbalColors[iGimbal][iLen + 1] = vmath.vec4(0.9, 0.9, 0.9, 1.0);
+		gimbalColors[iGimbal][iLen + 2] = vmath.vec4(0.9, 0.9, 0.9, 1.0);
+	end,
+	function (iGimbal, vShort, vLong)
+		local iLen = #gimbalPoints[iGimbal];
+		gimbalPoints[iGimbal][iLen + 1] = vmath.vec3(vLong[1], vLong[2], -halfHeight);
+		gimbalPoints[iGimbal][iLen + 2] = vmath.vec3(vLong[1], vLong[2], halfHeight);
+		gimbalColors[iGimbal][iLen + 1] = vmath.vec4(0.75, 0.75, 0.75, 1.0);
+		gimbalColors[iGimbal][iLen + 2] = vmath.vec4(0.75, 0.75, 0.75, 1.0);
+	end,
+}
+
+for i, adder in ipairs(SegmentAdders) do
+	AddSegments(adder);
+end
+
+--Add the connecting pieces, on the left and right.
+local conSize = halfHeight * 0.6;
+local function AddConnector(radius, offset, points, color)
+	--Inside the current gimbal
+	points[#points + 1] = vmath.vec3(radius, conSize, conSize);
+	points[#points + 1] = vmath.vec3(radius, -conSize, conSize);
+	points[#points + 1] = vmath.vec3(radius, -conSize, -conSize);
+	points[#points + 1] = vmath.vec3(radius, conSize, -conSize);
+	
+	color[#color + 1] = vmath.vec4(1.0, 1.0, 1.0, 1.0);
+	color[#color + 1] = vmath.vec4(1.0, 1.0, 1.0, 1.0);
+	color[#color + 1] = vmath.vec4(1.0, 1.0, 1.0, 1.0);
+	color[#color + 1] = vmath.vec4(1.0, 1.0, 1.0, 1.0);
+
+	--Inside the outer gimbal.
+	points[#points + 1] = vmath.vec3(radius + offset, conSize, conSize);
+	points[#points + 1] = vmath.vec3(radius + offset, -conSize, conSize);
+	points[#points + 1] = vmath.vec3(radius + offset, -conSize, -conSize);
+	points[#points + 1] = vmath.vec3(radius + offset, conSize, -conSize);
+	
+	color[#color + 1] = vmath.vec4(1.0, 1.0, 1.0, 1.0);
+	color[#color + 1] = vmath.vec4(1.0, 1.0, 1.0, 1.0);
+	color[#color + 1] = vmath.vec4(1.0, 1.0, 1.0, 1.0);
+	color[#color + 1] = vmath.vec4(1.0, 1.0, 1.0, 1.0);
+	
+	--Front.
+	points[#points + 1] = vmath.vec3(radius, conSize, conSize);
+	points[#points + 1] = vmath.vec3(radius, -conSize, conSize);
+	points[#points + 1] = vmath.vec3(radius + offset, -conSize, conSize);
+	points[#points + 1] = vmath.vec3(radius + offset, conSize, conSize);
+	
+	color[#color + 1] = vmath.vec4(1.0, 1.0, 1.0, 1.0);
+	color[#color + 1] = vmath.vec4(1.0, 1.0, 1.0, 1.0);
+	color[#color + 1] = vmath.vec4(1.0, 1.0, 1.0, 1.0);
+	color[#color + 1] = vmath.vec4(1.0, 1.0, 1.0, 1.0);
+	
+	--Back.
+	points[#points + 1] = vmath.vec3(radius, conSize, -conSize);
+	points[#points + 1] = vmath.vec3(radius, -conSize, -conSize);
+	points[#points + 1] = vmath.vec3(radius + offset, -conSize, -conSize);
+	points[#points + 1] = vmath.vec3(radius + offset, conSize, -conSize);
+	
+	color[#color + 1] = vmath.vec4(0.9, 0.9, 0.9, 1.0);
+	color[#color + 1] = vmath.vec4(0.9, 0.9, 0.9, 1.0);
+	color[#color + 1] = vmath.vec4(0.9, 0.9, 0.9, 1.0);
+	color[#color + 1] = vmath.vec4(0.9, 0.9, 0.9, 1.0);
+	
+	--Top.
+	points[#points + 1] = vmath.vec3(radius, conSize, conSize);
+	points[#points + 1] = vmath.vec3(radius, conSize, -conSize);
+	points[#points + 1] = vmath.vec3(radius + offset, conSize, -conSize);
+	points[#points + 1] = vmath.vec3(radius + offset, conSize, conSize);
+	
+	color[#color + 1] = vmath.vec4(0.75, 0.75, 0.75, 1.0);
+	color[#color + 1] = vmath.vec4(0.75, 0.75, 0.75, 1.0);
+	color[#color + 1] = vmath.vec4(0.75, 0.75, 0.75, 1.0);
+	color[#color + 1] = vmath.vec4(0.75, 0.75, 0.75, 1.0);
+	
+	--Bottom.
+	points[#points + 1] = vmath.vec3(radius, -conSize, conSize);
+	points[#points + 1] = vmath.vec3(radius, -conSize, -conSize);
+	points[#points + 1] = vmath.vec3(radius + offset, -conSize, -conSize);
+	points[#points + 1] = vmath.vec3(radius + offset, -conSize, conSize);
+	
+	color[#color + 1] = vmath.vec4(0.5, 0.5, 0.5, 1.0);
+	color[#color + 1] = vmath.vec4(0.5, 0.5, 0.5, 1.0);
+	color[#color + 1] = vmath.vec4(0.5, 0.5, 0.5, 1.0);
+	color[#color + 1] = vmath.vec4(0.5, 0.5, 0.5, 1.0);
+end
+
+for iGimbal = 1, #gimbalRadii do
+	local points = gimbalPoints[iGimbal];
+	local colors = gimbalColors[iGimbal];
+
+	--Right connector.
+	AddConnector(gimbalRadii[iGimbal], gimbalConnect[iGimbal],
+		gimbalPoints[iGimbal], gimbalColors[iGimbal]);
+	
+	--Left connector.
+	AddConnector(-gimbalRadii[iGimbal], -gimbalConnect[iGimbal],
+		gimbalPoints[iGimbal], gimbalColors[iGimbal]);
+end
+
+--Compute strips.
+--Number of attributes that each circle strip takes.
+local indexOffset = iSegCount * 2;
+local function AddStripIndices(strip, baseIndex, stripIx)
+	strip[#strip + 1] = baseIndex + indexOffset * stripIx;
+	strip[#strip + 1] = baseIndex + indexOffset * stripIx + 1;
+end
+
+
+for iSeg = 1, iSegCount do
+	local baseIndex = ((iSeg - 1) * 2);
+	AddStripIndices(gimbalTriStrips[1], baseIndex, 0);
+	AddStripIndices(gimbalTriStrips[2], baseIndex, 1);
+	AddStripIndices(gimbalTriStrips[3], baseIndex, 2);
+	AddStripIndices(gimbalTriStrips[4], baseIndex, 3);
+end
+
+local lastStripIndex = iSegCount * 2;
+AddStripIndices(gimbalTriStrips[1], 0, 0);
+AddStripIndices(gimbalTriStrips[2], 0, 1);
+AddStripIndices(gimbalTriStrips[3], 0, 2);
+AddStripIndices(gimbalTriStrips[4], 0, 3);
+
+local firstTriIndex = indexOffset * 4;
+local numValuesPerConnecter = 24;
+
+local connectTris = {
+--Inside the current gimbal
+	0, 1, 2,
+	2, 3, 0,
+--Inside the outer gimbal.
+	4, 6, 5,
+	6, 4, 7,
+--Front.
+	8, 10, 9,
+	11, 10, 8,
+--Back.
+	12, 13, 14,
+	15, 12, 14,
+--Top.
+	16, 17, 18,
+	18, 19, 16,
+--Bottom.
+	20, 22, 21,
+	22, 20, 23,
+}
+
+for i=1, #connectTris, 3 do
+	connectTris[#connectTris + 1] = connectTris[i] + numValuesPerConnecter;
+	connectTris[#connectTris + 1] = connectTris[i + 2] + numValuesPerConnecter;
+	connectTris[#connectTris + 1] = connectTris[i + 1] + numValuesPerConnecter;
+end
+
+for i, index in ipairs(connectTris) do
+	gimbalTris[#gimbalTris + 1] = firstTriIndex + index;
+end
+
+
+
+--Write the gimbal to the file.
+local function WriteGimbal(iGimbal)
+	local writer = XmlWriter.XmlWriter(gimbalNames[iGimbal] .. "Gimbal.xml");
+	writer:AddPI("oxygen", [[RNGSchema="../../Documents/meshFormat.rnc" type="compact"]]);
+	writer:PushElement("mesh", "http://www.arcsynthesis.com/gltut/mesh");
+		writer:PushElement("attribute");
+			writer:AddAttribute("index", "0");
+			writer:AddAttribute("type", "float");
+			writer:AddAttribute("size", "3");
+			writer:AddText(GenStringFromArray(gimbalPoints[iGimbal]));
+		writer:PopElement();
+		writer:PushElement("attribute");
+			writer:AddAttribute("index", "1");
+			writer:AddAttribute("type", "float");
+			writer:AddAttribute("size", "4");
+			writer:AddText(GenStringFromArray(gimbalColors[iGimbal]));
+		writer:PopElement();
+		for iStrip = 1, #gimbalTriStrips do
+			writer:PushElement("indices");
+				writer:AddAttribute("cmd", "tri-strip");
+				writer:AddAttribute("type", "ushort");
+				writer:AddText(table.concat(gimbalTriStrips[iStrip], " "));
+			writer:PopElement();
+		end
+		if(#gimbalTris > 0) then
+			writer:PushElement("indices");
+				writer:AddAttribute("cmd", "triangles");
+				writer:AddAttribute("type", "ushort");
+				writer:AddText(table.concat(gimbalTris, " "));
+			writer:PopElement();
+		end
+	writer:PopElement();
+	writer:Close();
+end
+
+for iGimbal = 1, #gimbalRadii do
+	WriteGimbal(iGimbal);
+end

File Tut 08 Getting Oriented/data/LargeGimbal.xml

+<?xml version="1.0" encoding="UTF-8"?>
+<?oxygen RNGSchema="../../Documents/meshFormat.rnc" type="compact"?>
+
+<mesh xmlns="http://www.arcsynthesis.com/gltut/mesh" >
+	<attribute index="0" type="float" size="3" > 
+        28.642962479172 4.5365956858331 1
+        26.667585756471 4.2237270178446 1
+        27.580641350571 8.961485518103 1
+        25.67852815398 8.3434520340959 1
+        25.839194441925 13.165714207455 1
+        24.057181032137 12.257733917285 1
+        23.461501883368 17.045759865044 1
+        21.843467270722 15.870190219179 1
+        20.506110258098 20.506083050713 1
+        19.091895757539 19.091870426526 1
+        17.04579099363 23.46147926712 1
+        15.870219200966 21.843446214215 1
+        13.165748490754 25.8391769737 1
+        12.257765836219 24.057164768617 1
+        8.9615221119493 27.580629460494 1
+        8.3434861042286 25.678517083908 1
+        4.5366336891655 28.642956460015 1
+        4.2237624002576 26.667580152428 1
+        3.8477052003648e-005 28.999999999974 1
+        3.5823462210293e-005 26.999999999976 1
+        -4.5365576824927 28.642968498279 1
+        -4.2236916354242 26.667591360467 1
+        -8.9614489242409 27.5806532406 1
+        -8.3434179639484 25.678539224007 1
+        -13.165679924132 25.839211910105 1
+        -12.257701998329 24.057197295615 1
+        -17.045728736428 23.461524499574 1
+        -15.870161237364 21.84348832719 1
+        -20.506055843293 20.506137465446 1
+        -19.091845095479 19.091921088519 1
+        -23.461456650831 17.045822122186 1
+        -21.84342515767 15.870248182725 1
+        -25.83915950543 13.165782774031 1
+        -24.057148505055 12.257797755132 1
+        -27.580617570367 8.9615587057798 1
+        -25.67850601379 8.3435201743467 1
+        -28.642950440808 4.53667169249 1
+        -26.667574548338 4.2237977826631 1
+        -28.999999999898 7.6954104007229e-005 1
+        -26.999999999905 7.1646924420524e-005 1
+        -28.642974517336 -4.5365196791442 1
+        -26.667596964416 -4.2236562529963 1
+        -27.58066513058 -8.961412330363 1
+        -25.678550293989 -8.3433838937863 1
+        -25.839229378239 -13.165645640786 1
+        -24.05721355905 -12.257670079352 1
+        -23.461547115739 -17.045697607782 1
+        -21.843509383619 -15.870132255521 1
+        -20.506164672758 -20.506028635836 1
+        -19.091946419464 -19.091819764399 1
+        -17.045853250712 -23.4614340345 1
+        -15.870277164456 -21.843404101086 1
+        -13.165817057284 -25.839142037113 1
+        -12.257829674023 -24.05713224145 1
+        -8.9615952995946 -27.580605680193 1
+        -8.3435542444501 -25.678494943628 1
+        -4.5367096958065 -28.64294442155 1
+        -4.2238331650612 -26.667568944201 1
+        -0.00011543115602355 -28.99999999977 1
+        -0.00010747038664262 -26.999999999786 1
+        4.5364816757878 -28.642980536342 1
+        4.2236208705611 -26.667602568318 1
+        8.9613757364694 -27.580677020512 1
+        8.3433498236094 -25.678561363925 1
+        13.165611357416 -25.839246846328 1
+        12.257638160353 -24.057229822443 1
+        17.045666479106 -23.461569731863 1
+        15.87010327365 -21.843530440011 1
+        20.506001428343 -20.506191880034 1
+        19.091794433285 -19.091971750377 1
+        23.461411418128 -17.045884379208 1
+        21.843383044464 -15.870306146159 1
+        25.839124568752 -13.165851340514 1
+        24.057115977803 -12.257861592893 1
+        27.58059378997 -8.9616318933935 1
+        25.67848387342 -8.3435883145388 1
+        28.642938402241 -4.536747699115 1
+        26.667563340018 -4.2238685474519 1
+        28.999999999592 -0.00015390820801392 1
+        26.99999999962 -0.00014329384884054 1
+        26.667585756471 4.2237270178446 1
+        26.667585756471 4.2237270178446 -1
+        25.67852815398 8.3434520340959 1
+        25.67852815398 8.3434520340959 -1
+        24.057181032137 12.257733917285 1
+        24.057181032137 12.257733917285 -1
+        21.843467270722 15.870190219179 1
+        21.843467270722 15.870190219179 -1
+        19.091895757539 19.091870426526 1
+        19.091895757539 19.091870426526 -1
+        15.870219200966 21.843446214215 1
+        15.870219200966 21.843446214215 -1
+        12.257765836219 24.057164768617 1
+        12.257765836219 24.057164768617 -1
+        8.3434861042286 25.678517083908 1
+        8.3434861042286 25.678517083908 -1
+        4.2237624002576 26.667580152428 1
+        4.2237624002576 26.667580152428 -1
+        3.5823462210293e-005 26.999999999976 1
+        3.5823462210293e-005 26.999999999976 -1
+        -4.2236916354242 26.667591360467 1
+        -4.2236916354242 26.667591360467 -1
+        -8.3434179639484 25.678539224007 1
+        -8.3434179639484 25.678539224007 -1
+        -12.257701998329 24.057197295615 1
+        -12.257701998329 24.057197295615 -1
+        -15.870161237364 21.84348832719 1
+        -15.870161237364 21.84348832719 -1
+        -19.091845095479 19.091921088519 1
+        -19.091845095479 19.091921088519 -1
+        -21.84342515767 15.870248182725 1
+        -21.84342515767 15.870248182725 -1
+        -24.057148505055 12.257797755132 1
+        -24.057148505055 12.257797755132 -1
+        -25.67850601379 8.3435201743467 1
+        -25.67850601379 8.3435201743467 -1
+        -26.667574548338 4.2237977826631 1
+        -26.667574548338 4.2237977826631 -1
+        -26.999999999905 7.1646924420524e-005 1
+        -26.999999999905 7.1646924420524e-005 -1
+        -26.667596964416 -4.2236562529963 1
+        -26.667596964416 -4.2236562529963 -1
+        -25.678550293989 -8.3433838937863 1
+        -25.678550293989 -8.3433838937863 -1
+        -24.05721355905 -12.257670079352 1
+        -24.05721355905 -12.257670079352 -1
+        -21.843509383619 -15.870132255521 1
+        -21.843509383619 -15.870132255521 -1
+        -19.091946419464 -19.091819764399 1
+        -19.091946419464 -19.091819764399 -1
+        -15.870277164456 -21.843404101086 1
+        -15.870277164456 -21.843404101086 -1
+        -12.257829674023 -24.05713224145 1
+        -12.257829674023 -24.05713224145 -1
+        -8.3435542444501 -25.678494943628 1
+        -8.3435542444501 -25.678494943628 -1
+        -4.2238331650612 -26.667568944201 1
+        -4.2238331650612 -26.667568944201 -1
+        -0.00010747038664262 -26.999999999786 1
+        -0.00010747038664262 -26.999999999786 -1
+        4.2236208705611 -26.667602568318 1
+        4.2236208705611 -26.667602568318 -1
+        8.3433498236094 -25.678561363925 1
+        8.3433498236094 -25.678561363925 -1
+        12.257638160353 -24.057229822443 1
+        12.257638160353 -24.057229822443 -1
+        15.87010327365 -21.843530440011 1
+        15.87010327365 -21.843530440011 -1
+        19.091794433285 -19.091971750377 1
+        19.091794433285 -19.091971750377 -1
+        21.843383044464 -15.870306146159 1
+        21.843383044464 -15.870306146159 -1
+        24.057115977803 -12.257861592893 1
+        24.057115977803 -12.257861592893 -1
+        25.67848387342 -8.3435883145388 1
+        25.67848387342 -8.3435883145388 -1
+        26.667563340018 -4.2238685474519 1
+        26.667563340018 -4.2238685474519 -1
+        26.99999999962 -0.00014329384884054 1
+        26.99999999962 -0.00014329384884054 -1
+        26.667585756471 4.2237270178446 -1
+        28.642962479172 4.5365956858331 -1
+        25.67852815398 8.3434520340959 -1
+        27.580641350571 8.961485518103 -1
+        24.057181032137 12.257733917285 -1
+        25.839194441925 13.165714207455 -1
+        21.843467270722 15.870190219179 -1
+        23.461501883368 17.045759865044 -1
+        19.091895757539 19.091870426526 -1
+        20.506110258098 20.506083050713 -1
+        15.870219200966 21.843446214215 -1
+        17.04579099363 23.46147926712 -1
+        12.257765836219 24.057164768617 -1
+        13.165748490754 25.8391769737 -1
+        8.3434861042286 25.678517083908 -1
+        8.9615221119493 27.580629460494 -1
+        4.2237624002576 26.667580152428 -1
+        4.5366336891655 28.642956460015 -1
+        3.5823462210293e-005 26.999999999976 -1
+        3.8477052003648e-005 28.999999999974 -1
+        -4.2236916354242 26.667591360467 -1
+        -4.5365576824927 28.642968498279 -1
+        -8.3434179639484 25.678539224007 -1
+        -8.9614489242409 27.5806532406 -1
+        -12.257701998329 24.057197295615 -1
+        -13.165679924132 25.839211910105 -1
+        -15.870161237364 21.84348832719 -1
+        -17.045728736428 23.461524499574 -1
+        -19.091845095479 19.091921088519 -1
+        -20.506055843293 20.506137465446 -1
+        -21.84342515767 15.870248182725 -1
+        -23.461456650831 17.045822122186 -1
+        -24.057148505055 12.257797755132 -1
+        -25.83915950543 13.165782774031 -1
+        -25.67850601379 8.3435201743467 -1
+        -27.580617570367 8.9615587057798 -1
+        -26.667574548338 4.2237977826631 -1
+        -28.642950440808 4.53667169249 -1
+        -26.999999999905 7.1646924420524e-005 -1
+        -28.999999999898 7.6954104007229e-005 -1
+        -26.667596964416 -4.2236562529963 -1
+        -28.642974517336 -4.5365196791442 -1
+        -25.678550293989 -8.3433838937863 -1
+        -27.58066513058 -8.961412330363 -1
+        -24.05721355905 -12.257670079352 -1
+        -25.839229378239 -13.165645640786 -1
+        -21.843509383619 -15.870132255521 -1
+        -23.461547115739 -17.045697607782 -1
+        -19.091946419464 -19.091819764399 -1
+        -20.506164672758 -20.506028635836 -1
+        -15.870277164456 -21.843404101086 -1
+        -17.045853250712 -23.4614340345 -1
+        -12.257829674023 -24.05713224145 -1
+        -13.165817057284 -25.839142037113 -1
+        -8.3435542444501 -25.678494943628 -1
+        -8.9615952995946 -27.580605680193 -1
+        -4.2238331650612 -26.667568944201 -1
+        -4.5367096958065 -28.64294442155 -1
+        -0.00010747038664262 -26.999999999786 -1
+        -0.00011543115602355 -28.99999999977 -1
+        4.2236208705611 -26.667602568318 -1
+        4.5364816757878 -28.642980536342 -1
+        8.3433498236094 -25.678561363925 -1
+        8.9613757364694 -27.580677020512 -1
+        12.257638160353 -24.057229822443 -1
+        13.165611357416 -25.839246846328 -1
+        15.87010327365 -21.843530440011 -1
+        17.045666479106 -23.461569731863 -1
+        19.091794433285 -19.091971750377 -1
+        20.506001428343 -20.506191880034 -1
+        21.843383044464 -15.870306146159 -1
+        23.461411418128 -17.045884379208 -1
+        24.057115977803 -12.257861592893 -1
+        25.839124568752 -13.165851340514 -1
+        25.67848387342 -8.3435883145388 -1
+        27.58059378997 -8.9616318933935 -1
+        26.667563340018 -4.2238685474519 -1
+        28.642938402241 -4.536747699115 -1
+        26.99999999962 -0.00014329384884054 -1
+        28.999999999592 -0.00015390820801392 -1
+        28.642962479172 4.5365956858331 -1
+        28.642962479172 4.5365956858331 1
+        27.580641350571 8.961485518103 -1
+        27.580641350571 8.961485518103 1
+        25.839194441925 13.165714207455 -1
+        25.839194441925 13.165714207455 1
+        23.461501883368 17.045759865044 -1
+        23.461501883368 17.045759865044 1
+        20.506110258098 20.506083050713 -1
+        20.506110258098 20.506083050713 1
+        17.04579099363 23.46147926712 -1
+        17.04579099363 23.46147926712 1
+        13.165748490754 25.8391769737 -1
+        13.165748490754 25.8391769737 1
+        8.9615221119493 27.580629460494 -1
+        8.9615221119493 27.580629460494 1
+        4.5366336891655 28.642956460015 -1
+        4.5366336891655 28.642956460015 1
+        3.8477052003648e-005 28.999999999974 -1
+        3.8477052003648e-005 28.999999999974 1
+        -4.5365576824927 28.642968498279 -1
+        -4.5365576824927 28.642968498279 1
+        -8.9614489242409 27.5806532406 -1
+        -8.9614489242409 27.5806532406 1
+        -13.165679924132 25.839211910105 -1
+        -13.165679924132 25.839211910105 1
+        -17.045728736428 23.461524499574 -1
+        -17.045728736428 23.461524499574 1
+        -20.506055843293 20.506137465446 -1
+        -20.506055843293 20.506137465446 1
+        -23.461456650831 17.045822122186 -1
+        -23.461456650831 17.045822122186 1
+        -25.83915950543 13.165782774031 -1
+        -25.83915950543 13.165782774031 1
+        -27.580617570367 8.9615587057798 -1
+        -27.580617570367 8.9615587057798 1
+        -28.642950440808 4.53667169249 -1
+        -28.642950440808 4.53667169249 1
+        -28.999999999898 7.6954104007229e-005 -1
+        -28.999999999898 7.6954104007229e-005 1
+        -28.642974517336 -4.5365196791442 -1
+        -28.642974517336 -4.5365196791442 1
+        -27.58066513058 -8.961412330363 -1
+        -27.58066513058 -8.961412330363 1
+        -25.839229378239 -13.165645640786 -1
+        -25.839229378239 -13.165645640786 1
+        -23.461547115739 -17.045697607782 -1
+        -23.461547115739 -17.045697607782 1
+        -20.506164672758 -20.506028635836 -1
+        -20.506164672758 -20.506028635836 1
+        -17.045853250712 -23.4614340345 -1
+        -17.045853250712 -23.4614340345 1
+        -13.165817057284 -25.839142037113 -1
+        -13.165817057284 -25.839142037113 1
+        -8.9615952995946 -27.580605680193 -1
+        -8.9615952995946 -27.580605680193 1
+        -4.5367096958065 -28.64294442155 -1
+        -4.5367096958065 -28.64294442155 1
+        -0.00011543115602355 -28.99999999977 -1
+        -0.00011543115602355 -28.99999999977 1
+        4.5364816757878 -28.642980536342 -1
+        4.5364816757878 -28.642980536342 1
+        8.9613757364694 -27.580677020512 -1
+        8.9613757364694 -27.580677020512 1
+        13.165611357416 -25.839246846328 -1
+        13.165611357416 -25.839246846328 1
+        17.045666479106 -23.461569731863 -1
+        17.045666479106 -23.461569731863 1
+        20.506001428343 -20.506191880034 -1
+        20.506001428343 -20.506191880034 1
+        23.461411418128 -17.045884379208 -1
+        23.461411418128 -17.045884379208 1
+        25.839124568752 -13.165851340514 -1
+        25.839124568752 -13.165851340514 1
+        27.58059378997 -8.9616318933935 -1
+        27.58059378997 -8.9616318933935 1
+        28.642938402241 -4.536747699115 -1
+        28.642938402241 -4.536747699115 1
+        28.999999999592 -0.00015390820801392 -1
+        28.999999999592 -0.00015390820801392 1
+        28 0.6 0.6
+        28 -0.6 0.6
+        28 -0.6 -0.6
+        28 0.6 -0.6
+        32 0.6 0.6
+        32 -0.6 0.6
+        32 -0.6 -0.6
+        32 0.6 -0.6
+        28 0.6 0.6
+        28 -0.6 0.6
+        32 -0.6 0.6
+        32 0.6 0.6
+        28 0.6 -0.6
+        28 -0.6 -0.6
+        32 -0.6 -0.6
+        32 0.6 -0.6
+        28 0.6 0.6
+        28 0.6 -0.6
+        32 0.6 -0.6
+        32 0.6 0.6
+        28 -0.6 0.6
+        28 -0.6 -0.6
+        32 -0.6 -0.6
+        32 -0.6 0.6
+        -28 0.6 0.6
+        -28 -0.6 0.6
+        -28 -0.6 -0.6
+        -28 0.6 -0.6
+        -32 0.6 0.6
+        -32 -0.6 0.6
+        -32 -0.6 -0.6
+        -32 0.6 -0.6
+        -28 0.6 0.6
+        -28 -0.6 0.6
+        -32 -0.6 0.6
+        -32 0.6 0.6
+        -28 0.6 -0.6
+        -28 -0.6 -0.6
+        -32 -0.6 -0.6
+        -32 0.6 -0.6
+        -28 0.6 0.6
+        -28 0.6 -0.6
+        -32 0.6 -0.6
+        -32 0.6 0.6
+        -28 -0.6 0.6
+        -28 -0.6 -0.6
+        -32 -0.6 -0.6
+        -32 -0.6 0.6</attribute>
+	<attribute index="1" type="float" size="4" > 
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        1 1 1 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.9 0.9 0.9 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.75 0.75 0.75 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1
+        0.5 0.5 0.5 1</attribute>
+	<indices cmd="tri-strip" type="ushort" >0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 0 1</indices>
+	<indices cmd="tri-strip" type="ushort" >80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 80 81</indices>
+	<indices cmd="tri-strip" type="ushort" >160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 160 161</indices>
+	<indices cmd="tri-strip" type="ushort" >240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 240 241</indices>
+	<indices cmd="triangles" type="ushort" >320 321 322 322 323 320 324 326 325 326 324 327 328 330 329 331 330 328 332 333 334 335 332 334 336 337 338 338 339 336 340 342 341 342 340 343 344 346 345 346 344 347 348 349 350 350 351 348 352 353 354 355 352 354 356 358 357 359 358 356 360 362 361 362 360 363 364 365 366 366 367 364</indices>
+</mesh>

File Tut 08 Getting Oriented/data/MediumGimbal.xml

+<?xml version="1.0" encoding="UTF-8"?>
+<?oxygen RNGSchema="../../Documents/meshFormat.rnc" type="compact"?>
+
+<mesh xmlns="http://www.arcsynthesis.com/gltut/mesh" >
+	<attribute index="0" type="float" size="3" > 
+        24.692209033769 3.9108583498561 1
+        22.716832311068 3.5979896818676 1
+        23.776414957389 7.7254185500888 1
+        21.874301760798 7.1073850660817 1
+        22.27516762235 11.349753627116 1
+        20.493154212562 10.441773336947 1
+        20.225432658076 14.694620573314 1
+        18.60739804543 13.519050927448 1
+        17.677681256981 17.677657802339 1
+        16.263466756422 16.263445178152 1
+        14.694647408301 20.22541316131 1
+        13.519075615637 18.607380108405 1
+        11.349783181685 22.275152563535 1
+        10.44180052715 20.493140358452 1
+        7.725450096508 23.776404707322 1
+        7.1074140887873 21.874292330736 1
+        3.9108911113496 24.692203844841 1
+        3.5980198224416 22.716827537253 1
+        3.3169872416938e-005 24.999999999978 1
+        3.0516282623583e-005 22.99999999998 1
+        -3.9108255883557 24.692214222655 1
+        -3.5979595412873 22.716837084842 1
+        -7.7253870036559 23.776425207414 1
+        -7.1073560433634 21.874311190821 1
+        -11.349724072527 22.275182681125 1
+        -10.441746146725 20.493168066635 1
+        -14.6945937383 20.225452154805 1
+        -13.519026239236 18.607415982421 1
+        -17.677634347666 17.677704711591 1
+        -16.263423599853 16.263488334664 1
+        -20.225393664509 14.694674243264 1
+        -18.607362171348 13.519100303802 1
+        -22.275137504681 11.349812736233 1
+        -20.493126504306 10.441827717335 1
+        -23.776394457213 7.7254816429136 1
+        -21.874282900636 7.1074431114805 1
+        -24.692198655869 3.9109238728362 1
+        -22.716822763399 3.5980499630093 1
+        -24.999999999912 6.6339744833818e-005 1
+        -22.999999999919 6.1032565247113e-005 1
+        -24.692219411496 -3.9107928268485 1
+        -22.716841858577 -3.5979294007006 1
+        -23.776435457397 -7.7253554572095 1
+        -21.874320620805 -7.1073270206327 1
+        -22.275197739861 -11.349694517919 1
+        -20.493181920673 -10.441718956485 1
+        -20.2254716515 -14.69456690326 1
+        -18.60743391938 -13.519001550999 1
+        -17.677728166171 -17.677610892962 1
+        -16.263509912877 -16.263402021525 1
+        -14.6947010782 -20.225374167673 1
+        -13.519124991944 -18.607344234259 1
+        -11.349842290762 -22.275122445787 1
+        -10.441854907501 -20.493112650124 1
+        -7.7255131893056 -23.776384207063 1
+        -7.1074721341612 -21.874273470498 1
+        -3.9109566343159 -24.692193466853 1
+        -3.5980801035707 -22.716817989505 1
+        -9.9509617261683e-005 -24.999999999802 1
+        -9.1548847880749e-005 -22.999999999818 1
+        3.9107600653343 -24.692224600294 1
+        3.5978992601076 -22.716846632271 1
+        7.7253239107495 -23.776445707338 1
+        7.1072979978895 -21.874330050751 1
+        11.34966496329 -22.275212798559 1
+        10.441691766227 -20.493195774674 1
+        14.694540068195 -20.225491148158 1
+        13.518976862739 -18.607451856305 1
+        17.677587438227 -17.677751620719 1
+        16.263380443169 -16.263531491062 1
+        20.2253546708 -14.69472791311 1
+        18.607326297136 -13.519149680061 1
+        22.275107386855 -11.349871845271 1
+        20.493098795907 -10.441882097649 1
+        23.77637395687 -7.7255447356841 1
+        21.874264040321 -7.1075011568293 1
+        24.692188277794 -3.9109893957888 1
+        22.71681321557 -3.5981102441257 1
+        24.999999999648 -0.00013267948966717 1
+        22.999999999676 -0.0001220651304938 1
+        22.716832311068 3.5979896818676 1
+        22.716832311068 3.5979896818676 -1
+        21.874301760798 7.1073850660817 1
+        21.874301760798 7.1073850660817 -1
+        20.493154212562 10.441773336947 1
+        20.493154212562 10.441773336947 -1
+        18.60739804543 13.519050927448 1
+        18.60739804543 13.519050927448 -1
+        16.263466756422 16.263445178152 1
+        16.263466756422 16.263445178152 -1
+        13.519075615637 18.607380108405 1
+        13.519075615637 18.607380108405 -1
+        10.44180052715 20.493140358452 1
+        10.44180052715 20.493140358452 -1
+        7.1074140887873 21.874292330736 1
+        7.1074140887873 21.874292330736 -1
+        3.5980198224416 22.716827537253 1
+        3.5980198224416 22.716827537253 -1
+        3.0516282623583e-005 22.99999999998 1
+        3.0516282623583e-005 22.99999999998 -1
+        -3.5979595412873 22.716837084842 1
+        -3.5979595412873 22.716837084842 -1
+        -7.1073560433634 21.874311190821 1
+        -7.1073560433634 21.874311190821 -1
+        -10.441746146725 20.493168066635 1
+        -10.441746146725 20.493168066635 -1
+        -13.519026239236 18.607415982421 1
+        -13.519026239236 18.607415982421 -1
+        -16.263423599853 16.263488334664 1
+        -16.263423599853 16.263488334664 -1
+        -18.607362171348 13.519100303802 1
+        -18.607362171348 13.519100303802 -1
+        -20.493126504306 10.441827717335 1
+        -20.493126504306 10.441827717335 -1
+        -21.874282900636 7.1074431114805 1
+        -21.874282900636 7.1074431114805 -1
+        -22.716822763399 3.5980499630093 1
+        -22.716822763399 3.5980499630093 -1
+        -22.999999999919 6.1032565247113e-005 1
+        -22.999999999919 6.1032565247113e-005 -1
+        -22.716841858577 -3.5979294007006 1
+        -22.716841858577 -3.5979294007006 -1
+        -21.874320620805 -7.1073270206327 1
+        -21.874320620805 -7.1073270206327 -1
+        -20.493181920673 -10.441718956485 1
+        -20.493181920673 -10.441718956485 -1
+        -18.60743391938 -13.519001550999 1
+        -18.60743391938 -13.519001550999 -1
+        -16.263509912877 -16.263402021525 1
+        -16.263509912877 -16.263402021525 -1
+        -13.519124991944 -18.607344234259 1
+        -13.519124991944 -18.607344234259 -1
+        -10.441854907501 -20.493112650124 1
+        -10.441854907501 -20.493112650124 -1
+        -7.1074721341612 -21.874273470498 1
+        -7.1074721341612 -21.874273470498 -1
+        -3.5980801035707 -22.716817989505 1
+        -3.5980801035707 -22.716817989505 -1
+        -9.1548847880749e-005 -22.999999999818 1
+        -9.1548847880749e-005 -22.999999999818 -1
+        3.5978992601076 -22.716846632271 1
+        3.5978992601076 -22.716846632271 -1
+        7.1072979978895 -21.874330050751 1
+        7.1072979978895 -21.874330050751 -1
+        10.441691766227 -20.493195774674 1
+        10.441691766227 -20.493195774674 -1
+        13.518976862739 -18.607451856305 1
+        13.518976862739 -18.607451856305 -1
+        16.263380443169 -16.263531491062 1
+        16.263380443169 -16.263531491062 -1
+        18.607326297136 -13.519149680061 1
+        18.607326297136 -13.519149680061 -1
+        20.493098795907 -10.441882097649 1
+        20.493098795907 -10.441882097649 -1
+        21.874264040321 -7.1075011568293 1
+        21.874264040321 -7.1075011568293 -1
+        22.71681321557 -3.5981102441257 1
+        22.71681321557 -3.5981102441257 -1
+        22.999999999676 -0.0001220651304938 1
+        22.999999999676 -0.0001220651304938 -1
+        22.716832311068 3.5979896818676 -1
+        24.692209033769 3.9108583498561 -1
+        21.874301760798 7.1073850660817 -1
+        23.776414957389 7.7254185500888 -1
+        20.493154212562 10.441773336947 -1
+        22.27516762235 11.349753627116 -1
+        18.60739804543 13.519050927448 -1
+        20.225432658076 14.694620573314 -1
+        16.263466756422 16.263445178152 -1
+        17.677681256981 17.677657802339 -1
+        13.519075615637 18.607380108405 -1
+        14.694647408301 20.22541316131 -1
+        10.44180052715 20.493140358452 -1
+        11.349783181685 22.275152563535 -1
+        7.1074140887873 21.874292330736 -1
+        7.725450096508 23.776404707322 -1
+        3.5980198224416 22.716827537253 -1
+        3.9108911113496 24.692203844841 -1
+        3.0516282623583e-005 22.99999999998 -1
+        3.3169872416938e-005 24.999999999978 -1
+        -3.5979595412873 22.716837084842 -1
+        -3.9108255883557 24.692214222655 -1
+        -7.1073560433634 21.874311190821 -1
+        -7.7253870036559 23.776425207414 -1
+        -10.441746146725 20.493168066635 -1
+        -11.349724072527 22.275182681125 -1
+        -13.519026239236 18.607415982421 -1
+        -14.6945937383 20.225452154805 -1
+        -16.263423599853 16.263488334664 -1
+        -17.677634347666 17.677704711591 -1
+        -18.607362171348 13.519100303802 -1
+        -20.225393664509 14.694674243264 -1
+        -20.493126504306 10.441827717335 -1
+        -22.275137504681 11.349812736233 -1
+        -21.874282900636 7.1074431114805 -1
+        -23.776394457213 7.7254816429136 -1
+        -22.716822763399 3.5980499630093 -1
+        -24.692198655869 3.9109238728362 -1
+        -22.999999999919 6.1032565247113e-005 -1
+        -24.999999999912 6.6339744833818e-005 -1
+        -22.716841858577 -3.5979294007006 -1
+        -24.692219411496 -3.9107928268485 -1
+        -21.874320620805 -7.1073270206327 -1
+        -23.776435457397 -7.7253554572095 -1
+        -20.493181920673 -10.441718956485 -1
+        -22.275197739861 -11.349694517919 -1
+        -18.60743391938 -13.519001550999 -1
+        -20.2254716515 -14.69456690326 -1
+        -16.263509912877 -16.263402021525 -1
+        -17.677728166171 -17.677610892962 -1
+        -13.519124991944 -18.607344234259 -1
+        -14.6947010782 -20.225374167673 -1
+        -10.441854907501 -20.493112650124 -1
+        -11.349842290762 -22.275122445787 -1
+        -7.1074721341612 -21.874273470498 -1
+        -7.7255131893056 -23.776384207063 -1
+        -3.5980801035707 -22.716817989505 -1
+        -3.9109566343159 -24.692193466853 -1
+        -9.1548847880749e-005 -22.999999999818 -1
+        -9.9509617261683e-005 -24.999999999802 -1
+        3.5978992601076 -22.716846632271 -1
+        3.9107600653343 -24.692224600294 -1
+        7.1072979978895 -21.874330050751 -1
+        7.7253239107495 -23.776445707338 -1
+        10.441691766227 -20.493195774674 -1
+        11.34966496329 -22.275212798559 -1
+        13.518976862739 -18.607451856305 -1
+        14.694540068195 -20.225491148158 -1
+        16.263380443169 -16.263531491062 -1
+        17.677587438227 -17.677751620719 -1
+        18.607326297136 -13.519149680061 -1
+        20.2253546708 -14.69472791311 -1
+        20.493098795907 -10.441882097649 -1
+        22.275107386855 -11.349871845271 -1
+        21.874264040321 -7.1075011568293 -1
+        23.77637395687 -7.7255447356841 -1
+        22.71681321557 -3.5981102441257 -1
+        24.692188277794 -3.9109893957888 -1
+        22.999999999676 -0.0001220651304938 -1
+        24.999999999648 -0.00013267948966717 -1
+        24.692209033769 3.9108583498561 -1
+        24.692209033769 3.9108583498561 1
+        23.776414957389 7.7254185500888 -1
+        23.776414957389 7.7254185500888 1
+        22.27516762235 11.349753627116 -1
+        22.27516762235 11.349753627116 1
+        20.225432658076 14.694620573314 -1
+        20.225432658076 14.694620573314 1
+        17.677681256981 17.677657802339 -1
+        17.677681256981 17.677657802339 1
+        14.694647408301 20.22541316131 -1
+        14.694647408301 20.22541316131 1
+        11.349783181685 22.275152563535 -1
+        11.349783181685 22.275152563535 1
+        7.725450096508 23.776404707322 -1
+        7.725450096508 23.776404707322 1
+        3.9108911113496 24.692203844841 -1
+        3.9108911113496 24.692203844841 1
+        3.3169872416938e-005 24.999999999978 -1
+        3.3169872416938e-005 24.999999999978 1
+        -3.9108255883557 24.692214222655 -1
+        -3.9108255883557 24.692214222655 1
+        -7.7253870036559 23.776425207414 -1
+        -7.7253870036559 23.776425207414 1
+        -11.349724072527 22.275182681125 -1
+        -11.349724072527 22.275182681125 1
+        -14.6945937383 20.225452154805 -1
+        -14.6945937383 20.225452154805 1
+        -17.677634347666 17.677704711591 -1
+        -17.677634347666 17.677704711591 1
+        -20.225393664509 14.694674243264 -1
+        -20.225393664509 14.694674243264 1
+        -22.275137504681 11.349812736233 -1
+        -22.275137504681 11.349812736233 1
+        -23.776394457213 7.7254816429136 -1
+        -23.776394457213 7.7254816429136 1
+        -24.692198655869 3.9109238728362 -1
+        -24.692198655869 3.9109238728362 1
+        -24.999999999912 6.6339744833818e-005 -1
+        -24.999999999912 6.6339744833818e-005 1
+        -24.692219411496 -3.9107928268485 -1
+        -24.692219411496 -3.9107928268485 1
+        -23.776435457397 -7.7253554572095 -1
+        -23.776435457397 -7.7253554572095 1
+        -22.275197739861 -11.349694517919 -1
+        -22.275197739861 -11.349694517919 1
+        -20.2254716515 -14.69456690326 -1
+        -20.2254716515 -14.69456690326 1
+        -17.677728166171 -17.677610892962 -1
+        -17.677728166171 -17.677610892962 1
+        -14.6947010782 -20.225374167673 -1
+        -14.6947010782 -20.225374167673 1