Jason McKesson avatar Jason McKesson committed 05ffdcf

Tut16: Checkers and gamma correction code done.

Comments (0)

Files changed (8)

Tut 16 Gamma and Textures/Gamma Checkers.cpp

+#include <string>
+#include <vector>
+#include <stack>
+#include <math.h>
+#include <stdio.h>
+#include <sstream>
+#include <memory>
+#include <glimg/glimg.h>
+#include <glimg/TextureGenerator.h>
+#include <glload/gl_3_3.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 "../framework/directories.h"
+#include <glm/glm.hpp>
+#include <glm/gtc/type_ptr.hpp>
+#include <glm/gtc/matrix_transform.hpp>
+
+#define ARRAY_COUNT( array ) (sizeof( array ) / (sizeof( array[0] ) * (sizeof( array ) != sizeof(void*) || sizeof( array[0] ) <= sizeof(void*))))
+
+struct ProgramData
+{
+	GLuint theProgram;
+
+	GLuint modelToCameraMatrixUnif;
+};
+
+float g_fzNear = 1.0f;
+float g_fzFar = 1000.0f;
+
+ProgramData g_progNoGamma;
+ProgramData g_progGamma;
+
+const int g_projectionBlockIndex = 0;
+const int g_colorTexUnit = 0;
+
+ProgramData LoadProgram(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));
+
+	ProgramData data;
+	data.theProgram = Framework::CreateProgram(shaderList);
+	data.modelToCameraMatrixUnif = glGetUniformLocation(data.theProgram, "modelToCameraMatrix");
+
+	GLuint projectionBlock = glGetUniformBlockIndex(data.theProgram, "Projection");
+
+	glUniformBlockBinding(data.theProgram, projectionBlock, g_projectionBlockIndex);
+
+	GLuint colorTextureUnif = glGetUniformLocation(data.theProgram, "colorTexture");
+	glUseProgram(data.theProgram);
+	glUniform1i(colorTextureUnif, g_colorTexUnit);
+	glUseProgram(0);
+
+	return data;
+}
+
+void InitializePrograms()
+{
+	g_progNoGamma = LoadProgram("PT.vert", "textureNoGamma.frag");
+	g_progGamma = LoadProgram("PT.vert", "textureGamma.frag");
+}
+
+struct ProjectionBlock
+{
+	glm::mat4 cameraToClipMatrix;
+};
+
+GLuint g_projectionUniformBuffer = 0;
+GLuint g_linearTexture = 0;
+GLuint g_gammaTexture = 0;
+
+const int NUM_SAMPLERS = 2;
+GLuint g_samplers[NUM_SAMPLERS];
+
+void CreateSamplers()
+{
+	glGenSamplers(NUM_SAMPLERS, &g_samplers[0]);
+
+	for(int samplerIx = 0; samplerIx < NUM_SAMPLERS; samplerIx++)
+	{
+		glSamplerParameteri(g_samplers[samplerIx], GL_TEXTURE_WRAP_S, GL_REPEAT);
+		glSamplerParameteri(g_samplers[samplerIx], GL_TEXTURE_WRAP_T, GL_REPEAT);
+	}
+
+	//Linear mipmap linear
+	glSamplerParameteri(g_samplers[0], GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+	glSamplerParameteri(g_samplers[0], GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+
+	//Max anisotropic
+	GLfloat maxAniso = 0.0f;
+	glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAniso);
+
+	glSamplerParameteri(g_samplers[1], GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+	glSamplerParameteri(g_samplers[1], GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+	glSamplerParameterf(g_samplers[1], GL_TEXTURE_MAX_ANISOTROPY_EXT, maxAniso);
+}
+
+void LoadCheckerTextures()
+{
+	try
+	{
+		std::string filename(LOCAL_FILE_DIR);
+		filename += "checker_linear.dds";
+
+		std::auto_ptr<glimg::ImageSet> pImageSet(glimg::loaders::dds::LoadFromFile(filename.c_str()));
+
+		glGenTextures(1, &g_linearTexture);
+		glBindTexture(GL_TEXTURE_2D, g_linearTexture);
+
+		for(int mipmapLevel = 0; mipmapLevel < pImageSet->GetMipmapCount(); mipmapLevel++)
+		{
+			glimg::SingleImage image = pImageSet->GetImage(mipmapLevel, 0, 0);
+			glimg::Dimensions dims = image.GetDimensions();
+
+			glTexImage2D(GL_TEXTURE_2D, mipmapLevel, GL_SRGB8, dims.width, dims.height, 0,
+				GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, image.GetImageData());
+		}
+
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, pImageSet->GetMipmapCount() - 1);
+
+		filename = std::string(LOCAL_FILE_DIR) + "checker_gamma.dds";
+
+		pImageSet.reset(glimg::loaders::dds::LoadFromFile(filename.c_str()));
+
+		glGenTextures(1, &g_gammaTexture);
+		glBindTexture(GL_TEXTURE_2D, g_gammaTexture);
+
+		for(int mipmapLevel = 0; mipmapLevel < pImageSet->GetMipmapCount(); mipmapLevel++)
+		{
+			glimg::SingleImage image = pImageSet->GetImage(mipmapLevel, 0, 0);
+			glimg::Dimensions dims = image.GetDimensions();
+
+			glTexImage2D(GL_TEXTURE_2D, mipmapLevel, GL_SRGB8, dims.width, dims.height, 0,
+				GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, image.GetImageData());
+		}
+
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, pImageSet->GetMipmapCount() - 1);
+		glBindTexture(GL_TEXTURE_2D, 0);
+	}
+	catch(std::exception &e)
+	{
+		printf("%s\n", e.what());
+		throw;
+	}
+}
+
+Framework::Mesh *g_pPlane = NULL;
+Framework::Mesh *g_pCorridor = NULL;
+
+//Called after the window and OpenGL are initialized. Called exactly once, before the main loop.
+void init()
+{
+	InitializePrograms();
+
+	try
+	{
+		g_pCorridor = new Framework::Mesh("Corridor.xml");
+		g_pPlane = new Framework::Mesh("BigPlane.xml");
+	}
+	catch(std::exception &except)
+	{
+		printf("%s\n", except.what());
+		throw;
+	}
+
+	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_projectionUniformBuffer);
+	glBindBuffer(GL_UNIFORM_BUFFER, g_projectionUniformBuffer);
+	glBufferData(GL_UNIFORM_BUFFER, sizeof(ProjectionBlock), NULL, GL_DYNAMIC_DRAW);
+
+	glBindBufferRange(GL_UNIFORM_BUFFER, g_projectionBlockIndex, g_projectionUniformBuffer,
+		0, sizeof(ProjectionBlock));
+
+	glBindBuffer(GL_UNIFORM_BUFFER, 0);
+
+	LoadCheckerTextures();
+	CreateSamplers();
+}
+
+using Framework::Timer;
+
+Timer g_camTimer = Timer(Timer::TT_LOOP, 5.0f);
+int g_currSampler = 0;
+
+bool g_drawCorridor = false;
+bool g_drawGammaTexture = false;
+bool g_drawGammaProgram = 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()
+{
+	glClearColor(0.75f, 0.75f, 1.0f, 1.0f);
+	glClearDepth(1.0f);
+	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+	if(g_pPlane && g_pCorridor)
+	{
+		g_camTimer.Update();
+
+		float cyclicAngle = g_camTimer.GetAlpha() * 6.28f;
+		float hOffset = cosf(cyclicAngle) * 0.25f;
+		float vOffset = sinf(cyclicAngle) * 0.25f;
+
+		Framework::MatrixStack modelMatrix;
+		const glm::mat4 &worldToCamMat = glm::lookAt(
+			glm::vec3(hOffset, 1.0f, -64.0f),
+			glm::vec3(hOffset, -5.0f + vOffset, -44.0f),
+			glm::vec3(0.0f, 1.0f, 0.0f));
+
+		modelMatrix.ApplyMatrix(worldToCamMat);
+
+		{
+			Framework::MatrixStackPusher push(modelMatrix);
+
+			const ProgramData &prog = g_drawGammaProgram ? g_progGamma : g_progNoGamma;
+
+			glUseProgram(prog.theProgram);
+			glUniformMatrix4fv(prog.modelToCameraMatrixUnif, 1, GL_FALSE,
+				glm::value_ptr(modelMatrix.Top()));
+
+ 			glActiveTexture(GL_TEXTURE0 + g_colorTexUnit);
+			glBindTexture(GL_TEXTURE_2D, g_drawGammaTexture ? g_gammaTexture : g_linearTexture);
+ 			glBindSampler(g_colorTexUnit, g_samplers[g_currSampler]);
+
+			if(g_drawCorridor)
+				g_pCorridor->Render("tex");
+			else
+				g_pPlane->Render("tex");
+
+ 			glBindSampler(g_colorTexUnit, 0);
+ 			glBindTexture(GL_TEXTURE_2D, 0);
+
+			glUseProgram(0);
+		}
+	}
+
+	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(90.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_pPlane;
+		delete g_pCorridor;
+		g_pPlane = NULL;
+		g_pCorridor = NULL;
+		glutLeaveMainLoop();
+		return;
+	case 'a':
+		g_drawGammaProgram = !g_drawGammaProgram;
+		break;
+	case 'g':
+		g_drawGammaTexture = !g_drawGammaTexture;
+		break;
+	case 32:
+		g_drawGammaProgram = !g_drawGammaProgram;
+		g_drawGammaTexture = !g_drawGammaTexture;
+		break;
+	case 'y':
+		g_drawCorridor = !g_drawCorridor;
+		break;
+	case 'p':
+		g_camTimer.TogglePause();
+		break;
+	}
+
+	printf("----\n");
+	printf("Rendering:\t\t%s\n", g_drawGammaProgram ? "Gamma" : "Linear");
+	printf("Mipmap Generation:\t%s\n", g_drawGammaTexture ? "Gamma" : "Linear");
+
+	if(('1' <= key) && (key <= '9'))
+	{
+		int number = key - '1';
+		if(number < NUM_SAMPLERS)
+		{
+			g_currSampler = number;
+		}
+	}
+}
+
+unsigned int defaults(unsigned int displayMode, int &width, int &height) {return displayMode;}

Tut 16 Gamma and Textures/GammaRamp.cpp

 
 	glActiveTexture(GL_TEXTURE0 + g_gammaRampTextureUnit);
 	glBindTexture(GL_TEXTURE_2D, g_textures[g_useGammaCorrect[0] ? 1 : 0]);
+	glBindSampler(g_gammaRampTextureUnit, g_samplerObj);
 
 	glBindVertexArray(g_vao);
 
 
 	glActiveTexture(GL_TEXTURE0 + g_gammaRampTextureUnit);
 	glBindTexture(GL_TEXTURE_2D, 0);
+	glBindSampler(g_gammaRampTextureUnit, 0);
 
 	glutSwapBuffers();
 	glutPostRedisplay();

Tut 16 Gamma and Textures/data/BigPlane.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" > 
+        64 0 -64
+        64 0 64
+        -64 0 64
+        -64 0 -64
+        64 0 -64
+        64 0 64
+        -64 0 64
+        -64 0 -64</attribute>
+	<attribute index="5" type="float" size="2" > 
+        64 -64
+        64 64
+        -64 64
+        -64 -64
+        64 -64
+        64 64
+        -64 64
+        -64 -64</attribute>
+	<vao name="flat" >
+		<source attrib="0" />
+	</vao>
+	<vao name="tex" >
+		<source attrib="0" />
+		<source attrib="5" />
+	</vao>
+	<indices cmd="triangles" type="ushort" > 
+        0 1 2
+        2 3 0
+        4 6 5
+        6 4 7</indices>
+</mesh>

Tut 16 Gamma and Textures/data/Corridor.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" > 
+        1 0 -64
+        1 0 64
+        -1 0 64
+        -1 0 -64
+        -1 0 -64
+        -1 0 64
+        -1 2 64
+        -1 2 -64
+        1 0 64
+        1 0 -64
+        1 2 -64
+        1 2 64
+        1 2 64
+        1 2 -64
+        -1 2 -64
+        -1 2 64</attribute>
+	<attribute index="5" type="float" size="2" > 
+        1 -64
+        1 64
+        -1 64
+        -1 -64
+        1 -64
+        1 64
+        -1 64
+        -1 -64
+        1 -64
+        1 64
+        -1 64
+        -1 -64
+        1 -64
+        1 64
+        -1 64
+        -1 -64</attribute>
+	<vao name="flat" >
+		<source attrib="0" />
+	</vao>
+	<vao name="tex" >
+		<source attrib="0" />
+		<source attrib="5" />
+	</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</indices>
+</mesh>

Tut 16 Gamma and Textures/data/GenBigPlane.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( 64.0, 0.0, -64.0),
+	vmath.vec3( 64.0, 0.0,  64.0),
+	vmath.vec3(-64.0, 0.0,  64.0),
+	vmath.vec3(-64.0, 0.0, -64.0),
+
+	vmath.vec3( 64.0, 0.0, -64.0),
+	vmath.vec3( 64.0, 0.0,  64.0),
+	vmath.vec3(-64.0, 0.0,  64.0),
+	vmath.vec3(-64.0, 0.0, -64.0),
+};
+
+local texCoords =
+{
+	vmath.vec2(64.0, -64.0),
+	vmath.vec2(64.0, 64.0),
+	vmath.vec2(-64.0, 64.0),
+	vmath.vec2(-64.0, -64.0),
+
+	vmath.vec2(64.0, -64.0),
+	vmath.vec2(64.0, 64.0),
+	vmath.vec2(-64.0, 64.0),
+	vmath.vec2(-64.0, -64.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("BigPlane.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", "5");
+			writer:AddAttribute("type", "float");
+			writer:AddAttribute("size", "2");
+			writer:AddText(GenStringFromArray(texCoords));
+		writer:PopElement();
+		writer:PushElement("vao");
+			writer:AddAttribute("name", "flat");
+			writer:PushElement("source"); writer:AddAttribute("attrib", "0"); writer:PopElement();
+		writer:PopElement();
+		writer:PushElement("vao");
+			writer:AddAttribute("name", "tex");
+			writer:PushElement("source"); writer:AddAttribute("attrib", "0"); writer:PopElement();
+			writer:PushElement("source"); writer:AddAttribute("attrib", "5"); 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 16 Gamma and Textures/data/GenCorridor.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 halfWidth = 1.0;
+
+local positions =
+{
+	vmath.vec3( halfWidth, 0.0, -64.0),
+	vmath.vec3( halfWidth, 0.0,  64.0),
+	vmath.vec3(-halfWidth, 0.0,  64.0),
+	vmath.vec3(-halfWidth, 0.0, -64.0),
+	
+	vmath.vec3(-halfWidth, 0.0,           -64.0),
+	vmath.vec3(-halfWidth, 0.0,            64.0),
+	vmath.vec3(-halfWidth, halfWidth * 2,  64.0),
+	vmath.vec3(-halfWidth, halfWidth * 2, -64.0),
+	
+	vmath.vec3( halfWidth, 0.0,            64.0),
+	vmath.vec3( halfWidth, 0.0,           -64.0),
+	vmath.vec3( halfWidth, halfWidth * 2, -64.0),
+	vmath.vec3( halfWidth, halfWidth * 2,  64.0),
+
+	vmath.vec3( halfWidth, halfWidth * 2,  64.0),
+	vmath.vec3( halfWidth, halfWidth * 2, -64.0),
+	vmath.vec3(-halfWidth, halfWidth * 2, -64.0),
+	vmath.vec3(-halfWidth, halfWidth * 2,  64.0),
+};
+
+local texCoords =
+{
+	vmath.vec2( halfWidth, -64.0),
+	vmath.vec2( halfWidth,  64.0),
+	vmath.vec2(-halfWidth,  64.0),
+	vmath.vec2(-halfWidth, -64.0),
+
+	vmath.vec2( halfWidth, -64.0),
+	vmath.vec2( halfWidth,  64.0),
+	vmath.vec2(-halfWidth,  64.0),
+	vmath.vec2(-halfWidth, -64.0),
+
+	vmath.vec2( halfWidth, -64.0),
+	vmath.vec2( halfWidth,  64.0),
+	vmath.vec2(-halfWidth,  64.0),
+	vmath.vec2(-halfWidth, -64.0),
+
+	vmath.vec2( halfWidth, -64.0),
+	vmath.vec2( halfWidth,  64.0),
+	vmath.vec2(-halfWidth,  64.0),
+	vmath.vec2(-halfWidth, -64.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),
+};
+
+do
+	local writer = XmlWriter.XmlWriter("Corridor.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", "5");
+			writer:AddAttribute("type", "float");
+			writer:AddAttribute("size", "2");
+			writer:AddText(GenStringFromArray(texCoords));
+		writer:PopElement();
+		writer:PushElement("vao");
+			writer:AddAttribute("name", "flat");
+			writer:PushElement("source"); writer:AddAttribute("attrib", "0"); writer:PopElement();
+		writer:PopElement();
+		writer:PushElement("vao");
+			writer:AddAttribute("name", "tex");
+			writer:PushElement("source"); writer:AddAttribute("attrib", "0"); writer:PopElement();
+			writer:PushElement("source"); writer:AddAttribute("attrib", "5"); 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 16 Gamma and Textures/data/PT.vert

+#version 330
+
+layout(std140) uniform;
+
+layout(location = 0) in vec3 position;
+layout(location = 5) in vec2 texCoord;
+
+out vec2 colorCoord;
+
+uniform Projection
+{
+	mat4 cameraToClipMatrix;
+};
+
+uniform mat4 modelToCameraMatrix;
+
+void main()
+{
+	gl_Position = cameraToClipMatrix * (modelToCameraMatrix * vec4(position, 1.0));
+	colorCoord = texCoord;
+}

Tut 16 Gamma and Textures/tutorials.lua

 
-SetupProject("Tut 16 Gamma Ramp", "GammaRamp.cpp", "data/standard.vert", "data/standard.frag")
+SetupProject("Tut 16 Gamma Ramp", "GammaRamp.cpp",
+	"data/screenCoords.vert",
+	"data/textureGamma.frag", "data/textureNoGamma.frag")
+
+SetupProject("Tut 16 Gamma Checkers", "Gamma Checkers.cpp",
+	"data/PT.vert",
+	"data/textureGamma.frag", "data/textureNoGamma.frag")
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.