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->RenderSetUniform<2, int>("screensize", {&window_width, &window_height}); |
107 | render_object->Render(); |
108 | } |
109 | } |
110 | } |
111 |
|
112 | m_rWindow.Update(); |
113 |
|
114 | m_rTimer.Update(); |
115 | m_frameTimeSum += (*m_rTimer.GetGlobalTimePointer() - frame_start); |
116 | m_frameCount++; |
117 |
|
118 | if (m_rTimer.IsExpired()) |
119 | { |
120 | UpdateDebug(); |
121 | m_rTimer.Reset(); |
122 | m_rTimer.Start(); |
123 | } |
124 |
|
125 | return false; |
126 | } |
127 |
|
128 | void Renderer::OnWindowMinimizedEvent() |
129 | { |
130 | m_doRender = false; |
131 | } |
132 |
|
133 | void Renderer::OnWindowMaximizedEvent() |
134 | { |
135 | m_doRender = true; |
136 | } |
137 |
|
138 | void Renderer::OnWindowRestoredEvent() |
139 | { |
140 | m_doRender = true; |
141 | } |
142 |
|
143 | void Renderer::OnWindowExposedEvent() |
144 | { |
145 | m_doRender = true; |
146 | } |
147 |
|
148 | void Renderer::OnWindowResizedEvent(uint64_t new_width, uint64_t new_height) |
149 | { |
150 | LOGGER.Log(Logger::VERBOSE, "Window resized: {}x{}", new_width, new_height); |
151 | m_windowWidth = new_width; |
152 | m_windowHeight = new_height; |
153 | } |
154 |
|
155 | void Renderer::OnWindowRequestedCloseEvent() |
156 | { |
157 |
|
158 | } |
159 |
|
160 | void Renderer::UpdateDebug() |
161 | { |
162 | m_framerate = static_cast<float>(m_frameCount) / (static_cast<float>(m_frameTimeSum) / 1000.); |
163 | m_rWindow.SetTitle(fmt::format("Zydeco ({:.1f} FPS, OpenGL {})", m_framerate, m_glString)); |
164 | LOGGER.Log(Logger::VERBOSE, "{}ms: {} fps", *m_rTimer.GetGlobalTimePointer(), m_framerate); |
165 | m_frameTimeSum = 0; |
166 | m_frameCount = 0; |
167 | } |
168 |
|