#include #include #include #include "client/engine/Wrapper.h" DummyClient DummyClient::dummy; IClient* Engine::client = &DummyClient::dummy; // window data GLFWwindow* Engine::window = nullptr; int Engine::scale = 1; int Engine::width = 0; int Engine::height = 0; int Engine::resizeTicks = -1; // projection data float Engine::fovY = 60; float Engine::nearClip = 0.1f; float Engine::farClip = 1000.0f; Matrix3D Engine::projMatrix; // rectangle for framebuffer drawing FramebufferRectangle Engine::rectangle; int Engine::stage = 0; // shader stage 1 - world WorldShader Engine::worldShader; // shader stage 2 - world ssao SSAOShader Engine::ssaoShader; // shader stage 3 - world ssao blur SSAOBlurShader Engine::ssaoBlurShader; // shader stage 4 - world post WorldPostShader Engine::worldPostShader; // shader stage 5 - 2D overlay OverlayShader Engine::overlayShader; void Engine::sleep(uint64_t nanos) { uint64_t end = glfwGetTimerValue() + nanos - 10000; // non busy wait until a close range while(end > glfwGetTimerValue() + 1000000) { this_thread::sleep_for(chrono::nanoseconds(1000000)); } while(end > glfwGetTimerValue() + 100000) { this_thread::sleep_for(chrono::nanoseconds(100000)); } // busy wait for higher accuracy at the end while(end > glfwGetTimerValue()); } void Engine::stop() { glfwSetWindowShouldClose(window, 1); } void Engine::onKeyEvent(GLFWwindow* w, int key, int scancode, int action, int mods) { client->onKeyEvent(key, scancode, action, mods); } void Engine::onMouseMove(GLFWwindow* w, double x, double y) { client->onMouseMove(x, y); } void Engine::onMouseClick(GLFWwindow* w, int button, int action, int mods) { client->onMouseClick(button, action, mods); } void Engine::onWindowResize(GLFWwindow* w, int width, int height) { Engine::width = width; Engine::height = height; resizeTicks = 10; } void Engine::updateScale() { scale = 1; while(width / (scale + 1) >= 400 && height / (scale + 1) >= 300) { scale++; } } int Engine::getScale() { return scale; } int Engine::getWidth() { return width; } int Engine::getHeight() { return height; } float Engine::getScaledWidth() { return (float) width / scale; } float Engine::getScaledHeight() { return (float) height / scale; } float Engine::getFieldOfView() { return fovY; } float Engine::getNearClip() { return nearClip; } float Engine::getFarClip() { return farClip; } void Engine::printError() { GLenum error = glGetError(); switch(error) { case GL_NO_ERROR: //cout << "> No error has been recorded." << endl; break; case GL_INVALID_ENUM: cout << "> An unacceptable value is specified for an enumerated argument." << endl; break; case GL_INVALID_VALUE: cout << "> A numeric argument is out of range." << endl; break; case GL_INVALID_OPERATION: cout << "> The specified operation is not allowed in the current state." << endl; break; case GL_INVALID_FRAMEBUFFER_OPERATION: cout << "> The framebuffer object is not complete." << endl; break; case GL_OUT_OF_MEMORY: cout << "> There is not enough memory left to execute the command." << endl; break; case GL_STACK_UNDERFLOW: cout << "> An attempt has been made to perform an operation that would cause an internal stack to underflow." << endl; break; case GL_STACK_OVERFLOW: cout << "> An attempt has been made to perform an operation that would cause an internal stack to overflow." << endl; break; default: cout << "> Unknown OpenGL error: " << error << endl; } } void Engine::onRenderTick(float lag) { // update projection matrix float tan = tanf((0.5f * fovY) * M_PI / 180.0f); float q = 1.0f / tan; float aspect = (float) width / height; projMatrix.set(0, 0, q / aspect); projMatrix.set(1, 1, q); projMatrix.set(2, 2, (nearClip + farClip) / (nearClip - farClip)); projMatrix.set(3, 2, -1.0f); projMatrix.set(2, 3, (2.0f * nearClip * farClip) / (nearClip - farClip)); projMatrix.set(3, 3, 0); // ------------------------------------------------------------------------- // shader stage 1 - world // ------------------------------------------------------------------------- stage = 1; worldShader.preRender(projMatrix.getValues()); // call render tick for further drawing client->render3DTick(lag); // ------------------------------------------------------------------------- // shader stage 2 - world ssao // ------------------------------------------------------------------------- stage = 2; ssaoShader.preRender(projMatrix.getValues()); // bind previously generated texture data buffers worldShader.bindPositionTexture(1); worldShader.bindNormalTexture(2); worldShader.bindColorTexture(3); worldShader.bindDepthTexture(4); ssaoShader.bindNoiseTexture(5); rectangle.draw(); // ------------------------------------------------------------------------- // shader stage 3 - world ssao blur // ------------------------------------------------------------------------- stage = 3; ssaoBlurShader.preRender(); ssaoShader.bindTexture(6); rectangle.draw(); // ------------------------------------------------------------------------- // shader stage 4 - world post // ------------------------------------------------------------------------- stage = 4; worldPostShader.preRender(); ssaoBlurShader.bindTexture(7); rectangle.draw(); // ------------------------------------------------------------------------- // shader stage 5 - 2D overlay // ------------------------------------------------------------------------- stage = 5; overlayShader.preRender(); worldPostShader.bindTexture(0); rectangle.draw(); overlayShader.setViewMatrix(); setMixMode(); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendEquation(GL_FUNC_ADD); client->render2DTick(lag); glDisable(GL_BLEND); } void Engine::setViewMatrix(const float* data) { if(stage == 1) { worldShader.setViewMatrix(data); } } void Engine::setModelMatrix(const float* data) { if(stage == 1) { worldShader.setModelMatrix(data); } else if(stage == 5) { overlayShader.setModelMatrix(data); } } void Engine::setMouseTrapped(bool mode) { if(mode) { glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); } else { glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); } } void Engine::setMixMode() { if(stage == 5) { overlayShader.setUseColor(true); overlayShader.setUseTexture(true); } } void Engine::setColorMode() { if(stage == 5) { overlayShader.setUseColor(true); overlayShader.setUseTexture(false); } } void Engine::setTextureMode() { if(stage == 5) { overlayShader.setUseColor(false); overlayShader.setUseTexture(true); } }