LkEngine 0.1.2
 
Loading...
Searching...
No Matches
LkOpenGL.h
1#pragma once
2
3#include <glad/glad.h>
4
6#include "LkEngine/Core/LObject/ObjectPtr.h"
7#include "LkEngine/Core/Memory/MemoryUtils.h"
8
9#include "LkEngine/Renderer/TextureEnum.h"
10#include "LkEngine/Renderer/Image.h"
11#include "LkEngine/Renderer/Framebuffer.h"
12#include "LkEngine/Renderer/Shader.h"
13#include "LkEngine/Renderer/VertexBuffer.h"
14#include "LkEngine/Renderer/BlendingSpecification.h"
15#include "LkEngine/Renderer/ArrayTextureSpecification.h"
16#include "LkEngine/Renderer/GeometryPool.h"
17
24#define LK_OpenGL_Verify(OpenGLFunction) \
25 LOpenGL_Internal::CheckForErrors(); \
26 OpenGLFunction; \
27 LK_CORE_VERIFY(LOpenGL_Internal::VerifyFunctionResult(#OpenGLFunction, __FILE__, __LINE__))
28
34#define LK_OpenGL_Verify_Func(Func, ...) { LK_OpenGL_Verify(Func(__VA_ARGS__)); }
35
40#if 0
41#define glTexImage2D(...) LK_OpenGL_Verify_Func(glTexImage2D, __VA_ARGS__)
42#define glTexSubImage2D(...) LK_OpenGL_Verify_Func(glTexSubImage2D, __VA_ARGS__)
43#endif
44
45namespace LkEngine {
46
47 class LSceneCamera;
48 class LArrayTexture;
49
55 namespace LOpenGL_Internal
56 {
57 FORCEINLINE static void CheckForErrors()
58 {
59 while (glGetError() != GL_NO_ERROR)
60 {
61 }
62 }
63
64 FORCEINLINE static bool VerifyFunctionResult(const char* InFunction, const char* InFile, int InLine)
65 {
66 while (GLenum Error = glGetError())
67 {
68 LK_CORE_ERROR_TAG("OpenGL", "Error {}\n Function: {}\n File: {}\n Line: {}",
69 static_cast<int>(Error), InFunction, InFile, InLine);
70 return false;
71 }
72
73 return true;
74 }
75 }
76
77 static_assert(std::conjunction_v<std::is_same<int, GLint>, std::is_same<int32_t, GLint>>);
78 static_assert(std::conjunction_v<std::is_same<uint32_t, GLuint>, std::is_same<unsigned int, GLuint>>);
79 static_assert(std::is_same_v<byte, GLubyte>);
80
85 {
90 static void LoadInfo()
91 {
92 int Major, Minor;
93 LK_OpenGL_Verify(glGetIntegerv(GL_MAJOR_VERSION, &Major));
94 LK_OpenGL_Verify(glGetIntegerv(GL_MINOR_VERSION, &Minor));
95 Version.Major = Major;
96 Version.Minor = Minor;
97
98 int Extensions;
99 glGetIntegerv(GL_NUM_EXTENSIONS, &Extensions);
100 SupportedExtensions.reserve(Extensions);
101 for (int i = 0; i < Extensions; i++)
102 {
103 SupportedExtensions.push_back(std::string(reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, i))));
104 }
105 }
106
107 static std::string GetVersion()
108 {
109 char CharBuf[140];
110 std::sprintf(CharBuf, "%s", glGetString(GL_VERSION));
111
112 return std::string(CharBuf);
113 }
114
115 static bool IsExtensionSupported(const char* Extension)
116 {
117 int Extensions;
118 LK_OpenGL_Verify(glGetIntegerv(GL_NUM_EXTENSIONS, &Extensions));
119 for (GLint i = 0; i < Extensions; i++)
120 {
121 const char* Ext = reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, i));
122 if (strcmp(Ext, Extension) == 0)
123 {
124 return true;
125 }
126 }
127
128 return false;
129 }
130
131 static const std::vector<std::string>& GetSupportedExtensions()
132 {
133 return SupportedExtensions;
134 }
135
136 static int GetMajorVersion() { return Version.Major; }
137 static int GetMinorVersion() { return Version.Minor; }
138
139 protected:
141 {
142 int Major = 0;
143 int Minor = 0;
144 };
145 static GLVersion Version;
146
147 static std::vector<std::string> SupportedExtensions;
148 };
149
155 struct LOpenGL3 : public LOpenGLBase
156 {
157 };
158
164 struct LOpenGL4 : public LOpenGLBase
165 {
169 FORCEINLINE static int GetSourceBlendFunction(const ESourceBlendFunction InBlendFunction)
170 {
171 switch (InBlendFunction)
172 {
173 case ESourceBlendFunction::Zero: return GL_ZERO;
174 case ESourceBlendFunction::One: return GL_ONE;
175 case ESourceBlendFunction::Alpha: return GL_SRC_ALPHA;
176 case ESourceBlendFunction::Color: return GL_SRC_COLOR;
177 case ESourceBlendFunction::One_Minus_DestinationAlpha: return GL_ONE_MINUS_DST_ALPHA;
178 }
179
180 LK_CORE_ASSERT(false, "Invalid source blend function");
181 return -1;
182 }
183
187 FORCEINLINE static int GetDestinationBlendFunction(const EDestinationBlendFunction InBlendFunction)
188 {
189 switch (InBlendFunction)
190 {
191 case EDestinationBlendFunction::Zero: return GL_ZERO;
192 case EDestinationBlendFunction::One: return GL_ONE;
193 case EDestinationBlendFunction::Alpha: return GL_DST_ALPHA;
194 case EDestinationBlendFunction::Color: return GL_DST_COLOR;
195 case EDestinationBlendFunction::One_Minus_SourceAlpha: return GL_ONE_MINUS_SRC_ALPHA;
196 }
197
198 LK_CORE_ASSERT(false, "Invalid destination blend function");
199 return -1;
200 }
201
202 FORCEINLINE static const GLubyte* GetExtensions()
203 {
204 return glGetString(GL_EXTENSIONS);
205 }
206
207 FORCEINLINE static void PrintExtensions()
208 {
209 int Extensions{};
210 LK_OpenGL_Verify(glGetIntegerv(GL_NUM_EXTENSIONS, &Extensions));
211 for (int Index = 0; Index < Extensions; Index++)
212 {
213 const byte* Extension = glGetStringi(GL_EXTENSIONS, Index);
214 LK_CORE_INFO("OpenGL Extension: {}", std::string(reinterpret_cast<const char*>(Extension)));
215 }
216 }
217
218 FORCEINLINE static GLenum GetFormatDataType(EImageFormat ImageFormat)
219 {
220 switch (ImageFormat)
221 {
222 case EImageFormat::RGB:
223 case EImageFormat::RGBA:
224 case EImageFormat::RGBA8: return GL_UNSIGNED_BYTE;
225 case EImageFormat::RGBA16F:
226 case EImageFormat::RGBA32F: return GL_FLOAT;
227 }
228
229 LK_CORE_ASSERT(false, "Unknown OpenGLFormatDataType: {}", static_cast<int>(ImageFormat));
230 return GL_INVALID_VALUE;
231 }
232
233 FORCEINLINE static GLenum GetImageFormat(const EImageFormat ImageFormat)
234 {
235 switch (ImageFormat)
236 {
237 case EImageFormat::RGB: return GL_RGB;
238
239 /* RGBA. */
240 case EImageFormat::RGBA:
241 case EImageFormat::RGBA8:
242 case EImageFormat::RGBA16F:
243 case EImageFormat::RGBA32F: return GL_RGBA;
244
245 /* SRGB. */
246 case EImageFormat::SRGB: return GL_SRGB;
247 case EImageFormat::SRGBA: return GL_SRGB_ALPHA;
248 }
249
250 LK_CORE_ASSERT(false, "Unknown OpenGLImageFormat {}", static_cast<int>(ImageFormat));
251 return GL_INVALID_ENUM;
252 }
253
254 FORCEINLINE static GLenum GetImageInternalFormat(const EImageFormat Format)
255 {
256 switch (Format)
257 {
258 case EImageFormat::RGB: return GL_RGB8;
259 case EImageFormat::RGBA: return GL_RGBA8;
260 case EImageFormat::RGBA8: return GL_RGBA8;
261 case EImageFormat::RGBA16F: return GL_RGBA16F;
262 case EImageFormat::RGBA32F: return GL_RGBA32F;
263 case EImageFormat::DEPTH24STENCIL8: return GL_DEPTH24_STENCIL8;
264 case EImageFormat::DEPTH32F: return GL_DEPTH_COMPONENT32F;
265 }
266
267 LK_CORE_ASSERT(false, "Invalid image format");
268 return GL_INVALID_ENUM;
269 }
270
271 FORCEINLINE static GLenum GetSamplerWrap(const ETextureWrap TextureWrap)
272 {
273 switch (TextureWrap)
274 {
275 case ETextureWrap::Clamp: return GL_CLAMP_TO_EDGE;
276 case ETextureWrap::Repeat: return GL_REPEAT;
277 }
278
279 LK_CORE_ASSERT(false, "Unknown OpenGLSamplerWrap: {}", static_cast<int>(TextureWrap));
280 return GL_INVALID_VALUE;
281 }
282
283 FORCEINLINE static GLenum GetSamplerFilter(const ETextureFilter TextureFilter, const bool bUseMipmap)
284 {
285 switch (TextureFilter)
286 {
287 case ETextureFilter::Linear: return bUseMipmap ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR;
288 case ETextureFilter::Nearest: return bUseMipmap ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST;
289 }
290
291 LK_CORE_ASSERT(false, "Unknown OpenGLSamplerFilter: {}, mipmap: {}", static_cast<int>(TextureFilter), bUseMipmap);
292 return GL_INVALID_VALUE;
293 }
294
295 FORCEINLINE static GLenum ImageFormatToDataFormat(EImageFormat ImageFormat)
296 {
297 switch (ImageFormat)
298 {
299 case EImageFormat::RGBA:
300 case EImageFormat::RGBA8:
301 case EImageFormat::RGBA16F:
302 case EImageFormat::RGBA32F: return GL_RGBA;
303
304 case EImageFormat::RG8:
305 case EImageFormat::RG16F:
306 case EImageFormat::RG32F: return GL_RG;
307
308 case EImageFormat::RGB:
309 case EImageFormat::RGB8: return GL_RGB;
310
311 case EImageFormat::RED8UI:
312 case EImageFormat::RED16UI:
313 case EImageFormat::RED32UI: return GL_RED_INTEGER;
314 case EImageFormat::RED32F: return GL_RED_INTEGER;
315 }
316
317 LK_CORE_ASSERT(false, "Invalid ImageFormat: {}", static_cast<int>(ImageFormat));
318 return GL_INVALID_VALUE;
319 }
320
321 FORCEINLINE static constexpr GLenum ImageFormatToInternalFormat(EImageFormat ImageFormat)
322 {
323 switch (ImageFormat)
324 {
325 case EImageFormat::RGB: return GL_RGB32F;
326 case EImageFormat::RGB8: return GL_RGB8;
327
328 case EImageFormat::RGBA: return GL_RGBA32F;
329 case EImageFormat::RGBA8: return GL_RGBA8;
330 case EImageFormat::RGBA16F: return GL_RGBA16F;
331 case EImageFormat::RGBA32F: return GL_RGBA32F;
332
333 case EImageFormat::RG16F: return GL_RG16F;
334 case EImageFormat::RG32F: return GL_RG32F;
335
336 case EImageFormat::RED8UI: return GL_R8UI;
337 case EImageFormat::RED16UI: return GL_R16UI;
338 case EImageFormat::RED32UI: return GL_R32UI;
339 case EImageFormat::RED32F: return GL_R32F;
340 }
341
342 LK_CORE_ASSERT(false, "Invalid internal ImageFormat: {}", static_cast<int>(ImageFormat));
343 return GL_INVALID_VALUE;
344 }
345
346 FORCEINLINE static constexpr GLenum ShaderDataTypeToOpenGLBaseType(EShaderDataType type)
347 {
348 switch (type)
349 {
350 case EShaderDataType::Float: return GL_FLOAT;
351 case EShaderDataType::Float2: return GL_FLOAT;
352 case EShaderDataType::Float3: return GL_FLOAT;
353 case EShaderDataType::Float4: return GL_FLOAT;
354 case EShaderDataType::Mat3: return GL_FLOAT;
355 case EShaderDataType::Mat4: return GL_FLOAT;
356 case EShaderDataType::Int:
357 case EShaderDataType::Int2:
358 case EShaderDataType::Int3:
359 case EShaderDataType::Int4: return GL_INT;
360 case EShaderDataType::Bool: return GL_BOOL;
361 }
362
363 return GL_INVALID_ENUM;
364 }
365
366 FORCEINLINE static GLenum TextureTarget(const bool IsMultisampled)
367 {
368 return (IsMultisampled ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D);
369 }
370
371 FORCEINLINE static void CreateTextures(const bool bMultisampled, uint32_t* OutTextureID, const uint32_t Count)
372 {
373 LK_OpenGL_Verify(
374 glCreateTextures(TextureTarget(bMultisampled), Count, OutTextureID)
375 );
376 }
377
378 FORCEINLINE static void BindTexture(const bool bMultisampled, const uint32_t ID)
379 {
380 LK_OpenGL_Verify(
381 glBindTexture(TextureTarget(bMultisampled), ID)
382 );
383 }
384
385 FORCEINLINE static void AttachColorTexture(const uint32_t ID, const int Samples, const GLenum InternalFormat,
386 const GLenum Format, const uint32_t Width, const uint32_t Height,
387 const int Index)
388 {
389 const bool bMultisampled = (Samples > 1);
390 if (bMultisampled)
391 {
392 LK_OpenGL_Verify(
393 glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, Samples, InternalFormat, Width, Height, GL_FALSE)
394 );
395 }
396 else
397 {
398 LK_OpenGL_Verify(glTexImage2D(GL_TEXTURE_2D, 0, InternalFormat, Width, Height, 0, Format, GL_UNSIGNED_BYTE, nullptr));
399 LK_OpenGL_Verify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
400 LK_OpenGL_Verify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
401 LK_OpenGL_Verify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE));
402 LK_OpenGL_Verify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
403 LK_OpenGL_Verify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
404 }
405
406 LK_OpenGL_Verify(
407 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + Index, TextureTarget(bMultisampled), ID, 0)
408 );
409 }
410
411 FORCEINLINE static void AttachDepthTexture(const uint32_t ID, const int Samples, const GLenum Format,
412 const GLenum AttachmentType, const uint32_t Width, const uint32_t Height)
413 {
414 const bool bMultisampled = (Samples > 1);
415 if (bMultisampled)
416 {
417 LK_OpenGL_Verify(
418 glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, Samples, Format, Width, Height, GL_FALSE)
419 );
420 }
421 else
422 {
423 LK_OpenGL_Verify(glTexStorage2D(GL_TEXTURE_2D, 1, Format, Width, Height));
424 LK_OpenGL_Verify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
425 LK_OpenGL_Verify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
426 LK_OpenGL_Verify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE));
427 LK_OpenGL_Verify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
428 LK_OpenGL_Verify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
429 }
430
431 LK_OpenGL_Verify(glFramebufferTexture2D(GL_FRAMEBUFFER, AttachmentType, TextureTarget(bMultisampled), ID, 0));
432 }
433
434 FORCEINLINE static GLenum GetFramebufferTextureFormat(const EImageFormat ImageFormat)
435 {
436 switch (ImageFormat)
437 {
438 case EImageFormat::RGBA8: return GL_RGBA8;
439 case EImageFormat::RGBA16F: return GL_RGBA16F;
440 case EImageFormat::RGBA32F: return GL_RGBA32F;
441 case EImageFormat::RED8UI:
442 case EImageFormat::RED8UN:
443 case EImageFormat::RED16UI:
444 case EImageFormat::RED32UI: return GL_RED_INTEGER;
445 case EImageFormat::DEPTH24STENCIL8: return GL_DEPTH24_STENCIL8;
446 }
447
448 LK_CORE_ASSERT(false, "Invalid ImageFormat");
449 return GL_INVALID_VALUE;
450 }
451
452 FORCEINLINE static void ApplyTextureFilter(ETextureFilter TextureFilter, bool bGenerateMipmap)
453 {
454 if (TextureFilter == ETextureFilter::Linear)
455 {
456 if (bGenerateMipmap)
457 {
458 LK_OpenGL_Verify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR));
459 }
460 else
461 {
462 LK_OpenGL_Verify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
463 }
464
465 LK_OpenGL_Verify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
466 }
467 else if (TextureFilter == ETextureFilter::Nearest)
468 {
469 if (bGenerateMipmap)
470 {
471 LK_OpenGL_Verify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST));
472 }
473 else
474 {
475 LK_OpenGL_Verify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
476 }
477
478 LK_OpenGL_Verify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
479 }
480 else if (TextureFilter == ETextureFilter::None)
481 {
482 LK_OpenGL_Verify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
483 LK_OpenGL_Verify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
484 }
485 }
486
487 static void ApplyTextureWrap(ETextureWrap TextureWrap)
488 {
489 if (TextureWrap == ETextureWrap::Clamp)
490 {
491 /* S: x Y: y */
492 LK_OpenGL_Verify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
493 LK_OpenGL_Verify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
494 }
495 else if (TextureWrap == ETextureWrap::Repeat)
496 {
497 /* S: x Y: y */
498 LK_OpenGL_Verify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)); /* S: x */
499 LK_OpenGL_Verify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)); /* T: y */
500 }
501 }
502
503 static void ApplyTextureFilter(const LRendererID& RendererID, const ETextureFilter TextureFilter,
504 bool bGenerateMipmap = true)
505 {
506 switch (TextureFilter)
507 {
508 case ETextureFilter::Linear:
509 {
510 /* Min Filter. */
511 LK_OpenGL_Verify(glTextureParameteri(RendererID, GL_TEXTURE_MIN_FILTER,
512 (bGenerateMipmap ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR)));
513
514 /* Mag Filter. */
515 LK_OpenGL_Verify(glTextureParameteri(RendererID, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
516
517 break;
518 }
519
520 case ETextureFilter::Nearest:
521 {
522 /* Min Filter. */
523 LK_OpenGL_Verify(glTextureParameteri(RendererID, GL_TEXTURE_MIN_FILTER,
524 (bGenerateMipmap ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST)));
525
526 LK_OpenGL_Verify(glTextureParameteri(RendererID, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
527
528 break;
529 }
530
531 case ETextureFilter::None:
532 {
533 /* Min Filter. */
534 LK_OpenGL_Verify(glTextureParameteri(RendererID, GL_TEXTURE_MIN_FILTER,
535 (bGenerateMipmap ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST)));
536
537 /* Mag Filter. */
538 LK_OpenGL_Verify(glTextureParameteri(RendererID, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
539
540 return;
541 }
542 }
543 }
544
545 FORCEINLINE static void ApplyTextureWrap(const LRendererID RendererID, const ETextureWrap TextureWrap)
546 {
547 switch (TextureWrap)
548 {
549 case ETextureWrap::None:
550 {
551 LK_OpenGL_Verify(glTextureParameteri(RendererID, GL_TEXTURE_WRAP_S, GL_REPEAT));
552 LK_OpenGL_Verify(glTextureParameteri(RendererID, GL_TEXTURE_WRAP_T, GL_REPEAT));
553 break;
554 }
555
556 case ETextureWrap::Clamp:
557 {
558 LK_OpenGL_Verify(glTextureParameteri(RendererID, GL_TEXTURE_WRAP_S, GL_REPEAT));
559 LK_OpenGL_Verify(glTextureParameteri(RendererID, GL_TEXTURE_WRAP_T, GL_REPEAT));
560 break;
561 }
562
563 case ETextureWrap::Repeat:
564 {
565 LK_OpenGL_Verify(glTextureParameteri(RendererID, GL_TEXTURE_WRAP_S, GL_REPEAT));
566 LK_OpenGL_Verify(glTextureParameteri(RendererID, GL_TEXTURE_WRAP_T, GL_REPEAT));
567 break;
568 }
569
570 default: LK_CORE_ASSERT(false, "Unknown texture wrap: {}", static_cast<int>(TextureWrap));
571 }
572 }
573
577 FORCEINLINE static float GetSampleDepth(int x, int y, int WindowWidth, int WindowHeight)
578 {
579 GLint Viewport[4];
580 LK_OpenGL_Verify(glGetIntegerv(GL_VIEWPORT, Viewport));
581
582 /* Convert screen coordinates to OpenGL viewport coordinates. */
583 y = WindowHeight - y;
584
585 float Depth = 0.0f;
586 LK_OpenGL_Verify(glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &Depth));
587
588 return Depth;
589 }
590
591 FORCEINLINE static std::pair<int, int> ConvertDimensionsToWidthAndHeight(const EArrayTextureDimension TexDim)
592 {
593 switch (TexDim)
594 {
595 case EArrayTextureDimension::Dim_200x200: return { 200, 200 };
596 case EArrayTextureDimension::Dim_512x512: return { 512, 512 };
597 case EArrayTextureDimension::Dim_1024x1024: return { 1024, 1024 };
598 case EArrayTextureDimension::Dim_2048x2048: return { 2048, 2048 };
599 case EArrayTextureDimension::Dim_4096x4096: return { 4096, 4096 };
600 }
601
602 LK_CORE_ASSERT(false, "Unknown OpenGLTextureArrayDimension");
603 return {};
604 }
605
606 FORCEINLINE static EArrayTextureDimension DetermineDimension(const int InWidth, const int InHeight)
607 {
608 LK_VERIFY(InWidth == InHeight, "Passed dimension size is not equal");
609 switch (InWidth)
610 {
611 case 200: return EArrayTextureDimension::Dim_200x200;
612 case 512: return EArrayTextureDimension::Dim_512x512;
613 case 1024: return EArrayTextureDimension::Dim_1024x1024;
614 case 2048: return EArrayTextureDimension::Dim_2048x2048;
615 case 4096: return EArrayTextureDimension::Dim_4096x4096;
616 }
617
618 LK_CORE_ASSERT(false, "Failed to determine dimension");
619 return {};
620 }
621
622 FORCEINLINE static void GenerateTextureArrayImage(const LRendererID ID, const FArrayTextureSpecification& Specification)
623 {
624 auto [Width, Height] = ConvertDimensionsToWidthAndHeight(Specification.Dimension);
625 LK_OpenGL_Verify(glTextureStorage3D(ID,
626 Specification.Layers,
627 ImageFormatToDataFormat(Specification.ImageFormat),
628 Width,
629 Height,
630 0));
631 }
632
633 FORCEINLINE static int GetPrimitiveTopology(const EPrimitiveTopology Topology)
634 {
635 switch (Topology)
636 {
637 case EPrimitiveTopology::Points: return GL_POINTS;
638 case EPrimitiveTopology::Lines: return GL_LINES;
639 case EPrimitiveTopology::Triangles: return GL_TRIANGLES;
640 }
641
642 LK_CORE_ASSERT(false, "Unknown topology, cannot convert to OpenGL format");
643 return GL_INVALID_ENUM;
644 }
645 };
646
647 #if defined(LK_OPENGL4)
648 using LOpenGL = LOpenGL4;
649 #elif defined(LK_OPENGL3)
650 using LOpenGL = LOpenGL3;
651 #else
652 using LOpenGL = LOpenGL4;
653 #endif
654
655 //-----------------------------------------------------------
656 // LOpenGL Debugging
657 //-----------------------------------------------------------
658 namespace LOpenGL_Debug
659 {
660 extern uint32_t CubeTexture_;
661 extern uint32_t FloorTexture_;
662
663 extern uint32_t CubeVAO;
664 extern uint32_t CubeVBO;
665 extern uint32_t QuadVAO;
666 extern uint32_t QuadVBO;
667 extern LRendererID SkyboxVAO;
668 extern uint32_t SkyboxVBO;
669
670 extern TObjectPtr<LVertexBuffer> CubeVertexBuffer;
671 extern TObjectPtr<LVertexBuffer> PlaneVertexBuffer;
672 extern TObjectPtr<LTexture2D> CubeTexture;
673 extern TObjectPtr<LTexture2D> PlaneTexture;
674
675 extern TObjectPtr<LShader> ScreenShader;
676 extern TObjectPtr<LShader> DebugShader;
677 extern TObjectPtr<LShader> CubeDebugShader;
678
679 /* Skybox. */
680 extern TObjectPtr<LVertexBuffer> SkyboxVertexBuffer;
681 extern TObjectPtr<LTextureCube> SkyboxTexture;
682 extern TObjectPtr<LShader> SkyboxShader;
683 extern uint32_t CubemapTexture;
684
685 extern glm::mat4 ModelMVP;
686 extern glm::mat4 View;
687 extern glm::mat4 Projection;
688
689 /* clang-format off */
690 static float Cube_Vertices[] = {
691 // Positions // Texture Coords
692 -0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
693 0.5f, -0.5f, -0.5f, 1.0f, 0.0f,
694 0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
695 0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
696 -0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
697 -0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
698
699 -0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
700 0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
701 0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
702 0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
703 -0.5f, 0.5f, 0.5f, 0.0f, 1.0f,
704 -0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
705
706 -0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
707 -0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
708 -0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
709 -0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
710 -0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
711 -0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
712
713 0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
714 0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
715 0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
716 0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
717 0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
718 0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
719
720 -0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
721 0.5f, -0.5f, -0.5f, 1.0f, 1.0f,
722 0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
723 0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
724 -0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
725 -0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
726
727 -0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
728 0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
729 0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
730 0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
731 -0.5f, 0.5f, 0.5f, 0.0f, 0.0f,
732 -0.5f, 0.5f, -0.5f, 0.0f, 1.0f
733 };
734
735 static float Cube_TextureCoords[] = {
736 0.0f, 0.0f,
737 1.0f, 0.0f,
738 1.0f, 1.0f,
739 1.0f, 1.0f,
740 0.0f, 1.0f,
741 0.0f, 0.0f,
742
743 0.0f, 0.0f,
744 1.0f, 0.0f,
745 1.0f, 1.0f,
746 1.0f, 1.0f,
747 0.0f, 1.0f,
748 0.0f, 0.0f,
749
750 1.0f, 0.0f,
751 1.0f, 1.0f,
752 0.0f, 1.0f,
753 0.0f, 1.0f,
754 0.0f, 0.0f,
755 1.0f, 0.0f,
756
757 1.0f, 0.0f,
758 1.0f, 1.0f,
759 0.0f, 1.0f,
760 0.0f, 1.0f,
761 0.0f, 0.0f,
762 1.0f, 0.0f,
763
764 0.0f, 1.0f,
765 1.0f, 1.0f,
766 1.0f, 0.0f,
767 1.0f, 0.0f,
768 0.0f, 0.0f,
769 0.0f, 1.0f,
770
771 0.0f, 1.0f,
772 1.0f, 1.0f,
773 1.0f, 0.0f,
774 1.0f, 0.0f,
775 0.0f, 0.0f,
776 0.0f, 1.0f
777 };
778
779 #if 0
780 static float Plane_Vertices[] = {
781 /* Positions Texture Coordinates */
782 5.0f, -0.5f, 5.0f, 2.0f, 0.0f,
783 -5.0f, -0.5f, 5.0f, 0.0f, 0.0f,
784 -5.0f, -0.5f, -5.0f, 0.0f, 2.0f,
785
786 5.0f, -0.5f, 5.0f, 2.0f, 0.0f,
787 -5.0f, -0.5f, -5.0f, 0.0f, 2.0f,
788 5.0f, -0.5f, -5.0f, 2.0f, 2.0f
789 };
790 #endif
791
792 static float Quad_Vertices[] = {
793 /* Positions Texture Coordinates */
794 -0.3f, 1.0f, 0.0f, 1.0f,
795 -0.3f, 0.7f, 0.0f, 0.0f,
796 0.3f, 0.7f, 1.0f, 0.0f,
797
798 -0.3f, 1.0f, 0.0f, 1.0f,
799 0.3f, 0.7f, 1.0f, 0.0f,
800 0.3f, 1.0f, 1.0f, 1.0f
801 };
802
803 #if 0
804 static float Skybox_Vertices[] = {
805 -1.0f, 1.0f, -1.0f,
806 -1.0f, -1.0f, -1.0f,
807 1.0f, -1.0f, -1.0f,
808 1.0f, -1.0f, -1.0f,
809 1.0f, 1.0f, -1.0f,
810 -1.0f, 1.0f, -1.0f,
811
812 -1.0f, -1.0f, 1.0f,
813 -1.0f, -1.0f, -1.0f,
814 -1.0f, 1.0f, -1.0f,
815 -1.0f, 1.0f, -1.0f,
816 -1.0f, 1.0f, 1.0f,
817 -1.0f, -1.0f, 1.0f,
818
819 1.0f, -1.0f, -1.0f,
820 1.0f, -1.0f, 1.0f,
821 1.0f, 1.0f, 1.0f,
822 1.0f, 1.0f, 1.0f,
823 1.0f, 1.0f, -1.0f,
824 1.0f, -1.0f, -1.0f,
825
826 -1.0f, -1.0f, 1.0f,
827 -1.0f, 1.0f, 1.0f,
828 1.0f, 1.0f, 1.0f,
829 1.0f, 1.0f, 1.0f,
830 1.0f, -1.0f, 1.0f,
831 -1.0f, -1.0f, 1.0f,
832
833 -1.0f, 1.0f, -1.0f,
834 1.0f, 1.0f, -1.0f,
835 1.0f, 1.0f, 1.0f,
836 1.0f, 1.0f, 1.0f,
837 -1.0f, 1.0f, 1.0f,
838 -1.0f, 1.0f, -1.0f,
839
840 -1.0f, -1.0f, -1.0f,
841 -1.0f, -1.0f, 1.0f,
842 1.0f, -1.0f, -1.0f,
843 1.0f, -1.0f, -1.0f,
844 -1.0f, -1.0f, 1.0f,
845 1.0f, -1.0f, 1.0f
846 };
847 #endif
848
852 static float Cube_Vertices_NT[] = {
853 /* Positions Normals Texture Coords */
854 -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
855 0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f,
856 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
857 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
858 -0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f,
859 -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
860
861 -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
862 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f,
863 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
864 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
865 -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
866 -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
867
868 -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
869 -0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
870 -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
871 -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
872 -0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
873 -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
874
875 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
876 0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
877 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
878 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
879 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
880 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
881
882 -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
883 0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f,
884 0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
885 0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
886 -0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f,
887 -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
888
889 -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
890 0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f,
891 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
892 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
893 -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
894 -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f
895 };
896
897 /* clang-format on */
898
899 FORCEINLINE static uint32_t LoadTexture(const char* path)
900 {
901 uint32_t TextureID;
902 LK_OpenGL_Verify(glGenTextures(1, &TextureID));
903
904 int Width;
905 int Height;
906 int Channels;
907 unsigned char* data = stbi_load(path, &Width, &Height, &Channels, 0);
908 if (data)
909 {
910 GLenum Format;
911 if (Channels == 1)
912 {
913 Format = GL_RED;
914 }
915 else if (Channels == 3)
916 {
917 Format = GL_RGB;
918 }
919 else if (Channels == 4)
920 {
921 Format = GL_RGBA;
922 }
923 else
924 {
925 LK_CORE_ASSERT(false, "Invalid GLFormat");
926 Format = GL_INVALID_ENUM;
927 }
928
929 LK_OpenGL_Verify(glBindTexture(GL_TEXTURE_2D, TextureID));
930 LK_OpenGL_Verify(glTexImage2D(GL_TEXTURE_2D, 0, Format, Width, Height, 0, Format, GL_UNSIGNED_BYTE, data));
931 LK_OpenGL_Verify(glGenerateMipmap(GL_TEXTURE_2D));
932
933 LK_OpenGL_Verify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT));
934 LK_OpenGL_Verify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT));
935 LK_OpenGL_Verify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR));
936 LK_OpenGL_Verify(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
937
938 stbi_image_free(data);
939 }
940 else
941 {
942 LK_CORE_ERROR_TAG("OpenGLRenderer2D", "Texture failed to load at path {}", path);
943 stbi_image_free(data);
944 }
945
946 return TextureID;
947 }
948
953
954 void SetupDebugCube();
955 void GeneratePlaneVaoAndVbo();
956 void GenerateScreenQuadVaoAndVbo(uint32_t& vao, uint32_t& vbo);
957 void SetupTexturesAndShaders();
958 void SetupSkybox();
959
960 void RenderMirrorTexture(const glm::mat4& view = glm::mat4(1.0f), const glm::mat4& proj = glm::mat4(1.0f));
961 void RenderScreenTexture(const glm::mat4& view = glm::mat4(1.0f), const glm::mat4& proj = glm::mat4(1.0f));
962 void RenderCubes(const glm::mat4& view = glm::mat4(1.0f), const glm::mat4& proj = glm::mat4(1.0f));
963 void RenderFloor(const glm::mat4& view = glm::mat4(1.0f), const glm::mat4& proj = glm::mat4(1.0f));
964 void RenderSkybox(const TObjectPtr<LSceneCamera> Camera);
965 void RenderSkybox(const glm::mat4& ViewMatrix, const glm::mat4& ProjectionMatrix);
966
967 TObjectPtr<LShader> GetDebugShader();
968 TObjectPtr<LShader> GetScreenShader();
969
970 static uint32_t LoadCubemap(std::vector<std::string> faces)
971 {
972 LK_MARK_FUNC_FOR_REMOVAL();
973
974 uint32_t TextureID;
975 glGenTextures(1, &TextureID);
976 glBindTexture(GL_TEXTURE_CUBE_MAP, TextureID);
977
978 int Width, Height, Channels;
979 for (uint32_t i = 0; i < faces.size(); i++)
980 {
981 unsigned char* Data = stbi_load(faces[i].c_str(), &Width, &Height, &Channels, 0);
982 if (Data)
983 {
984 LK_OpenGL_Verify(
985 glTexImage2D((GL_TEXTURE_CUBE_MAP_POSITIVE_X + i), 0, GL_RGB, Width, Height, 0, GL_RGB, GL_UNSIGNED_BYTE, Data)
986 );
987 stbi_image_free(Data);
988 }
989 else
990 {
991 LK_CORE_ASSERT(false, "Failed to load texture {}", faces[i]);
992 stbi_image_free(Data);
993 }
994 }
995
996 LK_OpenGL_Verify(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
997 LK_OpenGL_Verify(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
998 LK_OpenGL_Verify(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
999 LK_OpenGL_Verify(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
1000 LK_OpenGL_Verify(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE));
1001
1002 return TextureID;
1003 }
1004
1005 FORCEINLINE static void GenerateSkybox(LRendererID& InSkyboxVao, LRendererID& InSkyboxVbo)
1006 {
1007 LK_MARK_FUNC_FOR_REMOVAL();
1008
1009 LK_CORE_DEBUG_TAG("LOpenGL", "Generating skybox");
1010 LK_OpenGL_Verify(glGenVertexArrays(1, &InSkyboxVao));
1011 LK_OpenGL_Verify(glGenBuffers(1, &InSkyboxVbo));
1012 LK_OpenGL_Verify(glBindVertexArray(InSkyboxVao));
1013 LK_OpenGL_Verify(glBindBuffer(GL_ARRAY_BUFFER, InSkyboxVbo));
1014 LK_OpenGL_Verify(glBufferData(GL_ARRAY_BUFFER, sizeof(Geometry::Vertices::Skybox), &Geometry::Vertices::Skybox, GL_STATIC_DRAW));
1015 LK_OpenGL_Verify(glEnableVertexAttribArray(0));
1016 LK_OpenGL_Verify(glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0));
1017
1018 SkyboxShader = LShader::Create("Assets/Shaders/OpenGL/Skybox.shader");
1019 SkyboxShader->Bind();
1020 SkyboxShader->Set("skybox", 0);
1021 }
1022
1023 static void RenderSkybox(const LRendererID texture, const glm::mat4& view, const glm::mat4& projection)
1024 {
1025 LK_MARK_FUNC_FOR_REMOVAL();
1026
1027 /* Change depth function so depth test passes when values are equal to depth buffer's content. */
1028 LK_OpenGL_Verify(glDepthFunc(GL_LEQUAL));
1029 SkyboxShader->Bind();
1030 SkyboxShader->Set("view", view);
1031 SkyboxShader->Set("projection", projection);
1032
1033 // Skybox Cube
1034 LK_OpenGL_Verify(glBindVertexArray(SkyboxVAO));
1035 LK_OpenGL_Verify(glActiveTexture(GL_TEXTURE0));
1036 LK_OpenGL_Verify(glBindTexture(GL_TEXTURE_CUBE_MAP, texture));
1037 LK_OpenGL_Verify(glDrawArrays(GL_TRIANGLES, 0, 36));
1038 LK_OpenGL_Verify(glBindVertexArray(0));
1039 LK_OpenGL_Verify(glDepthFunc(GL_LESS)); /* Set back to default. */
1040 }
1041
1042 }
1043
1044 /*****************************************************************************/
1045
1046 namespace Enum {
1047
1048 FORCEINLINE static constexpr const char* ToString(const EArrayTextureDimension TextureArrayDimension)
1049 {
1050 switch (TextureArrayDimension)
1051 {
1052 case EArrayTextureDimension::Dim_512x512: return "512x512";
1053 case EArrayTextureDimension::Dim_1024x1024: return "1024x1024";
1054 case EArrayTextureDimension::Dim_2048x2048: return "2048x2048";
1055 case EArrayTextureDimension::Dim_4096x4096: return "4096x4096";
1056 }
1057
1058 LK_CORE_ASSERT(false, "Unknown ETextureArrayDimension value: {}", static_cast<int>(TextureArrayDimension));
1059 return {};
1060 }
1061
1062 }
1063
1064}
1065
LObject implementation.
uint32_t LRendererID
Definition CoreTypes.h:30
void InitializeEnvironment()
Setup debug environment with a plane and two cubes.
Definition LkOpenGL.cpp:268
Definition Asset.h:11
EShaderDataType
Definition VertexBufferLayout.h:12
Definition LkOpenGL.h:156
Definition LkOpenGL.h:165
static FORCEINLINE int GetSourceBlendFunction(const ESourceBlendFunction InBlendFunction)
Convert ESourceBlendFunction to OpenGL source blend function.
Definition LkOpenGL.h:169
static FORCEINLINE int GetDestinationBlendFunction(const EDestinationBlendFunction InBlendFunction)
Convert EDestinationBlendFunction to OpenGL destination blend function.
Definition LkOpenGL.h:187
static FORCEINLINE float GetSampleDepth(int x, int y, int WindowWidth, int WindowHeight)
Definition LkOpenGL.h:577
Definition LkOpenGL.h:141
Definition LkOpenGL.h:85
static void LoadInfo()
Load info about the GL backend. Load major/minor version, populate vector with supported extensions.
Definition LkOpenGL.h:90