CSC8502_Advanced_Graphics_For_Games / Blank Project / Renderer.cpp
Renderer.cpp
Raw
#include "Renderer.h"
#include "../nclgl/Camera.h"
#include "../nclgl/HeightMap.h"
#include "../nclgl/SceneNode.h"
#include "../nclgl/MeshAnimation.h"
#include "../nclgl/MeshMaterial.h"
#include "../nclgl/CubeRobot.h"

#define SHADOWSIZE 2048
const int POST_PASSES = 10;

Renderer::Renderer(Window& parent) : OGLRenderer(parent) {
	fullScreenQuad = Mesh::GenerateQuad();

	terrain = new HeightMap(TEXTUREDIR"noise.png");
	
	waterTex = SOIL_load_OGL_texture(TEXTUREDIR"water.TGA",
		SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_MIPMAPS);

	earthTex = SOIL_load_OGL_texture(TEXTUREDIR"Barren Reds.JPG",
		SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_MIPMAPS);

	earthBump = SOIL_load_OGL_texture(TEXTUREDIR"Barren RedsDOT3.JPG",
		SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_MIPMAPS);

	skybox = SOIL_load_OGL_cubemap(
		TEXTUREDIR"rusted_west.jpg", TEXTUREDIR"rusted_east.jpg",
		TEXTUREDIR"rusted_up.jpg", TEXTUREDIR"rusted_down.jpg",
		TEXTUREDIR"rusted_south.jpg", TEXTUREDIR"rusted_north.jpg",
		SOIL_LOAD_RGB, SOIL_CREATE_NEW_ID, 0);

	if (!earthTex || !earthBump || !skybox || !waterTex) {
		return;
	}

	SetTextureRepeating(earthTex, true);
	SetTextureRepeating(earthBump, true);
	SetTextureRepeating(waterTex, true);

	sceneShader = new Shader("SceneVertex.glsl", "SceneFragment.glsl");
	reflectShader = new Shader("reflectVertex.glsl", "reflectFragment.glsl");
	skyboxShader = new Shader("skyboxVertex.glsl", "skyboxFragment.glsl");
	lightShader = new Shader("BumpVertex.glsl", "BumpFragment.glsl");
	skinningShader = new Shader("SkinningVertex.glsl", "TexturedFragment.glsl");
	shadowShader = new Shader("shadowVert.glsl", "shadowFrag.glsl");
	shadowSceneShader = new Shader("shadowscenevert.glsl", "shadowscenefrag.glsl");
	//reflectSphereShader - new Shader("BumpVertex.glsl", "reflectSphereFragment.glsl");
	redShader = new Shader("presentVert.glsl", "redFrag.glsl");
	combineShader = new Shader("combinevert.glsl", "combinefrag.glsl");
	//sceneBlurShader = new Shader("TexturedVertex.glsl","TexturedFragment.glsl");
	//processBlurShader = new Shader("TexturedVertex.glsl","processfrag.glsl");


	if (!sceneShader->LoadSuccess() ||
		!reflectShader->LoadSuccess() ||
		!skyboxShader->LoadSuccess() ||
		!lightShader->LoadSuccess() ||
		!skinningShader->LoadSuccess() || 
		!shadowShader->LoadSuccess() || 
		!shadowSceneShader->LoadSuccess() 
		 //|| !reflectSphereShader->LoadSuccess() 
		|| !redShader->LoadSuccess()
		|| !combineShader->LoadSuccess()
		//|| sceneBlurShader->LoadSuccess()
		//|| processBlurShader->LoadSuccess()
		){ 
		return;
	}

	root = new SceneNode();

	terrain->SetTexture(SOIL_load_OGL_texture(TEXTUREDIR"Barren Reds.JPG", SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_MIPMAPS));
	terrain->SetBumpMap(SOIL_load_OGL_texture(TEXTUREDIR"Barren RedsDOT3.JPG", SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_MIPMAPS));
	
	SetTextureRepeating(terrain->GetTexture(), true);
	SetTextureRepeating(terrain->GetBumpMap(), true);

	Vector3 heightmapSize = terrain->GetHeightmapSize();

	//Mesh* sphere = Mesh::LoadFromMeshFile("Sphere.msh");
	//SceneNode* sphereNode = new SceneNode(sphere);
	//sphereNode->SetTransform(Matrix4::Translation(Vector3(500, 300, 0)) * Matrix4::Scale(Vector3(50, 50, 50)));
	//sphereNode->SetShader(reflectShader);
	//sphereNode->SetBoundingRadius(50.0f);
	//root->AddChild(sphereNode);

	Mesh* sphere2 = Mesh::LoadFromMeshFile("Sphere.msh");
	sphere2->SetTexture(SOIL_load_OGL_texture(TEXTUREDIR"brick.tga", SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_MIPMAPS));
	SetTextureRepeating(sphere2->GetTexture(), true);
	SceneNode* sphereNode2 = new SceneNode(sphere2);
	sphereNode2->SetTransform(Matrix4::Translation(Vector3(800, 300, 500)) * Matrix4::Scale(Vector3(50, 50, 50)));
	sphereNode2->SetShader(reflectShader);
	sphereNode2->SetBoundingRadius(500.0f);
	root->AddChild(sphereNode2);

	//Mesh* sphere = Mesh::LoadFromMeshFile("Sphere.msh");
	//sphere->SetTexture(SOIL_load_OGL_texture(TEXTUREDIR"brick.tga", SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_MIPMAPS));
	//SetTextureRepeating(sphere->GetTexture(), true);
	//SceneNode* sphereNode = new SceneNode(sphere);
	//sphereNode->SetTransform(Matrix4::Scale(Vector3(5, 5, 5)) * Matrix4::Translation(heightmapSize * Vector3(0.0f, 1.5f, 0.0f)));
	////sphereNode->SetTransform(Matrix4::Scale(Vector3(2000, 2000, 2000)));;
	////sphereNode->SetTransform(Matrix4::Translation(Vector3(-50, 50, 50)));
	//sphereNode->SetShader(reflectShader);
	//sphereNode->SetBoundingRadius(500.0f);

	//sphereNode->SetColour(Vector4(1, 0, 0, 1));

	//root->AddChild(sphereNode);

	cubeRobot = Mesh::LoadFromMeshFile("OffsetCubeY.msh");

	SceneNode* cubeRobotNode = new SceneNode(cubeRobot);
	//cubeRobotNode->SetTransform(Matrix4::Translation(Vector3(1000, 1000, 1000)) * Matrix4::Scale(Vector3(100, 100, 100)));
	sphereNode2->SetTransform(Matrix4::Translation(Vector3(1000, 300, 0)) * Matrix4::Scale(Vector3(50, 50, 50)));
	sphereNode2->SetShader(reflectShader);
	cubeRobotNode->SetBoundingRadius(20);
	root->AddChild(new CubeRobot(cubeRobot));

	/// ////////////
	mesh = Mesh::LoadFromMeshFile("Role_T.msh");
	anim = new MeshAnimation("Role_T.anm");
	material = new MeshMaterial("Role_T.mat");

	for (int i = 0; i < mesh->GetSubMeshCount(); ++i) {
		const MeshMaterialEntry* matEntry =
			material->GetMaterialForLayer(i);

		const string* filename = nullptr;
		matEntry->GetEntry("Diffuse", &filename);
		string path = TEXTUREDIR + *filename;
		GLuint texID = SOIL_load_OGL_texture(path.c_str(), SOIL_LOAD_AUTO,
			SOIL_CREATE_NEW_ID, SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y);
		matTextures.emplace_back(texID);
	}
	currentFrame = 0;
	frameTime = 0.0f;

	SceneNode* meshNode = new SceneNode(mesh);
	meshNode->SetShader(skinningShader);
	BindShader(skinningShader);
	meshNode->SetBoundingRadius(100.0f);
	root->AddChild(meshNode);

	/// 
	glGenTextures(1, &shadowTex);
	glBindTexture(GL_TEXTURE_2D, shadowTex);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

	glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT,
		SHADOWSIZE, SHADOWSIZE, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);

	glBindTexture(GL_TEXTURE_2D, 0);

	glGenFramebuffers(1, &shadowFBO);
	glBindFramebuffer(GL_FRAMEBUFFER, shadowFBO);
	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
		GL_TEXTURE_2D, shadowTex, 0);

	glDrawBuffer(GL_NONE);
	glBindFramebuffer(GL_FRAMEBUFFER, 0);

	sceneMeshes.emplace_back(Mesh::GenerateQuad());
	sceneMeshes.emplace_back(Mesh::LoadFromMeshFile("Sphere.msh"));
	sceneMeshes.emplace_back(Mesh::LoadFromMeshFile("Cylinder.msh"));
	sceneMeshes.emplace_back(Mesh::LoadFromMeshFile("Cone.msh"));

	sceneDiffuse = SOIL_load_OGL_texture(TEXTUREDIR"Barren Reds.JPG",
		SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_MIPMAPS);
	sceneBump = SOIL_load_OGL_texture(TEXTUREDIR"Barren RedsDOT3.JPG",
		SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_MIPMAPS);
	SetTextureRepeating(sceneDiffuse, true);
	SetTextureRepeating(sceneBump, true);
 

	glEnable(GL_DEPTH_TEST);

	sceneTransforms.resize(4);
	sceneTransforms[0] = Matrix4::Translation(Vector3(500, 500, 500)) * Matrix4::Rotation(45, Vector3(1, 0, 0)) *
		Matrix4::Scale(Vector3(100, 100, 100));

	sceneTransforms[1] = Matrix4::Rotation(45, Vector3(1, 0, 0)) *
		Matrix4::Scale(Vector3(100, 100, 100));

	sceneTransforms[2] = Matrix4::Rotation(45, Vector3(1, 0, 0)) *
		Matrix4::Scale(Vector3(100, 100, 100));

	sceneTransforms[3] = Matrix4::Rotation(45, Vector3(1, 0, 0)) *
		Matrix4::Scale(Vector3(100, 100, 100));

	

	sceneTime = 0.0f;

	light2 = new Light(heightmapSize * Vector3(0.0f, 1.0f, 0.0f),
		Vector4(1, 1, 1, 1), heightmapSize.x);
	//	camOne = new Camera(-45.0f, 0.0f,
	//heightmapSize* Vector3(0.5f, 5.0f, 0.5f));


		camOne = new Camera(-10.0f, 180.0f, Vector3(16.0f, 350.0f, -805.0f));
		//camOne->SetSpeed(0.1f);

		camTwo = new Camera(-10.0f, 180.0f, Vector3(16.0f, 350.0f, -805.0f));
		//camTwo->SetSpeed(0.1f);

		cameraPerspectiveMatrix = Matrix4::Perspective(1.0f, 10000.0f, (float)width / (float)height, 45.0f);
		cameraSplitScreenPerspectiveMatrix = Matrix4::Perspective(1.0f, 10000.0f, (float)width / ((float)height / 2.0f), 45.0f);
		shadowPerspectiveMatrix = Matrix4::Perspective(1.0f, 10000.0f, 1, 90.0f);


	light = new Light(heightmapSize * Vector3(0.5f, 1.5f, 0.5f),
		Vector4(1, 1, 1, 1), heightmapSize.x);
 

	projMatrix = Matrix4::Perspective(1.0f, 15000.0f,
		(float)width / (float)height, 45.0f);


	//glGenFramebuffers(1, &bufferFBO);
	//glGenFramebuffers(1, &pointLightFBO);
	//glGenFramebuffers(1, &shadowFBO);
	//glGenFramebuffers(1, &shadowCubeMapFBO);
	//glGenFramebuffers(1, &combinedFBO);

	//gBuffer[0] = GL_COLOR_ATTACHMENT0;
	//gBuffer[1] = GL_COLOR_ATTACHMENT1;
	//gBuffer[2] = GL_COLOR_ATTACHMENT2;

	//lightBuffer[0] = GL_COLOR_ATTACHMENT0;
	//lightBuffer[1] = GL_COLOR_ATTACHMENT1;

	//combinedBuffer[0] = GL_COLOR_ATTACHMENT0;

	//generateGBuffer();
	//generateLightBuffer();
	//generateShadowBuffer();
	//generateShadowCubeMapBuffer();
	//generateCombinedBuffer();


	glEnable(GL_DEPTH_TEST);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
	waterRotate = 0.0f;
	waterCycle = 0.0f;
	init = true;
}

Renderer::~Renderer(void) {
	delete camOne;
	delete terrain;
	delete fullScreenQuad;

	delete light;
	delete light2;

	delete root;
	delete cubeRobot;

	delete mesh;
	delete anim;
	delete material;

	delete sceneShader;
	delete lightShader;
	delete reflectShader;
	delete skyboxShader;
	delete skinningShader;
	delete shadowShader;
	delete shadowSceneShader;
	delete redShader;
	delete combineShader;


	glDeleteTextures(1, &shadowTex);
	glDeleteFramebuffers(1, &shadowFBO);

	for (auto& i : sceneMeshes) {
		delete i;
	}


	glDeleteTextures(1, &bufferColourTex);
	glDeleteTextures(1, &bufferNormalTex);
	glDeleteTextures(1, &bufferPosTex);
	glDeleteTextures(1, &bufferDepthTex);
	glDeleteTextures(1, &lightEmissiveTex);
	glDeleteTextures(1, &lightSpecularTex);
	glDeleteTextures(1, &shadowTex);
	glDeleteTextures(1, &shadowCubeMapTex);
	glDeleteTextures(1, &combinedTex);
	glDeleteTextures(2, bufferColourTexPost);

	glDeleteFramebuffers(1, &bufferFBO);
	glDeleteFramebuffers(1, &pointLightFBO);
	glDeleteFramebuffers(1, &shadowFBO);
	glDeleteFramebuffers(1, &shadowCubeMapFBO);
	glDeleteFramebuffers(1, &combinedFBO);
	glDeleteFramebuffers(1, &processFBO);


	
	root = NULL;
}



void Renderer::CombineBuffers() {

	glBindFramebuffer(GL_FRAMEBUFFER, combinedFBO);
	BindShader(combineShader);

	if (drawSplitScreen)
		projMatrix = cameraSplitScreenPerspectiveMatrix;
	else
		projMatrix = cameraPerspectiveMatrix;
	glUniformMatrix4fv(glGetUniformLocation(currentShader->GetProgram(), "oriProjMatrix"), 1, false, (float*)&projMatrix);

	projMatrix = Matrix4::Orthographic(-1, 1, 1, -1, -1, 1);
	viewMatrix = camOne->BuildViewMatrix();
	UpdateShaderMatrices();

	glUniform1i(glGetUniformLocation(currentShader->GetProgram(), "diffuseTex"), 2);
	glUniform1i(glGetUniformLocation(currentShader->GetProgram(), "emissiveTex"), 3);
	glUniform1i(glGetUniformLocation(currentShader->GetProgram(), "specularTex"), 4);
	glUniform1i(glGetUniformLocation(currentShader->GetProgram(), "posTex"), 5);
	glUniform1i(glGetUniformLocation(currentShader->GetProgram(), "depthTex"), 6);
	glUniform1i(glGetUniformLocation(currentShader->GetProgram(), "skybox"), 7);


	glActiveTexture(GL_TEXTURE2);
	glBindTexture(GL_TEXTURE_2D, bufferColourTex);

	glActiveTexture(GL_TEXTURE3);
	glBindTexture(GL_TEXTURE_2D, lightEmissiveTex);

	glActiveTexture(GL_TEXTURE4);
	glBindTexture(GL_TEXTURE_2D, lightSpecularTex);

	glActiveTexture(GL_TEXTURE5);
	glBindTexture(GL_TEXTURE_2D, bufferPosTex);

	glActiveTexture(GL_TEXTURE6);
	glBindTexture(GL_TEXTURE_2D, bufferDepthTex);

	glActiveTexture(GL_TEXTURE7);
	glBindTexture(GL_TEXTURE_CUBE_MAP, skybox);

	fullScreenQuad->Draw();

	glUseProgram(0);
	glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

void Renderer::UpdateScene(float dt) {
	Matrix4 rotation = Matrix4::Rotation(camOne->GetYaw(), Vector3(0, 1, 0));
	Vector3 forward = rotation * Vector3(0, 0, -1);
	Vector3 right = rotation * Vector3(1, 0, 0);
	if (cameraAutomatic) {
		if (waitCameraTime == 0.0f) {
		//	camOne->SetYaw(10.0);
		}
		waitCameraTime += dt;
		//camOne->SetYaw((Window::GetMouse()->GetRelativePosition().x));
		if (waitCameraTime > 25.0f) { //25.0f
			camOne->SetPosition(camOne->GetPosition() + forward * 1.0);

			std::cout << "X: " << camOne->GetPosition().x
				<< "Y: " << camOne->GetPosition().y
				<< "Z: " << camOne->GetPosition().z;
			std::cout << "Yaw: " << camOne->GetYaw()
				<< "Pitch: " << camOne->GetPitch();

			if (camOne->GetPosition().z > 1350.0f) {
				//camOne->SetYaw(30.0f);
				camOne->SetPosition(camOne->GetPosition() - right * 1.0);
			}
			if (camOne->GetPosition().x > 1900.0f) {
				//camOne->SetYaw(30.0f);
				camOne->SetPosition(camOne->GetPosition() - forward * 1.0);
			}
			//if (camOne->GetPosition().z > 650.0f) {
			//	//camOne->SetYaw(30.0f);
			//	camOne->SetPosition(camOne->GetPosition() - forward * 1.0);
			//}
		}
		moveCamOne = true;	
	}  
	else {
		moveCamOne = true;
	}

	if (moveCamOne)
		camOne->UpdateCamera(dt);
	else
		camTwo->UpdateCamera(dt);

	camOne->UpdateCamera(dt);
	viewMatrix = camOne->BuildViewMatrix();
	frameFrustum.FromMatrix(projMatrix * viewMatrix);
	waterRotate += dt * 2.0f;
	waterCycle += dt * 0.25f;
	
	sceneTime += dt;

	frameTime -= dt;
	while (frameTime < 0.0f) {
		currentFrame = (currentFrame + 1) % anim->GetFrameCount();
		frameTime += 1.0f / anim->GetFrameRate();
	}


	for (int i = 0; i < 4; ++i) {
		Vector3 t = Vector3(-10 + (5 * i), 2.0f + sin(sceneTime * i), 0);
		sceneTransforms[i] = Matrix4::Translation(t) *
			Matrix4::Rotation(sceneTime * 10 * i, Vector3(1, 0, 0));
	}

	redIntensity += dt / 1000.0f;
	if (redIntensity >= 90.0f)
		redIntensity -= 90.0f;

	root->Update(dt);
}

void Renderer::RenderScene() {
	currentCamera = camOne;
	modelMatrix.ToIdentity();
	if (drawSplitScreen)
		projMatrix = cameraSplitScreenPerspectiveMatrix;
	else
		projMatrix = cameraPerspectiveMatrix;

	//	glBindFramebuffer(GL_FRAMEBUFFER, 0);
	glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
	DrawSkybox();
	DrawHeightmap();
	DrawWater();

	DrawCharacter();

	DrawMainNodeScene();

	DrawShadowScene();
	DrawMainShadowScene();


	//CombineBuffers();

	if (applyRedPostProcess)
		DrawRedPostProcess();
	if (drawSplitScreen)
		glViewport(0, 0, width, height / 2);

	if (drawSplitScreen) {
		currentCamera = camTwo;
		modelMatrix.ToIdentity();
		projMatrix = cameraSplitScreenPerspectiveMatrix;

		glViewport(0, height / 2, width, height / 2);
		DrawSkybox();
		DrawHeightmap();
		DrawWater();

		DrawCharacter();

		DrawMainNodeScene();

		DrawShadowScene();
		DrawMainShadowScene();
		glViewport(0, 0, width, height);
	}

}


void Renderer::DrawRedPostProcess() {
	glBindFramebuffer(GL_FRAMEBUFFER, combinedFBO);
	BindShader(redShader);

	UpdateShaderMatrices();

	glUniform1i(glGetUniformLocation(currentShader->GetProgram(), "diffuseTex"), 2);
	glActiveTexture(GL_TEXTURE2);
	glBindTexture(GL_TEXTURE_2D, combinedTex);

	glUniform1f(glGetUniformLocation(currentShader->GetProgram(), "intensity"), sin(redIntensity));

	fullScreenQuad->Draw();

	glUseProgram(0);
	glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

void Renderer::DrawSkybox() {
	glDepthMask(GL_FALSE);

	BindShader(skyboxShader);
	UpdateShaderMatrices();

	fullScreenQuad->Draw();

	glDepthMask(GL_TRUE);
}

void Renderer::DrawHeightmap() {
	BindShader(lightShader);
	SetShaderLight(*light);
	glUniform3fv(glGetUniformLocation(
		lightShader->GetProgram(), "cameraPos"), 1, (float*)&camOne->GetPosition());

	glUniform1i(glGetUniformLocation(
		lightShader->GetProgram(), "diffuseTex"), 0);
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, earthTex);

	glUniform1i(glGetUniformLocation(
		lightShader->GetProgram(), "bumpTex"), 1);
	glActiveTexture(GL_TEXTURE1);
	glBindTexture(GL_TEXTURE_2D, earthBump);

	modelMatrix.ToIdentity();
	textureMatrix.ToIdentity();

	UpdateShaderMatrices();

	terrain->Draw();
}

void Renderer::DrawWater() {
	BindShader(reflectShader);

	glUniform3fv(glGetUniformLocation(
		reflectShader->GetProgram(), "cameraPos"), 1, (float*)&camOne->GetPosition());

	glUniform1i(glGetUniformLocation(
		reflectShader->GetProgram(), "diffuseTex"), 0);
	glUniform1i(glGetUniformLocation(
		reflectShader->GetProgram(), "cubeTex"), 2);

	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, waterTex);

	glActiveTexture(GL_TEXTURE2);
	glBindTexture(GL_TEXTURE_CUBE_MAP, skybox);

	Vector3 hSize = terrain->GetHeightmapSize();

	modelMatrix =
		Matrix4::Translation(hSize * 0.5f) *
		Matrix4::Scale(hSize * 0.5f) *
		Matrix4::Rotation(90, Vector3(1, 0, 0));

	textureMatrix =
		Matrix4::Translation(Vector3(waterCycle, 0.0f, waterCycle)) *
		Matrix4::Scale(Vector3(10, 10, 10)) *
		Matrix4::Rotation(waterRotate, Vector3(0, 0, 1));

	UpdateShaderMatrices();
	//SetShaderLight (* light ); // No lighting in this shader !
	fullScreenQuad->Draw();
}


void Renderer::DrawCharacter() {
	BindShader(skinningShader);
	glUniform1i(
		glGetUniformLocation(skinningShader->GetProgram(),
			"diffuseTex"), 0);
	modelMatrix = Matrix4::Translation(Vector3(500,150,120)) * Matrix4::Scale(Vector3(100, 100, 100));
	UpdateShaderMatrices();

	vector<Matrix4> frameMatrices;

	const Matrix4* invBindPose = mesh->GetInverseBindPose();
	const Matrix4* frameData = anim->GetJointData(currentFrame);

	for (unsigned int i = 0; i < mesh->GetJointCount(); ++i) {
		frameMatrices.emplace_back(frameData[i] * invBindPose[i]);
	}

	int j = glGetUniformLocation(skinningShader->GetProgram(), "joints");
	glUniformMatrix4fv(j, frameMatrices.size(), false,
		(float*)frameMatrices.data());

	for (int i = 0; i < mesh->GetSubMeshCount(); ++i) {
		glActiveTexture(GL_TEXTURE0);
		glBindTexture(GL_TEXTURE_2D, matTextures[i]);
		mesh->DrawSubMesh(i);
	}
}

void Renderer::DrawShadowScene() {
	glBindFramebuffer(GL_FRAMEBUFFER, shadowFBO);

	glClear(GL_DEPTH_BUFFER_BIT);
	glViewport(0, 0, SHADOWSIZE, SHADOWSIZE);
	glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);

	BindShader(shadowShader);

	viewMatrix = Matrix4::BuildViewMatrix(
		light2->GetPosition(), Vector3(0, 0, 0));
	projMatrix = Matrix4::Perspective(1, 100, 1, 45);
	shadowMatrix = projMatrix * viewMatrix;

	for (int i = 0; i < 4; ++i) {
		modelMatrix = sceneTransforms[i];
		UpdateShaderMatrices();
		sceneMeshes[i]->Draw();
	}

	glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
	glViewport(0, 0, width, height);

	glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

void Renderer::DrawMainShadowScene() {
	BindShader(shadowSceneShader);
	SetShaderLight(*light2);
	viewMatrix = camOne->BuildViewMatrix();
	projMatrix = Matrix4::Perspective(1.0f, 15000.0f,
		(float)width / (float)height, 45.0f);

	glUniform1i(glGetUniformLocation(shadowSceneShader->GetProgram(),
		"diffuseTex"), 0);
	glUniform1i(glGetUniformLocation(shadowSceneShader->GetProgram(),
		"bumpTex"), 1);
	glUniform1i(glGetUniformLocation(shadowSceneShader->GetProgram(),
		"shadowTex"), 2);

	glUniform3fv(glGetUniformLocation(shadowSceneShader->GetProgram(),
		"cameraPos"), 1, (float*)&camOne->GetPosition());

	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, sceneDiffuse);

	glActiveTexture(GL_TEXTURE1);
	glBindTexture(GL_TEXTURE_2D, sceneBump);

	glActiveTexture(GL_TEXTURE2);
	glBindTexture(GL_TEXTURE_2D, shadowTex);

	
	for (int i = 0; i < 4; ++i) {
		int tr = 300 * i;
		modelMatrix = sceneTransforms[i] * Matrix4::Translation(Vector3(tr, 250, 250)) * Matrix4::Scale(Vector3(100,100,100));
		UpdateShaderMatrices();
		sceneMeshes[i]->Draw();
	}
}

void Renderer::DrawMainNodeScene() {
	BuildNodeLists(root);
	SortNodeLists();
	BindShader(sceneShader);
	UpdateShaderMatrices();

	glUniform1i(
		glGetUniformLocation(sceneShader->GetProgram(),
			"diffuseTex"), 0);

	DrawNodes();

	ClearNodeLists();
}

void Renderer::BuildNodeLists(SceneNode* from) {
	if (frameFrustum.InsideFrustum(*from)) {
		Vector3 dir = from->GetWorldTransform().GetPositionVector() -
			camOne->GetPosition();
		from->SetCameraDistance(Vector3::Dot(dir, dir));

		if (from->GetColour().w < 1.0f) {
			transparentNodeList.push_back(from);
		}
		else {
			nodeList.push_back(from);
		}
	}

	for (vector<SceneNode*>::const_iterator i =
		from->GetChildIteratorStart();
		i != from->GetChildIteratorEnd(); ++i) {
		BuildNodeLists((*i));
	}
}

void Renderer::SortNodeLists() {
	std::sort(transparentNodeList.rbegin(),
		transparentNodeList.rend(),
		SceneNode::CompareByCameraDistance);
	std::sort(nodeList.begin(),
		nodeList.end(),
		SceneNode::CompareByCameraDistance);
}

void Renderer::DrawNodes() {
	for (const auto& i : nodeList) {
		DrawNode(i);
	}
	for (const auto& i : transparentNodeList) {
		DrawNode(i);
	}
}

void Renderer::DrawNode(SceneNode* n) {
	if (n->GetMesh()) {
		Matrix4 model = n->GetWorldTransform() *
			Matrix4::Scale(n->GetModelScale());

		glUniformMatrix4fv(
			glGetUniformLocation(currentShader->GetProgram(),
				"modelMatrix"), 1, false, model.values);

		glUniform4fv(
			glGetUniformLocation(currentShader->GetProgram(),
				"nodeColour"), 1, (float*)&n->GetColour());

		GLuint texture = n->GetTexture();
		glActiveTexture(GL_TEXTURE0);
		glBindTexture(GL_TEXTURE_2D, texture);

		glUniform1i(
			glGetUniformLocation(currentShader->GetProgram(),
				"useTexture"), texture);

		n->Draw(*this);
	}
}

void Renderer::ClearNodeLists() {
	transparentNodeList.clear();
	nodeList.clear();
}


void Renderer::GenerateScreenTexture(GLuint& into, bool depth) {
	glGenTextures(1, &into);
	glBindTexture(GL_TEXTURE_2D, into);

	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

	glTexImage2D(GL_TEXTURE_2D, 0,
		depth ? GL_DEPTH_COMPONENT24 : GL_RGBA8,
		width, height, 0,
		depth ? GL_DEPTH_COMPONENT : GL_RGBA,
		GL_UNSIGNED_BYTE, NULL);

	glBindTexture(GL_TEXTURE_2D, 0);
}

void Renderer::GenerateShadowTexture(GLuint& into) {
	glGenTextures(1, &into);
	glBindTexture(GL_TEXTURE_2D, into);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

	glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, SHADOWSIZE, SHADOWSIZE, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);

	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);

	glBindTexture(GL_TEXTURE_2D, 0);
}

void Renderer::GenerateShadowCubeMapTexture(GLuint& into) {
	glGenTextures(1, &into);
	glBindTexture(GL_TEXTURE_CUBE_MAP, into);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

	for (int i = 0; i < 6; ++i) {
		glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_DEPTH_COMPONENT24, SHADOWSIZE, SHADOWSIZE, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
	}

	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);

	glBindTexture(GL_TEXTURE_2D, 0);
}

void Renderer::generateGBuffer() {
	GenerateScreenTexture(bufferColourTex);
	GenerateScreenTexture(bufferNormalTex);
	GenerateScreenTexture(bufferPosTex);
	GenerateScreenTexture(bufferDepthTex, true);

	glBindFramebuffer(GL_FRAMEBUFFER, bufferFBO);
	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, bufferColourTex, 0);
	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, bufferNormalTex, 0);
	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, bufferPosTex, 0);
	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, bufferDepthTex, 0);
	glDrawBuffers(3, gBuffer);

	if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
		return;
	}

	glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

void Renderer::generateLightBuffer() {
	GenerateScreenTexture(lightEmissiveTex);
	GenerateScreenTexture(lightSpecularTex);

	glBindFramebuffer(GL_FRAMEBUFFER, pointLightFBO);
	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, lightEmissiveTex, 0);
	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, lightSpecularTex, 0);
	glDrawBuffers(2, lightBuffer);

	if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
		return;
	}

	glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

void Renderer::generateShadowBuffer() {
	GenerateShadowTexture(shadowTex);

	glBindFramebuffer(GL_FRAMEBUFFER, shadowFBO);
	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, shadowTex, 0);

	glDrawBuffer(GL_NONE);

	if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
		return;
	}

	glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

void Renderer::generateShadowCubeMapBuffer() {
	GenerateShadowCubeMapTexture(shadowCubeMapTex);

	glBindFramebuffer(GL_FRAMEBUFFER, shadowCubeMapFBO);

	glDrawBuffer(GL_NONE);

	glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

void Renderer::generateCombinedBuffer() {
	GenerateScreenTexture(combinedTex);

	glBindFramebuffer(GL_FRAMEBUFFER, combinedFBO);
	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, combinedTex, 0);

	glDrawBuffers(1, combinedBuffer);

	if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
		return;
	}

	glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

void Renderer::DrawPostProcess() {
	glBindFramebuffer(GL_FRAMEBUFFER, processFBO);
	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
		GL_TEXTURE_2D, bufferColourTexPost[1], 0);

	glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);

	BindShader(sceneShader);
	modelMatrix.ToIdentity();
	viewMatrix.ToIdentity();
	projMatrix.ToIdentity();
	UpdateShaderMatrices();

	glDisable(GL_DEPTH_TEST);

	glActiveTexture(GL_TEXTURE0);
	glUniform1i(glGetUniformLocation(
		sceneShader->GetProgram(), "sceneTex"), 0);
	for (int i = 0; i < POST_PASSES; ++i) {
		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
			GL_TEXTURE_2D, bufferColourTexPost[1], 0);
		glUniform1i(glGetUniformLocation(sceneShader->GetProgram(),
			"isVertical"), 0);

		glBindTexture(GL_TEXTURE_2D, bufferColourTexPost[0]);
		fullScreenQuad->Draw();
		//Now to swap the colour buffers, and do the second blur pass
		glUniform1i(glGetUniformLocation(sceneShader->GetProgram(),
			"isVertical"), 1);

		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
			GL_TEXTURE_2D, bufferColourTexPost[0], 0);
		glBindTexture(GL_TEXTURE_2D, bufferColourTexPost[1]);
		fullScreenQuad->Draw();
	}
	glBindFramebuffer(GL_FRAMEBUFFER, 0);
	glEnable(GL_DEPTH_TEST);
}