// Load functions are performed on initialization void TextureCorridor::LoadMesh(int corridorType) { for (int i = 0; i < squareList.size(); ++i) delete squareList[i]; squareList.clear(); Square* square = new Square; vector<float> xValues = { corridorWidth,corridorWidth, 2.0f*corridorWidth, 2.0f*corridorWidth, corridorWidth }; square->SetScaling(2.0f*corridorWidth, 60*wallHeight); square->SetRotation(-90.0f, 0.0f, 0.0f); square->SetPosition(0.0f, 0.0f, -(corridorDepth-wallHeight)); square->SetTextureID(textureMap["floor"]); squareList.push_back(square); switch (corridorType) { // Straight corridor case 1: for (size_t wallIndex = 1; wallIndex <= 60; ++wallIndex) { float x1 = corridorWidth; float x2 = corridorWidth; float y1 = wallHeight ; float y2 = 0.0f; float z1 = -((wallIndex - 1)*wallHeight); float z2 = z1 - wallHeight; string texname = "tex" + to_string(((wallIndex - 1) % nTextures) + 1); // left wall #1 square = new Square; square->SetTopLeft(x1, y1, z1);; square->SetBottomLeft(x1, y2, z1); square->SetTopRight(x2, y1, z2); square->SetBottomRight(x2, y2, z2); square->SetTextureID(textureMap[texname]); square->Apply(); squareList.push_back(square); // right wall square = new Square; square->SetTopLeft(-x1, y1, z1);; square->SetBottomLeft(-x1, y2, z1); square->SetTopRight(-x2, y1, z2); square->SetBottomRight(-x2, y2, z2); square->SetTextureID(textureMap[texname]); square->Apply(); squareList.push_back(square); } break; // Corridor with varying geometry case 2: for (size_t wallIndex = 1; wallIndex <= 60; ++wallIndex) { float x1 = xValues[(wallIndex - 1) % xValues.size()]; float x2 = xValues[(wallIndex) % xValues.size()]; float y1 = wallHeight; float y2 = 0.0f; float z1 = -((wallIndex - 1)*wallHeight); float z2 = z1 - wallHeight; string texname = "tex" + to_string(((wallIndex - 1) % nTextures) + 1); // left wall #1 square = new Square; square->SetTopLeft(x1, y1, z1);; square->SetBottomLeft(x1, y2, z1); square->SetTopRight(x2, y1, z2); square->SetBottomRight(x2, y2, z2); square->SetTextureID(textureMap[texname]); square->Apply(); squareList.push_back(square); // right wall square = new Square; square->SetTopLeft(-x1, y1, z1);; square->SetBottomLeft(-x1, y2, z1); square->SetTopRight(-x2, y1, z2); square->SetBottomRight(-x2, y2, z2); square->SetTextureID(textureMap[texname]); square->Apply(); squareList.push_back(square); } break; default: break; } }
int main() { InitGlfw initGlfw; ShaderLoader shaderLoader; TextureLoader textureLoader; TextRenderer textRenderer; // Init initGlfw.Init(); textRenderer.Init(); glfwSetKeyCallback(initGlfw.window, KeyCallback); glfwSetMouseButtonCallback(initGlfw.window, MouseButtonCallback); glfwSetCursorPosCallback(initGlfw.window, MouseMoveCallback); // Shader loading GLuint defaultShaderProgram; GLuint textShaderProgram; GLuint simpleShaderProgram; defaultShaderProgram = shaderLoader.CreateProgram("Shaders\\vertex_shader.glsl", "Shaders\\fragment_shader.glsl"); textShaderProgram = shaderLoader.CreateProgram("Shaders\\text_vs.glsl", "Shaders\\text_fs.glsl"); simpleShaderProgram = shaderLoader.CreateProgram("Shaders\\simple_vertex_shader.glsl", "Shaders\\simple_fragment_shader.glsl"); // Load texture GLuint texture = textureLoader.LoadRGB("Images\\container.jpg"); GLuint blankTexture = textureLoader.LoadBlank(); cout << "Blank texture status: " << blankTexture << endl; // Define camera component vectors float wallDistanceMargin = 0.2f; float currentX; float currentZ; glm::vec3 cameraPos = glm::vec3(0.0f, -0.5f, 6.0f); glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f); glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f); float yaw = -90.0f; glm::vec3 front(cos(glm::radians(yaw)), 0.0f, sin(glm::radians(yaw))); // Define model and view matrices and get shader locations GLuint modelLocation = glGetUniformLocation(defaultShaderProgram, "model"); GLuint viewLocation = glGetUniformLocation(defaultShaderProgram, "view"); GLuint projectionLocation = glGetUniformLocation(defaultShaderProgram, "projection"); double currentTime = glfwGetTime(); double delta; glm::mat4 view; glm::mat4 proj1; glm::mat4 idm = glm::mat4(); // Hard-coded virtual environment Square backWall; Square leftWall; Square rightWall; Square floorSquare; Square frontWall; Square rewardZone; float corridorDepth = 10.0f; float corridorWidth = 3.0f; float wallHeight = 2.0f; float rewardZoneDepth = 2.0f; float rewardZonePosition = -3.0f; float rewardZoneLowZ = rewardZonePosition - rewardZoneDepth; float rewardZoneHighZ = rewardZonePosition + rewardZoneDepth; bool inRewardZone = false; backWall.SetColor(0.5f, 0.5f, 0.9f); backWall.SetScaling(corridorWidth, wallHeight); backWall.SetPosition(0.0f, wallHeight/2, -corridorDepth); frontWall.SetColor(0.5f, 0.5f, 0.9f); frontWall.SetScaling(corridorWidth, wallHeight); frontWall.SetPosition(0.0f, wallHeight / 2.0f, corridorDepth); leftWall.SetColor(0.5f, 0.9f, 0.5f); leftWall.SetScaling(corridorDepth, wallHeight); leftWall.SetRotation(0.0f, 90.0f, 0.0f); leftWall.SetPosition(-corridorWidth, wallHeight/2, 0.0f); rightWall.SetColor(0.5f, 0.9f, 0.5f); rightWall.SetScaling(corridorDepth, wallHeight); rightWall.SetRotation(0.0f, 90.0f, 0.0f); rightWall.SetPosition(corridorWidth,wallHeight/2, 0.0f); floorSquare.SetColor(0.1f, 0.1f, 0.1f); floorSquare.SetScaling(corridorWidth, corridorDepth); floorSquare.SetRotation(-90.0f, 0.0f, 0.0f); floorSquare.SetPosition(0.0f, -wallHeight/2.0f, 0.0f); rewardZone.SetColor(0.2f, 0.9f, 0.2f); rewardZone.SetScaling(corridorWidth, rewardZoneDepth); rewardZone.SetRotation(-90.0f, 0.0f, 0.0f); rewardZone.SetPosition(0.0f, -wallHeight / 2.0f + 0.01f, rewardZonePosition); proj1 = glm::perspective(45.0f, (float)2.0f*initGlfw.windowInfo.width / initGlfw.windowInfo.height, 0.1f, 100.0f); glEnable(GL_DEPTH_TEST); // Create frame buffer for offscreen rendering, configured to draw to a texture buffer from which we sample // to draw on each window. GLuint frameBufferObject; GLuint frameBufferTexture; GLuint renderBufferObject; int fullWidth = 2*initGlfw.windowInfo.width; glGenTextures(1, &frameBufferTexture); glBindTexture(GL_TEXTURE_2D, frameBufferTexture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, fullWidth, initGlfw.windowInfo.height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glBindTexture(GL_TEXTURE_2D, 0); glGenRenderbuffers(1, &renderBufferObject); glBindRenderbuffer(GL_RENDERBUFFER, renderBufferObject); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, fullWidth, initGlfw.windowInfo.height); glBindRenderbuffer(GL_RENDERBUFFER, 0); glGenFramebuffers(1, &frameBufferObject); glBindFramebuffer(GL_FRAMEBUFFER, frameBufferObject); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, frameBufferTexture, 0); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderBufferObject); glBindFramebuffer(GL_FRAMEBUFFER, 0); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE) cout << "Framebuffer completed" << endl; // Generate quads for left and right window GLfloat leftScreenVertices[] = { // Positions // TexCoords -1.0f, 1.0f, 0.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, -1.0f, 0.5f, 0.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, -1.0f, 0.5f, 0.0f, 1.0f, 1.0f, 0.5f, 1.0f }; GLfloat rightScreenVertices[] = { // Positions // TexCoords -1.0f, 1.0f, 0.5f, 1.0f, -1.0f, -1.0f, 0.5f, 0.0f, 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 1.0f, 0.5f, 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f }; GLuint leftScreenVBO; GLuint rightScreenVBO; glGenBuffers(1, &leftScreenVBO); glBindBuffer(GL_ARRAY_BUFFER, leftScreenVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(leftScreenVertices), leftScreenVertices, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); glGenBuffers(1, &rightScreenVBO); glBindBuffer(GL_ARRAY_BUFFER, rightScreenVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(rightScreenVertices), rightScreenVertices, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); // Game loop int updateTick = 0; while (!glfwWindowShouldClose(initGlfw.window)) { // Get time delta = glfwGetTime() - currentTime; currentTime = glfwGetTime(); std::string fpsString = "FPS: " + std::to_string(delta); // Update view matrix // sensor readings need to be plugged in here front = glm::vec3(cos(glm::radians(yaw)), 0.0f, sin(glm::radians(yaw))); currentX = cameraPos.x; currentZ = cameraPos.z; cameraPos += yVelocity * front; cameraPos -= glm::normalize(glm::cross(cameraFront, cameraUp)) * xVelocity; // Collision detection, reset to previous position if wall boundary is crossed if ( (cameraPos.x-wallDistanceMargin) < -corridorWidth | (cameraPos.x + wallDistanceMargin)> corridorWidth) cameraPos.x = currentX; if ((cameraPos.z-wallDistanceMargin) < -corridorDepth | (cameraPos.z + wallDistanceMargin) > corridorDepth) cameraPos.z = currentZ; // Check reward zone entries if (!inRewardZone && (cameraPos.z > rewardZoneLowZ && cameraPos.z < rewardZoneHighZ)) { inRewardZone = true; cout << "Reward zone ENTRY detected." << endl; } if (inRewardZone && (cameraPos.z < rewardZoneLowZ || cameraPos.z > rewardZoneHighZ)) { inRewardZone = false; cout << "Reward zone EXIT detected." << endl; } view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp); // Draw the complete screen to the offscreen framebuffer glfwMakeContextCurrent(initGlfw.window); glBindFramebuffer(GL_FRAMEBUFFER, frameBufferObject); glViewport(0, 0, fullWidth, initGlfw.windowInfo.height); glEnable(GL_DEPTH_TEST); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); if (showFPS) textRenderer.RenderText(textShaderProgram, fpsString, 0.0f, GLfloat(initGlfw.windowInfo.height - 20), 1.0, glm::vec3(0.8, 0.6, 0.6)); glUseProgram(defaultShaderProgram); glUniformMatrix4fv(viewLocation, 1, GL_FALSE, glm::value_ptr(view)); glUniformMatrix4fv(projectionLocation, 1, GL_FALSE, glm::value_ptr(proj1)); glUniformMatrix4fv(modelLocation, 1, GL_FALSE, glm::value_ptr(idm)); glBindTexture(GL_TEXTURE_2D, texture); frontWall.Draw(); backWall.Draw(); leftWall.Draw(); rightWall.Draw(); floorSquare.Draw(); glBindTexture(GL_TEXTURE_2D, blankTexture); rewardZone.Draw(); glBindTexture(GL_TEXTURE_2D, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0); // First monitor drawing calls //glfwMakeContextCurrent(initGlfw.window); glClear(GL_COLOR_BUFFER_BIT); glDisable(GL_DEPTH_TEST); glViewport(0, 0, initGlfw.windowInfo.width, initGlfw.windowInfo.height); glUseProgram(simpleShaderProgram); glBindTexture(GL_TEXTURE_2D, frameBufferTexture); glBindBuffer(GL_ARRAY_BUFFER, rightScreenVBO); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (GLvoid*)0); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (GLvoid*)(2 * sizeof(GLfloat))); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glDrawArrays(GL_TRIANGLES, 0, 6); glBindBuffer(GL_ARRAY_BUFFER, 0); glfwSwapBuffers(initGlfw.window); // Second monitor drawing calls glfwMakeContextCurrent(initGlfw.window2); glClear(GL_COLOR_BUFFER_BIT); glDisable(GL_DEPTH_TEST); glUseProgram(simpleShaderProgram); glBindTexture(GL_TEXTURE_2D, frameBufferTexture); glBindBuffer(GL_ARRAY_BUFFER, leftScreenVBO); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (GLvoid*)0); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (GLvoid*)(2 * sizeof(GLfloat))); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glDrawArrays(GL_TRIANGLES, 0, 6); glBindBuffer(GL_ARRAY_BUFFER, 0); glfwSwapBuffers(initGlfw.window2); // Check events glfwPollEvents(); // Output information ++updateTick; if (updateTick % 60 == 0) { cout << "Camera position: (" << cameraPos.x << ", " << cameraPos.y << ", " << cameraPos.z << ")" << endl; updateTick = 0; } } glfwTerminate(); // Clean up after exiting glDeleteFramebuffers(1, &frameBufferObject); return 0; }