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