123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434 |
- #include <cmath>
- #include <chrono>
- #include <thread>
- #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;
- bool Engine::init(int width, int height, const char* name)
- {
- Engine::width = width;
- Engine::height = height;
- updateScale();
-
- if(!glfwInit())
- {
- cout << "could not initialize GLFW" << endl;
- return false;
- }
- glfwDefaultWindowHints();
- glfwWindowHint(GLFW_VISIBLE, 0);
- glfwWindowHint(GLFW_RESIZABLE, 1);
-
- glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
- glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
- glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
-
- window = glfwCreateWindow(width, height, name, nullptr, nullptr);
- if(!window)
- {
- cout << "could not create window" << endl;
- glfwTerminate();
- return false;
- }
- glfwMakeContextCurrent(window);
- glfwSwapInterval(1);
- glfwShowWindow(window);
- GLenum err = glewInit();
- if(GLEW_OK != err)
- {
- cout << "could not initialize GLEW: " << glewGetErrorString(err) << endl;
- return false;
- }
- cout << "Status: Using GLEW " << glewGetString(GLEW_VERSION) << endl;
- if(!worldShader.init() || !ssaoShader.init() || !ssaoBlurShader.init() ||
- !worldPostShader.init() || !overlayShader.init() || !rectangle.init())
- {
- glfwDestroyWindow(window);
- glfwTerminate();
- return false;
- }
-
- glfwSetKeyCallback(window, onKeyEvent);
- glfwSetMouseButtonCallback(window, onMouseClick);
- glfwSetFramebufferSizeCallback(window, onWindowResize);
- glfwSetCursorPosCallback(window, onMouseMove);
- return true;
- }
- 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::start(IClient* client)
- {
- if(client != nullptr)
- {
- Engine::client = client;
- }
-
- glEnable(GL_CULL_FACE);
- glDepthFunc(GL_LEQUAL);
-
- uint64_t newTime = glfwGetTimerValue();
- uint64_t oldTime = newTime;
- uint64_t lag = 0;
- uint64_t frameLag = 0;
- uint64_t lastFrame = 0;
-
- while(!glfwWindowShouldClose(window))
- {
- oldTime = newTime;
- newTime = glfwGetTimerValue();
- lag += newTime - oldTime;
- frameLag += newTime - oldTime;
-
- if(lag >= NANOS_PER_TICK || frameLag >= NANOS_PER_FRAME)
- {
- int ticksPerFrame = 0;
- while(lag >= NANOS_PER_TICK)
- {
- lag -= NANOS_PER_TICK;
- Engine::client->tick();
- ticksPerFrame++;
-
- resizeTicks -= (resizeTicks >= 0);
- if(resizeTicks == 0)
- {
- glViewport(0, 0, width, height);
- updateScale();
- worldShader.resize();
- ssaoShader.resize();
- ssaoBlurShader.resize();
- worldPostShader.resize();
- }
- if(ticksPerFrame >= MAX_TICKS_PER_FRAME)
- {
- long skip = lag / NANOS_PER_TICK;
- lag -= skip * NANOS_PER_TICK;
- if(skip > 0)
- {
- cout << "skipped " << skip << " game ticks " << lag << endl;
- }
- break;
- }
- }
- if(frameLag >= NANOS_PER_FRAME)
- {
- frameLag -= NANOS_PER_FRAME;
- // make sure no frames are rendered immediately after each other
- // this happens if the game tick takes too long
- if(lastFrame + NANOS_PER_FRAME - 1000000 < glfwGetTimerValue())
- {
- lastFrame = glfwGetTimerValue();
- if(resizeTicks == -1)
- {
- onRenderTick((float) lag / NANOS_PER_TICK);
- glfwSwapBuffers(window);
- }
- }
- }
- glfwPollEvents();
- }
- else
- {
- // wait until next frame
- long waitingTime = min(NANOS_PER_FRAME - frameLag, NANOS_PER_TICK - lag);
- sleep(waitingTime);
- }
- }
-
- glfwDestroyWindow(window);
- glfwTerminate();
- }
- 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);
- }
- }
|