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