#include <algorithm>#include <string>#include <vector>#include <stack>#include <math.h>#include <glloader/gl_3_3_comp.h>#include <GL/freeglut.h>#include "../framework/framework.h"#include "../framework/Mesh.h"#include "../framework/MatrixStack.h"#include "../framework/MousePole.h"#include "../framework/ObjectPole.h"#include "../framework/Timer.h"#include <glm/glm.hpp>#include <glm/gtc/type_ptr.hpp>#include "Lights.h"#include "Scene.h"#define ARRAY_COUNT( array ) (sizeof( array ) / (sizeof( array[0] ) * (sizeof( array ) != sizeof(void*) || sizeof( array[0] ) <= sizeof(void*))))structUnlitProgData{GLuinttheProgram;GLuintobjectColorUnif;GLuintcameraToClipMatrixUnif;GLuintmodelToCameraMatrixUnif;voidSetWindowData(constglm::mat4cameraToClip){glUseProgram(theProgram);glUniformMatrix4fv(cameraToClipMatrixUnif,1,GL_FALSE,glm::value_ptr(cameraToClip));glUseProgram(0);}};floatg_fzNear=1.0f;floatg_fzFar=1000.0f;structShaders{constchar*fileVertexShader;constchar*fileFragmentShader;};ProgramDatag_Programs[LP_MAX_LIGHTING_PROGRAM_TYPES];Shadersg_ShaderFiles[LP_MAX_LIGHTING_PROGRAM_TYPES]={{"PCN.vert","DiffuseSpecularGamma.frag"},{"PCN.vert","DiffuseOnlyGamma.frag"},{"PN.vert","DiffuseSpecularMtlGamma.frag"},{"PN.vert","DiffuseOnlyMtlGamma.frag"},};UnlitProgDatag_Unlit;constintg_materialBlockIndex=0;constintg_lightBlockIndex=1;constintg_projectionBlockIndex=2;UnlitProgDataLoadUnlitProgram(conststd::string&strVertexShader,conststd::string&strFragmentShader){std::vector<GLuint>shaderList;shaderList.push_back(Framework::LoadShader(GL_VERTEX_SHADER,strVertexShader));shaderList.push_back(Framework::LoadShader(GL_FRAGMENT_SHADER,strFragmentShader));UnlitProgDatadata;data.theProgram=Framework::CreateProgram(shaderList);data.modelToCameraMatrixUnif=glGetUniformLocation(data.theProgram,"modelToCameraMatrix");data.objectColorUnif=glGetUniformLocation(data.theProgram,"objectColor");GLuintprojectionBlock=glGetUniformBlockIndex(data.theProgram,"Projection");glUniformBlockBinding(data.theProgram,projectionBlock,g_projectionBlockIndex);returndata;}ProgramDataLoadLitProgram(conststd::string&strVertexShader,conststd::string&strFragmentShader){std::vector<GLuint>shaderList;shaderList.push_back(Framework::LoadShader(GL_VERTEX_SHADER,strVertexShader));shaderList.push_back(Framework::LoadShader(GL_FRAGMENT_SHADER,strFragmentShader));ProgramDatadata;data.theProgram=Framework::CreateProgram(shaderList);data.modelToCameraMatrixUnif=glGetUniformLocation(data.theProgram,"modelToCameraMatrix");data.normalModelToCameraMatrixUnif=glGetUniformLocation(data.theProgram,"normalModelToCameraMatrix");GLuintmaterialBlock=glGetUniformBlockIndex(data.theProgram,"Material");GLuintlightBlock=glGetUniformBlockIndex(data.theProgram,"Light");GLuintprojectionBlock=glGetUniformBlockIndex(data.theProgram,"Projection");glUniformBlockBinding(data.theProgram,materialBlock,g_materialBlockIndex);glUniformBlockBinding(data.theProgram,lightBlock,g_lightBlockIndex);glUniformBlockBinding(data.theProgram,projectionBlock,g_projectionBlockIndex);returndata;}voidInitializePrograms(){for(intiProg=0;iProg<LP_MAX_LIGHTING_PROGRAM_TYPES;iProg++){g_Programs[iProg]=LoadLitProgram(g_ShaderFiles[iProg].fileVertexShader,g_ShaderFiles[iProg].fileFragmentShader);}g_Unlit=LoadUnlitProgram("PosTransform.vert","UniformColor.frag");}constProgramData&GetProgram(LightingProgramTypeseType){returng_Programs[eType];}LightManagerg_lights;Framework::RadiusDefradiusDef={50.0f,3.0f,80.0f,4.0f,1.0f};glm::vec3objectCenter=glm::vec3(-59.5f,4.0f,65.0f);Framework::MousePoleg_mousePole(objectCenter,radiusDef);namespace{voidMouseMotion(intx,inty){g_mousePole.GLUTMouseMove(glm::ivec2(x,y));glutPostRedisplay();}voidMouseButton(intbutton,intstate,intx,inty){g_mousePole.GLUTMouseButton(button,state,glm::ivec2(x,y));glutPostRedisplay();}voidMouseWheel(intwheel,intdirection,intx,inty){g_mousePole.GLUTMouseWheel(direction,glm::ivec2(x,y));glutPostRedisplay();}}structProjectionBlock{glm::mat4cameraToClipMatrix;};GLuintg_lightUniformBuffer;GLuintg_materialUniformBuffer;GLuintg_projectionUniformBuffer;constglm::vec4g_skyDaylightColor=glm::vec4(0.65f,0.65f,1.0f,1.0f);voidSetupHDRLighting(){SunlightValueHDRvalues[]={{0.0f/24.0f,glm::vec4(0.6f,0.6f,0.6f,1.0f),glm::vec4(1.8f,1.8f,1.8f,1.0f),g_skyDaylightColor,3.0f},{4.5f/24.0f,glm::vec4(0.6f,0.6f,0.6f,1.0f),glm::vec4(1.8f,1.8f,1.8f,1.0f),g_skyDaylightColor,3.0f},{6.5f/24.0f,glm::vec4(0.225f,0.075f,0.075f,1.0f),glm::vec4(0.45f,0.15f,0.15f,1.0f),glm::vec4(0.5f,0.1f,0.1f,1.0f),1.5f},{8.0f/24.0f,glm::vec4(0.0f,0.0f,0.0f,1.0f),glm::vec4(0.0f,0.0f,0.0f,1.0f),glm::vec4(0.0f,0.0f,0.0f,1.0f),1.0f},{18.0f/24.0f,glm::vec4(0.0f,0.0f,0.0f,1.0f),glm::vec4(0.0f,0.0f,0.0f,1.0f),glm::vec4(0.0f,0.0f,0.0f,1.0f),1.0f},{19.5f/24.0f,glm::vec4(0.225f,0.075f,0.075f,1.0f),glm::vec4(0.45f,0.15f,0.15f,1.0f),glm::vec4(0.5f,0.1f,0.1f,1.0f),1.5f},{20.5f/24.0f,glm::vec4(0.6f,0.6f,0.6f,1.0f),glm::vec4(1.8f,1.8f,1.8f,1.0f),g_skyDaylightColor,3.0f},};g_lights.SetSunlightValues(values,7);g_lights.SetPointLightIntensity(0,glm::vec4(0.6f,0.6f,0.6f,1.0f));g_lights.SetPointLightIntensity(1,glm::vec4(0.0f,0.0f,0.7f,1.0f));g_lights.SetPointLightIntensity(2,glm::vec4(0.7f,0.0f,0.0f,1.0f));}Scene*g_pScene=NULL;//Called after the window and OpenGL are initialized. Called exactly once, before the main loop.voidinit(){InitializePrograms();try{g_pScene=newScene();}catch(std::exception&except){printf(except.what());throw;}SetupHDRLighting();g_lights.CreateTimer("tetra",Framework::Timer::TT_LOOP,2.5f);glutMouseFunc(MouseButton);glutMotionFunc(MouseMotion);glutMouseWheelFunc(MouseWheel);glEnable(GL_CULL_FACE);glCullFace(GL_BACK);glFrontFace(GL_CW);constfloatdepthZNear=0.0f;constfloatdepthZFar=1.0f;glEnable(GL_DEPTH_TEST);glDepthMask(GL_TRUE);glDepthFunc(GL_LEQUAL);glDepthRange(depthZNear,depthZFar);glEnable(GL_DEPTH_CLAMP);//Setup our Uniform BuffersglGenBuffers(1,&g_lightUniformBuffer);glBindBuffer(GL_UNIFORM_BUFFER,g_lightUniformBuffer);glBufferData(GL_UNIFORM_BUFFER,sizeof(LightBlock),NULL,GL_DYNAMIC_DRAW);glGenBuffers(1,&g_projectionUniformBuffer);glBindBuffer(GL_UNIFORM_BUFFER,g_projectionUniformBuffer);glBufferData(GL_UNIFORM_BUFFER,sizeof(ProjectionBlock),NULL,GL_DYNAMIC_DRAW);//Bind the static buffers.glBindBufferRange(GL_UNIFORM_BUFFER,g_lightBlockIndex,g_lightUniformBuffer,0,sizeof(LightBlock));glBindBufferRange(GL_UNIFORM_BUFFER,g_projectionBlockIndex,g_projectionUniformBuffer,0,sizeof(ProjectionBlock));glBindBuffer(GL_UNIFORM_BUFFER,0);}boolg_bDrawCameraPos=false;boolg_bDrawLights=true;boolg_isGammaCorrect=false;floatg_gammaValue=2.2f;glm::vec4GammaCorrect(constglm::vec4&input,floatgamma){glm::vec4ret;ret[0]=powf(input[0],1.0f/gamma);ret[1]=powf(input[1],1.0f/gamma);ret[2]=powf(input[2],1.0f/gamma);ret[3]=input[3];returnret;}//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.voiddisplay(){g_lights.UpdateTime();floatgamma=g_isGammaCorrect?g_gammaValue:1.0f;glm::vec4bkg=GammaCorrect(g_lights.GetBackgroundColor(),gamma);glClearColor(bkg[0],bkg[1],bkg[2],bkg[3]);glClearDepth(1.0f);glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);Framework::MatrixStackmodelMatrix;modelMatrix.SetMatrix(g_mousePole.CalcMatrix());constglm::mat4&worldToCamMat=modelMatrix.Top();LightBlockGammalightData=g_lights.GetLightInformationGamma(worldToCamMat);lightData.gamma=gamma;glBindBuffer(GL_UNIFORM_BUFFER,g_lightUniformBuffer);glBufferSubData(GL_UNIFORM_BUFFER,0,sizeof(lightData),&lightData);glBindBuffer(GL_UNIFORM_BUFFER,0);if(g_pScene){Framework::MatrixStackPusherpush(modelMatrix);g_pScene->Draw(modelMatrix,g_materialBlockIndex,g_lights.GetTimerValue("tetra"));}{Framework::MatrixStackPusherpush(modelMatrix);//Render the sun{Framework::MatrixStackPusherpush(modelMatrix);glm::vec3sunlightDir(g_lights.GetSunlightDirection());modelMatrix.Translate(sunlightDir*500.0f);modelMatrix.Scale(30.0f,30.0f,30.0f);glUseProgram(g_Unlit.theProgram);glUniformMatrix4fv(g_Unlit.modelToCameraMatrixUnif,1,GL_FALSE,glm::value_ptr(modelMatrix.Top()));glm::vec4lightColor=GammaCorrect(g_lights.GetSunlightIntensity(),gamma);glUniform4fv(g_Unlit.objectColorUnif,1,glm::value_ptr(lightColor));g_pScene->GetSphereMesh()->Render("flat");}//Render the lightsif(g_bDrawLights){for(intlight=0;light<g_lights.GetNumberOfPointLights();light++){Framework::MatrixStackPusherpush(modelMatrix);modelMatrix.Translate(g_lights.GetWorldLightPosition(light));glUseProgram(g_Unlit.theProgram);glUniformMatrix4fv(g_Unlit.modelToCameraMatrixUnif,1,GL_FALSE,glm::value_ptr(modelMatrix.Top()));glm::vec4lightColor=GammaCorrect(g_lights.GetPointLightIntensity(light),gamma);glUniform4fv(g_Unlit.objectColorUnif,1,glm::value_ptr(lightColor));g_pScene->GetCubeMesh()->Render("flat");}}if(g_bDrawCameraPos){Framework::MatrixStackPusherpush(modelMatrix);modelMatrix.SetIdentity();modelMatrix.Translate(glm::vec3(0.0f,0.0f,-g_mousePole.GetLookAtDistance()));glDisable(GL_DEPTH_TEST);glDepthMask(GL_FALSE);glUseProgram(g_Unlit.theProgram);glUniformMatrix4fv(g_Unlit.modelToCameraMatrixUnif,1,GL_FALSE,glm::value_ptr(modelMatrix.Top()));glUniform4f(g_Unlit.objectColorUnif,0.25f,0.25f,0.25f,1.0f);g_pScene->GetCubeMesh()->Render("flat");glDepthMask(GL_TRUE);glEnable(GL_DEPTH_TEST);glUniform4f(g_Unlit.objectColorUnif,1.0f,1.0f,1.0f,1.0f);g_pScene->GetCubeMesh()->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.voidreshape(intw,inth){Framework::MatrixStackpersMatrix;persMatrix.Perspective(45.0f,(h/(float)w),g_fzNear,g_fzFar);ProjectionBlockprojData;projData.cameraToClipMatrix=persMatrix.Top();glBindBuffer(GL_UNIFORM_BUFFER,g_projectionUniformBuffer);glBufferSubData(GL_UNIFORM_BUFFER,0,sizeof(ProjectionBlock),&projData);glBindBuffer(GL_UNIFORM_BUFFER,0);glViewport(0,0,(GLsizei)w,(GLsizei)h);glutPostRedisplay();}TimerTypesg_eTimerMode=TIMER_ALL;//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.voidkeyboard(unsignedcharkey,intx,inty){boolbChangedShininess=false;boolbChangedLightModel=false;switch(key){case27:deleteg_pScene;g_pScene=NULL;glutLeaveMainLoop();break;case'p':g_lights.TogglePause(g_eTimerMode);break;case'-':g_lights.RewindTime(g_eTimerMode,1.0f);break;case'=':g_lights.FastForwardTime(g_eTimerMode,1.0f);break;case't':g_bDrawCameraPos=!g_bDrawCameraPos;break;case'1':g_eTimerMode=TIMER_ALL;printf("All\n");break;case'2':g_eTimerMode=TIMER_SUN;printf("Sun\n");break;case'3':g_eTimerMode=TIMER_LIGHTS;printf("Lights\n");break;case'l':g_isGammaCorrect=!g_isGammaCorrect;if(g_isGammaCorrect)printf("Gamma on!\n");elseprintf("Gamma off!\n");break;case32:{floatsunAlpha=g_lights.GetSunTime();floatsunTimeHours=sunAlpha*24.0f+12.0f;sunTimeHours=sunTimeHours>24.0f?sunTimeHours-24.0f:sunTimeHours;intsunHours=int(sunTimeHours);floatsunTimeMinutes=(sunTimeHours-sunHours)*60.0f;intsunMinutes=int(sunTimeMinutes);printf("%02i:%02i\n",sunHours,sunMinutes);}break;}g_mousePole.GLUTKeyOffset(key,5.0f,1.0f);}