Jason McKesson avatar Jason McKesson committed cbb3d8d

Tut18: basic scene partially setup.

Comments (0)

Files changed (13)

Documents/sceneFormat.rnc

         element scn:scene { sc.scene.content }
 
     sc.scene.content =
-        (sc.mesh | sc.texture | sc.prog | sc.node)+
+        (sc.mesh | sc.texture | sc.prog | sc.node | sc.camera )+
         
     sc.mesh =
         ##A mesh to load. Meshes have a name and a filename.
         sc.node.texture.attlist
         
     sc.node.variant =
+        ##Associates a named variant, which can have different shaders and textures.
         element scn:variant { sc.node.variant.content }
         
     sc.node.variant.content =
         sc.node.variant.attlist, sc.node.texture*
        
+    sc.camera =
+        ##Defines the attributes of a named camera.
+        element scn:camera { sc.camera.content }
+        
+    sc.camera.content =
+        sc.camera.attlist
 }
 
 ##Attributes
         sc.variant.name.attribute,
         (sc.node.prog.attribute | sc.variant.base.attribute)
     
+    sc.camera.attlist =
+        sc.xml.id.attribute,
+        sc.camera.start-pos.attribute,
+        sc.camera.start-orient.attribute,
+        sc.camera.start-radius.attribute,
+        sc.camera.start-up-spin.attribute,
+        sc.camera.radius-limits.attribute,
+        sc.camera.radius-deltas.attribute,
+        sc.camera.pos-deltas.attribute,
+        sc.camera.rotation-scale.attribute
+    
     sc.xml.id.attribute =
         ##Uniquely named object
         attribute xml:id { xsd:ID }
         
     sc.node.pos.attribute =
         ##The position of the object in world-space.
-        attribute pos { text }
+        attribute pos { acc.position3d.type }
         
     sc.node.orient.attribute =
         ##The orientation of the object in world-space, as a quaternion. In XYZW format.
-        attribute orient { text }
+        attribute orient { acc.quaternion.type }
         
     sc.node.scale.attribute =
         ##The scale of the object in world-space. Can be one float or 3.
-        attribute scale { text }
+        attribute scale { acc.position3d.type }
         
     sc.note.name.attribute =
         ##The name of an annotation in a node. The note name must be unique within the node.
         attribute name { text }
         
     sc.variant.base.attribute =
-        ##The presence of this attribute means that the default variant should be used.
+        ##The presence of this attribute means that the default variant's data should be used.
         attribute base { empty }
+        
+    sc.camera.start-pos.attribute =
+        ##Initial camera position
+        attribute start-pos { acc.position3d.type }
+        
+    sc.camera.start-orient.attribute =
+        ##Initial camera orientation
+        attribute start-orient { acc.quaternion.type }
+        
+    sc.camera.start-radius.attribute =
+        ##Initial distance from rotate position
+        attribute start-radius { xsd:decimal }
+        
+    sc.camera.start-up-spin.attribute =
+        ##Initial up vector spin, in degrees, relative to the start-orient
+        attribute start-up-spin { xsd:decimal }
+        
+    sc.camera.radius-limits.attribute =
+        ##The smallest and largest allowed radius values.
+        attribute radius-limits { text }
+        
+    sc.camera.radius-deltas.attribute =
+        ##The small and large values incremented with wheel up/down motions.
+        attribute radius-deltas { text }
+        
+    sc.camera.pos-deltas.attribute =
+        ##The large and small values added to the camera position.
+        attribute pos-deltas { text }
+        
+    sc.camera.rotation-scale.attribute =
+        ##The scale factor for rotations. Larger means faster rotation.
+        attribute rotation-scale { xsd:decimal }
 }
 
 ## Accessories
     acc.filename.type = text
     acc.attribute.type =
         xsd:nonNegativeInteger { minInclusive = "0" maxExclusive = "16"}
+        
+    acc.position3d.type = text
+    acc.quaternion.type = text
 }

Tut 18 Bumpy Textures/Bumpy Square.cpp

+#include <string>
+#include <vector>
+#include <exception>
+#include <memory>
+#include <stdio.h>
+#include <glload/gl_3_3.h>
+#include <glimg/glimg.h>
+#include <GL/freeglut.h>
+#include <glutil/MatrixStack.h>
+#include <glutil/MousePoles.h>
+#include "../framework/framework_all.h"
+#include <glm/glm.hpp>
+#include <glm/gtc/type_ptr.hpp>
+#include <glm/gtc/quaternion.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*))))
+
+const float g_fzNear = 0.1f;
+const float g_fzFar = 100.0f;
+
+const int g_projectionBlockIndex = 0;
+const int g_lightBlockIndex = 1;
+
+struct ProjectionBlock
+{
+	glm::mat4 cameraToClipMatrix;
+};
+
+GLuint g_projectionUniformBuffer = 0;
+GLuint g_lightUniformBuffer = 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_MAG_FILTER, GL_LINEAR);
+		glSamplerParameteri(g_samplers[samplerIx], GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+	}
+
+	glSamplerParameteri(g_samplers[0], GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+	glSamplerParameteri(g_samplers[0], GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+	glSamplerParameteri(g_samplers[1], GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
+	glSamplerParameteri(g_samplers[1], GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
+
+	float color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+	glSamplerParameterfv(g_samplers[1], GL_TEXTURE_BORDER_COLOR, color);
+}
+*/
+
+/*
+struct TexDef { const char *filename; const char *name; };
+
+TexDef g_texDefs[] =
+{
+	{"Flashlight.dds", "Flashlight"},
+	{"PointsOfLight.dds", "Multiple Point Lights"},
+	{"Bands.dds", "Light Bands"},
+};
+
+GLuint g_lightTextures[ARRAY_COUNT(g_texDefs)];
+const int NUM_LIGHT_TEXTURES = ARRAY_COUNT(g_texDefs);
+int g_currTextureIndex = 0;
+
+void LoadTextures()
+{
+	try
+	{
+		for(int tex = 0; tex < NUM_LIGHT_TEXTURES; ++tex)
+		{
+			std::string filename(Framework::FindFileOrThrow(g_texDefs[tex].filename));
+
+			std::auto_ptr<glimg::ImageSet> pImageSet(glimg::loaders::dds::LoadFromFile(filename.c_str()));
+			g_lightTextures[tex] = glimg::CreateTexture(pImageSet.get(), 0);
+		}
+	}
+	catch(std::exception &e)
+	{
+		printf("%s\n", e.what());
+		throw;
+	}
+}
+*/
+
+glutil::ViewPole *g_pViewPole = NULL;
+
+namespace
+{
+	void MouseMotion(int x, int y)
+	{
+		if(g_pViewPole)
+			Framework::ForwardMouseMotion(*g_pViewPole, x, y);
+	}
+
+	void MouseButton(int button, int state, int x, int y)
+	{
+		if(g_pViewPole)
+			Framework::ForwardMouseButton(*g_pViewPole, button, state, x, y);
+	}
+
+	void MouseWheel(int wheel, int direction, int x, int y)
+	{
+		if(g_pViewPole)
+			Framework::ForwardMouseWheel(*g_pViewPole, wheel, direction, x, y);
+	}
+}
+
+Framework::Scene *g_pScene = NULL;
+std::vector<Framework::NodeRef> g_nodes;
+Framework::Timer g_timer(Framework::Timer::TT_LOOP, 10.0f);
+
+Framework::UniformIntBinder g_lightNumBinder;
+
+GLint g_unlitModelToCameraMatrixUnif;
+GLint g_unlitObjectColorUnif;
+GLuint g_unlitProg;
+Framework::Mesh *g_pSphereMesh = NULL;
+
+void LoadAndSetupScene()
+{
+	std::auto_ptr<Framework::Scene> pScene(new Framework::Scene("bump_square_scene.xml"));
+
+	std::vector<Framework::NodeRef> nodes = pScene->GetAllNodes();
+
+	AssociateUniformWithNodes(nodes, g_lightNumBinder, "numberOfLights");
+	SetStateBinderWithNodes(nodes, g_lightNumBinder);
+	
+	GLuint unlit = pScene->FindProgram("p_unlit");
+	Framework::Mesh *pSphereMesh = pScene->FindMesh("m_sphere");
+
+	std::auto_ptr<glutil::ViewPole> pViewPole(pScene->CreateCamera("c_main", glutil::MB_LEFT_BTN));
+	if(pViewPole.get() == NULL)
+		throw std::runtime_error("Could not find the main camera in the scene.");
+
+	//No more things that can throw.
+	g_unlitProg = unlit;
+	g_unlitModelToCameraMatrixUnif = glGetUniformLocation(unlit, "modelToCameraMatrix");
+	g_unlitObjectColorUnif = glGetUniformLocation(unlit, "objectColor");
+
+	std::swap(nodes, g_nodes);
+	nodes.clear();	//If something was there already, delete it.
+
+	std::swap(pSphereMesh, g_pSphereMesh);
+
+	glutil::ViewPole *pTemp = g_pViewPole;
+	g_pViewPole = pViewPole.release();
+	pViewPole.reset(pTemp);		//If something was there already, delete it.
+
+	Framework::Scene *pOldScene = g_pScene;
+	g_pScene = pScene.release();
+	pScene.reset(pOldScene);	//If something was there already, delete it.
+}
+
+struct PerLight
+{
+	glm::vec4 cameraSpaceLightPos;
+	glm::vec4 lightIntensity;
+};
+
+const int MAX_NUMBER_OF_LIGHTS = 4;
+
+struct LightBlock
+{
+	glm::vec4 ambientIntensity;
+	float lightAttenuation;
+	float maxIntensity;
+	float padding[2];
+	PerLight lights[MAX_NUMBER_OF_LIGHTS];
+};
+
+
+//Called after the window and OpenGL are initialized. Called exactly once, before the main loop.
+void init()
+{
+	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);
+	glEnable(GL_FRAMEBUFFER_SRGB);
+
+	//Setup our Uniform Buffers
+	glGenBuffers(1, &g_projectionUniformBuffer);
+	glBindBuffer(GL_UNIFORM_BUFFER, g_projectionUniformBuffer);
+	glBufferData(GL_UNIFORM_BUFFER, sizeof(ProjectionBlock), NULL, GL_STREAM_DRAW);
+
+	glBindBufferRange(GL_UNIFORM_BUFFER, g_projectionBlockIndex, g_projectionUniformBuffer,
+		0, sizeof(ProjectionBlock));
+
+//	CreateSamplers();
+//	LoadTextures();
+
+	try
+	{
+		LoadAndSetupScene();
+	}
+	catch(std::exception &except)
+	{
+		printf("%s\n", except.what());
+		throw;
+	}
+
+	glGenBuffers(1, &g_lightUniformBuffer);
+	glBindBuffer(GL_UNIFORM_BUFFER, g_lightUniformBuffer);
+	glBufferData(GL_UNIFORM_BUFFER, sizeof(LightBlock), NULL, GL_STREAM_DRAW);
+
+	glBindBufferRange(GL_UNIFORM_BUFFER, g_lightBlockIndex, g_lightUniformBuffer,
+		0, sizeof(LightBlock));
+
+	glBindBuffer(GL_UNIFORM_BUFFER, 0);
+}
+
+using Framework::Timer;
+
+// int g_currSampler = 0;
+
+bool g_bDrawCameraPos = false;
+bool g_bShowOtherLights = true;
+
+int g_displayWidth = 500;
+int g_displayHeight = 500;
+
+void BuildLights( const glm::mat4 &camMatrix )
+{
+	LightBlock lightData;
+	lightData.ambientIntensity = glm::vec4(0.2f, 0.2f, 0.2f, 1.0f);
+	lightData.lightAttenuation = 1.0f / (30.0f * 30.0f);
+	lightData.maxIntensity = 4.0f;
+	lightData.lights[0].lightIntensity = glm::vec4(0.2f, 0.2f, 0.2f, 1.0f);
+	lightData.lights[0].cameraSpaceLightPos = camMatrix *
+		glm::normalize(glm::vec4(-0.2f, 0.5f, 0.5f, 0.0f));
+	lightData.lights[1].lightIntensity = glm::vec4(5.0f, 5.0f, 5.0f, 1.0f);
+	lightData.lights[1].cameraSpaceLightPos = camMatrix *
+		glm::vec4(5.0f, 6.0f, 0.5f, 1.0f);
+
+	g_lightNumBinder.SetValue(2);
+
+	glBindBuffer(GL_UNIFORM_BUFFER, g_lightUniformBuffer);
+	glBufferData(GL_UNIFORM_BUFFER, sizeof(LightBlock), &lightData, GL_STREAM_DRAW);
+}
+
+//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()
+{
+	if(!g_pScene)
+		return;
+
+	g_timer.Update();
+
+	glClearColor(0.8f, 0.8f, 0.8f, 1.0f);
+	glClearDepth(1.0f);
+	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+	const glm::mat4 &cameraMatrix = g_pViewPole->CalcMatrix();
+
+	glutil::MatrixStack modelMatrix;
+	modelMatrix *= cameraMatrix;
+
+	BuildLights(cameraMatrix);
+
+	{
+		glViewport(0, 0, (GLsizei)g_displayWidth, (GLsizei)g_displayHeight);
+		glutil::MatrixStack persMatrix;
+		persMatrix.Perspective(60.0f, (g_displayWidth / (float)g_displayHeight), g_fzNear, g_fzFar);
+
+		ProjectionBlock projData;
+		projData.cameraToClipMatrix = persMatrix.Top();
+
+		glBindBuffer(GL_UNIFORM_BUFFER, g_projectionUniformBuffer);
+		glBufferData(GL_UNIFORM_BUFFER, sizeof(ProjectionBlock), &projData, GL_STREAM_DRAW);
+		glBindBuffer(GL_UNIFORM_BUFFER, 0);
+	}
+
+	g_pScene->Render(modelMatrix.Top());
+
+	if(g_bDrawCameraPos)
+	{
+		//Draw lookat point.
+		glutil::PushStack stackPush(modelMatrix);
+		modelMatrix.SetIdentity();
+		modelMatrix.Translate(glm::vec3(0.0f, 0.0f, -g_pViewPole->GetView().radius));
+		modelMatrix.Scale(0.125f);
+
+		glDisable(GL_DEPTH_TEST);
+		glDepthMask(GL_FALSE);
+		glUseProgram(g_unlitProg);
+		glUniformMatrix4fv(g_unlitModelToCameraMatrixUnif, 1, GL_FALSE,
+			glm::value_ptr(modelMatrix.Top()));
+		glUniform4f(g_unlitObjectColorUnif, 0.25f, 0.25f, 0.25f, 1.0f);
+		g_pSphereMesh->Render("flat");
+		glDepthMask(GL_TRUE);
+		glEnable(GL_DEPTH_TEST);
+		glUniform4f(g_unlitObjectColorUnif, 1.0f, 1.0f, 1.0f, 1.0f);
+		g_pSphereMesh->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)
+{
+	g_displayWidth = w;
+	g_displayHeight = 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_pScene;
+		g_pScene = NULL;
+		glutLeaveMainLoop();
+		return;
+	case 32:
+/*
+		if(g_pViewPole)
+		{
+			const glutil::ViewData &view = g_pViewPole->GetView();
+			printf("%f  %f  %f  %f\n", view.orient.x, view.orient.y, view.orient.z, view.orient.w);
+		}
+*/
+		break;
+	case 't':
+		g_bDrawCameraPos = !g_bDrawCameraPos;
+		break;
+	case 'g':
+		g_bShowOtherLights = !g_bShowOtherLights;
+		break;
+	case 'p':
+		g_timer.TogglePause();
+		break;
+	case '\r': //Enter key.
+		{
+			try
+			{
+				LoadAndSetupScene();
+			}
+			catch(std::exception &except)
+			{
+				printf("Failed to reload, due to: %s\n", except.what());
+				return;
+			}
+		}
+		break;
+	}
+
+	if(g_pViewPole)
+		g_pViewPole->CharPress(key);
+}
+
+unsigned int defaults(unsigned int displayMode, int &width, int &height)
+{
+	g_displayWidth = width;
+	g_displayHeight = height;
+	return displayMode | GLUT_SRGB;
+}
+

Tut 18 Bumpy Textures/data/bump_square_scene.xml

+<?xml version="1.0" encoding="UTF-8"?>
+<?oxygen RNGSchema="../../Documents/sceneFormat.rnc" type="compact"?>
+<scene xmlns="http://www.arcsynthesis.com/gltut/scene">
+    <mesh xml:id="m_sphere" file="UnitSphere.xml"/>
+    <mesh xml:id="m_cube" file="UnitCube.xml"/>
+    <mesh xml:id="m_plane" file="UnitPlane.xml"/>
+    <mesh xml:id="m_square" file="UnitPlane.xml"/>
+    
+    <texture xml:id="t_sandy_ground" file="dsc_1621_small.dds"/>
+    <texture xml:id="t_bump_texture" file="dsc_1621_small.dds"/>
+    <prog
+        xml:id="p_litBump"
+        vert="litBump.vert"
+        frag="litBump.frag"
+        model-to-camera="modelToCameraMatrix"
+        normal-model-to-camera="normalModelToCameraMatrix">
+        <block name="Projection" binding="0"/>
+        <block name="Light" binding="1"/>
+        <sampler name="normalTex" unit="0"/>
+    </prog>
+    <prog
+        xml:id="p_lit"
+        vert="litTexture.vert"
+        frag="litTexture.frag"
+        model-to-camera="modelToCameraMatrix"
+        normal-model-to-camera="normalModelToCameraMatrix">
+        <block name="Projection" binding="0"/>
+		<block name="Light" binding="1"/>
+        <sampler name="diffuseColorTex" unit="0"/>
+    </prog>
+    <prog
+        xml:id="p_unlit"
+        vert="Unlit.vert"
+        frag="Unlit.frag"
+        model-to-camera="modelToCameraMatrix">
+        <block name="Projection" binding="0"/>
+    </prog>
+    
+    <camera xml:id="c_main"
+        start-pos="0.0 1.0 0.0"
+        start-orient="0.074608 -0.137399 -0.010379 0.987647"
+        start-radius="5.0"
+        start-up-spin="0"
+
+        radius-limits="0.5 10.0"
+        radius-deltas="1.0 0.5"
+        pos-deltas="0.5 0.25"
+        rotation-scale="0.36"/>
+    
+
+    <node
+        name="object"
+        mesh="m_square"
+        prog="p_litBump"
+        orient="0.707 0 0 0.707"
+        pos="0 1 -1"
+        scale="1">
+        <texture name="t_bump_texture" unit="0" sampler="anisotropic"/>
+    </node>
+    
+    <node
+        name="floor"
+        mesh="m_plane"
+        prog="p_lit"
+        pos="0 0 0"
+        scale="20">
+        <texture name="t_sandy_ground" unit="0" sampler="anisotropic"/>
+    </node>
+</scene>

Tut 18 Bumpy Textures/data/litBump.frag

+#version 330
+
+in vec2 colorCoord;
+in vec3 cameraSpacePosition;
+in vec3 cameraSpaceNormal;
+
+out vec4 outputColor;
+
+layout(std140) uniform;
+
+struct PerLight
+{
+	vec4 cameraSpaceLightPos;
+	vec4 lightIntensity;
+};
+
+uniform Light
+{
+	vec4 ambientIntensity;
+	float lightAttenuation;
+	float maxIntensity;
+	PerLight lights[4];
+} Lgt;
+
+uniform int numberOfLights;
+
+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 vec4 diffuseColor, in PerLight lightData)
+{
+	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;
+	
+	vec4 lighting = diffuseColor * lightIntensity * cosAngIncidence;
+	
+	return lighting;
+}
+
+uniform sampler2D normalTex;
+
+void main()
+{
+	vec4 diffuseColor = texture(normalTex, colorCoord);
+
+	vec4 accumLighting = diffuseColor * Lgt.ambientIntensity;
+	for(int light = 0; light < numberOfLights; light++)
+	{
+		accumLighting += ComputeLighting(diffuseColor, Lgt.lights[light]);
+	}
+	
+	outputColor = accumLighting / Lgt.maxIntensity;
+}

Tut 18 Bumpy Textures/data/litBump.vert

+#version 330
+
+layout(std140) uniform;
+
+layout(location = 0) in vec3 position;
+layout(location = 2) in vec3 normal;
+layout(location = 5) in vec2 texCoord;
+
+out vec2 colorCoord;
+out vec3 cameraSpacePosition;
+out vec3 cameraSpaceNormal;
+
+uniform Projection
+{
+	mat4 cameraToClipMatrix;
+};
+
+uniform mat4 modelToCameraMatrix;
+uniform mat3 normalModelToCameraMatrix;
+
+void main()
+{
+	cameraSpacePosition = (modelToCameraMatrix * vec4(position, 1.0)).xyz;
+	gl_Position = cameraToClipMatrix * vec4(cameraSpacePosition, 1.0);
+	cameraSpaceNormal = normalize(normalModelToCameraMatrix * normal);
+
+	colorCoord = texCoord;
+}

Tut 18 Bumpy Textures/data/litTexture.frag

+#version 330
+
+in vec2 colorCoord;
+in vec3 cameraSpacePosition;
+in vec3 cameraSpaceNormal;
+
+out vec4 outputColor;
+
+layout(std140) uniform;
+
+struct PerLight
+{
+	vec4 cameraSpaceLightPos;
+	vec4 lightIntensity;
+};
+
+uniform Light
+{
+	vec4 ambientIntensity;
+	float lightAttenuation;
+	float maxIntensity;
+	PerLight lights[4];
+} Lgt;
+
+uniform int numberOfLights;
+
+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 vec4 diffuseColor, in PerLight lightData)
+{
+	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;
+	
+	vec4 lighting = diffuseColor * lightIntensity * cosAngIncidence;
+	
+	return lighting;
+}
+
+uniform sampler2D diffuseColorTex;
+
+void main()
+{
+	vec4 diffuseColor = texture(diffuseColorTex, colorCoord);
+
+	vec4 accumLighting = diffuseColor * Lgt.ambientIntensity;
+	for(int light = 0; light < numberOfLights; light++)
+	{
+		accumLighting += ComputeLighting(diffuseColor, Lgt.lights[light]);
+	}
+	
+	outputColor = accumLighting / Lgt.maxIntensity;
+}

Tut 18 Bumpy Textures/data/litTexture.vert

+#version 330
+
+layout(std140) uniform;
+
+layout(location = 0) in vec3 position;
+layout(location = 2) in vec3 normal;
+layout(location = 5) in vec2 texCoord;
+
+out vec2 colorCoord;
+out vec3 cameraSpacePosition;
+out vec3 cameraSpaceNormal;
+
+uniform Projection
+{
+	mat4 cameraToClipMatrix;
+};
+
+uniform mat4 modelToCameraMatrix;
+uniform mat3 normalModelToCameraMatrix;
+
+void main()
+{
+	cameraSpacePosition = (modelToCameraMatrix * vec4(position, 1.0)).xyz;
+	gl_Position = cameraToClipMatrix * vec4(cameraSpacePosition, 1.0);
+	cameraSpaceNormal = normalize(normalModelToCameraMatrix * normal);
+
+	colorCoord = texCoord;
+}

Tut 18 Bumpy Textures/premake4.lua

+
+dofile("../framework/framework.lua")
+
+SetupSolution("Tutorial18")
+dofile("tutorials.lua");

Tut 18 Bumpy Textures/tutorials.lua

+
+SetupProject("Tut 18 Bumpy Square", "Bumpy Square.cpp")
+
+

framework/Mesh.cpp

 			, oVAO(0)
 		{}
 
+		~MeshData()
+		{
+			glDeleteBuffers(1, &oAttribArraysBuffer);
+			glDeleteBuffers(1, &oIndexBuffer);
+			glDeleteVertexArrays(1, &oVAO);
+
+			for(VAOMap::iterator curr = namedVAOs.begin(); curr != namedVAOs.end(); ++curr)
+			{
+				glDeleteVertexArrays(1, &curr->second);
+			}
+		}
+
 		GLuint oAttribArraysBuffer;
 		GLuint oIndexBuffer;
 		GLuint oVAO;

framework/Scene.cpp

 #include <glm/gtc/type_ptr.hpp>
 #include <glm/gtc/matrix_transform.hpp>
 #include <glimg/glimg.h>
+#include <glutil/MousePoles.h>
 
 
 #define PARSE_THROW(cond, message)\
 		GLuint GetTexture() const {return m_texObj;}
 		GLenum GetType() const {return m_texType;}
 
+		GLuint SetTexture(GLuint newTexObj, GLenum newTexType)
+		{
+			GLuint ret = m_texObj;
+			m_texObj = newTexObj;
+			m_texType = newTexType;
+			return ret;
+		}
+
 	private:
 		GLuint m_texObj;
 		GLenum m_texType;
 
 	typedef std::map<std::string, Variation> VariantMap;
 
+	struct SceneCamera
+	{
+		glutil::ViewData initialData;
+		glutil::ViewScale scale;
+	};
+
+	typedef std::map<std::string, SceneCamera> CameraMap;
+
 	class SceneNode
 	{
 	public:
 		TextureMap m_textures;
 		ProgramMap m_progs;
 		NodeMap m_nodes;
+		CameraMap m_cameras;
 
 		std::vector<SceneNode *> m_rootNodes;
 
 				ReadMeshes(*pSceneNode);
 				ReadTextures(*pSceneNode);
 				ReadPrograms(*pSceneNode);
+				ReadCameras(*pSceneNode);
 				ReadNodes(NULL, *pSceneNode);
 			}
 			catch(...)
 			return NodeRef(theIt->second);
 		}
 
+		std::vector<NodeRef> GetAllNodes()
+		{
+			std::vector<NodeRef> ret;
+
+			for(NodeMap::iterator theIt = m_nodes.begin();
+				theIt != m_nodes.end();
+				++theIt)
+			{
+				ret.push_back(NodeRef(theIt->second));
+			}
+
+			return ret;
+		}
+
 		GLuint FindProgram(const std::string &progName)
 		{
 			ProgramMap::iterator theIt = m_progs.find(progName);
 			return std::make_pair(theIt->second->GetTexture(), theIt->second->GetType());
 		}
 
+		GLuint ReplaceTexture(const std::string &textureName, GLuint newTexObj, GLenum newTexType)
+		{
+			TextureMap::iterator theIt = m_textures.find(textureName);
+			if(theIt == m_textures.end())
+				return 0;
+
+			return theIt->second->SetTexture(newTexObj, newTexType);
+		}
+
+		glutil::ViewPole *CreateCamera(const std::string &cameraName,
+			glutil::MouseButtons actionButton, bool bRightKeyboardCtrls) const
+		{
+			CameraMap::const_iterator theIt = m_cameras.find(cameraName);
+			if(theIt == m_cameras.end())
+				return NULL;
+
+			return new glutil::ViewPole(theIt->second.initialData, theIt->second.scale,
+				actionButton, bRightKeyboardCtrls);
+		}
+
 	private:
 
 		void ReadMeshes(const xml_node<> &scene)
 			}
 		}
 
+		void ReadCameras(const xml_node<> &scene)
+		{
+			for(const xml_node<> *pCamNode = scene.first_node("camera");
+				pCamNode;
+				pCamNode = pCamNode->next_sibling("camera"))
+			{
+				ReadCamera(*pCamNode);
+			}
+		}
+
+		void ReadCamera(const xml_node<> &cameraNode)
+		{
+			const xml_attribute<> *pNameNode = cameraNode.first_attribute("xml:id");
+			const xml_attribute<> *pStartPosNode = cameraNode.first_attribute("start-pos");
+			const xml_attribute<> *pStartOrientNode = cameraNode.first_attribute("start-orient");
+			const xml_attribute<> *pStartRadiusNode = cameraNode.first_attribute("start-radius");
+			const xml_attribute<> *pStartUpSpinNode = cameraNode.first_attribute("start-up-spin");
+
+			const xml_attribute<> *pRadiusLimitNode = cameraNode.first_attribute("radius-limits");
+			const xml_attribute<> *pRadiusDeltaNode = cameraNode.first_attribute("radius-deltas");
+			const xml_attribute<> *pPosDeltaNode = cameraNode.first_attribute("pos-deltas");
+			const xml_attribute<> *pRotScaleNode = cameraNode.first_attribute("rotation-scale");
+
+			PARSE_THROW(pNameNode, "Camera found with no `xml:id` name specified.");
+			PARSE_THROW(pStartPosNode, "Camera found with no `start-pos` attribute specified.");
+			PARSE_THROW(pStartOrientNode, "Camera found with no `start-orient` attribute specified.");
+			PARSE_THROW(pStartRadiusNode, "Camera found with no `start-radius` attribute specified.");
+			PARSE_THROW(pStartUpSpinNode, "Camera found with no `start-up-spin` attribute specified.");
+
+			PARSE_THROW(pRadiusLimitNode, "Camera found with no `radius-limits` attribute specified.");
+			PARSE_THROW(pRadiusDeltaNode, "Camera found with no `radius-deltas` attribute specified.");
+			PARSE_THROW(pPosDeltaNode, "Camera found with no `pos-deltas` attribute specified.");
+			PARSE_THROW(pRotScaleNode, "Camera found with no `rotation-scale` attribute specified.");
+
+			std::string name = make_string(*pNameNode);
+			if(m_cameras.find(name) != m_cameras.end())
+				throw std::runtime_error("The camera named \"" + name + "\" already exists.");
+
+			SceneCamera &theCam = m_cameras[name];
+
+			theCam.initialData.targetPos = rapidxml::attrib_to_vec3(*pStartPosNode, ThrowAttrib);
+			theCam.initialData.orient = glm::normalize(rapidxml::attrib_to_quat(*pStartOrientNode, ThrowAttrib));
+			theCam.initialData.radius = rapidxml::attrib_to_float(*pStartRadiusNode, ThrowAttrib);
+			theCam.initialData.degSpinRotation = rapidxml::attrib_to_float(*pStartOrientNode, ThrowAttrib);
+
+			glm::vec2 pairVec;
+			pairVec = rapidxml::attrib_to_vec2(*pRadiusLimitNode, ThrowAttrib);
+			theCam.scale.minRadius = pairVec.x;
+			theCam.scale.maxRadius = pairVec.y;
+			pairVec = rapidxml::attrib_to_vec2(*pRadiusDeltaNode, ThrowAttrib);
+			theCam.scale.smallRadiusDelta = pairVec.x;
+			theCam.scale.largeRadiusDelta = pairVec.y;
+			pairVec = rapidxml::attrib_to_vec2(*pPosDeltaNode, ThrowAttrib);
+			theCam.scale.smallPosOffset = pairVec.x;
+			theCam.scale.largePosOffset = pairVec.y;
+			theCam.scale.rotationScale = rapidxml::attrib_to_float(*pRotScaleNode, ThrowAttrib);
+		}
+
 		void ReadNodes(SceneNode *pParent, const xml_node<> &scene)
 		{
 			for(const xml_node<> *pNodeNode = scene.first_node("node");
 		return m_pImpl->FindNode(nodeName);
 	}
 
+	std::vector<NodeRef> Scene::GetAllNodes()
+	{
+		return m_pImpl->GetAllNodes();
+	}
+
 	GLuint Scene::FindProgram( const std::string &progName )
 	{
 		return m_pImpl->FindProgram(progName);
 	{
 		return m_pImpl->FindMesh(meshName);
 	}
+
+	GLuint Scene::ReplaceTexture( const std::string &textureName, GLuint newTexObj, GLenum newTexType )
+	{
+		return m_pImpl->ReplaceTexture(textureName, newTexObj, newTexType);
+	}
+
+	glutil::ViewPole * Scene::CreateCamera( const std::string &cameraName,
+		glutil::MouseButtons actionButton, bool bRightKeyboardCtrls ) const
+	{
+		return m_pImpl->CreateCamera(cameraName, actionButton, bRightKeyboardCtrls);
+	}
 }

framework/Scene.h

 #define FRAMEWORK_SCENE_H
 
 #include <string>
+#include <vector>
 #include <glm/glm.hpp>
 #include <glm/gtc/quaternion.hpp>
+#include <glutil/MousePoles.h>
 
 namespace Framework
 {
 
 		NodeRef FindNode(const std::string &nodeName);
 
+		std::vector<NodeRef> GetAllNodes();
+
 		GLuint FindProgram(const std::string &progName);
 
 		Mesh *FindMesh(const std::string &meshName);
 
+		//Returns the old texture name, or 0 if not found.
+		GLuint ReplaceTexture(const std::string &textureName, GLuint newTexObj, GLenum newTexType);
+
+		//Constructs a camera. Note that this is *constructs*, not retrieves a stored one.
+		//Every call creates a new, *independent* camera.
+		glutil::ViewPole *CreateCamera(const std::string &cameraName,
+			glutil::MouseButtons actionButton = glutil::MB_LEFT_BTN, bool bRightKeyboardCtrls = false) const;
+
 	private:
 		SceneImpl *m_pImpl;
 	};

framework/rapidxml_helpers.h

 	}
 
 	template<typename Callable>
+	glm::vec2 attrib_to_vec2(const xml_attribute<> &attrib, Callable FailFunc)
+	{
+		std::istrstream inData(attrib.value(), attrib.value_size());
+		inData >> std::skipws;
+		glm::vec2 ret;
+		inData >> ret.x >> ret.y;
+		if(inData.fail())
+			FailFunc(attrib, "must be a vec2.");
+
+		return ret;
+	}
+
+	inline glm::vec2 attrib_to_vec2_opt(const xml_attribute<> &attrib, const glm::vec2 &optRet)
+	{
+		std::istrstream inData(attrib.value(), attrib.value_size());
+		inData >> std::skipws;
+		glm::vec2 ret;
+		inData >> ret.x >> ret.y;
+		if(inData.fail())
+			return optRet;
+
+		return ret;
+	}
+
+
+	template<typename Callable>
 	glm::vec3 attrib_to_vec3(const xml_attribute<> &attrib, Callable FailFunc)
 	{
 		std::istrstream inData(attrib.value(), attrib.value_size());
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.