Commits

Jason McKesson committed 1602eaf

Tut13: moved the directory.

  • Participants
  • Parent commits 7a19715

Comments (0)

Files changed (40)

Tut 13 Imposters/BasicImposter.cpp

-#include <string>
-#include <vector>
-#include <stack>
-#include <math.h>
-#include <glloader/gl_3_3_comp.h>
-#include <GL/freeglut.h>
-#include "../framework/framework.h"
-#include "../framework/Mesh.h"
-#include "../framework/MatrixStack.h"
-#include "../framework/MousePole.h"
-#include "../framework/ObjectPole.h"
-#include "../framework/Timer.h"
-#include "../framework/UniformBlockArray.h"
-#include <glm/glm.hpp>
-#include <glm/gtc/type_ptr.hpp>
-
-#define ARRAY_COUNT( array ) (sizeof( array ) / (sizeof( array[0] ) * (sizeof( array ) != sizeof(void*) || sizeof( array[0] ) <= sizeof(void*))))
-
-struct ProgramMeshData
-{
-	GLuint theProgram;
-
-	GLuint modelToCameraMatrixUnif;
-	GLuint normalModelToCameraMatrixUnif;
-};
-
-struct ProgramImposData
-{
-	GLuint theProgram;
-
-	GLuint sphereRadiusUnif;
-	GLuint cameraSpherePosUnif;
-};
-
-struct UnlitProgData
-{
-	GLuint theProgram;
-
-	GLuint objectColorUnif;
-	GLuint modelToCameraMatrixUnif;
-};
-
-float g_fzNear = 1.0f;
-float g_fzFar = 1000.0f;
-
-enum Impostors
-{
-	IMP_BASIC,
- 	IMP_PERSPECTIVE,
- 	IMP_DEPTH,
-
-	IMP_NUM_IMPOSTORS,
-};
-
-ProgramMeshData g_litMeshProg;
-ProgramImposData g_litImpProgs[IMP_NUM_IMPOSTORS];
-UnlitProgData g_Unlit;
-
-const int g_materialBlockIndex = 0;
-const int g_lightBlockIndex = 1;
-const int g_projectionBlockIndex = 2;
-
-UnlitProgData LoadUnlitProgram(const std::string &strVertexShader, const std::string &strFragmentShader)
-{
-	std::vector<GLuint> shaderList;
-
-	shaderList.push_back(Framework::LoadShader(GL_VERTEX_SHADER, strVertexShader));
-	shaderList.push_back(Framework::LoadShader(GL_FRAGMENT_SHADER, strFragmentShader));
-
-	UnlitProgData data;
-	data.theProgram = Framework::CreateProgram(shaderList);
-	data.modelToCameraMatrixUnif = glGetUniformLocation(data.theProgram, "modelToCameraMatrix");
-	data.objectColorUnif = glGetUniformLocation(data.theProgram, "objectColor");
-
-	GLuint projectionBlock = glGetUniformBlockIndex(data.theProgram, "Projection");
-	glUniformBlockBinding(data.theProgram, projectionBlock, g_projectionBlockIndex);
-
-	return data;
-}
-
-ProgramMeshData LoadLitMeshProgram(const std::string &strVertexShader, const std::string &strFragmentShader)
-{
-	std::vector<GLuint> shaderList;
-
-	shaderList.push_back(Framework::LoadShader(GL_VERTEX_SHADER, strVertexShader));
-	shaderList.push_back(Framework::LoadShader(GL_FRAGMENT_SHADER, strFragmentShader));
-
-	ProgramMeshData data;
-	data.theProgram = Framework::CreateProgram(shaderList);
-	data.modelToCameraMatrixUnif = glGetUniformLocation(data.theProgram, "modelToCameraMatrix");
-
-	data.normalModelToCameraMatrixUnif = glGetUniformLocation(data.theProgram, "normalModelToCameraMatrix");
-
-	GLuint materialBlock = glGetUniformBlockIndex(data.theProgram, "Material");
-	GLuint lightBlock = glGetUniformBlockIndex(data.theProgram, "Light");
-	GLuint projectionBlock = glGetUniformBlockIndex(data.theProgram, "Projection");
-
-	glUniformBlockBinding(data.theProgram, materialBlock, g_materialBlockIndex);
-	glUniformBlockBinding(data.theProgram, lightBlock, g_lightBlockIndex);
-	glUniformBlockBinding(data.theProgram, projectionBlock, g_projectionBlockIndex);
-
-	return data;
-}
-
-ProgramImposData LoadLitImposProgram(const std::string &strVertexShader, const std::string &strFragmentShader)
-{
-	std::vector<GLuint> shaderList;
-
-	shaderList.push_back(Framework::LoadShader(GL_VERTEX_SHADER, strVertexShader));
-	shaderList.push_back(Framework::LoadShader(GL_FRAGMENT_SHADER, strFragmentShader));
-
-	ProgramImposData data;
-	data.theProgram = Framework::CreateProgram(shaderList);
-	data.sphereRadiusUnif = glGetUniformLocation(data.theProgram, "sphereRadius");
-	data.cameraSpherePosUnif = glGetUniformLocation(data.theProgram, "cameraSpherePos");
-
-	GLuint materialBlock = glGetUniformBlockIndex(data.theProgram, "Material");
-	GLuint lightBlock = glGetUniformBlockIndex(data.theProgram, "Light");
-	GLuint projectionBlock = glGetUniformBlockIndex(data.theProgram, "Projection");
-
-	glUniformBlockBinding(data.theProgram, materialBlock, g_materialBlockIndex);
-	glUniformBlockBinding(data.theProgram, lightBlock, g_lightBlockIndex);
-	glUniformBlockBinding(data.theProgram, projectionBlock, g_projectionBlockIndex);
-
-	return data;
-}
-
-const char *g_impShaderNames[IMP_NUM_IMPOSTORS * 2] =
-{
-	"BasicImpostor.vert", "BasicImpostor.frag",
- 	"PerspImpostor.vert", "PerspImpostor.frag",
- 	"DepthImpostor.vert", "DepthImpostor.frag",
-};
-
-void InitializePrograms()
-{
-	g_litMeshProg = LoadLitMeshProgram("PN.vert", "Lighting.frag");
-
-	for(int iLoop = 0; iLoop < IMP_NUM_IMPOSTORS; iLoop++)
-	{
-		g_litImpProgs[iLoop] = LoadLitImposProgram(
-			g_impShaderNames[iLoop * 2], g_impShaderNames[iLoop * 2 + 1]);
-	}
-
-	g_Unlit = LoadUnlitProgram("Unlit.vert", "Unlit.frag");
-}
-
-Framework::RadiusDef radiusDef = {10.0f, 3.0f, 70.0f, 3.5f, 1.5f};
-glm::vec3 objectCenter = glm::vec3(0.0f, 30.0f, 25.0f);
-
-Framework::MousePole g_mousePole(objectCenter, radiusDef);
-Framework::ObjectPole g_objectPole(objectCenter, &g_mousePole);
-
-namespace
-{
-	void MouseMotion(int x, int y)
-	{
-		g_mousePole.GLUTMouseMove(glm::ivec2(x, y));
-		g_objectPole.GLUTMouseMove(glm::ivec2(x, y));
-		glutPostRedisplay();
-	}
-
-	void MouseButton(int button, int state, int x, int y)
-	{
-		g_mousePole.GLUTMouseButton(button, state, glm::ivec2(x, y));
-		g_objectPole.GLUTMouseButton(button, state, glm::ivec2(x, y));
-		glutPostRedisplay();
-	}
-
-	void MouseWheel(int wheel, int direction, int x, int y)
-	{
-		g_mousePole.GLUTMouseWheel(direction, glm::ivec2(x, y));
-		g_objectPole.GLUTMouseWheel(direction, glm::ivec2(x, y));
-		glutPostRedisplay();
-	}
-}
-
-struct ProjectionBlock
-{
-	glm::mat4 cameraToClipMatrix;
-};
-
-struct PerLight
-{
-	glm::vec4 cameraSpaceLightPos;
-	glm::vec4 lightIntensity;
-};
-
-const int NUMBER_OF_LIGHTS = 2;
-
-struct LightBlock
-{
-	glm::vec4 ambientIntensity;
-	float lightAttenuation;
-	float padding[3];
-	PerLight lights[NUMBER_OF_LIGHTS];
-};
-
-struct MaterialBlock
-{
-	glm::vec4 diffuseColor;
-	glm::vec4 specularColor;
-	float specularShininess;
-	float padding[3];
-};
-
-Framework::Mesh *g_pPlaneMesh = NULL;
-Framework::Mesh *g_pSphereMesh = NULL;
-Framework::Mesh *g_pCubeMesh = NULL;
-
-GLuint g_lightUniformBuffer = 0;
-GLuint g_projectionUniformBuffer = 0;
-GLuint g_materialUniformBuffer = 0;
-
-int g_materialBlockOffset = 0;
-
-enum MaterialNames
-{
-	MTL_TERRAIN = 0,
-	MTL_BLUE_SHINY,
-	MTL_GOLD_METAL,
-	MTL_DULL_GREY,
-	MTL_BLACK_SHINY,
-
-	NUM_MATERIALS,
-};
-
-void CreateMaterials()
-{
-	Framework::UniformBlockArray<MaterialBlock, NUM_MATERIALS> ubArray;
-	g_materialBlockOffset = ubArray.GetArrayOffset();
-
-	MaterialBlock mtl;
-	mtl.diffuseColor = glm::vec4(0.5f, 0.5f, 0.5f, 1.0f);
-	mtl.specularColor = glm::vec4(0.5f, 0.5f, 0.5f, 1.0f);
-	mtl.specularShininess = 0.6f;
-	ubArray[MTL_TERRAIN] = mtl;
-
-	mtl.diffuseColor = glm::vec4(0.1f, 0.1f, 0.8f, 1.0f);
-	mtl.specularColor = glm::vec4(0.8f, 0.8f, 0.8f, 1.0f);
-	mtl.specularShininess = 0.1f;
-	ubArray[MTL_BLUE_SHINY] = mtl;
-
-	mtl.diffuseColor = glm::vec4(0.803f, 0.709f, 0.15f, 1.0f);
-	mtl.specularColor = glm::vec4(0.803f, 0.709f, 0.15f, 1.0f) * 0.75;
-	mtl.specularShininess = 0.18f;
-	ubArray[MTL_GOLD_METAL] = mtl;
-
-	mtl.diffuseColor = glm::vec4(0.4f, 0.4f, 0.4f, 1.0f);
-	mtl.specularColor = glm::vec4(0.1f, 0.1f, 0.1f, 1.0f);
-	mtl.specularShininess = 0.8f;
-	ubArray[MTL_DULL_GREY] = mtl;
-
-	mtl.diffuseColor = glm::vec4(0.05f, 0.05f, 0.05f, 1.0f);
-	mtl.specularColor = glm::vec4(0.95f, 0.95f, 0.95f, 1.0f);
-	mtl.specularShininess = 0.3f;
-	ubArray[MTL_BLACK_SHINY] = mtl;
-
-	g_materialUniformBuffer = ubArray.CreateBufferObject();
-}
-
-GLuint g_imposterVAO;
-GLuint g_imposterVBO;
-
-//Called after the window and OpenGL are initialized. Called exactly once, before the main loop.
-void init()
-{
-	InitializePrograms();
-
-	try
-	{
-		g_pPlaneMesh = new Framework::Mesh("LargePlane.xml");
-		g_pSphereMesh = new Framework::Mesh("UnitSphere.xml");
-		g_pCubeMesh = new Framework::Mesh("UnitCube.xml");
-	}
-	catch(std::exception &except)
-	{
-		printf(except.what());
-		throw;
-	}
-
-	glutMouseFunc(MouseButton);
-	glutMotionFunc(MouseMotion);
-	glutMouseWheelFunc(MouseWheel);
-
-	glEnable(GL_CULL_FACE);
-	glCullFace(GL_BACK);
-	glFrontFace(GL_CW);
-
-	const float depthZNear = 0.0f;
-	const float depthZFar = 1.0f;
-
-	glEnable(GL_DEPTH_TEST);
-	glDepthMask(GL_TRUE);
-	glDepthFunc(GL_LEQUAL);
-	glDepthRange(depthZNear, depthZFar);
-	glEnable(GL_DEPTH_CLAMP);
-
-	//Setup our Uniform Buffers
-	glGenBuffers(1, &g_lightUniformBuffer);
-	glBindBuffer(GL_UNIFORM_BUFFER, g_lightUniformBuffer);
-	glBufferData(GL_UNIFORM_BUFFER, sizeof(LightBlock), NULL, GL_DYNAMIC_DRAW);
-
-	glGenBuffers(1, &g_projectionUniformBuffer);
-	glBindBuffer(GL_UNIFORM_BUFFER, g_projectionUniformBuffer);
-	glBufferData(GL_UNIFORM_BUFFER, sizeof(ProjectionBlock), NULL, GL_DYNAMIC_DRAW);
-
-	//Bind the static buffers.
-	glBindBufferRange(GL_UNIFORM_BUFFER, g_lightBlockIndex, g_lightUniformBuffer,
-		0, sizeof(LightBlock));
-
-	glBindBufferRange(GL_UNIFORM_BUFFER, g_projectionBlockIndex, g_projectionUniformBuffer,
-		0, sizeof(ProjectionBlock));
-
-	glBindBuffer(GL_UNIFORM_BUFFER, 0);
-
-	glGenBuffers(1, &g_imposterVBO);
-	glBindBuffer(GL_ARRAY_BUFFER, g_imposterVBO);
-	glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(float), NULL, GL_STATIC_DRAW);
-
-	glGenVertexArrays(1, &g_imposterVAO);
-	glBindVertexArray(g_imposterVAO);
-	glEnableVertexAttribArray(0);
-	glVertexAttribPointer(0, 1, GL_FLOAT, GL_FALSE, 0, (void*)(0));
-
-	glBindVertexArray(0);
-	glBindBuffer(GL_ARRAY_BUFFER, 0);
-
-	CreateMaterials();
-}
-
-int g_currImpostor = IMP_BASIC;
-
-void DrawSphere(Framework::MatrixStack &modelMatrix,
-				const glm::vec3 &position, float radius, MaterialNames material,
-				bool bDrawImposter = false)
-{
-	glBindBufferRange(GL_UNIFORM_BUFFER, g_materialBlockIndex, g_materialUniformBuffer,
-		material * g_materialBlockOffset, sizeof(MaterialBlock));
-
-	if(bDrawImposter)
-	{
-		glm::vec4 cameraSpherePos = modelMatrix.Top() * glm::vec4(position, 1.0f);
-		glUseProgram(g_litImpProgs[g_currImpostor].theProgram);
-		glUniform3fv(g_litImpProgs[g_currImpostor].cameraSpherePosUnif, 1, glm::value_ptr(cameraSpherePos));
-		glUniform1f(g_litImpProgs[g_currImpostor].sphereRadiusUnif, radius);
-
-		glBindVertexArray(g_imposterVAO);
-
-		glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-
-		glBindVertexArray(0);
-		glUseProgram(0);
-	}
-	else
-	{
-		Framework::MatrixStackPusher push(modelMatrix);
-		modelMatrix.Translate(position);
-		modelMatrix.Scale(radius * 2.0f); //The unit sphere has a radius 0.5f.
-
-		glm::mat3 normMatrix(modelMatrix.Top());
-		normMatrix = glm::transpose(glm::inverse(normMatrix));
-
-		glUseProgram(g_litMeshProg.theProgram);
-		glUniformMatrix4fv(g_litMeshProg.modelToCameraMatrixUnif, 1, GL_FALSE,
-			glm::value_ptr(modelMatrix.Top()));
-		glUniformMatrix3fv(g_litMeshProg.normalModelToCameraMatrixUnif, 1, GL_FALSE,
-			glm::value_ptr(normMatrix));
-
-		g_pSphereMesh->Render("lit");
-
-		glUseProgram(0);
-	}
-
-	glBindBufferRange(GL_UNIFORM_BUFFER, g_materialBlockIndex, 0, 0, 0);
-}
-
-void DrawSphereOrbit(Framework::MatrixStack &modelMatrix,
-					 const glm::vec3 &orbitCenter, const glm::vec3 &orbitAxis,
-					 float orbitRadius, float orbitAlpha, float sphereRadius, MaterialNames material,
-					 bool drawImposter = false)
-{
-	Framework::MatrixStackPusher push(modelMatrix);
-
-	modelMatrix.Translate(orbitCenter);
-	modelMatrix.Rotate(orbitAxis, 360.0f * orbitAlpha);
-
-	glm::vec3 offsetDir = glm::cross(orbitAxis, glm::vec3(0.0f, 1.0f, 0.0f));
-	if(glm::length(offsetDir) < 0.001f)
-		offsetDir = glm::cross(orbitAxis, glm::vec3(1.0f, 0.0f, 0.0f));
-
-	offsetDir = glm::normalize(offsetDir);
-
-	modelMatrix.Translate(offsetDir * orbitRadius);
-
-	DrawSphere(modelMatrix, glm::vec3(0.0f), sphereRadius, material, drawImposter);
-}
-
-bool g_bDrawCameraPos = false;
-bool g_bDrawLights = true;
-
-Framework::Timer g_sphereTimer(Framework::Timer::TT_LOOP, 6.0f);
-
-float g_lightHeight = 20.0f;
-
-glm::vec4 CalcLightPosition()
-{
-	const float fLoopDuration = 5.0f;
-	const float fScale = 3.14159f * 2.0f;
-
-	float timeThroughLoop = g_sphereTimer.GetAlpha();
-
-	glm::vec4 ret(0.0f, g_lightHeight, 0.0f, 1.0f);
-
-	ret.x = cosf(timeThroughLoop * fScale) * 20.0f;
-	ret.z = sinf(timeThroughLoop * fScale) * 20.0f;
-
-	return ret;
-}
-
-const float g_fHalfLightDistance = 25.0f;
-const float g_fLightAttenuation = 1.0f / (g_fHalfLightDistance * g_fHalfLightDistance);
-
-bool g_drawImposter[4] = { false, false, false, false };
-
-//Called to update the display.
-//You should call glutSwapBuffers after all of your rendering to display what you rendered.
-//If you need continuous updates of the screen, call glutPostRedisplay() at the end of the function.
-void display()
-{
-	g_sphereTimer.Update();
-
-	glClearColor(0.75f, 0.75f, 1.0f, 1.0f);
-	glClearDepth(1.0f);
-	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
-	if(g_pPlaneMesh && g_pSphereMesh && g_pCubeMesh)
-	{
-		Framework::MatrixStack modelMatrix;
-		modelMatrix.SetMatrix(g_mousePole.CalcMatrix());
-		const glm::mat4 &worldToCamMat = modelMatrix.Top();
-
-		LightBlock lightData;
-
-		lightData.ambientIntensity = glm::vec4(0.2f, 0.2f, 0.2f, 1.0f);
-		lightData.lightAttenuation = g_fLightAttenuation;
-
-		lightData.lights[0].cameraSpaceLightPos = worldToCamMat * glm::vec4(0.707f, 0.707f, 0.0f, 0.0f);
-		lightData.lights[0].lightIntensity = glm::vec4(0.6f, 0.6f, 0.6f, 1.0f);
-
-		lightData.lights[1].cameraSpaceLightPos = worldToCamMat * CalcLightPosition();
-		lightData.lights[1].lightIntensity = glm::vec4(0.4f, 0.4f, 0.4f, 1.0f);
-
-		glBindBuffer(GL_UNIFORM_BUFFER, g_lightUniformBuffer);
-		glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(lightData), &lightData);
-		glBindBuffer(GL_UNIFORM_BUFFER, 0);
-
-		{
-			glBindBufferRange(GL_UNIFORM_BUFFER, g_materialBlockIndex, g_materialUniformBuffer,
-				MTL_TERRAIN * g_materialBlockOffset, sizeof(MaterialBlock));
-
-			glm::mat3 normMatrix(modelMatrix.Top());
-			normMatrix = glm::transpose(glm::inverse(normMatrix));
-
-			glUseProgram(g_litMeshProg.theProgram);
-			glUniformMatrix4fv(g_litMeshProg.modelToCameraMatrixUnif, 1, GL_FALSE,
-				glm::value_ptr(modelMatrix.Top()));
-			glUniformMatrix3fv(g_litMeshProg.normalModelToCameraMatrixUnif, 1, GL_FALSE,
-				glm::value_ptr(normMatrix));
-
-			g_pPlaneMesh->Render();
-
-			glUseProgram(0);
-			glBindBufferRange(GL_UNIFORM_BUFFER, g_materialBlockIndex, 0, 0, 0);
-		}
-
-		DrawSphere(modelMatrix, glm::vec3(0.0f, 10.0f, 0.0f), 4.0f, MTL_BLUE_SHINY,
-			g_drawImposter[0]);
-		DrawSphereOrbit(modelMatrix, glm::vec3(0.0f, 10.0f, 0.0f), glm::vec3(0.6f, 0.8f, 0.0f),
-			20.0f, g_sphereTimer.GetAlpha(), 2.0f, MTL_DULL_GREY, g_drawImposter[1]);
-		DrawSphereOrbit(modelMatrix, glm::vec3(-10.0f, 1.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f),
-			10.0f, g_sphereTimer.GetAlpha(), 1.0f, MTL_BLACK_SHINY, g_drawImposter[2]);
-		DrawSphereOrbit(modelMatrix, glm::vec3(10.0f, 1.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f),
-			10.0f, g_sphereTimer.GetAlpha() * 2.0f, 1.0f, MTL_GOLD_METAL, g_drawImposter[3]);
-
-		if(g_bDrawLights)
-		{
-			Framework::MatrixStackPusher push(modelMatrix);
-
-			modelMatrix.Translate(glm::vec3(CalcLightPosition()));
-			modelMatrix.Scale(0.5f);
-
-			glUseProgram(g_Unlit.theProgram);
-			glUniformMatrix4fv(g_Unlit.modelToCameraMatrixUnif, 1, GL_FALSE,
-				glm::value_ptr(modelMatrix.Top()));
-
-			glm::vec4 lightColor(1.0f);
-			glUniform4fv(g_Unlit.objectColorUnif, 1, glm::value_ptr(lightColor));
-			g_pCubeMesh->Render("flat");
-		}
-
-		if(g_bDrawCameraPos)
-		{
-			Framework::MatrixStackPusher push(modelMatrix);
-
-			modelMatrix.SetIdentity();
-			modelMatrix.Translate(glm::vec3(0.0f, 0.0f, -g_mousePole.GetLookAtDistance()));
-
-			glDisable(GL_DEPTH_TEST);
-			glDepthMask(GL_FALSE);
-			glUseProgram(g_Unlit.theProgram);
-			glUniformMatrix4fv(g_Unlit.modelToCameraMatrixUnif, 1, GL_FALSE,
-				glm::value_ptr(modelMatrix.Top()));
-			glUniform4f(g_Unlit.objectColorUnif, 0.25f, 0.25f, 0.25f, 1.0f);
-			g_pCubeMesh->Render("flat");
-			glDepthMask(GL_TRUE);
-			glEnable(GL_DEPTH_TEST);
-			glUniform4f(g_Unlit.objectColorUnif, 1.0f, 1.0f, 1.0f, 1.0f);
-			g_pCubeMesh->Render("flat");
-		}
-	}
-
-	glutPostRedisplay();
-	glutSwapBuffers();
-}
-
-//Called whenever the window is resized. The new window size is given, in pixels.
-//This is an opportunity to call glViewport or glScissor to keep up with the change in size.
-void reshape (int w, int h)
-{
-	Framework::MatrixStack persMatrix;
-	persMatrix.Perspective(45.0f, (h / (float)w), g_fzNear, g_fzFar);
-
-	ProjectionBlock projData;
-	projData.cameraToClipMatrix = persMatrix.Top();
-
-	glBindBuffer(GL_UNIFORM_BUFFER, g_projectionUniformBuffer);
-	glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(ProjectionBlock), &projData);
-	glBindBuffer(GL_UNIFORM_BUFFER, 0);
-
-	glViewport(0, 0, (GLsizei) w, (GLsizei) h);
-	glutPostRedisplay();
-}
-
-//Called whenever a key on the keyboard was pressed.
-//The key is given by the ''key'' parameter, which is in ASCII.
-//It's often a good idea to have the escape key (ASCII value 27) call glutLeaveMainLoop() to 
-//exit the program.
-void keyboard(unsigned char key, int x, int y)
-{
-	switch (key)
-	{
-	case 27:
-		delete g_pPlaneMesh;
-		delete g_pSphereMesh;
-		g_pPlaneMesh = NULL;
-		g_pSphereMesh = NULL;
-		glutLeaveMainLoop();
-		break;
-
-	case 'p': g_sphereTimer.TogglePause(); break;
-	case '-': g_sphereTimer.Rewind(0.5f); break;
-	case '=': g_sphereTimer.Fastforward(0.5f); break;
-	case 't': g_bDrawCameraPos = !g_bDrawCameraPos; break;
-	case 'g': g_bDrawLights = !g_bDrawLights; break;
-
-	case '1': g_drawImposter[0] = !g_drawImposter[0]; break;
-	case '2': g_drawImposter[1] = !g_drawImposter[1]; break;
-	case '3': g_drawImposter[2] = !g_drawImposter[2]; break;
-	case '4': g_drawImposter[3] = !g_drawImposter[3]; break;
-
-	case 'l':
-		{
-			g_currImpostor += 1;
-			g_currImpostor %= IMP_NUM_IMPOSTORS;
-			const char *impostorNames[IMP_NUM_IMPOSTORS] =
-			{
-				"basic",
- 				"perspective-correct",
- 				"depth-accurate",
-			};
-
-			printf("Now using %s impostor.\n", impostorNames[g_currImpostor]);
-		}
-		break;
-
-	case 32: InitializePrograms(); break;
-
-	}
-
-	g_mousePole.GLUTKeyOffset(key, 5.0f, 1.0f);
-}
-

Tut 13 Imposters/data/BasicImpostor.frag

-#version 330
-
-in vec2 mapping;
-
-out vec4 outputColor;
-
-uniform float sphereRadius;
-uniform vec3 cameraSpherePos;
-
-layout(std140) uniform;
-
-uniform Material
-{
-	vec4 diffuseColor;
-	vec4 specularColor;
-	float specularShininess;
-} Mtl;
-
-struct PerLight
-{
-	vec4 cameraSpaceLightPos;
-	vec4 lightIntensity;
-};
-
-const int numberOfLights = 2;
-
-uniform Light
-{
-	vec4 ambientIntensity;
-	float lightAttenuation;
-	PerLight lights[numberOfLights];
-} Lgt;
-
-
-float CalcAttenuation(in vec3 cameraSpacePosition,
-	in vec3 cameraSpaceLightPos,
-	out vec3 lightDirection)
-{
-	vec3 lightDifference =  cameraSpaceLightPos - cameraSpacePosition;
-	float lightDistanceSqr = dot(lightDifference, lightDifference);
-	lightDirection = lightDifference * inversesqrt(lightDistanceSqr);
-	
-	return (1 / ( 1.0 + Lgt.lightAttenuation * lightDistanceSqr));
-}
-
-uniform Projection
-{
-	mat4 cameraToClipMatrix;
-};
-
-vec4 ComputeLighting(in PerLight lightData, in vec3 cameraSpacePosition,
-	in vec3 cameraSpaceNormal)
-{
-	vec3 lightDir;
-	vec4 lightIntensity;
-	if(lightData.cameraSpaceLightPos.w == 0.0)
-	{
-		lightDir = vec3(lightData.cameraSpaceLightPos);
-		lightIntensity = lightData.lightIntensity;
-	}
-	else
-	{
-		float atten = CalcAttenuation(cameraSpacePosition,
-			lightData.cameraSpaceLightPos.xyz, lightDir);
-		lightIntensity = atten * lightData.lightIntensity;
-	}
-	
-	vec3 surfaceNormal = normalize(cameraSpaceNormal);
-	float cosAngIncidence = dot(surfaceNormal, lightDir);
-	cosAngIncidence = cosAngIncidence < 0.0001 ? 0.0 : cosAngIncidence;
-	
-	vec3 viewDirection = normalize(-cameraSpacePosition);
-	
-	vec3 halfAngle = normalize(lightDir + viewDirection);
-	float angleNormalHalf = acos(dot(halfAngle, surfaceNormal));
-	float exponent = angleNormalHalf / Mtl.specularShininess;
-	exponent = -(exponent * exponent);
-	float gaussianTerm = exp(exponent);
-
-	gaussianTerm = cosAngIncidence != 0.0 ? gaussianTerm : 0.0;
-	
-	vec4 lighting = Mtl.diffuseColor * lightIntensity * cosAngIncidence;
-	lighting += Mtl.specularColor * lightIntensity * gaussianTerm;
-	
-	return lighting;
-}
-
-void Impostor(out vec3 cameraPos, out vec3 cameraNormal)
-{
-	float lensqr = dot(mapping, mapping);
-	if(lensqr > 1.0)
-		discard;
-		
-	cameraNormal = vec3(mapping, sqrt(1.0 - lensqr));
-	cameraPos = (cameraNormal * sphereRadius) + cameraSpherePos;
-}
-
-void main()
-{
-	vec3 cameraPos;
-	vec3 cameraNormal;
-	
-	Impostor(cameraPos, cameraNormal);
-	
-	vec4 accumLighting = Mtl.diffuseColor * Lgt.ambientIntensity;
-	for(int light = 0; light < numberOfLights; light++)
-	{
-		accumLighting += ComputeLighting(Lgt.lights[light],
-			cameraPos, cameraNormal);
-	}
-	
-	outputColor = sqrt(accumLighting); //2.0 gamma correction
-}

Tut 13 Imposters/data/BasicImpostor.vert

-#version 330
-
-layout(std140) uniform;
-
-out vec2 mapping;
-
-uniform Projection
-{
-	mat4 cameraToClipMatrix;
-};
-
-uniform float sphereRadius;
-uniform vec3 cameraSpherePos;
-
-void main()
-{
-	vec2 offset;
-	switch(gl_VertexID)
-	{
-	case 0:
-		//Bottom-left
-		mapping = vec2(-1.0, -1.0);
-		offset = vec2(-sphereRadius, -sphereRadius);
-		break;
-	case 1:
-		//Top-left
-		mapping = vec2(-1.0, 1.0);
-		offset = vec2(-sphereRadius, sphereRadius);
-		break;
-	case 2:
-		//Bottom-right
-		mapping = vec2(1.0, -1.0);
-		offset = vec2(sphereRadius, -sphereRadius);
-		break;
-	case 3:
-		//Top-right
-		mapping = vec2(1.0, 1.0);
-		offset = vec2(sphereRadius, sphereRadius);
-		break;
-	}
-
-	vec4 cameraCornerPos = vec4(cameraSpherePos, 1.0);
-	cameraCornerPos.xy += offset;
-
-	gl_Position = cameraToClipMatrix * cameraCornerPos;
-}

Tut 13 Imposters/data/DepthImpostor.frag

-#version 330
-
-in vec2 mapping;
-
-out vec4 outputColor;
-
-uniform float sphereRadius;
-uniform vec3 cameraSpherePos;
-
-layout(std140) uniform;
-
-uniform Material
-{
-	vec4 diffuseColor;
-	vec4 specularColor;
-	float specularShininess;
-} Mtl;
-
-struct PerLight
-{
-	vec4 cameraSpaceLightPos;
-	vec4 lightIntensity;
-};
-
-const int numberOfLights = 2;
-
-uniform Light
-{
-	vec4 ambientIntensity;
-	float lightAttenuation;
-	PerLight lights[numberOfLights];
-} Lgt;
-
-
-float CalcAttenuation(in vec3 cameraSpacePosition,
-	in vec3 cameraSpaceLightPos,
-	out vec3 lightDirection)
-{
-	vec3 lightDifference =  cameraSpaceLightPos - cameraSpacePosition;
-	float lightDistanceSqr = dot(lightDifference, lightDifference);
-	lightDirection = lightDifference * inversesqrt(lightDistanceSqr);
-	
-	return (1 / ( 1.0 + Lgt.lightAttenuation * lightDistanceSqr));
-}
-
-uniform Projection
-{
-	mat4 cameraToClipMatrix;
-};
-
-vec4 ComputeLighting(in PerLight lightData, in vec3 cameraSpacePosition,
-	in vec3 cameraSpaceNormal)
-{
-	vec3 lightDir;
-	vec4 lightIntensity;
-	if(lightData.cameraSpaceLightPos.w == 0.0)
-	{
-		lightDir = vec3(lightData.cameraSpaceLightPos);
-		lightIntensity = lightData.lightIntensity;
-	}
-	else
-	{
-		float atten = CalcAttenuation(cameraSpacePosition,
-			lightData.cameraSpaceLightPos.xyz, lightDir);
-		lightIntensity = atten * lightData.lightIntensity;
-	}
-	
-	vec3 surfaceNormal = normalize(cameraSpaceNormal);
-	float cosAngIncidence = dot(surfaceNormal, lightDir);
-	cosAngIncidence = cosAngIncidence < 0.0001 ? 0.0 : cosAngIncidence;
-	
-	vec3 viewDirection = normalize(-cameraSpacePosition);
-	
-	vec3 halfAngle = normalize(lightDir + viewDirection);
-	float angleNormalHalf = acos(dot(halfAngle, surfaceNormal));
-	float exponent = angleNormalHalf / Mtl.specularShininess;
-	exponent = -(exponent * exponent);
-	float gaussianTerm = exp(exponent);
-
-	gaussianTerm = cosAngIncidence != 0.0 ? gaussianTerm : 0.0;
-	
-	vec4 lighting = Mtl.diffuseColor * lightIntensity * cosAngIncidence;
-	lighting += Mtl.specularColor * lightIntensity * gaussianTerm;
-	
-	return lighting;
-}
-
-void Impostor(out vec3 cameraPos, out vec3 cameraNormal)
-{
-	vec3 cameraPlanePos = vec3(mapping * sphereRadius, 0.0) + cameraSpherePos;
-	vec3 rayDirection = normalize(cameraPlanePos);
-	
-	float B = 2.0 * dot(rayDirection, -cameraSpherePos);
-	float C = dot(cameraSpherePos, cameraSpherePos) - (sphereRadius * sphereRadius);
-	
-	float det = (B * B) - (4 * C);
-	if(det < 0.0)
-		discard;
-		
-	float sqrtDet = sqrt(det);
-	float posT = (-B + sqrtDet)/2;
-	float negT = (-B - sqrtDet)/2;
-	
-	float intersectT = min(posT, negT);
-	cameraPos = rayDirection * intersectT;
-	cameraNormal = normalize(cameraPos - cameraSpherePos);
-}
-
-void main()
-{
-	vec3 cameraPos;
-	vec3 cameraNormal;
-	
-	Impostor(cameraPos, cameraNormal);
-	
-	//Set the depth based on the new cameraPos.
-	vec4 clipPos = cameraToClipMatrix * vec4(cameraPos, 1.0);
-	float ndcDepth = clipPos.z / clipPos.w;
-	gl_FragDepth = ((gl_DepthRange.diff * ndcDepth) + gl_DepthRange.near + gl_DepthRange.far) / 2.0;
-	
-	vec4 accumLighting = Mtl.diffuseColor * Lgt.ambientIntensity;
-	for(int light = 0; light < numberOfLights; light++)
-	{
-		accumLighting += ComputeLighting(Lgt.lights[light],
-			cameraPos, cameraNormal);
-	}
-	
-	outputColor = sqrt(accumLighting); //2.0 gamma correction
-}

Tut 13 Imposters/data/DepthImpostor.vert

-#version 330
-
-layout(std140) uniform;
-
-out vec2 mapping;
-
-uniform Projection
-{
-	mat4 cameraToClipMatrix;
-};
-
-uniform float sphereRadius;
-uniform vec3 cameraSpherePos;
-
-const float g_boxCorrection = 1.5;
-
-void main()
-{
-	vec2 offset;
-	switch(gl_VertexID)
-	{
-	case 0:
-		//Bottom-left
-		mapping = vec2(-1.0, -1.0) * g_boxCorrection;
-		offset = vec2(-sphereRadius, -sphereRadius);
-		break;
-	case 1:
-		//Top-left
-		mapping = vec2(-1.0, 1.0) * g_boxCorrection;
-		offset = vec2(-sphereRadius, sphereRadius);
-		break;
-	case 2:
-		//Bottom-right
-		mapping = vec2(1.0, -1.0) * g_boxCorrection;
-		offset = vec2(sphereRadius, -sphereRadius);
-		break;
-	case 3:
-		//Top-right
-		mapping = vec2(1.0, 1.0) * g_boxCorrection;
-		offset = vec2(sphereRadius, sphereRadius);
-		break;
-	}
-
-	vec4 cameraCornerPos = vec4(cameraSpherePos, 1.0);
-	cameraCornerPos.xy += offset * g_boxCorrection;
-
-	gl_Position = cameraToClipMatrix * cameraCornerPos;
-}

Tut 13 Imposters/data/GenCube.lua

-require "XmlWriter"
-require "vmath"
-
-local function GenStringFromArray(theArray, bAsInt)
-	local array = {" "}
-	for i, vector in ipairs(theArray) do
-		local elements = vector;
-		if(bAsInt) then
-			elements = {};
-			for i, value in ipairs(vector) do
-				elements[#elements + 1] = string.format("%i", value);
-			end
-		end
-		
-		array[#array + 1] = "        " .. table.concat(vector, " ");
-	end
-	
-	return table.concat(array, "\n");
-end
-
-local positions =
-{
-	--Front
-	vmath.vec3( 0.5,  0.5,  0.5),
-	vmath.vec3( 0.5, -0.5,  0.5),
-	vmath.vec3(-0.5, -0.5,  0.5),
-	vmath.vec3(-0.5,  0.5,  0.5),
-
-	--Top
-	vmath.vec3( 0.5,  0.5,  0.5),
-	vmath.vec3(-0.5,  0.5,  0.5),
-	vmath.vec3(-0.5,  0.5, -0.5),
-	vmath.vec3( 0.5,  0.5, -0.5),
-
-	--Left
-	vmath.vec3( 0.5,  0.5,  0.5),
-	vmath.vec3( 0.5,  0.5, -0.5),
-	vmath.vec3( 0.5, -0.5, -0.5),
-	vmath.vec3( 0.5, -0.5,  0.5),
-
-	--Back
-	vmath.vec3( 0.5,  0.5, -0.5),
-	vmath.vec3(-0.5,  0.5, -0.5),
-	vmath.vec3(-0.5, -0.5, -0.5),
-	vmath.vec3( 0.5, -0.5, -0.5),
-
-	--Bottom
-	vmath.vec3( 0.5, -0.5,  0.5),
-	vmath.vec3( 0.5, -0.5, -0.5),
-	vmath.vec3(-0.5, -0.5, -0.5),
-	vmath.vec3(-0.5, -0.5,  0.5),
-
-	--Right
-	vmath.vec3(-0.5,  0.5,  0.5),
-	vmath.vec3(-0.5, -0.5,  0.5),
-	vmath.vec3(-0.5, -0.5, -0.5),
-	vmath.vec3(-0.5,  0.5, -0.5),
-};
-
-local normals =
-{
-	--Front
-	vmath.vec3(0.0,  0.0,  1.0),
-	vmath.vec3(0.0,  0.0,  1.0),
-	vmath.vec3(0.0,  0.0,  1.0),
-	vmath.vec3(0.0,  0.0,  1.0),
-
-	--Top
-	vmath.vec3(0.0,  1.0,  0.0),
-	vmath.vec3(0.0,  1.0,  0.0),
-	vmath.vec3(0.0,  1.0,  0.0),
-	vmath.vec3(0.0,  1.0,  0.0),
-
-	--Left
-	vmath.vec3(1.0,  0.0,  0.0),
-	vmath.vec3(1.0,  0.0,  0.0),
-	vmath.vec3(1.0,  0.0,  0.0),
-	vmath.vec3(1.0,  0.0,  0.0),
-
-	--Back
-	vmath.vec3(0.0,  0.0, -1.0),
-	vmath.vec3(0.0,  0.0, -1.0),
-	vmath.vec3(0.0,  0.0, -1.0),
-	vmath.vec3(0.0,  0.0, -1.0),
-
-	--Bottom
-	vmath.vec3(0.0, -1.0,  0.0),
-	vmath.vec3(0.0, -1.0,  0.0),
-	vmath.vec3(0.0, -1.0,  0.0),
-	vmath.vec3(0.0, -1.0,  0.0),
-
-	--Right
-	vmath.vec3(-1.0,  0.0,  0.0),
-	vmath.vec3(-1.0,  0.0,  0.0),
-	vmath.vec3(-1.0,  0.0,  0.0),
-	vmath.vec3(-1.0,  0.0,  0.0),
-}
-
-local colors =
-{
-	vmath.vec4(0.25, 1.0, 0.25, 1.0),
-	vmath.vec4(0.25, 1.0, 0.25, 1.0),
-	vmath.vec4(0.25, 1.0, 0.25, 1.0),
-	vmath.vec4(0.25, 1.0, 0.25, 1.0),
-
-	vmath.vec4(0.5, 0.5, 1.0, 1.0),
-	vmath.vec4(0.5, 0.5, 1.0, 1.0),
-	vmath.vec4(0.5, 0.5, 1.0, 1.0),
-	vmath.vec4(0.5, 0.5, 1.0, 1.0),
-
-	vmath.vec4(1.0, 0.5, 0.5, 1.0),
-	vmath.vec4(1.0, 0.5, 0.5, 1.0),
-	vmath.vec4(1.0, 0.5, 0.5, 1.0),
-	vmath.vec4(1.0, 0.5, 0.5, 1.0),
-
-	vmath.vec4(1.0, 1.0, 0.5, 1.0),
-	vmath.vec4(1.0, 1.0, 0.5, 1.0),
-	vmath.vec4(1.0, 1.0, 0.5, 1.0),
-	vmath.vec4(1.0, 1.0, 0.5, 1.0),
-
-	vmath.vec4(0.5, 1.0, 1.0, 1.0),
-	vmath.vec4(0.5, 1.0, 1.0, 1.0),
-	vmath.vec4(0.5, 1.0, 1.0, 1.0),
-	vmath.vec4(0.5, 1.0, 1.0, 1.0),
-
-	vmath.vec4(1.0, 0.5, 1.0, 1.0),
-	vmath.vec4(1.0, 0.5, 1.0, 1.0),
-	vmath.vec4(1.0, 0.5, 1.0, 1.0),
-	vmath.vec4(1.0, 0.5, 1.0, 1.0),
-}
-
-local indices =
-{
-	vmath.vec3(0, 1, 2),
-	vmath.vec3(2, 3, 0),
-
-	vmath.vec3(4, 5, 6),
-	vmath.vec3(6, 7, 4),
-
-	vmath.vec3(8, 9, 10),
-	vmath.vec3(10, 11, 8),
-
-	vmath.vec3(12, 13, 14),
-	vmath.vec3(14, 15, 12),
-
-	vmath.vec3(16, 17, 18),
-	vmath.vec3(18, 19, 16),
-
-	vmath.vec3(20, 21, 22),
-	vmath.vec3(22, 23, 20),
-};
-
-do
-	local writer = XmlWriter.XmlWriter("UnitCube.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(positions));
-		writer:PopElement();
-		writer:PushElement("attribute");
-			writer:AddAttribute("index", "1");
-			writer:AddAttribute("type", "float");
-			writer:AddAttribute("size", "4");
-			writer:AddText(GenStringFromArray(colors));
-		writer:PopElement();
-		writer:PushElement("attribute");
-			writer:AddAttribute("index", "2");
-			writer:AddAttribute("type", "float");
-			writer:AddAttribute("size", "3");
-			writer:AddText(GenStringFromArray(normals));
-		writer:PopElement();
-		writer:PushElement("vao");
-			writer:AddAttribute("name", "lit");
-			writer:PushElement("source"); writer:AddAttribute("attrib", "0"); writer:PopElement();
-			writer:PushElement("source"); writer:AddAttribute("attrib", "2"); writer:PopElement();
-		writer:PopElement();
-		writer:PushElement("vao");
-			writer:AddAttribute("name", "lit-color");
-			writer:PushElement("source"); writer:AddAttribute("attrib", "0"); writer:PopElement();
-			writer:PushElement("source"); writer:AddAttribute("attrib", "1"); writer:PopElement();
-			writer:PushElement("source"); writer:AddAttribute("attrib", "2"); writer:PopElement();
-		writer:PopElement();
-		writer:PushElement("vao");
-			writer:AddAttribute("name", "color");
-			writer:PushElement("source"); writer:AddAttribute("attrib", "0"); writer:PopElement();
-			writer:PushElement("source"); writer:AddAttribute("attrib", "1"); writer:PopElement();
-		writer:PopElement();
-		writer:PushElement("vao");
-			writer:AddAttribute("name", "flat");
-			writer:PushElement("source"); writer:AddAttribute("attrib", "0"); writer:PopElement();
-		writer:PopElement();
-		writer:PushElement("indices");
-			writer:AddAttribute("cmd", "triangles");
-			writer:AddAttribute("type", "ushort");
-			writer:AddText(GenStringFromArray(indices, true));
-		writer:PopElement();
-	writer:PopElement();
-	writer:Close();
-end

Tut 13 Imposters/data/GenPlane.lua

-require "XmlWriter"
-require "vmath"
-
-local function GenStringFromArray(theArray, bAsInt)
-	local array = {" "}
-	for i, vector in ipairs(theArray) do
-		local elements = vector;
-		if(bAsInt) then
-			elements = {};
-			for i, value in ipairs(vector) do
-				elements[#elements + 1] = string.format("%i", value);
-			end
-		end
-		
-		array[#array + 1] = "        " .. table.concat(vector, " ");
-	end
-	
-	return table.concat(array, "\n");
-end
-
-local positions =
-{
-	vmath.vec3(0.5, 0.0, -0.5),
-	vmath.vec3(0.5, 0.0, 0.5),
-	vmath.vec3(-0.5, 0.0, 0.5),
-	vmath.vec3(-0.5, 0.0, -0.5),
-
-	vmath.vec3(0.5, 0.0, -0.5),
-	vmath.vec3(0.5, 0.0, 0.5),
-	vmath.vec3(-0.5, 0.0, 0.5),
-	vmath.vec3(-0.5, 0.0, -0.5),
-};
-
-local largePositions =
-{
-	vmath.vec3(30.0, 0.0, -30.0),
-	vmath.vec3(30.0, 0.0, 30.0),
-	vmath.vec3(-30.0, 0.0, 30.0),
-	vmath.vec3(-30.0, 0.0, -30.0),
-
-	vmath.vec3(30.0, 0.0, -30.0),
-	vmath.vec3(30.0, 0.0, 30.0),
-	vmath.vec3(-30.0, 0.0, 30.0),
-	vmath.vec3(-30.0, 0.0, -30.0),
-};
-
-local normals =
-{
-	vmath.vec3(0.0, 1.0, 0.0),
-	vmath.vec3(0.0, 1.0, 0.0),
-	vmath.vec3(0.0, 1.0, 0.0),
-	vmath.vec3(0.0, 1.0, 0.0),
-
-	vmath.vec3(0.0, -1.0, 0.0),
-	vmath.vec3(0.0, -1.0, 0.0),
-	vmath.vec3(0.0, -1.0, 0.0),
-	vmath.vec3(0.0, -1.0, 0.0),
-};
-
-local indices =
-{
-	vmath.vec3(0, 1, 2),
-	vmath.vec3(2, 3, 0),
-
-	vmath.vec3(4, 6, 5),
-	vmath.vec3(6, 4, 7),
-};
-
-do
-	local writer = XmlWriter.XmlWriter("UnitPlane.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(positions));
-		writer:PopElement();
-		writer:PushElement("attribute");
-			writer:AddAttribute("index", "2");
-			writer:AddAttribute("type", "float");
-			writer:AddAttribute("size", "3");
-			writer:AddText(GenStringFromArray(normals));
-		writer:PopElement();
-		writer:PushElement("indices");
-			writer:AddAttribute("cmd", "triangles");
-			writer:AddAttribute("type", "ushort");
-			writer:AddText(GenStringFromArray(indices, true));
-		writer:PopElement();
-	writer:PopElement();
-	writer:Close();
-end
-
-do
-	local writer = XmlWriter.XmlWriter("LargePlane.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(largePositions));
-		writer:PopElement();
-		writer:PushElement("attribute");
-			writer:AddAttribute("index", "2");
-			writer:AddAttribute("type", "float");
-			writer:AddAttribute("size", "3");
-			writer:AddText(GenStringFromArray(normals));
-		writer:PopElement();
-		writer:PushElement("indices");
-			writer:AddAttribute("cmd", "triangles");
-			writer:AddAttribute("type", "ushort");
-			writer:AddText(GenStringFromArray(indices, true));
-		writer:PopElement();
-	writer:PopElement();
-	writer:Close();
-end

Tut 13 Imposters/data/GenSphere.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 positions = {};
-local colors = {};
-local normals = {};
-local topFan = {};
-local botFan = {};
-local strips = {};
-local restartIndex = 65535;
-
-local iSegCount, iColorRepeatCount, iRingCount = ...;
-iSegCount = iSegCount or 10;
-iColorRepeatCount = iColorRepeatCount or 3;
-iRingCount = iRingCount or 8;
-
-local rhoAngle = math.pi * 2.0 / iSegCount;
-local thetaAngle = math.pi / (iRingCount + 1);
-local iColorCycleAngle = math.pi * 2.0 / iColorRepeatCount;
-local highColor = vmath.vec4(0.9, 0.5, 0.5, 1.0);
-local lowColor = vmath.vec4(0.5, 0.1, 0.1, 1.0)
-
---Compute vertex attributes
-positions[#positions + 1] = vmath.vec3(0.0, 0.5, 0.0);
-colors[#colors + 1] = vmath.vec4(1.0, 1.0, 1.0, 1.0);
-normals[#normals + 1] = vmath.vec3(0.0, 1.0, 0.0);
-
-local firstSideIx = #positions;
-
-for iRing = 1, iRingCount do
-	local theta = (thetaAngle * iRing)
-	local sinTheta, cosTheta = math.sin(theta), math.cos(theta);
-
-	for iSeg = 0, (iSegCount - 1) do
-		local rho = rhoAngle * iSeg;
-		local sinRho, cosRho = math.sin(rho), math.cos(rho);
-		
-		local point = vmath.vec3(sinTheta * cosRho, cosTheta, sinTheta * sinRho);
-		positions[#positions + 1] = 0.5 * point;
-		normals[#normals + 1] = vmath.vec3(sinTheta * cosRho, cosTheta, sinTheta * sinRho);
-		colors[#colors + 1] = vmath.vec4(1.0, 1.0, 1.0, 1.0);
-	end
-end
-
-positions[#positions + 1] = vmath.vec3(0.0, -0.5, 0.0);
-colors[#colors + 1] = vmath.vec4(1.0, 1.0, 1.0, 1.0);
-normals[#normals + 1] = vmath.vec3(0.0, -1.0, 0.0);
-
---Compute cap fans.
-topFan[#topFan + 1] = 0;
-botFan[#botFan + 1] = #positions - 1;
-
-for iSeg = 1, iSegCount do
-	topFan[#topFan + 1] = iSeg;
-	botFan[#botFan + 1] = (#positions - 1) - iSeg;
-end
-
-topFan[#topFan + 1] = 1;
-botFan[#botFan + 1] = (#positions - 2);
-
---Compute the strips.
-
-for iRing = 1, iRingCount - 1 do
-	local topRingStart = 1 + ((iRing - 1) * iSegCount);
-	local botRingStart = 1 + (iRing * iSegCount);
-	local strip = {};
-	strips[#strips + 1] = strip;
-	
-	for iSeg = 0, (iSegCount - 1) do
-		strip[#strip + 1] = topRingStart + iSeg;
-		strip[#strip + 1] = botRingStart + iSeg;
-	end
-
-	strip[#strip + 1] = topRingStart;
-	strip[#strip + 1] = botRingStart;
-end
-
-
-do
-	local writer = XmlWriter.XmlWriter("UnitSphere.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(positions));
-		writer:PopElement();
-		writer:PushElement("attribute");
-			writer:AddAttribute("index", "1");
-			writer:AddAttribute("type", "float");
-			writer:AddAttribute("size", "4");
-			writer:AddText(GenStringFromArray(colors));
-		writer:PopElement();
-		writer:PushElement("attribute");
-			writer:AddAttribute("index", "2");
-			writer:AddAttribute("type", "float");
-			writer:AddAttribute("size", "3");
-			writer:AddText(GenStringFromArray(normals));
-		writer:PopElement();
-		writer:PushElement("vao");
-			writer:AddAttribute("name", "lit-color");
-			writer:PushElement("source"); writer:AddAttribute("attrib", "0"); writer:PopElement();
-			writer:PushElement("source"); writer:AddAttribute("attrib", "1"); writer:PopElement();
-			writer:PushElement("source"); writer:AddAttribute("attrib", "2"); writer:PopElement();
-		writer:PopElement();
-		writer:PushElement("vao");
-			writer:AddAttribute("name", "lit");
-			writer:PushElement("source"); writer:AddAttribute("attrib", "0"); writer:PopElement();
-			writer:PushElement("source"); writer:AddAttribute("attrib", "2"); writer:PopElement();
-		writer:PopElement();
-		writer:PushElement("vao");
-			writer:AddAttribute("name", "color");
-			writer:PushElement("source"); writer:AddAttribute("attrib", "0"); writer:PopElement();
-			writer:PushElement("source"); writer:AddAttribute("attrib", "1"); writer:PopElement();
-		writer:PopElement();
-		writer:PushElement("vao");
-			writer:AddAttribute("name", "flat");
-			writer:PushElement("source"); writer:AddAttribute("attrib", "0"); writer:PopElement();
-		writer:PopElement();
-		writer:PushElement("indices");
-			writer:AddAttribute("cmd", "tri-fan");
-			writer:AddAttribute("type", "ushort");
-			writer:AddText(table.concat(topFan, " "));
-		writer:PopElement();
-		writer:PushElement("indices");
-			writer:AddAttribute("cmd", "tri-fan");
-			writer:AddAttribute("type", "ushort");
-			writer:AddText(table.concat(botFan, " "));
-		writer:PopElement();
-		for i, strip in ipairs(strips) do
-			writer:PushElement("indices");
-				writer:AddAttribute("cmd", "tri-strip");
-				writer:AddAttribute("type", "ushort");
-				writer:AddText(table.concat(strip, " "));
-			writer:PopElement();
-		end
-	writer:PopElement();
-	writer:Close();
-end

Tut 13 Imposters/data/LargePlane.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" > 
-        30 0 -30
-        30 0 30
-        -30 0 30
-        -30 0 -30
-        30 0 -30
-        30 0 30
-        -30 0 30
-        -30 0 -30</attribute>
-	<attribute index="2" type="float" size="3" > 
-        0 1 0
-        0 1 0
-        0 1 0
-        0 1 0
-        0 -1 0
-        0 -1 0
-        0 -1 0
-        0 -1 0</attribute>
-	<indices cmd="triangles" type="ushort" > 
-        0 1 2
-        2 3 0
-        4 6 5
-        6 4 7</indices>
-</mesh>

Tut 13 Imposters/data/Lighting.frag

-#version 330
-
-in vec3 vertexNormal;
-in vec3 cameraSpacePosition;
-
-out vec4 outputColor;
-
-layout(std140) uniform;
-
-uniform Material
-{
-	vec4 diffuseColor;
-	vec4 specularColor;
-	float specularShininess;
-} Mtl;
-
-struct PerLight
-{
-	vec4 cameraSpaceLightPos;
-	vec4 lightIntensity;
-};
-
-const int numberOfLights = 2;
-
-uniform Light
-{
-	vec4 ambientIntensity;
-	float lightAttenuation;
-	PerLight lights[numberOfLights];
-} Lgt;
-
-
-float CalcAttenuation(in vec3 cameraSpacePosition,
-	in vec3 cameraSpaceLightPos,
-	out vec3 lightDirection)
-{
-	vec3 lightDifference =  cameraSpaceLightPos - cameraSpacePosition;
-	float lightDistanceSqr = dot(lightDifference, lightDifference);
-	lightDirection = lightDifference * inversesqrt(lightDistanceSqr);
-	
-	return (1 / ( 1.0 + Lgt.lightAttenuation * lightDistanceSqr));
-}
-
-vec4 ComputeLighting(in PerLight lightData, in vec3 cameraSpacePosition,
-	in vec3 cameraSpaceNormal)
-{
-	vec3 lightDir;
-	vec4 lightIntensity;
-	if(lightData.cameraSpaceLightPos.w == 0.0)
-	{
-		lightDir = vec3(lightData.cameraSpaceLightPos);
-		lightIntensity = lightData.lightIntensity;
-	}
-	else
-	{
-		float atten = CalcAttenuation(cameraSpacePosition,
-			lightData.cameraSpaceLightPos.xyz, lightDir);
-		lightIntensity = atten * lightData.lightIntensity;
-	}
-	
-	vec3 surfaceNormal = normalize(cameraSpaceNormal);
-	float cosAngIncidence = dot(surfaceNormal, lightDir);
-	cosAngIncidence = cosAngIncidence < 0.0001 ? 0.0 : cosAngIncidence;
-	
-	vec3 viewDirection = normalize(-cameraSpacePosition);
-	
-	vec3 halfAngle = normalize(lightDir + viewDirection);
-	float angleNormalHalf = acos(dot(halfAngle, surfaceNormal));
-	float exponent = angleNormalHalf / Mtl.specularShininess;
-	exponent = -(exponent * exponent);
-	float gaussianTerm = exp(exponent);
-
-	gaussianTerm = cosAngIncidence != 0.0 ? gaussianTerm : 0.0;
-	
-	vec4 lighting = Mtl.diffuseColor * lightIntensity * cosAngIncidence;
-	lighting += Mtl.specularColor * lightIntensity * gaussianTerm;
-	
-	return lighting;
-}
-
-void main()
-{
-	vec4 accumLighting = Mtl.diffuseColor * Lgt.ambientIntensity;
-	for(int light = 0; light < numberOfLights; light++)
-	{
-		accumLighting += ComputeLighting(Lgt.lights[light],
-			cameraSpacePosition, vertexNormal);
-	}
-	
-	outputColor = sqrt(accumLighting); //2.0 gamma correction
-}

Tut 13 Imposters/data/PN.vert

-#version 330
-
-layout(std140) uniform;
-
-layout(location = 0) in vec3 position;
-layout(location = 2) in vec3 normal;
-
-out vec3 vertexNormal;
-out vec3 cameraSpacePosition;
-
-uniform Projection
-{
-	mat4 cameraToClipMatrix;
-};
-
-uniform mat4 modelToCameraMatrix;
-uniform mat3 normalModelToCameraMatrix;
-
-void main()
-{
-	vec4 tempCamPosition = (modelToCameraMatrix * vec4(position, 1.0));
-	gl_Position = cameraToClipMatrix * tempCamPosition;
-
-	vertexNormal = normalize(normalModelToCameraMatrix * normal);
-	cameraSpacePosition = vec3(tempCamPosition);
-}

Tut 13 Imposters/data/PerspImpostor.frag

-#version 330
-
-in vec2 mapping;
-
-out vec4 outputColor;
-
-uniform float sphereRadius;
-uniform vec3 cameraSpherePos;
-
-layout(std140) uniform;
-
-uniform Material
-{
-	vec4 diffuseColor;
-	vec4 specularColor;
-	float specularShininess;
-} Mtl;
-
-struct PerLight
-{
-	vec4 cameraSpaceLightPos;
-	vec4 lightIntensity;
-};
-
-const int numberOfLights = 2;
-
-uniform Light
-{
-	vec4 ambientIntensity;
-	float lightAttenuation;
-	PerLight lights[numberOfLights];
-} Lgt;
-
-
-float CalcAttenuation(in vec3 cameraSpacePosition,
-	in vec3 cameraSpaceLightPos,
-	out vec3 lightDirection)
-{
-	vec3 lightDifference =  cameraSpaceLightPos - cameraSpacePosition;
-	float lightDistanceSqr = dot(lightDifference, lightDifference);
-	lightDirection = lightDifference * inversesqrt(lightDistanceSqr);
-	
-	return (1 / ( 1.0 + Lgt.lightAttenuation * lightDistanceSqr));
-}
-
-uniform Projection
-{
-	mat4 cameraToClipMatrix;
-};
-
-vec4 ComputeLighting(in PerLight lightData, in vec3 cameraSpacePosition,
-	in vec3 cameraSpaceNormal)
-{
-	vec3 lightDir;
-	vec4 lightIntensity;
-	if(lightData.cameraSpaceLightPos.w == 0.0)
-	{
-		lightDir = vec3(lightData.cameraSpaceLightPos);
-		lightIntensity = lightData.lightIntensity;
-	}
-	else
-	{
-		float atten = CalcAttenuation(cameraSpacePosition,
-			lightData.cameraSpaceLightPos.xyz, lightDir);
-		lightIntensity = atten * lightData.lightIntensity;
-	}
-	
-	vec3 surfaceNormal = normalize(cameraSpaceNormal);
-	float cosAngIncidence = dot(surfaceNormal, lightDir);
-	cosAngIncidence = cosAngIncidence < 0.0001 ? 0.0 : cosAngIncidence;
-	
-	vec3 viewDirection = normalize(-cameraSpacePosition);
-	
-	vec3 halfAngle = normalize(lightDir + viewDirection);
-	float angleNormalHalf = acos(dot(halfAngle, surfaceNormal));
-	float exponent = angleNormalHalf / Mtl.specularShininess;
-	exponent = -(exponent * exponent);
-	float gaussianTerm = exp(exponent);
-
-	gaussianTerm = cosAngIncidence != 0.0 ? gaussianTerm : 0.0;
-	
-	vec4 lighting = Mtl.diffuseColor * lightIntensity * cosAngIncidence;
-	lighting += Mtl.specularColor * lightIntensity * gaussianTerm;
-	
-	return lighting;
-}
-
-void Impostor(out vec3 cameraPos, out vec3 cameraNormal)
-{
-	vec3 cameraPlanePos = vec3(mapping * sphereRadius, 0.0) + cameraSpherePos;
-	vec3 rayDirection = normalize(cameraPlanePos);
-	
-	float B = 2.0 * dot(rayDirection, -cameraSpherePos);
-	float C = dot(cameraSpherePos, cameraSpherePos) - (sphereRadius * sphereRadius);
-	
-	float det = (B * B) - (4 * C);
-	if(det < 0.0)
-		discard;
-		
-	float sqrtDet = sqrt(det);
-	float posT = (-B + sqrtDet)/2;
-	float negT = (-B - sqrtDet)/2;
-	
-	float intersectT = min(posT, negT);
-	cameraPos = rayDirection * intersectT;
-	cameraNormal = normalize(cameraPos - cameraSpherePos);
-}
-
-void main()
-{
-	vec3 cameraPos;
-	vec3 cameraNormal;
-	
-	Impostor(cameraPos, cameraNormal);
-	
-	vec4 accumLighting = Mtl.diffuseColor * Lgt.ambientIntensity;
-	for(int light = 0; light < numberOfLights; light++)
-	{
-		accumLighting += ComputeLighting(Lgt.lights[light],
-			cameraPos, cameraNormal);
-	}
-	
-	outputColor = sqrt(accumLighting); //2.0 gamma correction
-}

Tut 13 Imposters/data/PerspImpostor.vert

-#version 330
-
-layout(std140) uniform;
-
-out vec2 mapping;
-
-uniform Projection
-{
-	mat4 cameraToClipMatrix;
-};
-
-uniform float sphereRadius;
-uniform vec3 cameraSpherePos;
-
-const float g_boxCorrection = 1.5;
-
-void main()
-{
-	vec2 offset;
-	switch(gl_VertexID)
-	{
-	case 0:
-		//Bottom-left
-		mapping = vec2(-1.0, -1.0) * g_boxCorrection;
-		offset = vec2(-sphereRadius, -sphereRadius);
-		break;
-	case 1:
-		//Top-left
-		mapping = vec2(-1.0, 1.0) * g_boxCorrection;
-		offset = vec2(-sphereRadius, sphereRadius);
-		break;
-	case 2:
-		//Bottom-right
-		mapping = vec2(1.0, -1.0) * g_boxCorrection;
-		offset = vec2(sphereRadius, -sphereRadius);
-		break;
-	case 3:
-		//Top-right
-		mapping = vec2(1.0, 1.0) * g_boxCorrection;
-		offset = vec2(sphereRadius, sphereRadius);
-		break;
-	}
-
-	vec4 cameraCornerPos = vec4(cameraSpherePos, 1.0);
-	cameraCornerPos.xy += offset * g_boxCorrection;
-
-	gl_Position = cameraToClipMatrix * cameraCornerPos;
-}

Tut 13 Imposters/data/UnitCube.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" > 
-        0.5 0.5 0.5
-        0.5 -0.5 0.5
-        -0.5 -0.5 0.5
-        -0.5 0.5 0.5
-        0.5 0.5 0.5
-        -0.5 0.5 0.5
-        -0.5 0.5 -0.5
-        0.5 0.5 -0.5
-        0.5 0.5 0.5
-        0.5 0.5 -0.5
-        0.5 -0.5 -0.5
-        0.5 -0.5 0.5
-        0.5 0.5 -0.5
-        -0.5 0.5 -0.5
-        -0.5 -0.5 -0.5
-        0.5 -0.5 -0.5
-        0.5 -0.5 0.5
-        0.5 -0.5 -0.5
-        -0.5 -0.5 -0.5
-        -0.5 -0.5 0.5
-        -0.5 0.5 0.5
-        -0.5 -0.5 0.5
-        -0.5 -0.5 -0.5
-        -0.5 0.5 -0.5</attribute>
-	<attribute index="1" type="float" size="4" > 
-        0.25 1 0.25 1
-        0.25 1 0.25 1
-        0.25 1 0.25 1
-        0.25 1 0.25 1
-        0.5 0.5 1 1
-        0.5 0.5 1 1
-        0.5 0.5 1 1
-        0.5 0.5 1 1
-        1 0.5 0.5 1
-        1 0.5 0.5 1
-        1 0.5 0.5 1
-        1 0.5 0.5 1
-        1 1 0.5 1
-        1 1 0.5 1
-        1 1 0.5 1
-        1 1 0.5 1
-        0.5 1 1 1
-        0.5 1 1 1
-        0.5 1 1 1
-        0.5 1 1 1
-        1 0.5 1 1
-        1 0.5 1 1
-        1 0.5 1 1
-        1 0.5 1 1</attribute>
-	<attribute index="2" type="float" size="3" > 
-        0 0 1
-        0 0 1
-        0 0 1
-        0 0 1
-        0 1 0
-        0 1 0
-        0 1 0
-        0 1 0
-        1 0 0
-        1 0 0
-        1 0 0
-        1 0 0
-        0 0 -1
-        0 0 -1
-        0 0 -1
-        0 0 -1
-        0 -1 0
-        0 -1 0
-        0 -1 0
-        0 -1 0
-        -1 0 0
-        -1 0 0
-        -1 0 0
-        -1 0 0</attribute>
-	<vao name="lit" >
-		<source attrib="0" />
-		<source attrib="2" />
-	</vao>
-	<vao name="lit-color" >
-		<source attrib="0" />
-		<source attrib="1" />
-		<source attrib="2" />
-	</vao>
-	<vao name="color" >
-		<source attrib="0" />
-		<source attrib="1" />
-	</vao>
-	<vao name="flat" >
-		<source attrib="0" />
-	</vao>
-	<indices cmd="triangles" type="ushort" > 
-        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</indices>
-</mesh>

Tut 13 Imposters/data/UnitPlane.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" > 
-        0.5 0 -0.5
-        0.5 0 0.5
-        -0.5 0 0.5
-        -0.5 0 -0.5
-        0.5 0 -0.5
-        0.5 0 0.5
-        -0.5 0 0.5
-        -0.5 0 -0.5</attribute>
-	<attribute index="2" type="float" size="3" > 
-        0 1 0
-        0 1 0
-        0 1 0
-        0 1 0
-        0 -1 0
-        0 -1 0
-        0 -1 0
-        0 -1 0</attribute>
-	<indices cmd="triangles" type="ushort" > 
-        0 1 2
-        2 3 0
-        4 6 5
-        6 4 7</indices>
-</mesh>

Tut 13 Imposters/data/UnitSphere.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" > 
-        0 0.5 0
-        0.17101007166283 0.46984631039295 0
-        0.13835005418451 0.46984631039295 0.10051719811689
-        0.052845018353093 0.46984631039295 0.16264024300704
-        -0.052845018353093 0.46984631039295 0.16264024300704
-        -0.13835005418451 0.46984631039295 0.10051719811689
-        -0.17101007166283 0.46984631039295 2.0942002032593e-017
-        -0.13835005418451 0.46984631039295 -0.10051719811689
-        -0.052845018353093 0.46984631039295 -0.16264024300704
-        0.052845018353093 0.46984631039295 -0.16264024300704
-        0.13835005418451 0.46984631039295 -0.10051719811689
-        0.32139380484327 0.38302222155949 0
-        0.26001305000503 0.38302222155949 0.18891053866504
-        0.099316147583396 0.38302222155949 0.30566367239308
-        -0.099316147583396 0.38302222155949 0.30566367239308
-        -0.26001305000503 0.38302222155949 0.18891053866504
-        -0.32139380484327 0.38302222155949 3.9358089549022e-017
-        -0.26001305000503 0.38302222155949 -0.18891053866504
-        -0.099316147583396 0.38302222155949 -0.30566367239308
-        0.099316147583396 0.38302222155949 -0.30566367239308
-        0.26001305000503 0.38302222155949 -0.18891053866504
-        0.43301270189222 0.25 0
-        0.35031463461102 0.25 0.25451848022756
-        0.13380828366491 0.25 0.41181955177317
-        -0.13380828366491 0.25 0.41181955177317
-        -0.35031463461102 0.25 0.25451848022756
-        -0.43301270189222 0.25 5.3027010602301e-017
-        -0.35031463461102 0.25 -0.25451848022756
-        -0.13380828366491 0.25 -0.41181955177317
-        0.13380828366491 0.25 -0.41181955177317
-        0.35031463461102 0.25 -0.25451848022756
-        0.4924038765061 0.086824088833465 0
-        0.39836310418954 0.086824088833465 0.28942773678193
-        0.15216116593649 0.086824088833465 0.46830391540012
-        -0.15216116593649 0.086824088833465 0.46830391540012
-        -0.39836310418954 0.086824088833465 0.28942773678193
-        -0.4924038765061 0.086824088833465 6.0300091581614e-017
-        -0.39836310418954 0.086824088833465 -0.28942773678193
-        -0.15216116593649 0.086824088833465 -0.46830391540012
-        0.15216116593649 0.086824088833465 -0.46830391540012
-        0.39836310418954 0.086824088833465 -0.28942773678193
-        0.4924038765061 -0.086824088833465 0
-        0.39836310418954 -0.086824088833465 0.28942773678193
-        0.15216116593649 -0.086824088833465 0.46830391540012
-        -0.15216116593649 -0.086824088833465 0.46830391540012
-        -0.39836310418954 -0.086824088833465 0.28942773678193
-        -0.4924038765061 -0.086824088833465 6.0300091581614e-017
-        -0.39836310418954 -0.086824088833465 -0.28942773678193
-        -0.15216116593649 -0.086824088833465 -0.46830391540012
-        0.15216116593649 -0.086824088833465 -0.46830391540012
-        0.39836310418954 -0.086824088833465 -0.28942773678193
-        0.43301270189222 -0.25 0
-        0.35031463461102 -0.25 0.25451848022756
-        0.13380828366491 -0.25 0.41181955177317
-        -0.13380828366491 -0.25 0.41181955177317
-        -0.35031463461102 -0.25 0.25451848022756
-        -0.43301270189222 -0.25 5.3027010602301e-017
-        -0.35031463461102 -0.25 -0.25451848022756
-        -0.13380828366491 -0.25 -0.41181955177317
-        0.13380828366491 -0.25 -0.41181955177317
-        0.35031463461102 -0.25 -0.25451848022756
-        0.32139380484327 -0.38302222155949 0
-        0.26001305000503 -0.38302222155949 0.18891053866504
-        0.099316147583396 -0.38302222155949 0.30566367239308
-        -0.099316147583396 -0.38302222155949 0.30566367239308
-        -0.26001305000503 -0.38302222155949 0.18891053866504
-        -0.32139380484327 -0.38302222155949 3.9358089549022e-017
-        -0.26001305000503 -0.38302222155949 -0.18891053866504
-        -0.099316147583396 -0.38302222155949 -0.30566367239308
-        0.099316147583396 -0.38302222155949 -0.30566367239308
-        0.26001305000503 -0.38302222155949 -0.18891053866504
-        0.17101007166283 -0.46984631039295 0
-        0.13835005418451 -0.46984631039295 0.10051719811689
-        0.052845018353093 -0.46984631039295 0.16264024300704
-        -0.052845018353093 -0.46984631039295 0.16264024300704