Aeon Engine c550894
AeonGames Open Source Game Engine
Loading...
Searching...
No Matches
OpenGLRenderer.cpp
1/*
2Copyright (C) 2016-2022,2024,2025,2026 Rodrigo Jose Hernandez Cordoba
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17#include <atomic>
18#include <cassert>
19#include "OpenGLRenderer.hpp"
20#include "OpenGLBuffer.hpp"
21#include "OpenGLWindow.hpp"
22#include "OpenGLFunctions.hpp"
24#include "aeongames/Mesh.hpp"
25#include "aeongames/Pipeline.hpp"
26#include "aeongames/Material.hpp"
27#include "aeongames/Texture.hpp"
29
30namespace AeonGames
31{
32 std::atomic<size_t> OpenGLRenderer::mRendererCount{0};
33#if defined(__unix__)
34 Display* OpenGLRenderer::mDisplay {};
35#endif
37 const GLchar vertex_shader_code[] =
38 R"(#version 450 core
39layout (location = 0) in vec2 aPos;
40layout (location = 1) in vec2 aTexCoords;
41
42out vec2 Pos;
43out vec2 TexCoords;
44
45void main()
46{
47 gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0);
48 Pos = aPos;
49 TexCoords = aTexCoords;
50}
51)";
53 const GLint vertex_shader_len { sizeof(vertex_shader_code) /*/ sizeof(vertex_shader_code[0])*/};
56
58 const GLchar fragment_shader_code[] =
59 R"(#version 450 core
60out vec4 FragColor;
61
62in vec2 Pos;
63in vec2 TexCoords;
64
65layout (location = 0) uniform sampler2D OverlayTexture;
66
67void main()
68{
69 FragColor = texture(OverlayTexture, TexCoords);
70}
71)";
72
74 const GLint fragment_shader_len { sizeof(fragment_shader_code) /*/ sizeof(fragment_shader_code[0])*/};
77
79 const float vertices[] = {
80 // positions // texCoords
81 -1.0f, 1.0f, 0.0f, 1.0f,
82 -1.0f, -1.0f, 0.0f, 0.0f,
83 1.0f, -1.0f, 1.0f, 0.0f,
84 1.0f, 1.0f, 1.0f, 1.0f
85 };
86
87 constexpr GLuint vertex_size{sizeof(vertices)};
88
89#ifdef _WIN32
90 static PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsString = nullptr;
91 static PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribs = nullptr;
92 const int ContextAttribs[] =
93 {
94 WGL_CONTEXT_MAJOR_VERSION_ARB, 4,
95 WGL_CONTEXT_MINOR_VERSION_ARB, 5,
96 WGL_CONTEXT_PROFILE_MASK_ARB,
97 WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
98 0
99 };
100
101 static ATOM gRendererWindowClass{0};
102 static std::atomic<size_t> mRendererCount{0};
103
104 static HWND CreateRendererWindow()
105 {
106 RECT rect = { 0, 0, 10, 10 };
107 if(gRendererWindowClass == 0)
108 {
109 WNDCLASSEX wcex;
110 wcex.cbSize = sizeof ( WNDCLASSEX );
111 wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
112 wcex.lpfnWndProc = ( WNDPROC ) DefWindowProc;
113 wcex.cbClsExtra = 0;
114 wcex.cbWndExtra = 0;
115 wcex.hInstance = GetModuleHandle ( nullptr );
116 wcex.hIcon = LoadIcon ( nullptr, IDI_WINLOGO );
117 wcex.hCursor = LoadCursor ( nullptr, IDC_ARROW );
118 wcex.hbrBackground = nullptr;
119 wcex.lpszMenuName = nullptr;
120 wcex.lpszClassName = "AeonEngineOpenGLInternalWindow";
121 wcex.hIconSm = nullptr;
122 gRendererWindowClass = RegisterClassEx ( &wcex );
123 }
124 ++mRendererCount;
125 return CreateWindowEx ( WS_EX_APPWINDOW | WS_EX_WINDOWEDGE,
126 MAKEINTATOM ( gRendererWindowClass ), "AeonEngine OpenGL Internal Window",
127 WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
128 0, 0, // Location
129 rect.right - rect.left, rect.bottom - rect.top, // dimensions
130 nullptr,
131 nullptr,
132 GetModuleHandle ( nullptr ),
133 nullptr );
134 }
135 static void DestroyRendererWindow(HWND hWnd)
136 {
137 assert(mRendererCount);
138 DestroyWindow ( hWnd );
139 if(--mRendererCount == 0)
140 {
141 UnregisterClass ( reinterpret_cast<LPCSTR> (
142#if defined(_M_X64) || defined(__amd64__)
143 0x0ULL +
144#endif
145 MAKELONG ( gRendererWindowClass, 0 ) ), nullptr );
146 gRendererWindowClass = 0;
147 }
148 }
149 OpenGLRenderer::OpenGLRenderer(void* aWindow) :
150 mWindowId{CreateRendererWindow()},
151 mDeviceContext{GetDC(mWindowId)}
152 {
153 PIXELFORMATDESCRIPTOR pfd{};
154 pfd.nSize = sizeof ( PIXELFORMATDESCRIPTOR );
155 pfd.nVersion = 1;
156 pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
157 pfd.iPixelType = PFD_TYPE_RGBA;
158 pfd.cColorBits = 32;
159 pfd.cDepthBits = 32;
160 pfd.iLayerType = PFD_MAIN_PLANE;
161 int pf = ChoosePixelFormat ( mDeviceContext, &pfd );
162 SetPixelFormat ( mDeviceContext, pf, &pfd );
163
164 // Create OpenGL Context
165 mOpenGLContext = wglCreateContext ( mDeviceContext );
166 MakeCurrent();
167
168 // Get newer functions if needed
169 if ( !wglGetExtensionsString )
170 {
171 if ( ! ( wglGetExtensionsString = ( PFNWGLGETEXTENSIONSSTRINGARBPROC ) wglGetProcAddress ( "wglGetExtensionsStringARB" ) ) )
172 {
173 wglDeleteContext ( static_cast<HGLRC> ( mOpenGLContext ) );
174 mOpenGLContext = nullptr;
175 ReleaseDC ( mWindowId, mDeviceContext );
176 DestroyRendererWindow ( mWindowId );
177 std::cout << LogLevel::Error << "Failed retrieving a pointer to wglGetExtensionsString" << std::endl;
178 throw std::runtime_error ( "Failed retrieving a pointer to wglGetExtensionsString" );
179 }
180 }
181 if ( !wglCreateContextAttribs )
182 {
183 if ( ! ( wglCreateContextAttribs = ( PFNWGLCREATECONTEXTATTRIBSARBPROC ) wglGetProcAddress ( "wglCreateContextAttribsARB" ) ) )
184 {
185 wglDeleteContext ( static_cast<HGLRC> ( mOpenGLContext ) );
186 mOpenGLContext = nullptr;
187 ReleaseDC ( mWindowId, mDeviceContext );
188 DestroyRendererWindow ( mWindowId );
189 std::cout << LogLevel::Error << "Failed retrieving a pointer to wglCreateContextAttribsARB" << std::endl;
190 throw std::runtime_error ( "Failed retrieving a pointer to wglCreateContextAttribsARB" );
191 }
192 }
193 if ( strstr ( wglGetExtensionsString ( mDeviceContext ), "WGL_ARB_create_context" ) != nullptr )
194 {
195 wglDeleteContext ( static_cast<HGLRC> ( mOpenGLContext ) );
196 if ( ! ( mOpenGLContext = wglCreateContextAttribs ( mDeviceContext, nullptr, ContextAttribs ) ) )
197 {
198 ReleaseDC ( mWindowId, mDeviceContext );
199 DestroyRendererWindow ( mWindowId );
200 std::cout << LogLevel::Error << "wglCreateContextAttribs Failed" << std::endl;
201 throw std::runtime_error ( "wglCreateContextAttribs Failed" );
202 }
203 }
204 else
205 {
206 wglDeleteContext ( static_cast<HGLRC> ( mOpenGLContext ) );
207 mOpenGLContext = nullptr;
208 ReleaseDC ( mWindowId, mDeviceContext );
209 DestroyRendererWindow ( mWindowId );
210 std::cout << LogLevel::Error << "WGL_ARB_create_context is not available" << std::endl;
211 throw std::runtime_error ( "WGL_ARB_create_context is not available" );
212 }
213 // Make OpenGL Context current.
214 MakeCurrent();
215 if ( !LoadOpenGLAPI() )
216 {
217 std::cout << LogLevel::Error << "Unable to Load OpenGL functions." << std::endl;
218 throw std::runtime_error ( "Unable to Load OpenGL functions." );
219 }
220 glGenVertexArrays ( 1, &mVertexArrayObject );
221 glBindVertexArray ( mVertexArrayObject );
222 AttachWindow ( static_cast<HWND> ( aWindow ) );
223 }
224
225 bool OpenGLRenderer::MakeCurrent(HDC aDeviceContext)
226 {
227 if ( !wglMakeCurrent ( (aDeviceContext==nullptr) ? mDeviceContext : aDeviceContext, mOpenGLContext ) )
228 {
229 LPSTR pBuffer = NULL;
230 FormatMessage ( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,
231 nullptr, GetLastError(), MAKELANGID ( LANG_NEUTRAL, SUBLANG_DEFAULT ), ( LPSTR ) &pBuffer, 0, nullptr );
232 if ( pBuffer != nullptr )
233 {
234 std::cout << pBuffer << std::endl;
235 LocalFree ( pBuffer );
236 }
237 return false;
238 }
239 return true;
240 }
241
242 OpenGLRenderer::~OpenGLRenderer()
243 {
244 mWindowStore.clear();
245 MakeCurrent();
246 mTextureStore.clear();
247 mMeshStore.clear();
248 mMaterialStore.clear();
249 mPipelineStore.clear();
250 wglMakeCurrent (nullptr, nullptr);
251 if ( wglDeleteContext ( static_cast<HGLRC> ( mOpenGLContext ) ) != TRUE )
252 {
253 std::cout << LogLevel::Error << "wglDeleteContext failed." << std::endl;
254 }
255 mOpenGLContext = nullptr;
256 ReleaseDC ( mWindowId, mDeviceContext );
257 DestroyRendererWindow ( mWindowId );
258 mDeviceContext = nullptr;
259 mWindowId = nullptr;
260 }
261#elif defined(__unix__)
262 static int context_attribs[] =
263 {
264 GLX_CONTEXT_MAJOR_VERSION_ARB, 4,
265 GLX_CONTEXT_MINOR_VERSION_ARB, 5,
266 GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
267 None
268 };
269
270 static GLXFBConfig GetGLXConfig ( Display* display, ::Window window)
271 {
272 XWindowAttributes xwa{};
273 XGetWindowAttributes(display, window, &xwa);
274 VisualID xwvid = XVisualIDFromVisual(xwa.visual);
275
276 int frame_buffer_config_count{};
277 GLXFBConfig *frame_buffer_configs =
278 glXGetFBConfigs ( display,
279 DefaultScreen ( display ),
280 &frame_buffer_config_count );
281 if ( !frame_buffer_configs )
282 {
283 std::cout << LogLevel::Error << "Failed to retrieve a framebuffer config" << std::endl;
284 throw std::runtime_error ( "Failed to retrieve a framebuffer config" );
285 }
286
287 (void) std::remove_if(frame_buffer_configs, frame_buffer_configs + frame_buffer_config_count,
288 [display,xwvid] ( const GLXFBConfig & x ) -> bool
289 {
290 XVisualInfo *xvi = glXGetVisualFromFBConfig(display, x);
291 if(xvi && xvi->visualid == xwvid)
292 {
293 XFree(xvi);
294 return false;
295 }
296 XFree(xvi);
297 return true;
298 });
299
300 GLXFBConfig result = frame_buffer_configs[ 0 ];
301 XFree ( frame_buffer_configs );
302 return result;
303 }
304
305 OpenGLRenderer::OpenGLRenderer(void* aWindow)
306 {
307 if(mRendererCount == 0)
308 {
309 XSetErrorHandler ( [] ( Display * mDisplay, XErrorEvent * error_event ) -> int
310 {
311 char error_string[1024];
312 XGetErrorText ( mDisplay, error_event->error_code, error_string, 1024 );
313 std::cout << AeonGames::LogLevel::Error << error_string << std::endl;
314 std::cout << AeonGames::LogLevel::Error << "Error Code " << static_cast<int> ( error_event->error_code ) << std::endl;
315 std::cout << AeonGames::LogLevel::Error << "Request Code " << static_cast<int> ( error_event->request_code ) << std::endl;
316 std::cout << AeonGames::LogLevel::Error << "Minor Code " << static_cast<int> ( error_event->minor_code ) << std::endl;
317 std::cout << AeonGames::LogLevel::Error << "Display " << error_event->display << std::endl;
318 std::cout << AeonGames::LogLevel::Error << "Resource Id " << error_event->resourceid << std::endl;
319 std::cout << AeonGames::LogLevel::Error << "Serial " << error_event->serial << std::endl;
320 std::cout << AeonGames::LogLevel::Error << "Type " << error_event->type << std::endl;
321 return 0;
322 } );
323 if(mDisplay){XCloseDisplay(mDisplay);}
324 mDisplay = XOpenDisplay ( nullptr );
325 }
326
327 // Retrieve Create Context function
328 if ( !glXCreateContextAttribsARB )
329 {
330 if ( ! ( glXCreateContextAttribsARB =
331 ( PFNGLXCREATECONTEXTATTRIBSARBPROC )
332 glXGetProcAddressARB ( ( const GLubyte * ) "glXCreateContextAttribsARB" ) ) )
333 {
334 std::cout << LogLevel::Error << "Failed retrieving glXCreateContextAttribsARB." << std::endl;
335 throw std::runtime_error ( "Failed retrieving glXCreateContextAttribsARB." );
336 }
337 }
338
339 GLXFBConfig glxconfig = GetGLXConfig(mDisplay,reinterpret_cast<::Window>(aWindow));
340
341 if ( nullptr == ( mOpenGLContext = glXCreateContextAttribsARB ( mDisplay, glxconfig, nullptr,
342 True, context_attribs ) ) )
343 {
344 std::cout << LogLevel::Error << "glXCreateContextAttribsARB Failed." << std::endl;
345 throw std::runtime_error ( "glXCreateContextAttribsARB Failed." );
346 }
347
348 // Verifying that context is a direct context
349 if ( ! glXIsDirect ( mDisplay, static_cast<GLXContext> ( mOpenGLContext ) ) )
350 {
351 std::cout << LogLevel ( LogLevel::Info ) <<
352 "Indirect GLX rendering context obtained" << std::endl;
353 }
354 else
355 {
356 std::cout << LogLevel ( LogLevel::Info ) <<
357 "Direct GLX rendering context obtained" << std::endl;
358 }
359
360 if ( !MakeCurrent(reinterpret_cast<::Window>(reinterpret_cast<::Window>(aWindow))) )
361 {
362 std::cout << LogLevel::Error << "glXMakeCurrent failed." << std::endl;
363 throw std::runtime_error ( "glXMakeCurrent failed." );
364 }
365
366 if ( !LoadOpenGLAPI() )
367 {
368 std::cout << LogLevel::Error << "Unable to Load OpenGL functions." << std::endl;
369 throw std::runtime_error ( "Unable to Load OpenGL functions." );
370 }
371
372 glGenVertexArrays ( 1, &mVertexArrayObject );
373 glBindVertexArray ( mVertexArrayObject );
374
375 AttachWindow(aWindow);
376 ++mRendererCount;
377 }
378
379
380 bool OpenGLRenderer::MakeCurrent(::Window aWindowId)
381 {
382 return glXMakeCurrent (mDisplay, (aWindowId) ? aWindowId : None , (aWindowId) ? mOpenGLContext : nullptr );
383 }
384
385 OpenGLRenderer::~OpenGLRenderer()
386 {
387 mWindowStore.clear();
388 MakeCurrent();
389 mTextureStore.clear();
390 mMeshStore.clear();
391 mMaterialStore.clear();
392 mPipelineStore.clear();
393 if ( mOpenGLContext != None )
394 {
395 glXDestroyContext ( mDisplay, mOpenGLContext );
396 mOpenGLContext = None;
397 }
398 if(--mRendererCount == 0)
399 {
400 XCloseDisplay(mDisplay);
401 mDisplay = None;
402 }
403 }
404#endif
405
407 {
408 /* Initialize Overlay Program. Consider moving into a separate function. */
409 GLint compile_status{};
410 mOverlayProgram = glCreateProgram();
411 OPENGL_CHECK_ERROR_THROW;
412 GLuint vertex_shader = glCreateShader ( GL_VERTEX_SHADER );
413 OPENGL_CHECK_ERROR_THROW;
414 glShaderSource (vertex_shader,1,&vertex_shader_code_ptr,&vertex_shader_len );
415 OPENGL_CHECK_ERROR_THROW;
416 glCompileShader ( vertex_shader );
417 OPENGL_CHECK_ERROR_THROW;
418 glGetShaderiv ( vertex_shader, GL_COMPILE_STATUS, &compile_status );
419 OPENGL_CHECK_ERROR_THROW;
420 if ( compile_status != GL_TRUE )
421 {
422 GLint info_log_len;
423 glGetShaderiv ( vertex_shader, GL_INFO_LOG_LENGTH, &info_log_len );
424 OPENGL_CHECK_ERROR_THROW;
425 std::string log_string;
426 log_string.resize ( info_log_len );
427 if ( info_log_len > 1 )
428 {
429 glGetShaderInfoLog ( vertex_shader, info_log_len, nullptr, const_cast<GLchar*> ( log_string.data() ) );
430 OPENGL_CHECK_ERROR_THROW;
431 std::cout << vertex_shader_code << std::endl;
432 std::cout << log_string << std::endl;
433 }
434 }
435 glAttachShader ( mOverlayProgram, vertex_shader );
436 OPENGL_CHECK_ERROR_THROW;
437 //-------------------------
438 uint32_t fragment_shader = glCreateShader ( GL_FRAGMENT_SHADER );
439 OPENGL_CHECK_ERROR_THROW;
440 glShaderSource ( fragment_shader, 1, &fragment_shader_code_ptr, &fragment_shader_len );
441 OPENGL_CHECK_ERROR_THROW;
442 glCompileShader ( fragment_shader );
443 OPENGL_CHECK_ERROR_THROW;
444 glGetShaderiv ( fragment_shader, GL_COMPILE_STATUS, &compile_status );
445 OPENGL_CHECK_ERROR_THROW;
446 if ( compile_status != GL_TRUE )
447 {
448 GLint info_log_len;
449 glGetShaderiv ( fragment_shader, GL_INFO_LOG_LENGTH, &info_log_len );
450 OPENGL_CHECK_ERROR_THROW;
451 std::string log_string;
452 log_string.resize ( info_log_len );
453 if ( info_log_len > 1 )
454 {
455 glGetShaderInfoLog ( fragment_shader, info_log_len, nullptr, const_cast<GLchar*> ( log_string.data() ) );
456 OPENGL_CHECK_ERROR_THROW;
457 std::cout << fragment_shader_code << std::endl;
458 std::cout << log_string << std::endl;
459 }
460 }
461 glAttachShader ( mOverlayProgram, fragment_shader );
462 OPENGL_CHECK_ERROR_THROW;
463
464 glLinkProgram ( mOverlayProgram );
465 OPENGL_CHECK_ERROR_THROW;
466 glDetachShader ( mOverlayProgram, vertex_shader );
467 OPENGL_CHECK_ERROR_THROW;
468 glDetachShader ( mOverlayProgram, fragment_shader );
469 OPENGL_CHECK_ERROR_THROW;
470 glDeleteShader ( vertex_shader );
471 OPENGL_CHECK_ERROR_THROW;
472 glDeleteShader ( fragment_shader );
473 OPENGL_CHECK_ERROR_THROW;
474 glUseProgram(mOverlayProgram);
475 OPENGL_CHECK_ERROR_THROW;
476 glUniform1i ( 0, 0 );
477 OPENGL_CHECK_ERROR_THROW;
478 /* End of Overlay Program Initialization. */
479 mOverlayQuad.Initialize(vertex_size, GL_STATIC_DRAW, vertices);
480 }
481
483 {
484 OPENGL_CHECK_ERROR_NO_THROW;
485 mOverlayQuad.Finalize();
486 if(glIsProgram(mOverlayProgram))
487 {
488 OPENGL_CHECK_ERROR_NO_THROW;
489 glUseProgram(0);
490 OPENGL_CHECK_ERROR_NO_THROW;
491 glDeleteProgram(mOverlayProgram);
492 OPENGL_CHECK_ERROR_NO_THROW;
493 mOverlayProgram = 0;
494 }
495 if ( glIsVertexArray ( mVertexArrayObject ) )
496 {
497 OPENGL_CHECK_ERROR_NO_THROW;
498 glDeleteVertexArrays ( 1, &mVertexArrayObject );
499 OPENGL_CHECK_ERROR_NO_THROW;
501 }
502 }
503
504 void OpenGLRenderer::LoadMesh ( const Mesh& aMesh )
505 {
506 auto it = mMeshStore.find(aMesh.GetConsecutiveId());
507 if(it!=mMeshStore.end())
508 {
509 std::cout << LogLevel::Warning << "Mesh with id " << aMesh.GetConsecutiveId() << " already loaded." << std::endl;
510 return;
511 }
512 mMeshStore.emplace(aMesh.GetConsecutiveId(),OpenGLMesh{*this,aMesh});
513 }
514
515 void OpenGLRenderer::UnloadMesh ( const Mesh& aMesh )
516 {
517 auto it = mMeshStore.find(aMesh.GetConsecutiveId());
518 if(it!=mMeshStore.end())
519 {
520 mMeshStore.erase(it);
521 }
522 }
523
525 {
526 auto it = mMeshStore.find(aMesh.GetConsecutiveId());
527 if(it==mMeshStore.end())
528 {
529 LoadMesh(aMesh);
530 it = mMeshStore.find(aMesh.GetConsecutiveId());
531 }
532 it->second.Bind();
533 if (mCurrentPipeline != nullptr)
534 {
535 it->second.EnableAttributes(mCurrentPipeline->GetVertexAttributes());
536 }
537 }
538
540 {
541 auto it = mPipelineStore.find(aPipeline.GetConsecutiveId());
542 if(it!=mPipelineStore.end())
543 {
544 std::cout << LogLevel::Error << "OpenGL object already loaded." << std::endl;
545 throw std::runtime_error ( "OpenGL object already loaded." );
546 }
547 mPipelineStore.emplace(aPipeline.GetConsecutiveId(),OpenGLPipeline{*this,aPipeline});
548 }
549
551 {
552 auto it = mPipelineStore.find(aPipeline.GetConsecutiveId());
553 if(it==mPipelineStore.end()){return;};
554 mPipelineStore.erase(it);
555 }
556
557 void OpenGLRenderer::BindPipeline ( const Pipeline& aPipeline)
558 {
559 auto it = mPipelineStore.find(aPipeline.GetConsecutiveId());
560 if(it==mPipelineStore.end())
561 {
562 LoadPipeline(aPipeline);
563 it = mPipelineStore.find(aPipeline.GetConsecutiveId());
564 };
565 mCurrentPipeline = &it->second;
566 glUseProgram ( mCurrentPipeline->GetProgramId() );
567 OPENGL_CHECK_ERROR_NO_THROW;
568 }
569
570 void OpenGLRenderer::SetMaterial ( const Material& aMaterial)
571 {
572 if(mCurrentPipeline == nullptr){return;}
573 auto it = mMaterialStore.find(aMaterial.GetConsecutiveId());
574 if(it==mMaterialStore.end())
575 {
576 LoadMaterial(aMaterial);
577 it = mMaterialStore.find(aMaterial.GetConsecutiveId());
578 };
579 it->second.Bind(*mCurrentPipeline);
580 }
581
582 void OpenGLRenderer::SetSkeleton ( const BufferAccessor& aSkeletonBuffer) const
583 {
584 if(mCurrentPipeline == nullptr){return;}
585 const OpenGLUniformBlock* uniform_block{ mCurrentPipeline->GetUniformBlock ( Mesh::SKELETON ) };
586 if ( uniform_block == nullptr ){return;}
587 const OpenGLMemoryPoolBuffer* memory_pool_buffer = reinterpret_cast<const OpenGLMemoryPoolBuffer*> ( aSkeletonBuffer.GetMemoryPoolBuffer() );
588 if ( GLuint buffer_id = ( memory_pool_buffer != nullptr ) ? reinterpret_cast<const OpenGLBuffer&>(memory_pool_buffer->GetBuffer()).GetBufferId() : 0 )
589 {
590 assert(static_cast<const size_t>(uniform_block->size) >= aSkeletonBuffer.GetSize());
591 glBindBufferRange ( GL_UNIFORM_BUFFER, uniform_block->binding, buffer_id, aSkeletonBuffer.GetOffset(), aSkeletonBuffer.GetSize() );
592 OPENGL_CHECK_ERROR_THROW;
593 };
594 }
595
596 void OpenGLRenderer::SetMatrices ( const OpenGLBuffer& aMatricesBuffer) const
597 {
598 if(mCurrentPipeline == nullptr){return;}
599 const OpenGLUniformBlock* uniform_block{ mCurrentPipeline->GetUniformBlock ( Mesh::MATRICES ) };
600 if ( uniform_block == nullptr ){return;}
601
602 assert(static_cast<const size_t>(uniform_block->size) == aMatricesBuffer.GetSize());
603 glBindBufferRange ( GL_UNIFORM_BUFFER, uniform_block->binding, aMatricesBuffer.GetBufferId(), 0, aMatricesBuffer.GetSize() );
604 OPENGL_CHECK_ERROR_THROW;
605
606 //glBindBufferBase ( GL_UNIFORM_BUFFER, uniform_block->binding, aMatricesBuffer.GetBufferId() );
607 //OPENGL_CHECK_ERROR_THROW;
608 }
609
611 {
612 auto it = mMaterialStore.find(aMaterial.GetConsecutiveId());
613 if(it!=mMaterialStore.end()){return;}
614 mMaterialStore.emplace(
615 aMaterial.GetConsecutiveId(),
616 OpenGLMaterial{*this,aMaterial});
617 }
618
620 {
621 auto it = mMaterialStore.find(aMaterial.GetConsecutiveId());
622 if(it==mMaterialStore.end()){return;}
623 mMaterialStore.erase(it);
624 }
625
627 {
628 auto it = mTextureStore.find(aTexture.GetConsecutiveId());
629 if(it!=mTextureStore.end())
630 {
631 return;
632 }
633 mTextureStore.emplace(aTexture.GetConsecutiveId(),OpenGLTexture{*this,aTexture});
634 }
635
637 {
638 auto it = mTextureStore.find(aTexture.GetConsecutiveId());
639 if(it==mTextureStore.end()){return;}
640 mTextureStore.erase(it);
641 }
642
643 GLuint OpenGLRenderer::GetTextureId ( const Texture& aTexture )
644 {
645 auto it = mTextureStore.find(aTexture.GetConsecutiveId());
646 if(it==mTextureStore.end())
647 {
648 LoadTexture(aTexture);
649 it = mTextureStore.find(aTexture.GetConsecutiveId());
650 }
651 return it->second.GetTextureId();
652 }
653
655 {
656 return mVertexArrayObject;
657 }
658
660 {
661 return mOverlayProgram;
662 }
663
665 {
666 return mOverlayQuad.GetBufferId();
667 }
668
669 void OpenGLRenderer::AttachWindow ( void* aWindowId )
670 {
671 auto it = mWindowStore.find ( aWindowId );
672 if ( it != mWindowStore.end() )
673 {
674 std::cout << LogLevel::Warning << " Window " << aWindowId << " Already Loaded at: " << __FUNCTION__ << std::endl;
675 return;
676 }
677#if defined(__unix__)
678 mWindowStore.emplace ( aWindowId, OpenGLWindow{*this, mDisplay, reinterpret_cast<::Window>(aWindowId)} );
679#elif defined(_WIN32)
680 mWindowStore.emplace ( aWindowId, OpenGLWindow{*this, reinterpret_cast<::HWND>(aWindowId)} );
681#endif
682 }
683 void OpenGLRenderer::DetachWindow ( void* aWindowId )
684 {
685 auto it = mWindowStore.find ( aWindowId );
686 if ( it == mWindowStore.end() )
687 {
688 return;
689 }
690 mWindowStore.erase ( it );
691 }
692
693 void OpenGLRenderer::SetProjectionMatrix ( void* aWindowId, const Matrix4x4& aMatrix )
694 {
695 auto it = mWindowStore.find ( aWindowId );
696 if ( it == mWindowStore.end() )
697 {
698 return;
699 }
700 it->second.SetProjectionMatrix ( aMatrix );
701 }
702
703 void OpenGLRenderer::SetViewMatrix ( void* aWindowId, const Matrix4x4& aMatrix )
704 {
705 auto it = mWindowStore.find ( aWindowId );
706 if ( it == mWindowStore.end() )
707 {
708 return;
709 }
710 it->second.SetViewMatrix ( aMatrix );
711 }
712
713 void OpenGLRenderer::SetClearColor ( void* aWindowId, float R, float G, float B, float A )
714 {
715 auto it = mWindowStore.find ( aWindowId );
716 if ( it == mWindowStore.end() )
717 {
718 return;
719 }
720 it->second.SetClearColor ( R, G, B, A );
721 }
722 void OpenGLRenderer::ResizeViewport ( void* aWindowId, int32_t aX, int32_t aY, uint32_t aWidth, uint32_t aHeight )
723 {
724 auto it = mWindowStore.find ( aWindowId );
725 if ( it == mWindowStore.end() )
726 {
727 return;
728 }
729 it->second.ResizeViewport ( aX, aY, aWidth, aHeight );
730 }
731
732 void OpenGLRenderer::BeginRender ( void* aWindowId )
733 {
734 auto it = mWindowStore.find ( aWindowId );
735 if ( it == mWindowStore.end() )
736 {
737 return;
738 }
739 it->second.BeginRender();
740 }
741 void OpenGLRenderer::EndRender ( void* aWindowId )
742 {
743 auto it = mWindowStore.find ( aWindowId );
744 if ( it == mWindowStore.end() )
745 {
746 return;
747 }
748 it->second.EndRender();
749 }
750 void OpenGLRenderer::Render ( void* aWindowId,
751 const Matrix4x4& aModelMatrix,
752 const Mesh& aMesh,
753 const Pipeline& aPipeline,
754 const Material* aMaterial,
755 const BufferAccessor* aSkeleton,
756 Topology aTopology,
757 uint32_t aVertexStart,
758 uint32_t aVertexCount,
759 uint32_t aInstanceCount,
760 uint32_t aFirstInstance ) const
761 {
762 auto it = mWindowStore.find ( aWindowId );
763 if ( it == mWindowStore.end() )
764 {
765 return;
766 }
767 it->second.Render ( aModelMatrix, aMesh, aPipeline, aMaterial, aSkeleton, aTopology, aVertexStart, aVertexCount, aInstanceCount, aFirstInstance );
768 }
769
770 const Frustum& OpenGLRenderer::GetFrustum ( void* aWindowId ) const
771 {
772 auto it = mWindowStore.find ( aWindowId );
773 if ( it == mWindowStore.end() )
774 {
775 std::cout << LogLevel::Error << "Unknown Window Id." << std::endl;
776 throw std::runtime_error ( "Unknown Window Id." );
777 }
778 return it->second.GetFrustum();
779 }
781 {
782 auto it = mWindowStore.find ( aWindowId );
783 if ( it == mWindowStore.end() )
784 {
785 std::cout << LogLevel::Error << "Unknown Window Id." << std::endl;
786 throw std::runtime_error ( "Unknown Window Id." );
787 }
788 return it->second.AllocateSingleFrameUniformMemory ( aSize );
789 }
790
792 {
793 return mOpenGLContext;
794 }
795}
Defines log severity levels and stream output for the AeonGames engine.
Platform-specific macros, includes, and DLL export/import definitions.
Provides access to a region within a memory pool buffer.
DLL const MemoryPoolBuffer * GetMemoryPoolBuffer() const
Get the underlying memory pool buffer.
DLL size_t GetOffset() const
Get the byte offset of this accessor within the memory pool buffer.
DLL size_t GetSize() const
Get the size of the accessible region.
View frustum defined by six clipping planes, extracted from a projection (or view-projection) matrix.
Definition Frustum.hpp:35
Represents a surface material with uniform properties and texture samplers.
Definition Material.hpp:38
4 by 4 matrix in colum mayor order.
Definition Matrix4x4.hpp:35
Represents a polygon mesh with vertex attributes and index data.
Definition Mesh.hpp:31
@ MATRICES
Matrices binding.
Definition Mesh.hpp:71
@ SKELETON
Skeleton binding.
Definition Mesh.hpp:73
OpenGL GPU buffer wrapper implementing the Buffer interface.
GLuint GetBufferId() const
Get the OpenGL buffer object identifier.
size_t GetSize() const final
Get the total size of the buffer in bytes.
OpenGL material binding handler for shader uniforms and textures.
OpenGL memory pool buffer for transient per-frame uniform allocations.
const Buffer & GetBuffer() const final
Get a reference to the underlying Buffer.
OpenGL mesh wrapper managing vertex and index buffers.
OpenGL shader program pipeline with attribute and uniform reflection.
void LoadPipeline(const Pipeline &aPipeline) final
Loads a rendering pipeline (shaders and state) into the renderer.
void FinalizeOverlay()
Release overlay shader program and quad buffer.
void UnloadTexture(const Texture &aTexture) final
Unloads a texture from GPU memory.
void LoadMaterial(const Material &aMaterial) final
Loads material data into the renderer.
void BindMesh(const Mesh &aMesh)
Bind a mesh for subsequent draw calls.
void SetViewMatrix(void *aWindowId, const Matrix4x4 &aMatrix) final
Sets the view matrix for a specific window surface.
void InitializeOverlay()
Initialize overlay shader program and quad buffer.
BufferAccessor AllocateSingleFrameUniformMemory(void *aWindowId, size_t aSize) final
Allocates uniform buffer memory that is valid for a single frame.
GLuint GetOverlayQuad() const
Get the overlay screen-quad buffer.
std::unordered_map< size_t, OpenGLMaterial > mMaterialStore
Loaded material cache.
void UnloadMesh(const Mesh &aMesh) final
Unloads mesh data from GPU memory.
void SetProjectionMatrix(void *aWindowId, const Matrix4x4 &aMatrix) final
Sets the projection matrix for a specific window surface.
void BeginRender(void *aWindowId) final
Begins a render pass for the given window surface.
void EndRender(void *aWindowId) final
Ends the current render pass for the given window surface.
std::unordered_map< void *, OpenGLWindow > mWindowStore
Attached window map.
void SetMatrices(const OpenGLBuffer &aMatricesBuffer) const
Bind the matrices uniform buffer for the current draw.
const Frustum & GetFrustum(void *aWindowId) const final
Returns the view frustum for the given window surface.
void SetSkeleton(const BufferAccessor &aSkeletonBuffer) const
Upload skeleton joint matrices for skinned rendering.
void LoadMesh(const Mesh &aMesh) final
Loads mesh data into GPU memory.
std::unordered_map< size_t, OpenGLPipeline > mPipelineStore
Loaded pipeline cache.
OpenGLRenderer(void *aWindow)
Construct from a native window handle.
GLuint mVertexArrayObject
General VAO.
std::unordered_map< size_t, OpenGLTexture > mTextureStore
Loaded texture cache.
void BindPipeline(const Pipeline &aPipeline)
Bind a pipeline (shader program) for rendering.
void Render(void *aWindowId, const Matrix4x4 &aModelMatrix, const Mesh &aMesh, const Pipeline &aPipeline, const Material *aMaterial=nullptr, const BufferAccessor *aSkeleton=nullptr, Topology aTopology=Topology::TRIANGLE_LIST, uint32_t aVertexStart=0, uint32_t aVertexCount=0xffffffff, uint32_t aInstanceCount=1, uint32_t aFirstInstance=0) const final
Issues a draw call for a mesh with the given pipeline and optional material.
void UnloadPipeline(const Pipeline &aPipeline) final
Unloads a rendering pipeline from the renderer.
OpenGLPipeline * mCurrentPipeline
Currently bound pipeline.
void SetMaterial(const Material &aMaterial)
Set the active material for rendering.
void LoadTexture(const Texture &aTexture) final
Loads a texture into GPU memory.
void UnloadMaterial(const Material &aMaterial) final
Unloads material data from the renderer.
std::unordered_map< size_t, OpenGLMesh > mMeshStore
Loaded mesh cache.
void SetClearColor(void *aWindowId, float R, float G, float B, float A) final
Sets the color to be used to clear the window background.
void ResizeViewport(void *aWindowId, int32_t aX, int32_t aY, uint32_t aWidth, uint32_t aHeight) final
Resizes the specific window surface's viewport.
void AttachWindow(void *aWindowId) final
Attach a Window as a rendering surface.
void DetachWindow(void *aWindowId) final
Detach a Window as a rendering surface.
GLuint GetOverlayProgram() const
Get the overlay shader program identifier.
GLuint GetVertexArrayObject() const
Get the shared vertex array object.
GLuint GetTextureId(const Texture &aTexture)
Get the OpenGL texture identifier for a loaded texture.
void * GetContext() const
Get the platform-specific OpenGL rendering context.
OpenGL texture resource wrapper.
OpenGL per-window rendering context and state.
Rendering pipeline resource.
Definition Pipeline.hpp:122
DLL size_t GetConsecutiveId() const
Get the Consecutive Id for the resource object.
Definition Resource.cpp:42
Represents a 2D texture image resource.
Definition Texture.hpp:33
OpenGLBuffer mOverlayQuad
Overlay quadrilateral.
GLuint mOverlayProgram
Raw overlay shader program.
<- This is here just for the literals
Definition AABB.hpp:31
const GLchar vertex_shader_code[]
Overlay vertex shader GLSL source code.
const GLint fragment_shader_len
Length of the overlay fragment shader source.
bool LoadOpenGLAPI()
Load all OpenGL function pointers and log driver information.
const GLchar *const fragment_shader_code_ptr
Pointer to the overlay fragment shader source.
const float vertices[]
Overlay screen-quad vertex data (positions and texture coordinates).
const GLchar *const vertex_shader_code_ptr
Pointer to the overlay vertex shader source.
const GLint vertex_shader_len
Length of the overlay vertex shader source.
const GLchar fragment_shader_code[]
Overlay fragment shader GLSL source code.
Topology
Primitive topology types for rendering.
Definition Pipeline.hpp:38
LogLevel
Severity levels for engine log messages.
Definition LogLevel.hpp:28
@ Warning
Potential issues that may need attention.
Definition LogLevel.hpp:32
@ Error
Error conditions.
Definition LogLevel.hpp:33
constexpr GLuint vertex_size
Total byte size of the overlay vertex data.
Describes an OpenGL uniform block with its binding and member variables.
GLint size
Total byte size of the uniform block.
GLint binding
Binding point index.