| 1 | #include "ZydecoCommon.hpp" |
| 2 | #include "Renderer.hpp" |
| 3 | #include "IEventHandler.hpp" |
| 4 | #include "IWindow.hpp" |
| 5 | #include "ITimer.hpp" |
| 6 | #include "GLShader.hpp" |
| 7 | #include "GLProgram.hpp" |
| 8 | #include "GLRenderObject.hpp" |
| 9 | #include "GLRenderObjectBackground.hpp" |
| 10 | #include "GLRenderObjectRainbowTriangle.hpp" |
| 11 |
|
| 12 |
|
| 13 | static Logger LOGGER("Renderer"); |
| 14 | static uint64_t frame_start; |
| 15 |
|
| 16 |
|
| 17 | // Set up OpenGL error handling |
| 18 | void MessageCallback(GLenum source, |
| 19 | GLenum type, |
| 20 | GLuint id, |
| 21 | GLenum severity, |
| 22 | GLsizei length, |
| 23 | const GLchar* message, |
| 24 | const void* userParam) |
| 25 | { |
| 26 | if (type == GL_DEBUG_TYPE_ERROR) |
| 27 | { |
| 28 | ZydecoFault("OpenGL Error: type = {}, severity = {}, message = {}", type, severity, message); |
| 29 | } |
| 30 | } |
| 31 |
|
| 32 |
|
| 33 | Renderer::Renderer(IEventHandler& r_event_handler, IWindow& r_window, ITimer& r_timer): |
| 34 | m_rWindow(r_window), |
| 35 | m_rTimer(r_timer), |
| 36 | m_windowWidth(800), |
| 37 | m_windowHeight(600), |
| 38 | m_glString(std::string((char*)glGetString(GL_VERSION))), |
| 39 | m_rendererString(std::string((char*)glGetString(GL_RENDERER))), |
| 40 | m_frameTimeSum(0), |
| 41 | m_frameCount(0), |
| 42 | m_doRender(true) |
| 43 | { |
| 44 | LOGGER.Log(Logger::TRACE, "Renderer()"); |
| 45 |
|
| 46 | r_event_handler.RegisterWindowEventSubscriber(this); |
| 47 |
|
| 48 | glEnable(GL_DEBUG_OUTPUT); |
| 49 | glDebugMessageCallback(MessageCallback, nullptr); |
| 50 |
|
| 51 |
|
| 52 | GLShader vert_shader {GL_VERTEX_SHADER, |
| 53 | #include "triangle.vs.glsl" |
| 54 | }; |
| 55 | GLShader frag_shader {GL_FRAGMENT_SHADER, |
| 56 | #include "triangle.fs.glsl" |
| 57 | }; |
| 58 | new GLProgram { "RainbowTriangle", {&vert_shader, &frag_shader} }; |
| 59 |
|
| 60 | GLShader sky_vert_shader {GL_VERTEX_SHADER, |
| 61 | #include "background.vs.glsl" |
| 62 | }; |
| 63 | GLShader sky_frag_shader {GL_FRAGMENT_SHADER, |
| 64 | #include "background.fs.glsl" |
| 65 | }; |
| 66 | new GLProgram { "Background", {&sky_vert_shader, &sky_frag_shader} }; |
| 67 | }; |
| 68 |
|
| 69 | bool Renderer::Update() |
| 70 | { |
| 71 | // Render loop |
| 72 | frame_start = *m_rTimer.GetGlobalTimePointer(); |
| 73 |
|
| 74 | if (m_doRender) |
| 75 | { |
| 76 | m_rWindow.MakeContextCurrent(); |
| 77 |
|
| 78 | glClearColor(0.18f, 0.18f, 0.18f, 0.0f); |
| 79 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
| 80 | glEnable(GL_BLEND); |
| 81 |
|
| 82 | glViewport(0, 0, m_windowWidth, m_windowHeight); |
| 83 |
|
| 84 | glBindFramebuffer(GL_FRAMEBUFFER, 0); |
| 85 |
|
| 86 | // Render objects are mapped with {int: order, list<GLRenderObject*>: objects} |
| 87 | // TODO: preliminary testing shows this iterator automatically sorts order keys, determine if actually true |
| 88 | std::map<uint64_t, std::list<GLRenderObject*>> objects = GLRenderObject::GetRenderObjects(); |
| 89 | for (std::pair<uint64_t, std::list<GLRenderObject*>> order_list : objects) |
| 90 | { |
| 91 | for (GLRenderObject *render_object : order_list.second) |
| 92 | { |
| 93 | LOGGER.Log(Logger::TRACE, |
| 94 | "Update(): Rendering {}", |
| 95 | (void*)render_object); |
| 96 | render_object->Render(); |
| 97 | } |
| 98 | } |
| 99 | } |
| 100 |
|
| 101 | m_rWindow.Update(); |
| 102 |
|
| 103 | m_frameTimeSum += (*m_rTimer.GetGlobalTimePointer() - frame_start); |
| 104 | m_frameCount++; |
| 105 |
|
| 106 | return false; |
| 107 | } |
| 108 |
|
| 109 | void Renderer::OnWindowMinimizedEvent() |
| 110 | { |
| 111 | m_doRender = false; |
| 112 | } |
| 113 |
|
| 114 | void Renderer::OnWindowMaximizedEvent() |
| 115 | { |
| 116 | m_doRender = true; |
| 117 | } |
| 118 |
|
| 119 | void Renderer::OnWindowRestoredEvent() |
| 120 | { |
| 121 | m_doRender = true; |
| 122 | } |
| 123 |
|
| 124 | void Renderer::OnWindowExposedEvent() |
| 125 | { |
| 126 | m_doRender = true; |
| 127 | } |
| 128 |
|
| 129 | void Renderer::OnWindowResizedEvent(uint64_t new_width, uint64_t new_height) |
| 130 | { |
| 131 | LOGGER.Log(Logger::VERBOSE, "Window resized: {}x{}", new_width, new_height); |
| 132 | m_windowWidth = new_width; |
| 133 | m_windowHeight = new_height; |
| 134 | } |
| 135 |
|
| 136 | void Renderer::OnWindowRequestedCloseEvent() |
| 137 | { |
| 138 |
|
| 139 | } |
| 140 |
|
| 141 | // Called periodically from Engine::Execute (main thread) |
| 142 | void Renderer::UpdateDebug() |
| 143 | { |
| 144 | m_framerate = static_cast<float>(m_frameCount) / (static_cast<float>(m_frameTimeSum) / 1000.); |
| 145 | m_rWindow.SetTitle(fmt::format("Zydeco ({:.1f} FPS, OpenGL {})", m_framerate, m_glString)); |
| 146 | m_frameTimeSum = 0; |
| 147 | m_frameCount = 0; |
| 148 | } |
| 149 |
|