#include <string>#include <vector>#include <stack>#include <math.h>#include <stdio.h>#include <glload/gl_3_3.h>#include <GL/freeglut.h>#include "../framework/framework.h"#include "../framework/Mesh.h"#include "../framework/MatrixStack.h"#include "../framework/MousePole.h"#include "../framework/ObjectPole.h"#include "../framework/Timer.h"#include <glm/glm.hpp>#include <glm/gtc/type_ptr.hpp>#define ARRAY_COUNT( array ) (sizeof( array ) / (sizeof( array[0] ) * (sizeof( array ) != sizeof(void*) || sizeof( array[0] ) <= sizeof(void*))))structProgramData{GLuinttheProgram;GLuintmodelToCameraMatrixUnif;GLuintlightIntensityUnif;GLuintambientIntensityUnif;GLuintnormalModelToCameraMatrixUnif;GLuintcameraSpaceLightPosUnif;GLuintlightAttenuationUnif;GLuintshininessFactorUnif;GLuintbaseDiffuseColorUnif;};structUnlitProgData{GLuinttheProgram;GLuintobjectColorUnif;GLuintmodelToCameraMatrixUnif;};floatg_fzNear=1.0f;floatg_fzFar=1000.0f;enumLightingModel{LM_PHONG_SPECULAR=0,LM_PHONG_ONLY,LM_BLINN_SPECULAR,LM_BLINN_ONLY,LM_MAX_LIGHTING_MODEL,};structProgramPairs{ProgramDatawhiteProg;ProgramDatacolorProg;};structShaderPairs{constchar*strWhiteVertShader;constchar*strColorVertShader;constchar*strFragmentShader;};ProgramPairsg_Programs[LM_MAX_LIGHTING_MODEL];ShaderPairsg_ShaderFiles[LM_MAX_LIGHTING_MODEL]={{"PN.vert","PCN.vert","PhongLighting.frag"},{"PN.vert","PCN.vert","PhongOnly.frag"},{"PN.vert","PCN.vert","BlinnLighting.frag"},{"PN.vert","PCN.vert","BlinnOnly.frag"},};UnlitProgDatag_Unlit;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.lightIntensityUnif=glGetUniformLocation(data.theProgram,"lightIntensity");data.ambientIntensityUnif=glGetUniformLocation(data.theProgram,"ambientIntensity");data.normalModelToCameraMatrixUnif=glGetUniformLocation(data.theProgram,"normalModelToCameraMatrix");data.cameraSpaceLightPosUnif=glGetUniformLocation(data.theProgram,"cameraSpaceLightPos");data.lightAttenuationUnif=glGetUniformLocation(data.theProgram,"lightAttenuation");data.shininessFactorUnif=glGetUniformLocation(data.theProgram,"shininessFactor");data.baseDiffuseColorUnif=glGetUniformLocation(data.theProgram,"baseDiffuseColor");GLuintprojectionBlock=glGetUniformBlockIndex(data.theProgram,"Projection");glUniformBlockBinding(data.theProgram,projectionBlock,g_projectionBlockIndex);returndata;}voidInitializePrograms(){for(intiProg=0;iProg<LM_MAX_LIGHTING_MODEL;iProg++){g_Programs[iProg].whiteProg=LoadLitProgram(g_ShaderFiles[iProg].strWhiteVertShader,g_ShaderFiles[iProg].strFragmentShader);g_Programs[iProg].colorProg=LoadLitProgram(g_ShaderFiles[iProg].strColorVertShader,g_ShaderFiles[iProg].strFragmentShader);}g_Unlit=LoadUnlitProgram("PosTransform.vert","UniformColor.frag");}Framework::Mesh*g_pCylinderMesh=NULL;Framework::Mesh*g_pPlaneMesh=NULL;Framework::Mesh*g_pCubeMesh=NULL;Framework::RadiusDefradiusDef={5.0f,3.0f,200.0f,1.5f,0.5f};glm::vec3objectCenter=glm::vec3(0.0f,0.5f,0.0f);Framework::MousePoleg_mousePole(objectCenter,radiusDef);Framework::ObjectPoleg_objectPole(objectCenter,&g_mousePole);namespace{voidMouseMotion(intx,inty){g_mousePole.GLUTMouseMove(glm::ivec2(x,y));g_objectPole.GLUTMouseMove(glm::ivec2(x,y));glutPostRedisplay();}voidMouseButton(intbutton,intstate,intx,inty){g_mousePole.GLUTMouseButton(button,state,glm::ivec2(x,y));g_objectPole.GLUTMouseButton(button,state,glm::ivec2(x,y));glutPostRedisplay();}voidMouseWheel(intwheel,intdirection,intx,inty){g_mousePole.GLUTMouseWheel(direction,glm::ivec2(x,y));g_objectPole.GLUTMouseWheel(direction,glm::ivec2(x,y));glutPostRedisplay();}}GLuintg_projectionUniformBuffer=0;structProjectionBlock{glm::mat4cameraToClipMatrix;};//Called after the window and OpenGL are initialized. Called exactly once, before the main loop.voidinit(){InitializePrograms();try{g_pCylinderMesh=newFramework::Mesh("UnitCylinder.xml");g_pPlaneMesh=newFramework::Mesh("LargePlane.xml");g_pCubeMesh=newFramework::Mesh("UnitCube.xml");}catch(std::exception&except){printf("%s\n",except.what());throw;}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);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_projectionBlockIndex,g_projectionUniformBuffer,0,sizeof(ProjectionBlock));glBindBuffer(GL_UNIFORM_BUFFER,0);}staticfloatg_fLightHeight=1.5f;staticfloatg_fLightRadius=1.0f;usingFramework::Timer;Timerg_LightTimer(Timer::TT_LOOP,5.0f);glm::vec4CalcLightPosition(){floatfCurrTimeThroughLoop=g_LightTimer.GetAlpha();glm::vec4ret(0.0f,g_fLightHeight,0.0f,1.0f);ret.x=cosf(fCurrTimeThroughLoop*(3.14159f*2.0f))*g_fLightRadius;ret.z=sinf(fCurrTimeThroughLoop*(3.14159f*2.0f))*g_fLightRadius;returnret;}staticintg_eLightModel=LM_BLINN_SPECULAR;staticboolg_bUseFragmentLighting=true;staticboolg_bDrawColoredCyl=false;staticboolg_bDrawLightSource=false;staticboolg_bScaleCyl=false;staticboolg_bDrawDark=false;constfloatg_fLightAttenuation=1.2f;constglm::vec4g_darkColor(0.2f,0.2f,0.2f,1.0f);constglm::vec4g_lightColor(1.0f);classMaterialParams{public:MaterialParams():m_fPhongExponent(4.0f),m_fBlinnExponent(4.0f){}operatorfloat()const{returnGetSpecularValue();}voidIncrement(boolbIsLarge){float&theParam=GetSpecularValue();if(bIsLarge)theParam+=0.5f;elsetheParam+=0.1f;ClampParam();}voidDecrement(boolbIsLarge){float&theParam=GetSpecularValue();if(bIsLarge)theParam-=0.5f;elsetheParam-=0.1f;ClampParam();}private:floatm_fPhongExponent;floatm_fBlinnExponent;float&GetSpecularValue(){switch(g_eLightModel){caseLM_PHONG_SPECULAR:caseLM_PHONG_ONLY:returnm_fPhongExponent;caseLM_BLINN_SPECULAR:caseLM_BLINN_ONLY:returnm_fBlinnExponent;}staticfloatfStopComplaint=0.0f;returnfStopComplaint;}constfloat&GetSpecularValue()const{switch(g_eLightModel){caseLM_PHONG_SPECULAR:caseLM_PHONG_ONLY:returnm_fPhongExponent;caseLM_BLINN_SPECULAR:caseLM_BLINN_ONLY:returnm_fBlinnExponent;}staticfloatfStopComplaint=0.0f;returnfStopComplaint;}voidClampParam(){float&theParam=GetSpecularValue();if(theParam<=0.0f)theParam=0.0001f;}};staticMaterialParamsg_matParams;//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_LightTimer.Update();glClearColor(0.0f,0.0f,0.0f,0.0f);glClearDepth(1.0f);glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);if(g_pPlaneMesh&&g_pCylinderMesh&&g_pCubeMesh){Framework::MatrixStackmodelMatrix;modelMatrix.SetMatrix(g_mousePole.CalcMatrix());constglm::vec4&worldLightPos=CalcLightPosition();constglm::vec4&lightPosCameraSpace=modelMatrix.Top()*worldLightPos;ProgramData&whiteProg=g_Programs[g_eLightModel].whiteProg;ProgramData&colorProg=g_Programs[g_eLightModel].colorProg;glUseProgram(whiteProg.theProgram);glUniform4f(whiteProg.lightIntensityUnif,0.8f,0.8f,0.8f,1.0f);glUniform4f(whiteProg.ambientIntensityUnif,0.2f,0.2f,0.2f,1.0f);glUniform3fv(whiteProg.cameraSpaceLightPosUnif,1,glm::value_ptr(lightPosCameraSpace));glUniform1f(whiteProg.lightAttenuationUnif,g_fLightAttenuation);glUniform1f(whiteProg.shininessFactorUnif,g_matParams);glUniform4fv(whiteProg.baseDiffuseColorUnif,1,g_bDrawDark?glm::value_ptr(g_darkColor):glm::value_ptr(g_lightColor));glUseProgram(colorProg.theProgram);glUniform4f(colorProg.lightIntensityUnif,0.8f,0.8f,0.8f,1.0f);glUniform4f(colorProg.ambientIntensityUnif,0.2f,0.2f,0.2f,1.0f);glUniform3fv(colorProg.cameraSpaceLightPosUnif,1,glm::value_ptr(lightPosCameraSpace));glUniform1f(colorProg.lightAttenuationUnif,g_fLightAttenuation);glUniform1f(colorProg.shininessFactorUnif,g_matParams);glUseProgram(0);{Framework::MatrixStackPusherpush(modelMatrix);//Render the ground plane.{Framework::MatrixStackPusherpush(modelMatrix);glm::mat3normMatrix(modelMatrix.Top());normMatrix=glm::transpose(glm::inverse(normMatrix));glUseProgram(whiteProg.theProgram);glUniformMatrix4fv(whiteProg.modelToCameraMatrixUnif,1,GL_FALSE,glm::value_ptr(modelMatrix.Top()));glUniformMatrix3fv(whiteProg.normalModelToCameraMatrixUnif,1,GL_FALSE,glm::value_ptr(normMatrix));g_pPlaneMesh->Render();glUseProgram(0);}//Render the Cylinder{Framework::MatrixStackPusherpush(modelMatrix);modelMatrix.ApplyMatrix(g_objectPole.CalcMatrix());if(g_bScaleCyl)modelMatrix.Scale(1.0f,1.0f,0.2f);glm::mat3normMatrix(modelMatrix.Top());normMatrix=glm::transpose(glm::inverse(normMatrix));ProgramData&prog=g_bDrawColoredCyl?colorProg:whiteProg;glUseProgram(prog.theProgram);glUniformMatrix4fv(prog.modelToCameraMatrixUnif,1,GL_FALSE,glm::value_ptr(modelMatrix.Top()));glUniformMatrix3fv(prog.normalModelToCameraMatrixUnif,1,GL_FALSE,glm::value_ptr(normMatrix));if(g_bDrawColoredCyl)g_pCylinderMesh->Render("lit-color");elseg_pCylinderMesh->Render("lit");glUseProgram(0);}//Render the lightif(g_bDrawLightSource){Framework::MatrixStackPusherpush(modelMatrix);modelMatrix.Translate(glm::vec3(worldLightPos));modelMatrix.Scale(0.1f,0.1f,0.1f);glUseProgram(g_Unlit.theProgram);glUniformMatrix4fv(g_Unlit.modelToCameraMatrixUnif,1,GL_FALSE,glm::value_ptr(modelMatrix.Top()));glUniform4f(g_Unlit.objectColorUnif,0.8078f,0.8706f,0.9922f,1.0f);g_pCubeMesh->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();}staticconstchar*strLightModelNames[]={"Phong Specular.","Phong Only","Blinn Specular.","Blinn Only",};//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_pPlaneMesh;deleteg_pCylinderMesh;deleteg_pCubeMesh;glutLeaveMainLoop();break;case32:g_bDrawColoredCyl=!g_bDrawColoredCyl;break;case'i':g_fLightHeight+=0.2f;break;case'k':g_fLightHeight-=0.2f;break;case'l':g_fLightRadius+=0.2f;break;case'j':g_fLightRadius-=0.2f;break;case'I':g_fLightHeight+=0.05f;break;case'K':g_fLightHeight-=0.05f;break;case'L':g_fLightRadius+=0.05f;break;case'J':g_fLightRadius-=0.05f;break;case'o':g_matParams.Increment(true);bChangedShininess=true;break;case'u':g_matParams.Decrement(true);bChangedShininess=true;break;case'O':g_matParams.Increment(false);bChangedShininess=true;break;case'U':g_matParams.Decrement(false);bChangedShininess=true;break;case'y':g_bDrawLightSource=!g_bDrawLightSource;break;case't':g_bScaleCyl=!g_bScaleCyl;break;case'b':g_LightTimer.TogglePause();break;case'g':g_bDrawDark=!g_bDrawDark;break;case'h':g_eLightModel+=2;g_eLightModel%=LM_MAX_LIGHTING_MODEL;bChangedLightModel=true;break;case'H':if(g_eLightModel%2)g_eLightModel-=1;elseg_eLightModel+=1;g_eLightModel%=LM_MAX_LIGHTING_MODEL;bChangedLightModel=true;break;}if(g_fLightRadius<0.2f)g_fLightRadius=0.2f;if(bChangedShininess)printf("Shiny: %f\n",(float)g_matParams);if(bChangedLightModel)printf("%s\n",strLightModelNames[g_eLightModel]);glutPostRedisplay();}unsignedintdefaults(unsignedintdisplayMode,int&width,int&height){returndisplayMode;}