#include <string>#include <vector>#include <stack>#include <math.h>#include <glloader/gl_3_2_comp.h>#include <GL/freeglut.h>#include "../framework/framework.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;GLuintglobalUniformBlockIndex;GLuintmodelToWorldMatrixUnif;GLuintbaseColorUnif;GLuintthing;};floatg_fzNear=1.0f;floatg_fzFar=1000.0f;ProgramDataUniformColor;ProgramDataObjectColor;ProgramDataUniformColorTint;GLuintg_GlobalMatricesUBO;staticconstintg_iGlobalMatricesBindingIndex=0;ProgramDataLoadProgram(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.modelToWorldMatrixUnif=glGetUniformLocation(data.theProgram,"modelToWorldMatrix");data.globalUniformBlockIndex=glGetUniformBlockIndex(data.theProgram,"GlobalMatrices");data.baseColorUnif=glGetUniformLocation(data.theProgram,"baseColor");glUniformBlockBinding(data.theProgram,data.globalUniformBlockIndex,g_iGlobalMatricesBindingIndex);returndata;}voidInitializeProgram(){UniformColor=LoadProgram("PosOnlyWorldTransformUBO.vert","ColorUniform.frag");ObjectColor=LoadProgram("PosColorWorldTransformUBO.vert","ColorPassthrough.frag");UniformColorTint=LoadProgram("PosColorWorldTransformUBO.vert","ColorMultUniform.frag");glGenBuffers(1,&g_GlobalMatricesUBO);glBindBuffer(GL_UNIFORM_BUFFER,g_GlobalMatricesUBO);glBufferData(GL_UNIFORM_BUFFER,sizeof(glm::mat4)*2,NULL,GL_STREAM_DRAW);glBindBuffer(GL_UNIFORM_BUFFER,0);glBindBufferRange(GL_UNIFORM_BUFFER,g_iGlobalMatricesBindingIndex,g_GlobalMatricesUBO,0,sizeof(glm::mat4)*2);}glm::mat4CalcLookAtMatrix(constglm::vec3&cameraPt,constglm::vec3&lookPt,constglm::vec3&upPt){glm::vec3lookDir=glm::normalize(lookPt-cameraPt);glm::vec3upDir=glm::normalize(upPt);glm::vec3rightDir=glm::normalize(glm::cross(lookDir,upDir));glm::vec3perpUpDir=glm::cross(rightDir,lookDir);glm::mat4rotMat(1.0f);rotMat[0]=glm::vec4(rightDir,0.0f);rotMat[1]=glm::vec4(perpUpDir,0.0f);rotMat[2]=glm::vec4(-lookDir,0.0f);rotMat=glm::transpose(rotMat);glm::mat4transMat(1.0f);transMat[3]=glm::vec4(-cameraPt,1.0f);returnrotMat*transMat;}Framework::Mesh*g_pConeMesh=NULL;Framework::Mesh*g_pCylinderMesh=NULL;Framework::Mesh*g_pCubeTintMesh=NULL;Framework::Mesh*g_pCubeColorMesh=NULL;Framework::Mesh*g_pPlaneMesh=NULL;//Called after the window and OpenGL are initialized. Called exactly once, before the main loop.voidinit(){InitializeProgram();try{g_pConeMesh=newFramework::Mesh("UnitConeTint.xml");g_pCylinderMesh=newFramework::Mesh("UnitCylinderTint.xml");g_pCubeTintMesh=newFramework::Mesh("UnitCubeTint.xml");g_pCubeColorMesh=newFramework::Mesh("UnitCubeColor.xml");g_pPlaneMesh=newFramework::Mesh("UnitPlane.xml");}catch(std::exception&except){printf(except.what());}glEnable(GL_CULL_FACE);glCullFace(GL_BACK);glFrontFace(GL_CW);glEnable(GL_DEPTH_TEST);glDepthMask(GL_TRUE);glDepthFunc(GL_LEQUAL);glDepthRange(0.0f,1.0f);}staticfloatg_fYAngle=0.0f;staticfloatg_fXAngle=0.0f;//Trees are 3x3 in X/Z, and fTrunkHeight+fConeHeight in the Y.voidDrawTree(Framework::MatrixStack&modelMatrix,floatfTrunkHeight=2.0f,floatfConeHeight=3.0f){//Draw trunk.{Framework::MatrixStackPusherpush(modelMatrix);modelMatrix.Scale(glm::vec3(1.0f,fTrunkHeight,1.0f));modelMatrix.Translate(glm::vec3(0.0f,0.5f,0.0f));glUseProgram(UniformColorTint.theProgram);glUniformMatrix4fv(UniformColorTint.modelToWorldMatrixUnif,1,GL_FALSE,glm::value_ptr(modelMatrix.Top()));glUniform4f(UniformColorTint.baseColorUnif,0.694f,0.4f,0.106f,1.0f);g_pCylinderMesh->Render();glUseProgram(0);}//Draw the treetop{Framework::MatrixStackPusherpush(modelMatrix);modelMatrix.Translate(glm::vec3(0.0f,fTrunkHeight,0.0f));modelMatrix.Scale(glm::vec3(3.0f,fConeHeight,3.0f));glUseProgram(UniformColorTint.theProgram);glUniformMatrix4fv(UniformColorTint.modelToWorldMatrixUnif,1,GL_FALSE,glm::value_ptr(modelMatrix.Top()));glUniform4f(UniformColorTint.baseColorUnif,0.0f,1.0f,0.0f,1.0f);g_pConeMesh->Render();glUseProgram(0);}}constfloatg_fColumnBaseHeight=0.25f;//Columns are 1x1 in the X/Z, and fHieght units in the Y.voidDrawColumn(Framework::MatrixStack&modelMatrix,floatfHeight=5.0f){//Draw the bottom of the column.{Framework::MatrixStackPusherpush(modelMatrix);modelMatrix.Scale(glm::vec3(1.0f,g_fColumnBaseHeight,1.0f));modelMatrix.Translate(glm::vec3(0.0f,0.5f,0.0f));glUseProgram(UniformColorTint.theProgram);glUniformMatrix4fv(UniformColorTint.modelToWorldMatrixUnif,1,GL_FALSE,glm::value_ptr(modelMatrix.Top()));glUniform4f(UniformColorTint.baseColorUnif,1.0f,1.0f,1.0f,1.0f);g_pCubeTintMesh->Render();glUseProgram(0);}//Draw the top of the column.{Framework::MatrixStackPusherpush(modelMatrix);modelMatrix.Translate(glm::vec3(0.0f,fHeight-g_fColumnBaseHeight,0.0f));modelMatrix.Scale(glm::vec3(1.0f,g_fColumnBaseHeight,1.0f));modelMatrix.Translate(glm::vec3(0.0f,0.5f,0.0f));glUseProgram(UniformColorTint.theProgram);glUniformMatrix4fv(UniformColorTint.modelToWorldMatrixUnif,1,GL_FALSE,glm::value_ptr(modelMatrix.Top()));glUniform4f(UniformColorTint.baseColorUnif,0.9f,0.9f,0.9f,0.9f);g_pCubeTintMesh->Render();glUseProgram(0);}//Draw the main column.{Framework::MatrixStackPusherpush(modelMatrix);modelMatrix.Translate(glm::vec3(0.0f,g_fColumnBaseHeight,0.0f));modelMatrix.Scale(glm::vec3(0.8f,fHeight-(g_fColumnBaseHeight*2.0f),0.8f));modelMatrix.Translate(glm::vec3(0.0f,0.5f,0.0f));glUseProgram(UniformColorTint.theProgram);glUniformMatrix4fv(UniformColorTint.modelToWorldMatrixUnif,1,GL_FALSE,glm::value_ptr(modelMatrix.Top()));glUniform4f(UniformColorTint.baseColorUnif,0.9f,0.9f,0.9f,0.9f);g_pCylinderMesh->Render();glUseProgram(0);}}constfloatg_fParthenonWidth=14.0f;constfloatg_fParthenonLength=20.0f;constfloatg_fParthenonColumnHeight=5.0f;constfloatg_fParthenonBaseHeight=1.0f;constfloatg_fParthenonTopHeight=2.0f;voidDrawParthenon(Framework::MatrixStack&modelMatrix){//Draw base.{Framework::MatrixStackPusherpush(modelMatrix);modelMatrix.Scale(glm::vec3(g_fParthenonWidth,g_fParthenonBaseHeight,g_fParthenonLength));modelMatrix.Translate(glm::vec3(0.0f,0.5f,0.0f));glUseProgram(UniformColorTint.theProgram);glUniformMatrix4fv(UniformColorTint.modelToWorldMatrixUnif,1,GL_FALSE,glm::value_ptr(modelMatrix.Top()));glUniform4f(UniformColorTint.baseColorUnif,0.9f,0.9f,0.9f,0.9f);g_pCubeTintMesh->Render();glUseProgram(0);}//Draw top.{Framework::MatrixStackPusherpush(modelMatrix);modelMatrix.Translate(glm::vec3(0.0f,g_fParthenonColumnHeight+g_fParthenonBaseHeight,0.0f));modelMatrix.Scale(glm::vec3(g_fParthenonWidth,g_fParthenonTopHeight,g_fParthenonLength));modelMatrix.Translate(glm::vec3(0.0f,0.5f,0.0f));glUseProgram(UniformColorTint.theProgram);glUniformMatrix4fv(UniformColorTint.modelToWorldMatrixUnif,1,GL_FALSE,glm::value_ptr(modelMatrix.Top()));glUniform4f(UniformColorTint.baseColorUnif,0.9f,0.9f,0.9f,0.9f);g_pCubeTintMesh->Render();glUseProgram(0);}//Draw columns.constfloatfFrontZVal=(g_fParthenonLength/2.0f)-1.0f;constfloatfRightXVal=(g_fParthenonWidth/2.0f)-1.0f;for(intiColumnNum=0;iColumnNum<int(g_fParthenonWidth/2.0f);iColumnNum++){{Framework::MatrixStackPusherpush(modelMatrix);modelMatrix.Translate(glm::vec3((2.0f*iColumnNum)-(g_fParthenonWidth/2.0f)+1.0f,g_fParthenonBaseHeight,fFrontZVal));DrawColumn(modelMatrix,g_fParthenonColumnHeight);}{Framework::MatrixStackPusherpush(modelMatrix);modelMatrix.Translate(glm::vec3((2.0f*iColumnNum)-(g_fParthenonWidth/2.0f)+1.0f,g_fParthenonBaseHeight,-fFrontZVal));DrawColumn(modelMatrix,g_fParthenonColumnHeight);}}//Don't draw the first or last columns, since they've been drawn already.for(intiColumnNum=1;iColumnNum<int((g_fParthenonLength-2.0f)/2.0f);iColumnNum++){{Framework::MatrixStackPusherpush(modelMatrix);modelMatrix.Translate(glm::vec3(fRightXVal,g_fParthenonBaseHeight,(2.0f*iColumnNum)-(g_fParthenonLength/2.0f)+1.0f));DrawColumn(modelMatrix,g_fParthenonColumnHeight);}{Framework::MatrixStackPusherpush(modelMatrix);modelMatrix.Translate(glm::vec3(-fRightXVal,g_fParthenonBaseHeight,(2.0f*iColumnNum)-(g_fParthenonLength/2.0f)+1.0f));DrawColumn(modelMatrix,g_fParthenonColumnHeight);}}//Draw interior.{Framework::MatrixStackPusherpush(modelMatrix);modelMatrix.Translate(glm::vec3(0.0f,1.0f,0.0f));modelMatrix.Scale(glm::vec3(g_fParthenonWidth-6.0f,g_fParthenonColumnHeight,g_fParthenonLength-6.0f));modelMatrix.Translate(glm::vec3(0.0f,0.5f,0.0f));glUseProgram(ObjectColor.theProgram);glUniformMatrix4fv(ObjectColor.modelToWorldMatrixUnif,1,GL_FALSE,glm::value_ptr(modelMatrix.Top()));g_pCubeColorMesh->Render();glUseProgram(0);}//Draw headpiece.{Framework::MatrixStackPusherpush(modelMatrix);modelMatrix.Translate(glm::vec3(0.0f,g_fParthenonColumnHeight+g_fParthenonBaseHeight+(g_fParthenonTopHeight/2.0f),g_fParthenonLength/2.0f));modelMatrix.RotateX(-135.0f);modelMatrix.RotateY(45.0f);glUseProgram(ObjectColor.theProgram);glUniformMatrix4fv(ObjectColor.modelToWorldMatrixUnif,1,GL_FALSE,glm::value_ptr(modelMatrix.Top()));g_pCubeColorMesh->Render();glUseProgram(0);}}structTreeData{floatfXPos;floatfZPos;floatfTrunkHeight;floatfConeHeight;};staticconstTreeDatag_forest[]={{-45.0f,-40.0f,2.0f,3.0f},{-42.0f,-35.0f,2.0f,3.0f},{-39.0f,-29.0f,2.0f,4.0f},{-44.0f,-26.0f,3.0f,3.0f},{-40.0f,-22.0f,2.0f,4.0f},{-36.0f,-15.0f,3.0f,3.0f},{-41.0f,-11.0f,2.0f,3.0f},{-37.0f,-6.0f,3.0f,3.0f},{-45.0f,0.0f,2.0f,3.0f},{-39.0f,4.0f,3.0f,4.0f},{-36.0f,8.0f,2.0f,3.0f},{-44.0f,13.0f,3.0f,3.0f},{-42.0f,17.0f,2.0f,3.0f},{-38.0f,23.0f,3.0f,4.0f},{-41.0f,27.0f,2.0f,3.0f},{-39.0f,32.0f,3.0f,3.0f},{-44.0f,37.0f,3.0f,4.0f},{-36.0f,42.0f,2.0f,3.0f},{-32.0f,-45.0f,2.0f,3.0f},{-30.0f,-42.0f,2.0f,4.0f},{-34.0f,-38.0f,3.0f,5.0f},{-33.0f,-35.0f,3.0f,4.0f},{-29.0f,-28.0f,2.0f,3.0f},{-26.0f,-25.0f,3.0f,5.0f},{-35.0f,-21.0f,3.0f,4.0f},{-31.0f,-17.0f,3.0f,3.0f},{-28.0f,-12.0f,2.0f,4.0f},{-29.0f,-7.0f,3.0f,3.0f},{-26.0f,-1.0f,2.0f,4.0f},{-32.0f,6.0f,2.0f,3.0f},{-30.0f,10.0f,3.0f,5.0f},{-33.0f,14.0f,2.0f,4.0f},{-35.0f,19.0f,3.0f,4.0f},{-28.0f,22.0f,2.0f,3.0f},{-33.0f,26.0f,3.0f,3.0f},{-29.0f,31.0f,3.0f,4.0f},{-32.0f,38.0f,2.0f,3.0f},{-27.0f,41.0f,3.0f,4.0f},{-31.0f,45.0f,2.0f,4.0f},{-28.0f,48.0f,3.0f,5.0f},{-25.0f,-48.0f,2.0f,3.0f},{-20.0f,-42.0f,3.0f,4.0f},{-22.0f,-39.0f,2.0f,3.0f},{-19.0f,-34.0f,2.0f,3.0f},{-23.0f,-30.0f,3.0f,4.0f},{-24.0f,-24.0f,2.0f,3.0f},{-16.0f,-21.0f,2.0f,3.0f},{-17.0f,-17.0f,3.0f,3.0f},{-25.0f,-13.0f,2.0f,4.0f},{-23.0f,-8.0f,2.0f,3.0f},{-17.0f,-2.0f,3.0f,3.0f},{-16.0f,1.0f,2.0f,3.0f},{-19.0f,4.0f,3.0f,3.0f},{-22.0f,8.0f,2.0f,4.0f},{-21.0f,14.0f,2.0f,3.0f},{-16.0f,19.0f,2.0f,3.0f},{-23.0f,24.0f,3.0f,3.0f},{-18.0f,28.0f,2.0f,4.0f},{-24.0f,31.0f,2.0f,3.0f},{-20.0f,36.0f,2.0f,3.0f},{-22.0f,41.0f,3.0f,3.0f},{-21.0f,45.0f,2.0f,3.0f},{-12.0f,-40.0f,2.0f,4.0f},{-11.0f,-35.0f,3.0f,3.0f},{-10.0f,-29.0f,1.0f,3.0f},{-9.0f,-26.0f,2.0f,2.0f},{-6.0f,-22.0f,2.0f,3.0f},{-15.0f,-15.0f,1.0f,3.0f},{-8.0f,-11.0f,2.0f,3.0f},{-14.0f,-6.0f,2.0f,4.0f},{-12.0f,0.0f,2.0f,3.0f},{-7.0f,4.0f,2.0f,2.0f},{-13.0f,8.0f,2.0f,2.0f},{-9.0f,13.0f,1.0f,3.0f},{-13.0f,17.0f,3.0f,4.0f},{-6.0f,23.0f,2.0f,3.0f},{-12.0f,27.0f,1.0f,2.0f},{-8.0f,32.0f,2.0f,3.0f},{-10.0f,37.0f,3.0f,3.0f},{-11.0f,42.0f,2.0f,2.0f},{15.0f,5.0f,2.0f,3.0f},{15.0f,10.0f,2.0f,3.0f},{15.0f,15.0f,2.0f,3.0f},{15.0f,20.0f,2.0f,3.0f},{15.0f,25.0f,2.0f,3.0f},{15.0f,30.0f,2.0f,3.0f},{15.0f,35.0f,2.0f,3.0f},{15.0f,40.0f,2.0f,3.0f},{15.0f,45.0f,2.0f,3.0f},{25.0f,5.0f,2.0f,3.0f},{25.0f,10.0f,2.0f,3.0f},{25.0f,15.0f,2.0f,3.0f},{25.0f,20.0f,2.0f,3.0f},{25.0f,25.0f,2.0f,3.0f},{25.0f,30.0f,2.0f,3.0f},{25.0f,35.0f,2.0f,3.0f},{25.0f,40.0f,2.0f,3.0f},{25.0f,45.0f,2.0f,3.0f},};voidDrawForest(Framework::MatrixStack&modelMatrix){for(intiTree=0;iTree<ARRAY_COUNT(g_forest);iTree++){constTreeData&currTree=g_forest[iTree];Framework::MatrixStackPusherpush(modelMatrix);modelMatrix.Translate(glm::vec3(currTree.fXPos,0.0f,currTree.fZPos));DrawTree(modelMatrix,currTree.fTrunkHeight,currTree.fConeHeight);}}staticboolg_bDrawLookatPoint=false;staticglm::vec3g_camTarget(0.0f,0.4f,0.0f);//In spherical coordinates.staticglm::vec3g_sphereCamRelPos(67.5f,-46.0f,150.0f);glm::vec3ResolveCamPosition(){Framework::MatrixStacktempMat;floatrho=Framework::DegToRad(g_sphereCamRelPos.x);floattheta=Framework::DegToRad(g_sphereCamRelPos.y+90.0f);floatfSinTheta=sinf(theta);floatfCosTheta=cosf(theta);floatfCosRho=cosf(rho);floatfSinRho=sinf(rho);glm::vec3dirToCamera(fSinTheta*fCosRho,fCosTheta,fSinTheta*fSinRho);return(dirToCamera*g_sphereCamRelPos.z)+g_camTarget;}//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(){glClearColor(0.0f,0.0f,0.0f,0.0f);glClearDepth(1.0f);glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);if(g_pConeMesh&&g_pCylinderMesh&&g_pCubeTintMesh&&g_pCubeColorMesh&&g_pPlaneMesh){constglm::vec3&camPos=ResolveCamPosition();Framework::MatrixStackcamMatrix;camMatrix.SetMatrix(CalcLookAtMatrix(camPos,g_camTarget,glm::vec3(0.0f,1.0f,0.0f)));glBindBuffer(GL_UNIFORM_BUFFER,g_GlobalMatricesUBO);glBufferSubData(GL_UNIFORM_BUFFER,sizeof(glm::mat4),sizeof(glm::mat4),glm::value_ptr(camMatrix.Top()));glBindBuffer(GL_UNIFORM_BUFFER,0);Framework::MatrixStackmodelMatrix;//Render the ground plane.{Framework::MatrixStackPusherpush(modelMatrix);modelMatrix.Scale(glm::vec3(100.0f,1.0f,100.0f));glUseProgram(UniformColor.theProgram);glUniformMatrix4fv(UniformColor.modelToWorldMatrixUnif,1,GL_FALSE,glm::value_ptr(modelMatrix.Top()));glUniform4f(UniformColor.baseColorUnif,0.302f,0.416f,0.0589f,1.0f);g_pPlaneMesh->Render();glUseProgram(0);}//Draw the treesDrawForest(modelMatrix);//Draw the building.{Framework::MatrixStackPusherpush(modelMatrix);modelMatrix.Translate(glm::vec3(20.0f,0.0f,-10.0f));// DrawParthenon(modelMatrix);}if(g_bDrawLookatPoint){/* glDisable(GL_DEPTH_TEST); glm::mat4 idenity(1.0f); Framework::MatrixStackPusher push(modelMatrix); glm::vec3 cameraAimVec = g_camTarget - camPos; modelMatrix.Translate(0.0f, 0.0, -glm::length(cameraAimVec)); modelMatrix.Scale(1.0f, 1.0f, 1.0f); glUseProgram(ObjectColor.theProgram); glUniformMatrix4fv(ObjectColor.modelToWorldMatrixUnif, 1, GL_FALSE, glm::value_ptr(modelMatrix.Top())); glUniformMatrix4fv(ObjectColor.worldToCameraMatrixUnif, 1, GL_FALSE, glm::value_ptr(idenity)); g_pCubeColorMesh->Render(); glUseProgram(0); glEnable(GL_DEPTH_TEST); */}}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);glBindBuffer(GL_UNIFORM_BUFFER,g_GlobalMatricesUBO);glBufferSubData(GL_UNIFORM_BUFFER,0,sizeof(glm::mat4),glm::value_ptr(persMatrix.Top()));glBindBuffer(GL_UNIFORM_BUFFER,0);/* glUseProgram(UniformColor.theProgram); glUniformMatrix4fv(UniformColor.cameraToClipMatrixUnif, 1, GL_FALSE, glm::value_ptr(persMatrix.Top())); glUseProgram(ObjectColor.theProgram); glUniformMatrix4fv(ObjectColor.cameraToClipMatrixUnif, 1, GL_FALSE, glm::value_ptr(persMatrix.Top())); glUseProgram(UniformColorTint.theProgram); glUniformMatrix4fv(UniformColorTint.cameraToClipMatrixUnif, 1, GL_FALSE, glm::value_ptr(persMatrix.Top())); glUseProgram(0);*/glViewport(0,0,(GLsizei)w,(GLsizei)h);glutPostRedisplay();}//Called whenever a key on the keyboard was pressed.//The key is given by the ''key'' parameter, which is in ASCII.//It's often a good idea to have the escape key (ASCII value 27) call glutLeaveMainLoop() to //exit the program.voidkeyboard(unsignedcharkey,intx,inty){switch(key){case27:deleteg_pConeMesh;g_pConeMesh=NULL;deleteg_pCylinderMesh;g_pCylinderMesh=NULL;deleteg_pCubeTintMesh;g_pCubeTintMesh=NULL;deleteg_pCubeColorMesh;g_pCubeColorMesh=NULL;deleteg_pPlaneMesh;g_pPlaneMesh=NULL;glutLeaveMainLoop();break;case'w':g_camTarget.z-=4.0f;break;case's':g_camTarget.z+=4.0f;break;case'd':g_camTarget.x+=4.0f;break;case'a':g_camTarget.x-=4.0f;break;case'e':g_camTarget.y-=4.0f;break;case'q':g_camTarget.y+=4.0f;break;case'W':g_camTarget.z-=0.4f;break;case'S':g_camTarget.z+=0.4f;break;case'D':g_camTarget.x+=0.4f;break;case'A':g_camTarget.x-=0.4f;break;case'E':g_camTarget.y-=0.4f;break;case'Q':g_camTarget.y+=0.4f;break;case'i':g_sphereCamRelPos.y-=11.25f;break;case'k':g_sphereCamRelPos.y+=11.25f;break;case'j':g_sphereCamRelPos.x-=11.25f;break;case'l':g_sphereCamRelPos.x+=11.25f;break;case'o':g_sphereCamRelPos.z-=5.0f;break;case'u':g_sphereCamRelPos.z+=5.0f;break;case'I':g_sphereCamRelPos.y-=1.125f;break;case'K':g_sphereCamRelPos.y+=1.125f;break;case'J':g_sphereCamRelPos.x-=1.125f;break;case'L':g_sphereCamRelPos.x+=1.125f;break;case'O':g_sphereCamRelPos.z-=0.5f;break;case'U':g_sphereCamRelPos.z+=0.5f;break;case32:g_bDrawLookatPoint=!g_bDrawLookatPoint;printf("Target: %f, %f, %f\n",g_camTarget.x,g_camTarget.y,g_camTarget.z);printf("Position: %f, %f, %f\n",g_sphereCamRelPos.x,g_sphereCamRelPos.y,g_sphereCamRelPos.z);break;}g_sphereCamRelPos.y=glm::clamp(g_sphereCamRelPos.y,-78.75f,-1.0f);g_camTarget.y=g_camTarget.y>0.0f?g_camTarget.y:0.0f;g_sphereCamRelPos.z=g_sphereCamRelPos.z>5.0f?g_sphereCamRelPos.z:5.0f;glutPostRedisplay();}