Roi Atalla avatar Roi Atalla committed 6c0661b

Example 11.3 ported.

Comments (0)

Files changed (18)

src/main/java/com/ra4king/opengl/arcsynthesis/gl33/chapter11/example1/example11.1.PhongOnly.frag

 	vec3 reflectDir = normalize(reflect(-lightDir, surfaceNormal));
 	float phongTerm = dot(viewDirection, reflectDir);
 	phongTerm = clamp(phongTerm, 0, 1);
-	phongTerm = dot(surfaceNormal, lightDir) > 0 ? phongTerm : 0;
+	phongTerm = dot(surfaceNormal, lightDir) > 0.0 ? phongTerm : 0.0;
 	phongTerm = pow(phongTerm, shininessFactor);
 	
 	outputColor = specularColor * attenIntensity * phongTerm + diffuseColor * ambientIntensity;

src/main/java/com/ra4king/opengl/arcsynthesis/gl33/chapter11/example2/example11.2.BlinnLighting.frag

 	vec3 halfAngle = normalize(lightDir + viewDirection);
 	float blinnTerm = dot(surfaceNormal, halfAngle);
 	blinnTerm = clamp(blinnTerm, 0, 1);
-	blinnTerm = cosAngIncidence != 0 ? blinnTerm : 0;
+	blinnTerm = cosAngIncidence != 0.0 ? blinnTerm : 0.0;
 	blinnTerm = pow(blinnTerm, shininessFactor);
 	
 	outputColor = diffuseColor  * attenIntensity * cosAngIncidence +

src/main/java/com/ra4king/opengl/arcsynthesis/gl33/chapter11/example2/example11.2.BlinnOnly.frag

 	vec3 halfAngle = normalize(lightDir + viewDirection);
 	float blinnTerm = dot(surfaceNormal, halfAngle);
 	blinnTerm = clamp(blinnTerm, 0, 1);
-	blinnTerm = dot(surfaceNormal, lightDir) >= 0 ? blinnTerm : 0;
+	blinnTerm = dot(surfaceNormal, lightDir) >= 0.0 ? blinnTerm : 0.0;
 	blinnTerm = pow(blinnTerm, shininessFactor);
 	
 	outputColor = specularColor * attenIntensity * blinnTerm + diffuseColor * ambientIntensity;

src/main/java/com/ra4king/opengl/arcsynthesis/gl33/chapter11/example2/example11.2.PhongOnly.frag

 	vec3 reflectDir = normalize(reflect(-lightDir, surfaceNormal));
 	float phongTerm = dot(viewDirection, reflectDir);
 	phongTerm = clamp(phongTerm, 0, 1);
-	phongTerm = dot(surfaceNormal, lightDir) > 0 ? phongTerm : 0;
+	phongTerm = dot(surfaceNormal, lightDir) > 0.0 ? phongTerm : 0.0;
 	phongTerm = pow(phongTerm, shininessFactor);
 	
 	outputColor = specularColor * attenIntensity * phongTerm + diffuseColor * ambientIntensity;

src/main/java/com/ra4king/opengl/arcsynthesis/gl33/chapter11/example3/Example11_3.java

+package com.ra4king.opengl.arcsynthesis.gl33.chapter11.example3;
+
+import static org.lwjgl.opengl.GL11.*;
+import static org.lwjgl.opengl.GL15.*;
+import static org.lwjgl.opengl.GL20.*;
+import static org.lwjgl.opengl.GL30.*;
+import static org.lwjgl.opengl.GL31.*;
+import static org.lwjgl.opengl.GL32.*;
+
+import org.lwjgl.input.Keyboard;
+
+import com.ra4king.opengl.GLProgram;
+import com.ra4king.opengl.util.Mesh;
+import com.ra4king.opengl.util.MousePoles.MouseButton;
+import com.ra4king.opengl.util.MousePoles.ObjectData;
+import com.ra4king.opengl.util.MousePoles.ObjectPole;
+import com.ra4king.opengl.util.MousePoles.ViewData;
+import com.ra4king.opengl.util.MousePoles.ViewPole;
+import com.ra4king.opengl.util.MousePoles.ViewScale;
+import com.ra4king.opengl.util.ShaderProgram;
+import com.ra4king.opengl.util.Timer;
+import com.ra4king.opengl.util.Utils;
+import com.ra4king.opengl.util.math.Matrix3;
+import com.ra4king.opengl.util.math.Matrix4;
+import com.ra4king.opengl.util.math.MatrixStack;
+import com.ra4king.opengl.util.math.Quaternion;
+import com.ra4king.opengl.util.math.Vector3;
+import com.ra4king.opengl.util.math.Vector4;
+
+public class Example11_3 extends GLProgram {
+	public static void main(String[] args) {
+		new Example11_3().run(true);
+	}
+	
+	private static enum LightingModel {
+		PHONG_SPECULAR, PHONG_ONLY, BLINN_SPECULAR, BLINN_ONLY, GAUSSIAN_SPECULAR, GAUSSIAN_ONLY
+	}
+	
+	private ProgramPair[] programs = new ProgramPair[LightingModel.values().length];
+	private ShaderPair[] shaderFiles = { new ShaderPair("PN.vert", "PCN.vert", "PhongLighting.frag"),
+										new ShaderPair("PN.vert", "PCN.vert", "PhongOnly.frag"),
+										new ShaderPair("PN.vert", "PCN.vert", "BlinnLighting.frag"),
+										new ShaderPair("PN.vert", "PCN.vert", "BlinnOnly.frag"),
+										new ShaderPair("PN.vert", "PCN.vert", "GaussianLighting.frag"),
+										new ShaderPair("PN.vert", "PCN.vert", "GaussianOnly.frag"),
+	};
+	
+	private UnlitProgramData unlit;
+	
+	private int projectionUniformBuffer;
+	private final int projectionBlockIndex = 2;
+	
+	private Mesh cylinderMesh;
+	private Mesh planeMesh;
+	private Mesh cubeMesh;
+	
+	private ViewPole viewPole;
+	private ObjectPole objectPole;
+	
+	private Timer lightTimer = new Timer(Timer.Type.LOOP, 5);
+	private float lightHeight = 1.5f, lightRadius = 1;
+	
+	private LightingModel lightModel = LightingModel.GAUSSIAN_SPECULAR;
+	private MaterialParams materialParams = new MaterialParams();
+	
+	private boolean drawColoredCyl, drawLightSource, scaleCyl, drawDark;
+	
+	private final float lightAttenuation = 1.2f;
+	
+	private Vector4 darkColor = new Vector4(0.2f, 0.2f, 0.2f, 1);
+	private Vector4 lightColor = new Vector4(1);
+	
+	public Example11_3() {
+		super("Example 11.3", 500, 500, true);
+	}
+	
+	@Override
+	public void init() {
+		glClearColor(0, 0, 0, 0);
+		glClearDepth(1);
+		
+		ViewData initialViewData = new ViewData(new Vector3(0, 0.5f, 0), new Quaternion(0.3826834f, 0, 0, 0.92387953f), 5, 0);
+		ViewScale viewScale = new ViewScale(3, 20, 1.5f, 0.5f, 0, 0, 90f / 250f);
+		ObjectData initialObjectData = new ObjectData(new Vector3(0, 0.5f, 0), new Quaternion());
+		
+		viewPole = new ViewPole(initialViewData, viewScale, MouseButton.LEFT_BUTTON, false);
+		objectPole = new ObjectPole(initialObjectData, 90f / 250f, MouseButton.RIGHT_BUTTON, viewPole);
+		
+		for(int a = 0; a < shaderFiles.length; a++)
+			programs[a] = new ProgramPair(loadLitProgram("example11.3." + shaderFiles[a].whiteVertexShader, "example11.3." + shaderFiles[a].fragmentShader),
+					loadLitProgram("example11.3." + shaderFiles[a].colorVertexShader, "example11.3." + shaderFiles[a].fragmentShader));
+		
+		unlit = loadUnlitProgramData("example11.3.PosTransform.vert", "example11.3.UniformColor.frag");
+		
+		try {
+			cylinderMesh = new Mesh(getClass().getResource("example11.3.UnitCylinder.xml"));
+			planeMesh = new Mesh(getClass().getResource("example11.3.LargePlane.xml"));
+			cubeMesh = new Mesh(getClass().getResource("example11.3.UnitCube.xml"));
+		} catch(Exception exc) {
+			exc.printStackTrace();
+			destroy();
+		}
+		
+		glEnable(GL_CULL_FACE);
+		glCullFace(GL_BACK);
+		glFrontFace(GL_CW);
+		
+		glEnable(GL_DEPTH_TEST);
+		glDepthMask(true);
+		glDepthFunc(GL_LEQUAL);
+		glDepthRange(0, 1);
+		glEnable(GL_DEPTH_CLAMP);
+		
+		projectionUniformBuffer = glGenBuffers();
+		glBindBuffer(GL_UNIFORM_BUFFER, projectionUniformBuffer);
+		glBufferData(GL_UNIFORM_BUFFER, 16 * 4, GL_DYNAMIC_DRAW);
+		glBindBufferRange(GL_UNIFORM_BUFFER, projectionBlockIndex, projectionUniformBuffer, 0, 16 * 4);
+		glBindBuffer(GL_UNIFORM_BUFFER, 0);
+	}
+	
+	private ProgramData loadLitProgram(String vertexFile, String fragmentFile) {
+		ProgramData data = new ProgramData(new ShaderProgram(readFromFile(vertexFile), readFromFile(fragmentFile)));
+		data.modelToCameraMatrixUniform = glGetUniformLocation(data.program.getProgram(), "modelToCameraMatrix");
+		data.lightIntensityUniform = glGetUniformLocation(data.program.getProgram(), "lightIntensity");
+		data.ambientIntensityUniform = glGetUniformLocation(data.program.getProgram(), "ambientIntensity");
+		
+		data.normalModelToCameraMatrixUniform = glGetUniformLocation(data.program.getProgram(), "normalModelToCameraMatrix");
+		data.cameraSpaceLightPositionUniform = glGetUniformLocation(data.program.getProgram(), "cameraSpaceLightPos");
+		data.lightAttenuationUniform = glGetUniformLocation(data.program.getProgram(), "lightAttenuation");
+		data.shininessFactorUniform = glGetUniformLocation(data.program.getProgram(), "shininessFactor");
+		data.baseDiffuseColorUniform = glGetUniformLocation(data.program.getProgram(), "baseDiffuseColor");
+		
+		int projectionBlock = glGetUniformBlockIndex(data.program.getProgram(), "Projection");
+		glUniformBlockBinding(data.program.getProgram(), projectionBlock, projectionBlockIndex);
+		
+		return data;
+	}
+	
+	private UnlitProgramData loadUnlitProgramData(String vertexFile, String fragmentFile) {
+		UnlitProgramData data = new UnlitProgramData(new ShaderProgram(readFromFile(vertexFile), readFromFile(fragmentFile)));
+		data.modelToCameraMatrixUniform = glGetUniformLocation(data.program.getProgram(), "modelToCameraMatrix");
+		data.objectColorUniform = glGetUniformLocation(data.program.getProgram(), "objectColor");
+		
+		int projectionBlock = glGetUniformBlockIndex(data.program.getProgram(), "Projection");
+		glUniformBlockBinding(data.program.getProgram(), projectionBlock, projectionBlockIndex);
+		
+		return data;
+	}
+	
+	@Override
+	public void resized() {
+		super.resized();
+		
+		glBindBuffer(GL_UNIFORM_BUFFER, projectionUniformBuffer);
+		glBufferSubData(GL_UNIFORM_BUFFER, 0, new Matrix4().clearToPerspectiveDeg(45, getWidth(), getHeight(), 1, 1000).toBuffer());
+		glBindBuffer(GL_UNIFORM_BUFFER, 0);
+	}
+	
+	@Override
+	public void update(long deltaTime) {
+		Utils.updateMousePoles(viewPole, objectPole);
+		
+		lightTimer.update(deltaTime);
+		
+		float speed = (deltaTime / (float)1e9) * (Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) || Keyboard.isKeyDown(Keyboard.KEY_RSHIFT) ? 0.5f : 2f);
+		
+		if(Keyboard.isKeyDown(Keyboard.KEY_I))
+			lightHeight += speed;
+		if(Keyboard.isKeyDown(Keyboard.KEY_K))
+			lightHeight -= speed;
+		if(Keyboard.isKeyDown(Keyboard.KEY_L))
+			lightRadius += speed;
+		if(Keyboard.isKeyDown(Keyboard.KEY_J))
+			lightRadius -= speed;
+		
+		if(lightRadius < 0.2f)
+			lightRadius = 0.2f;
+	}
+	
+	@Override
+	public void keyPressed(int key, char c) {
+		boolean changedShininess = false;
+		boolean changedLightModel = false;
+		
+		switch(key) {
+			case Keyboard.KEY_SPACE:
+				drawColoredCyl = !drawColoredCyl;
+				break;
+			case Keyboard.KEY_O:
+				materialParams.increment(!(Keyboard.isKeyDown(Keyboard.KEY_RSHIFT) || Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)));
+				changedShininess = true;
+				break;
+			case Keyboard.KEY_U:
+				materialParams.decrement(!(Keyboard.isKeyDown(Keyboard.KEY_RSHIFT) || Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)));
+				changedShininess = true;
+				break;
+			case Keyboard.KEY_Y:
+				drawLightSource = !drawLightSource;
+				break;
+			case Keyboard.KEY_T:
+				scaleCyl = !scaleCyl;
+				break;
+			case Keyboard.KEY_B:
+				lightTimer.togglePause();
+				break;
+			case Keyboard.KEY_G:
+				drawDark = !drawDark;
+				break;
+			case Keyboard.KEY_H:
+				if(Keyboard.isKeyDown(Keyboard.KEY_RSHIFT) || Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)) {
+					if(lightModel.ordinal() % 2 != 0)
+						lightModel = LightingModel.values()[(lightModel.ordinal() - 1) % LightingModel.values().length];
+					else
+						lightModel = LightingModel.values()[(lightModel.ordinal() + 1) % LightingModel.values().length];
+				}
+				else
+					lightModel = LightingModel.values()[(lightModel.ordinal() + 2) % LightingModel.values().length];
+				
+				changedLightModel = true;
+				break;
+		}
+		
+		if(changedShininess)
+			System.out.printf("Shiny: %f\n", materialParams.getSpecularValue());
+		
+		if(changedLightModel)
+			System.out.printf("%s\n", lightModel);
+	}
+	
+	private Vector4 calcLightPosition() {
+		float currTime = lightTimer.getAlpha();
+		
+		Vector4 ret = new Vector4(0, lightHeight, 0, 1);
+		ret.x((float)Math.cos(currTime * 2 * Math.PI) * lightRadius);
+		ret.z((float)Math.sin(currTime * 2 * Math.PI) * lightRadius);
+		
+		return ret;
+	}
+	
+	@Override
+	public void render() {
+		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+		
+		MatrixStack modelMatrix = new MatrixStack();
+		modelMatrix.setTop(viewPole.calcMatrix());
+		
+		Vector4 worldLightPos = calcLightPosition();
+		Vector4 lightPosCameraSpace = modelMatrix.getTop().mult(worldLightPos);
+		
+		ProgramData whiteProgram = programs[lightModel.ordinal()].whiteProgram;
+		ProgramData colorProgram = programs[lightModel.ordinal()].colorProgram;
+		
+		whiteProgram.program.begin();
+		glUniform4f(whiteProgram.lightIntensityUniform, 0.8f, 0.8f, 0.8f, 1);
+		glUniform4f(whiteProgram.ambientIntensityUniform, 0.2f, 0.2f, 0.2f, 1);
+		glUniform3(whiteProgram.cameraSpaceLightPositionUniform, lightPosCameraSpace.toBuffer());
+		glUniform1f(whiteProgram.lightAttenuationUniform, lightAttenuation);
+		glUniform1f(whiteProgram.shininessFactorUniform, materialParams.getSpecularValue());
+		glUniform4(whiteProgram.baseDiffuseColorUniform, drawDark ? darkColor.toBuffer() : lightColor.toBuffer());
+		whiteProgram.program.end();
+		
+		colorProgram.program.begin();
+		glUniform4f(colorProgram.lightIntensityUniform, 0.8f, 0.8f, 0.8f, 1);
+		glUniform4f(colorProgram.ambientIntensityUniform, 0.2f, 0.2f, 0.2f, 1);
+		glUniform3(colorProgram.cameraSpaceLightPositionUniform, lightPosCameraSpace.toBuffer());
+		glUniform1f(colorProgram.lightAttenuationUniform, lightAttenuation);
+		glUniform1f(colorProgram.shininessFactorUniform, materialParams.getSpecularValue());
+		colorProgram.program.end();
+		
+		{
+			modelMatrix.pushMatrix();
+			
+			{
+				modelMatrix.pushMatrix();
+				
+				whiteProgram.program.begin();
+				glUniformMatrix4(whiteProgram.modelToCameraMatrixUniform, false, modelMatrix.getTop().toBuffer());
+				glUniformMatrix3(whiteProgram.normalModelToCameraMatrixUniform, false, new Matrix3(modelMatrix.getTop()).inverse().transpose().toBuffer());
+				planeMesh.render();
+				whiteProgram.program.end();
+				
+				modelMatrix.popMatrix();
+			}
+			
+			{
+				modelMatrix.pushMatrix();
+				
+				modelMatrix.getTop().mult(objectPole.calcMatrix());
+				
+				if(scaleCyl)
+					modelMatrix.getTop().scale(1, 1, 0.2f);
+				
+				ProgramData prog = drawColoredCyl ? colorProgram : whiteProgram;
+				
+				prog.program.begin();
+				glUniformMatrix4(prog.modelToCameraMatrixUniform, false, modelMatrix.getTop().toBuffer());
+				glUniformMatrix3(prog.normalModelToCameraMatrixUniform, false, new Matrix3(modelMatrix.getTop()).inverse().transpose().toBuffer());
+				
+				if(drawColoredCyl)
+					cylinderMesh.render("lit-color");
+				else
+					cylinderMesh.render("lit");
+				
+				prog.program.end();
+				
+				modelMatrix.popMatrix();
+			}
+			
+			if(drawLightSource) {
+				modelMatrix.pushMatrix();
+				
+				modelMatrix.getTop().translate(new Vector3(worldLightPos));
+				modelMatrix.getTop().scale(0.1f, 0.1f, 0.1f);
+				
+				unlit.program.begin();
+				glUniformMatrix4(unlit.modelToCameraMatrixUniform, false, modelMatrix.getTop().toBuffer());
+				glUniform4f(unlit.objectColorUniform, 0.8078f, 0.8706f, 0.9922f, 1);
+				cubeMesh.render("flat");
+				unlit.program.end();
+				
+				modelMatrix.popMatrix();
+			}
+			
+			modelMatrix.popMatrix();
+		}
+	}
+	
+	private static class ProgramData {
+		private ShaderProgram program;
+		
+		private int modelToCameraMatrixUniform;
+		
+		private int lightIntensityUniform;
+		private int ambientIntensityUniform;
+		
+		private int normalModelToCameraMatrixUniform;
+		private int cameraSpaceLightPositionUniform;
+		private int lightAttenuationUniform;
+		private int shininessFactorUniform;
+		private int baseDiffuseColorUniform;
+		
+		public ProgramData(ShaderProgram program) {
+			this.program = program;
+		}
+	}
+	
+	private static class UnlitProgramData {
+		private ShaderProgram program;
+		
+		private int objectColorUniform;
+		private int modelToCameraMatrixUniform;
+		
+		public UnlitProgramData(ShaderProgram program) {
+			this.program = program;
+		}
+	}
+	
+	private static class ProgramPair {
+		private ProgramData whiteProgram;
+		private ProgramData colorProgram;
+		
+		public ProgramPair(ProgramData whiteProgram, ProgramData colorProgram) {
+			this.whiteProgram = whiteProgram;
+			this.colorProgram = colorProgram;
+		}
+	}
+	
+	private static class ShaderPair {
+		private String whiteVertexShader;
+		private String colorVertexShader;
+		private String fragmentShader;
+		
+		public ShaderPair(String whiteVertexShader, String colorVertexShader, String fragmentShader) {
+			this.whiteVertexShader = whiteVertexShader;
+			this.colorVertexShader = colorVertexShader;
+			this.fragmentShader = fragmentShader;
+		}
+	}
+	
+	private class MaterialParams {
+		private float phongExponent;
+		private float blinnExponent;
+		private float gaussianExponent;
+		
+		public MaterialParams() {
+			phongExponent = 4;
+			blinnExponent = 4;
+			gaussianExponent = 0.5f;
+		}
+		
+		public float getSpecularValue() {
+			switch(lightModel) {
+				case PHONG_SPECULAR:
+				case PHONG_ONLY:
+					return phongExponent;
+				case BLINN_SPECULAR:
+				case BLINN_ONLY:
+					return blinnExponent;
+				case GAUSSIAN_SPECULAR:
+				case GAUSSIAN_ONLY:
+					return gaussianExponent;
+					
+				default:
+					return 0;
+			}
+		}
+		
+		public void setSpecularValue(float value) {
+			switch(lightModel) {
+				case PHONG_SPECULAR:
+				case PHONG_ONLY:
+					phongExponent = value;
+					break;
+				case BLINN_SPECULAR:
+				case BLINN_ONLY:
+					blinnExponent = value;
+				case GAUSSIAN_SPECULAR:
+				case GAUSSIAN_ONLY:
+					gaussianExponent = value;
+			}
+		}
+		
+		public void increment(boolean isLarge) {
+			float param = getSpecularValue();
+			
+			if(isGaussianLightModel()) {
+				if(isLarge)
+					param += 0.1f;
+				else
+					param += 0.01f;
+			}
+			else {
+				if(isLarge)
+					param += 0.5f;
+				else
+					param += 0.1f;
+			}
+			
+			setSpecularValue(clamp(param));
+		}
+		
+		public void decrement(boolean isLarge) {
+			float param = getSpecularValue();
+			
+			if(isGaussianLightModel()) {
+				if(isLarge)
+					param -= 0.1f;
+				else
+					param -= 0.01f;
+			}
+			else {
+				if(isLarge)
+					param -= 0.5f;
+				else
+					param -= 0.1f;
+			}
+			
+			setSpecularValue(clamp(param));
+		}
+		
+		private float clamp(float param) {
+			if(isGaussianLightModel())
+				return Math.min(Math.max(0.00001f, param), 1);
+			else {
+				if(param <= 0f)
+					param = 0.0001f;
+			}
+			
+			return param;
+		}
+		
+		private boolean isGaussianLightModel() {
+			return lightModel == LightingModel.GAUSSIAN_SPECULAR || lightModel == LightingModel.GAUSSIAN_ONLY;
+		}
+	}
+}

src/main/java/com/ra4king/opengl/arcsynthesis/gl33/chapter11/example3/example11.3.BlinnLighting.frag

+#version 330
+
+in vec4 diffuseColor;
+in vec3 vertexNormal;
+in vec3 cameraSpacePosition;
+
+out vec4 outputColor;
+
+uniform vec4 lightIntensity;
+uniform vec4 ambientIntensity;
+
+uniform vec3 cameraSpaceLightPos;
+
+uniform float lightAttenuation;
+
+const vec4 specularColor = vec4(0.25, 0.25, 0.25, 1);
+uniform float shininessFactor;
+
+float CalcAttenuation(in vec3 cameraSpacePosition, out vec3 lightDirection)
+{
+	vec3 lightDifference = cameraSpaceLightPos - cameraSpacePosition;
+	float lightDistanceSqr = dot(lightDifference, lightDifference);
+	lightDirection = lightDifference * inversesqrt(lightDistanceSqr);
+	
+	return 1/ (1 + lightAttenuation * sqrt(lightDistanceSqr));
+}
+
+void main() {
+	vec3 lightDir = vec3(0);
+	float atten = CalcAttenuation(cameraSpacePosition, lightDir);
+	vec4 attenIntensity = atten * lightIntensity;
+	
+	vec3 surfaceNormal = normalize(vertexNormal);
+	float cosAngIncidence = dot(surfaceNormal, lightDir);
+	cosAngIncidence = clamp(cosAngIncidence, 0, 1);
+	
+	vec3 viewDirection = normalize(-cameraSpacePosition);
+	
+	vec3 halfAngle = normalize(lightDir + viewDirection);
+	float blinnTerm = dot(surfaceNormal, halfAngle);
+	blinnTerm = clamp(blinnTerm, 0, 1);
+	blinnTerm = cosAngIncidence != 0.0 ? blinnTerm : 0.0;
+	blinnTerm = pow(blinnTerm, shininessFactor);
+	
+	outputColor = diffuseColor  * attenIntensity * cosAngIncidence +
+				  specularColor * attenIntensity * blinnTerm 	   +
+				  diffuseColor  * ambientIntensity;
+}

src/main/java/com/ra4king/opengl/arcsynthesis/gl33/chapter11/example3/example11.3.BlinnOnly.frag

+#version 330
+
+in vec4 diffuseColor;
+in vec3 vertexNormal;
+in vec3 cameraSpacePosition;
+
+out vec4 outputColor;
+
+uniform vec4 lightIntensity;
+uniform vec4 ambientIntensity;
+
+uniform vec3 cameraSpaceLightPos;
+
+uniform float lightAttenuation;
+
+const vec4 specularColor = vec4(0.25, 0.25, 0.25, 1);
+uniform float shininessFactor;
+
+float CalcAttenuation(in vec3 cameraSpacePosition, out vec3 lightDirection)
+{
+	vec3 lightDifference = cameraSpaceLightPos - cameraSpacePosition;
+	float lightDistanceSqr = dot(lightDifference, lightDifference);
+	lightDirection = lightDifference * inversesqrt(lightDistanceSqr);
+	
+	return 1 / (1 + lightAttenuation * sqrt(lightDistanceSqr));
+}
+
+void main()
+{
+	vec3 lightDir = vec3(0);
+	float atten = CalcAttenuation(cameraSpacePosition, lightDir);
+	vec4 attenIntensity = atten * lightIntensity;
+	
+	vec3 surfaceNormal = normalize(vertexNormal);
+	
+	vec3 viewDirection = normalize(-cameraSpacePosition);
+	
+	vec3 halfAngle = normalize(lightDir + viewDirection);
+	float blinnTerm = dot(surfaceNormal, halfAngle);
+	blinnTerm = clamp(blinnTerm, 0, 1);
+	blinnTerm = dot(surfaceNormal, lightDir) >= 0.0 ? blinnTerm : 0.0;
+	blinnTerm = pow(blinnTerm, shininessFactor);
+	
+	outputColor = specularColor * attenIntensity * blinnTerm + diffuseColor * ambientIntensity;
+}

src/main/java/com/ra4king/opengl/arcsynthesis/gl33/chapter11/example3/example11.3.GaussianLighting.frag

+#version 330
+
+in vec4 diffuseColor;
+in vec3 vertexNormal;
+in vec3 cameraSpacePosition;
+
+out vec4 outputColor;
+
+uniform vec4 lightIntensity;
+uniform vec4 ambientIntensity;
+
+uniform vec3 cameraSpaceLightPos;
+
+uniform float lightAttenuation;
+
+const vec4 specularColor = vec4(0.25, 0.25, 0.25, 1);
+uniform float shininessFactor;
+
+float calcAttenuation(in vec3 cameraSpacePosition, out vec3 lightDirection)
+{
+	vec3 lightDifference = cameraSpaceLightPos - cameraSpacePosition;
+	float lightDistanceSqr = dot(lightDifference, lightDifference);
+	lightDirection = lightDifference * inversesqrt(lightDistanceSqr);
+	
+	return 1 / (1 + lightAttenuation * sqrt(lightDistanceSqr));
+}
+
+void main()
+{
+	vec3 lightDir = vec3(0);
+	float atten = calcAttenuation(cameraSpacePosition, lightDir);
+	vec4 attenIntensity = atten * lightIntensity;
+	
+	vec3 surfaceNormal = normalize(vertexNormal);
+	float cosAngIncidence = dot(surfaceNormal, lightDir);
+	cosAngIncidence = clamp(cosAngIncidence, 0, 1);
+	
+	vec3 viewDirection = normalize(-cameraSpacePosition);
+	
+	vec3 halfAngle = normalize(lightDir + viewDirection);
+	float angleNormalHalf = acos(dot(halfAngle, surfaceNormal));
+	float exponent = angleNormalHalf / shininessFactor;
+	exponent = -(exponent * exponent);
+	float gaussianTerm = exp(exponent);
+	
+	gaussianTerm = cosAngIncidence != 0.0 ? gaussianTerm : 0.0;
+	
+	outputColor = diffuseColor  * attenIntensity * cosAngIncidence +
+				  specularColor * attenIntensity * gaussianTerm +
+				  diffuseColor  * ambientIntensity;
+}

src/main/java/com/ra4king/opengl/arcsynthesis/gl33/chapter11/example3/example11.3.GaussianOnly.frag

+#version 330
+
+in vec4 diffuseColor;
+in vec3 vertexNormal;
+in vec3 cameraSpacePosition;
+
+out vec4 outputColor;
+
+uniform vec4 lightIntensity;
+uniform vec4 ambientIntensity;
+
+uniform vec3 cameraSpaceLightPos;
+
+uniform float lightAttenuation;
+
+const vec4 specularColor = vec4(0.25, 0.25, 0.25, 1);
+uniform float shininessFactor;
+
+float calcAttenuation(in vec3 cameraSpacePosition, out vec3 lightDirection)
+{
+	vec3 lightDifference = cameraSpaceLightPos - cameraSpacePosition;
+	float lightDistanceSqr = dot(lightDifference, lightDifference);
+	lightDirection = lightDifference * inversesqrt(lightDistanceSqr);
+	
+	return 1 / (1 + lightAttenuation * sqrt(lightDistanceSqr));
+}
+
+void main()
+{
+	vec3 lightDir = vec3(0);
+	float atten = calcAttenuation(cameraSpacePosition, lightDir);
+	vec4 attenIntensity = atten * lightIntensity;
+	
+	vec3 surfaceNormal = normalize(vertexNormal);
+	
+	vec3 viewDirection = normalize(-cameraSpacePosition);
+	
+	vec3 halfAngle = normalize(lightDir + viewDirection);
+	float angleNormalHalf = acos(dot(halfAngle, surfaceNormal));
+	float exponent = angleNormalHalf / shininessFactor;
+	exponent = -(exponent * exponent);
+	float gaussianTerm = exp(exponent);
+	
+	gaussianTerm = dot(surfaceNormal, lightDir) >= 0.0 ? gaussianTerm : 0.0;
+	
+	outputColor = specularColor * attenIntensity * gaussianTerm + diffuseColor * ambientIntensity;
+}

src/main/java/com/ra4king/opengl/arcsynthesis/gl33/chapter11/example3/example11.3.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>

src/main/java/com/ra4king/opengl/arcsynthesis/gl33/chapter11/example3/example11.3.PCN.vert

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

src/main/java/com/ra4king/opengl/arcsynthesis/gl33/chapter11/example3/example11.3.PN.vert

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

src/main/java/com/ra4king/opengl/arcsynthesis/gl33/chapter11/example3/example11.3.PhongLighting.frag

+#version 330
+
+in vec4 diffuseColor;
+in vec3 vertexNormal;
+in vec3 cameraSpacePosition;
+
+out vec4 outputColor;
+
+uniform vec4 lightIntensity;
+uniform vec4 ambientIntensity;
+
+uniform vec3 cameraSpaceLightPos;
+
+uniform float lightAttenuation;
+
+const vec4 specularColor = vec4(0.25, 0.25, 0.25, 1);
+uniform float shininessFactor;
+
+float CalcAttenuation(in vec3 cameraSpacePosition, out vec3 lightDirection)
+{
+	vec3 lightDifference = cameraSpaceLightPos - cameraSpacePosition;
+	float lightDistanceSqr = dot(lightDifference, lightDifference);
+	lightDirection = lightDifference * inversesqrt(lightDistanceSqr);
+	
+	return 1 / (1 + lightAttenuation * sqrt(lightDistanceSqr));
+}
+
+void main()
+{
+	vec3 lightDir = vec3(0);
+	float atten = CalcAttenuation(cameraSpacePosition, lightDir);
+	vec4 attenIntensity = atten * lightIntensity;
+	
+	vec3 surfaceNormal = normalize(vertexNormal);
+	float cosAngIncidence = dot(surfaceNormal, lightDir);
+	cosAngIncidence = clamp(cosAngIncidence, 0, 1);
+	
+	vec3 viewDirection = normalize(-cameraSpacePosition);
+	vec3 reflectDir = reflect(-lightDir, surfaceNormal);
+	float phongTerm = dot(viewDirection, reflectDir);
+	phongTerm = clamp(phongTerm, 0, 1);
+	phongTerm = cosAngIncidence != 0.0 ? phongTerm : 0.0;
+	phongTerm = pow(phongTerm, shininessFactor);
+	
+	outputColor = diffuseColor  * attenIntensity * cosAngIncidence +
+				  specularColor * attenIntensity * phongTerm	   +
+				  diffuseColor  * ambientIntensity;
+}

src/main/java/com/ra4king/opengl/arcsynthesis/gl33/chapter11/example3/example11.3.PhongOnly.frag

+#version 330
+
+in vec4 diffuseColor;
+in vec3 vertexNormal;
+in vec3 cameraSpacePosition;
+
+out vec4 outputColor;
+
+uniform vec4 lightIntensity;
+uniform vec4 ambientIntensity;
+
+uniform vec3 cameraSpaceLightPos;
+
+uniform float lightAttenuation;
+
+const vec4 specularColor = vec4(0.25, 0.25, 0.25, 1);
+uniform float shininessFactor;
+
+float CalcAttenuation(in vec3 cameraSpacePosition, out vec3 lightDirection)
+{
+	vec3 lightDifference = cameraSpaceLightPos - cameraSpacePosition;
+	float lightDistanceSqr = dot(lightDifference, lightDifference);
+	lightDirection = lightDifference * inversesqrt(lightDistanceSqr);
+	
+	return 1 / (1 + lightAttenuation * sqrt(lightDistanceSqr));
+}
+
+void main()
+{
+	vec3 lightDir = vec3(0);
+	float atten = CalcAttenuation(cameraSpacePosition, lightDir);
+	vec4 attenIntensity = atten * lightIntensity;
+	
+	vec3 surfaceNormal = normalize(vertexNormal);
+	
+	vec3 viewDirection = normalize(-cameraSpacePosition);
+	vec3 reflectDir = normalize(reflect(-lightDir, surfaceNormal));
+	float phongTerm = dot(viewDirection, reflectDir);
+	phongTerm = clamp(phongTerm, 0, 1);
+	phongTerm = dot(surfaceNormal, lightDir) > 0.0 ? phongTerm : 0.0;
+	phongTerm = pow(phongTerm, shininessFactor);
+	
+	outputColor = specularColor * attenIntensity * phongTerm + diffuseColor * ambientIntensity;
+}

src/main/java/com/ra4king/opengl/arcsynthesis/gl33/chapter11/example3/example11.3.PosTransform.vert

+#version 330
+
+layout(location = 0) in vec3 position;
+
+uniform mat4 modelToCameraMatrix;
+
+uniform Projection
+{
+	mat4 cameraToClipMatrix;
+};
+
+void main()
+{
+	gl_Position = cameraToClipMatrix * modelToCameraMatrix * vec4(position, 1);
+}

src/main/java/com/ra4king/opengl/arcsynthesis/gl33/chapter11/example3/example11.3.UniformColor.frag

+#version 330
+
+uniform vec4 objectColor;
+
+out vec4 outputColor;
+
+void main()
+{
+	outputColor = objectColor;
+}

src/main/java/com/ra4king/opengl/arcsynthesis/gl33/chapter11/example3/example11.3.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 1 0 1
+		0 1 0 1
+		0 1 0 1
+		0 1 0 1
+		0 0 1 1
+		0 0 1 1
+		0 0 1 1
+		0 0 1 1
+		1 0 0 1
+		1 0 0 1
+		1 0 0 1
+		1 0 0 1
+		1 1 0 1
+		1 1 0 1
+		1 1 0 1
+		1 1 0 1
+		0 1 1 1
+		0 1 1 1
+		0 1 1 1
+		0 1 1 1
+		1 0 1 1
+		1 0 1 1
+		1 0 1 1
+		1 0 1 1
+	</attribute>
+	<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>

src/main/java/com/ra4king/opengl/arcsynthesis/gl33/chapter11/example3/example11.3.UnitCylinder.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.5 0.5 0
+		0.5 -0.5 0
+		0.48907381875731 0.5 0.1039557588888
+		0.48907381875731 -0.5 0.1039557588888
+		0.45677280077542 0.5 0.20336815992623
+		0.45677280077542 -0.5 0.20336815992623
+		0.40450865316151 0.5 0.29389241146627
+		0.40450865316151 -0.5 0.29389241146627
+		0.33456556611288 0.5 0.37157217599218
+		0.33456556611288 -0.5 0.37157217599218
+		0.2500003830126 0.5 0.43301248075957
+		0.2500003830126 -0.5 0.43301248075957
+		0.15450900193016 0.5 0.47552809414644
+		0.15450900193016 -0.5 0.47552809414644
+		0.052264847412855 0.5 0.49726088296277
+		0.052264847412855 -0.5 0.49726088296277
+		-0.052263527886268 0.5 0.49726102165048
+		-0.052263527886268 -0.5 0.49726102165048
+		-0.15450774007312 0.5 0.47552850414828
+		-0.15450774007312 -0.5 0.47552850414828
+		-0.24999923397422 0.5 0.43301314415651
+		-0.24999923397422 -0.5 0.43301314415651
+		-0.33456458011157 0.5 0.37157306379065
+		-0.33456458011157 -0.5 0.37157306379065
+		-0.40450787329018 0.5 0.29389348486527
+		-0.40450787329018 -0.5 0.29389348486527
+		-0.45677226111814 0.5 0.20336937201315
+		-0.45677226111814 -0.5 0.20336937201315
+		-0.48907354289964 0.5 0.10395705668972
+		-0.48907354289964 -0.5 0.10395705668972
+		-0.49999999999824 0.5 1.3267948966764e-006
+		-0.49999999999824 -0.5 1.3267948966764e-006
+		-0.48907409461153 0.5 -0.10395446108714
+		-0.48907409461153 -0.5 -0.10395446108714
+		-0.45677334042948 0.5 -0.20336694783787
+		-0.45677334042948 -0.5 -0.20336694783787
+		-0.40450943302999 0.5 -0.2938913380652
+		-0.40450943302999 -0.5 -0.2938913380652
+		-0.33456655211184 0.5 -0.3715712881911
+		-0.33456655211184 -0.5 -0.3715712881911
+		-0.25000153204922 0.5 -0.43301181735958
+		-0.25000153204922 -0.5 -0.43301181735958
+		-0.15451026378611 0.5 -0.47552768414126
+		-0.15451026378611 -0.5 -0.47552768414126
+		-0.052266166939075 0.5 -0.49726074427155
+		-0.052266166939075 -0.5 -0.49726074427155
+		0.052262208359312 0.5 -0.4972611603347
+		0.052262208359312 -0.5 -0.4972611603347
+		0.15450647821499 0.5 -0.47552891414676
+		0.15450647821499 -0.5 -0.47552891414676
+		0.24999808493408 0.5 -0.4330138075504
+		0.24999808493408 -0.5 -0.4330138075504
+		0.3345635941079 0.5 -0.37157395158649
+		0.3345635941079 -0.5 -0.37157395158649
+		0.40450709341601 0.5 -0.2938945582622
+		0.40450709341601 -0.5 -0.2938945582622
+		0.45677172145764 0.5 -0.20337058409865
+		0.45677172145764 -0.5 -0.20337058409865
+		0.48907326703854 0.5 -0.10395835448992
+		0.48907326703854 -0.5 -0.10395835448992
+		0 -0.5 0
+		0.5 0.5 0
+		0.5 -0.5 0
+		0.48907381875731 0.5 0.1039557588888
+		0.48907381875731 -0.5 0.1039557588888
+		0.45677280077542 0.5 0.20336815992623
+		0.45677280077542 -0.5 0.20336815992623
+		0.40450865316151 0.5 0.29389241146627
+		0.40450865316151 -0.5 0.29389241146627
+		0.33456556611288 0.5 0.37157217599218
+		0.33456556611288 -0.5 0.37157217599218
+		0.2500003830126 0.5 0.43301248075957
+		0.2500003830126 -0.5 0.43301248075957
+		0.15450900193016 0.5 0.47552809414644
+		0.15450900193016 -0.5 0.47552809414644
+		0.052264847412855 0.5 0.49726088296277
+		0.052264847412855 -0.5 0.49726088296277
+		-0.052263527886268 0.5 0.49726102165048
+		-0.052263527886268 -0.5 0.49726102165048
+		-0.15450774007312 0.5 0.47552850414828
+		-0.15450774007312 -0.5 0.47552850414828
+		-0.24999923397422 0.5 0.43301314415651
+		-0.24999923397422 -0.5 0.43301314415651
+		-0.33456458011157 0.5 0.37157306379065
+		-0.33456458011157 -0.5 0.37157306379065
+		-0.40450787329018 0.5 0.29389348486527
+		-0.40450787329018 -0.5 0.29389348486527
+		-0.45677226111814 0.5 0.20336937201315
+		-0.45677226111814 -0.5 0.20336937201315
+		-0.48907354289964 0.5 0.10395705668972
+		-0.48907354289964 -0.5 0.10395705668972
+		-0.49999999999824 0.5 1.3267948966764e-006
+		-0.49999999999824 -0.5 1.3267948966764e-006
+		-0.48907409461153 0.5 -0.10395446108714
+		-0.48907409461153 -0.5 -0.10395446108714
+		-0.45677334042948 0.5 -0.20336694783787
+		-0.45677334042948 -0.5 -0.20336694783787
+		-0.40450943302999 0.5 -0.2938913380652
+		-0.40450943302999 -0.5 -0.2938913380652
+		-0.33456655211184 0.5 -0.3715712881911
+		-0.33456655211184 -0.5 -0.3715712881911
+		-0.25000153204922 0.5 -0.43301181735958
+		-0.25000153204922 -0.5 -0.43301181735958
+		-0.15451026378611 0.5 -0.47552768414126
+		-0.15451026378611 -0.5 -0.47552768414126
+		-0.052266166939075 0.5 -0.49726074427155
+		-0.052266166939075 -0.5 -0.49726074427155
+		0.052262208359312 0.5 -0.4972611603347
+		0.052262208359312 -0.5 -0.4972611603347
+		0.15450647821499 0.5 -0.47552891414676
+		0.15450647821499 -0.5 -0.47552891414676
+		0.24999808493408 0.5 -0.4330138075504
+		0.24999808493408 -0.5 -0.4330138075504
+		0.3345635941079 0.5 -0.37157395158649
+		0.3345635941079 -0.5 -0.37157395158649
+		0.40450709341601 0.5 -0.2938945582622
+		0.40450709341601 -0.5 -0.2938945582622
+		0.45677172145764 0.5 -0.20337058409865
+		0.45677172145764 -0.5 -0.20337058409865
+		0.48907326703854 0.5 -0.10395835448992
+		0.48907326703854 -0.5 -0.10395835448992
+	</attribute>
+	<attribute index="1" type="float" size="4" > 
+		1 1 1 1
+		0.9 0.5 0.5 1
+		0.9 0.5 0.5 1
+		0.82 0.42 0.42 1
+		0.82 0.42 0.42 1
+		0.74 0.34 0.34 1
+		0.74 0.34 0.34 1
+		0.66 0.26 0.26 1
+		0.66 0.26 0.26 1
+		0.58 0.18 0.18 1
+		0.58 0.18 0.18 1
+		0.5 0.1 0.1 1
+		0.5 0.1 0.1 1
+		0.58 0.18 0.18 1
+		0.58 0.18 0.18 1
+		0.66 0.26 0.26 1
+		0.66 0.26 0.26 1
+		0.74 0.34 0.34 1
+		0.74 0.34 0.34 1
+		0.82 0.42 0.42 1
+		0.82 0.42 0.42 1
+		0.9 0.5 0.5 1
+		0.9 0.5 0.5 1
+		0.82 0.42 0.42 1
+		0.82 0.42 0.42 1
+		0.74 0.34 0.34 1
+		0.74 0.34 0.34 1
+		0.66 0.26 0.26 1
+		0.66 0.26 0.26 1
+		0.58 0.18 0.18 1
+		0.58 0.18 0.18 1
+		0.5 0.1 0.1 1
+		0.5 0.1 0.1 1
+		0.58 0.18 0.18 1
+		0.58 0.18 0.18 1
+		0.66 0.26 0.26 1
+		0.66 0.26 0.26 1
+		0.74 0.34 0.34 1
+		0.74 0.34 0.34 1
+		0.82 0.42 0.42 1
+		0.82 0.42 0.42 1
+		0.9 0.5 0.5 1
+		0.9 0.5 0.5 1
+		0.82 0.42 0.42 1
+		0.82 0.42 0.42 1
+		0.74 0.34 0.34 1
+		0.74 0.34 0.34 1
+		0.66 0.26 0.26 1
+		0.66 0.26 0.26 1
+		0.58 0.18 0.18 1
+		0.58 0.18 0.18 1
+		0.5 0.1 0.1 1
+		0.5 0.1 0.1 1
+		0.58 0.18 0.18 1
+		0.58 0.18 0.18 1
+		0.66 0.26 0.26 1
+		0.66 0.26 0.26 1
+		0.74 0.34 0.34 1
+		0.74 0.34 0.34 1
+		0.82 0.42 0.42 1
+		0.82 0.42 0.42 1
+		1 1 1 1
+		0.9 0.5 0.5 1
+		0.9 0.5 0.5 1
+		0.82 0.42 0.42 1
+		0.82 0.42 0.42 1
+		0.74 0.34 0.34 1
+		0.74 0.34 0.34 1
+		0.66 0.26 0.26 1
+		0.66 0.26 0.26 1
+		0.58 0.18 0.18 1
+		0.58 0.18 0.18 1
+		0.5 0.1 0.1 1
+		0.5 0.1 0.1 1
+		0.58 0.18 0.18 1
+		0.58 0.18 0.18 1
+		0.66 0.26 0.26 1
+		0.66 0.26 0.26 1
+		0.74 0.34 0.34 1
+		0.74 0.34 0.34 1
+		0.82 0.42 0.42 1
+		0.82 0.42 0.42 1
+		0.9 0.5 0.5 1
+		0.9 0.5 0.5 1
+		0.82 0.42 0.42 1
+		0.82 0.42 0.42 1
+		0.74 0.34 0.34 1
+		0.74 0.34 0.34 1
+		0.66 0.26 0.26 1
+		0.66 0.26 0.26 1
+		0.58 0.18 0.18 1
+		0.58 0.18 0.18 1
+		0.5 0.1 0.1 1
+		0.5 0.1 0.1 1
+		0.58 0.18 0.18 1
+		0.58 0.18 0.18 1
+		0.66 0.26 0.26 1
+		0.66 0.26 0.26 1
+		0.74 0.34 0.34 1
+		0.74 0.34 0.34 1
+		0.82 0.42 0.42 1
+		0.82 0.42 0.42 1
+		0.9 0.5 0.5 1
+		0.9 0.5 0.5 1
+		0.82 0.42 0.42 1
+		0.82 0.42 0.42 1
+		0.74 0.34 0.34 1
+		0.74 0.34 0.34 1
+		0.66 0.26 0.26 1
+		0.66 0.26 0.26 1
+		0.58 0.18 0.18 1
+		0.58 0.18 0.18 1
+		0.5 0.1 0.1 1
+		0.5 0.1 0.1 1
+		0.58 0.18 0.18 1
+		0.58 0.18 0.18 1
+		0.66 0.26 0.26 1
+		0.66 0.26 0.26 1
+		0.74 0.34 0.34 1
+		0.74 0.34 0.34 1
+		0.82 0.42 0.42 1
+		0.82 0.42 0.42 1
+	</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
+		0 -1 0
+		0 1 0
+		0 -1 0
+		0 1 0
+		0 -1 0
+		0 1 0
+		0 -1 0
+		0 1 0
+		0 -1 0
+		0 1 0
+		0 -1 0
+		0 1 0
+		0 -1 0
+		0 1 0
+		0 -1 0
+		0 1 0
+		0 -1 0
+		0 1 0
+		0 -1 0
+		0 1 0
+		0 -1 0
+		0 1 0
+		0 -1 0
+		0 1 0
+		0 -1 0
+		0 1 0
+		0 -1 0
+		0 1 0
+		0 -1 0
+		0 1 0
+		0 -1 0
+		0 1 0
+		0 -1 0
+		0 1 0
+		0 -1 0
+		0 1 0
+		0 -1 0
+		0 1 0
+		0 -1 0
+		0 1 0
+		0 -1 0
+		0 1 0
+		0 -1 0
+		0 1 0
+		0 -1 0
+		0 1 0
+		0 -1 0
+		0 1 0
+		0 -1 0
+		0 1 0
+		0 -1 0
+		0 1 0
+		0 -1 0
+		0 -1 0
+		1 0 0
+		1 0 0
+		0.97814763751461 0 0.20791151777759
+		0.97814763751461 0 0.20791151777759
+		0.91354560155084 0 0.40673631985245
+		0.91354560155084 0 0.40673631985245
+		0.80901730632302 0 0.58778482293254
+		0.80901730632302 0 0.58778482293254
+		0.66913113222576 0 0.74314435198437
+		0.66913113222576 0 0.74314435198437
+		0.5000007660252 0 0.86602496151913
+		0.5000007660252 0 0.86602496151913
+		0.30901800386032 0 0.95105618829288
+		0.30901800386032 0 0.95105618829288
+		0.10452969482571 0 0.99452176592553
+		0.10452969482571 0 0.99452176592553
+		-0.10452705577254 0 0.99452204330096
+		-0.10452705577254 0 0.99452204330096
+		-0.30901548014624 0 0.95105700829655
+		-0.30901548014624 0 0.95105700829655
+		-0.49999846794844 0 0.86602628831301
+		-0.49999846794844 0 0.86602628831301
+		-0.66912916022314 0 0.7431461275813
+		-0.66912916022314 0 0.7431461275813
+		-0.80901574658037 0 0.58778696973054
+		-0.80901574658037 0 0.58778696973054
+		-0.91354452223627 0 0.40673874402631
+		-0.91354452223627 0 0.40673874402631
+		-0.97814708579929 0 0.20791411337945
+		-0.97814708579929 0 0.20791411337945
+		-0.99999999999648 0 2.6535897933527e-006
+		-0.99999999999648 0 2.6535897933527e-006
+		-0.97814818922305 0 -0.20790892217427
+		-0.97814818922305 0 -0.20790892217427
+		-0.91354668085897 0 -0.40673389567574
+		-0.91354668085897 0 -0.40673389567574
+		-0.80901886605998 0 -0.58778267613041
+		-0.80901886605998 0 -0.58778267613041
+		-0.66913310422368 0 -0.74314257638221
+		-0.66913310422368 0 -0.74314257638221
+		-0.50000306409843 0 -0.86602363471916
+		-0.50000306409843 0 -0.86602363471916
+		-0.30902052757222 0 -0.95105536828251
+		-0.30902052757222 0 -0.95105536828251
+		-0.10453233387815 0 -0.9945214885431
+		-0.10453233387815 0 -0.9945214885431
+		0.10452441671862 0 -0.99452232066939
+		0.10452441671862 0 -0.99452232066939
+		0.30901295642998 0 -0.95105782829353
+		0.30901295642998 0 -0.95105782829353
+		0.49999616986816 0 -0.8660276151008
+		0.49999616986816 0 -0.8660276151008
+		0.66912718821581 0 -0.74314790317299
+		0.66912718821581 0 -0.74314790317299
+		0.80901418683202 0 -0.5877891165244
+		0.80901418683202 0 -0.5877891165244
+		0.91354344291528 0 -0.40674116819729
+		0.91354344291528 0 -0.40674116819729
+		0.97814653407707 0 -0.20791670897984
+		0.97814653407707 0 -0.20791670897984
+	</attribute>
+	<vao name="lit-color" >
+		<source attrib="0" />
+		<source attrib="1" />
+		<source attrib="2" />
+	</vao>
+	<vao name="lit" >
+		<source attrib="0" />
+		<source attrib="2" />
+	</vao>
+	<vao name="color" >
+		<source attrib="0" />
+		<source attrib="1" />
+	</vao>
+	<indices cmd="tri-fan" type="ushort" >0 1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47 49 51 53 55 57 59 1</indices>
+	<indices cmd="tri-fan" type="ushort" >61 60 58 56 54 52 50 48 46 44 42 40 38 36 34 32 30 28 26 24 22 20 18 16 14 12 10 8 6 4 2 60</indices>
+	<indices cmd="tri-strip" type="ushort" >62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 62 63</indices>
+</mesh>
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.