From dfe9da43dab6c933bc1024f992383f08e01386de Mon Sep 17 00:00:00 2001 From: hachem Date: Tue, 18 Aug 2026 15:00:34 +0200 Subject: [fix]: macos compatibility --- src/Platform/OpenGL/OpenGLFramebuffer.cpp | 23 ++++-- src/Platform/OpenGL/OpenGLIndexBuffer.cpp | 2 +- src/Platform/OpenGL/OpenGLRendererAPI.cpp | 5 +- src/Platform/OpenGL/OpenGLShader.cpp | 23 +++++- src/Platform/OpenGL/OpenGLShader.h | 2 +- src/Platform/OpenGL/OpenGLTexture.cpp | 113 +++++++++++++++++------------ src/Platform/OpenGL/OpenGLVertexArray.cpp | 6 +- src/Platform/OpenGL/OpenGLVertexBuffer.cpp | 2 +- 8 files changed, 114 insertions(+), 62 deletions(-) (limited to 'src/Platform') diff --git a/src/Platform/OpenGL/OpenGLFramebuffer.cpp b/src/Platform/OpenGL/OpenGLFramebuffer.cpp index 3bb62f6..c46e0e6 100644 --- a/src/Platform/OpenGL/OpenGLFramebuffer.cpp +++ b/src/Platform/OpenGL/OpenGLFramebuffer.cpp @@ -19,7 +19,9 @@ namespace Donut static void CreateTextures(bool multisampled, uint32_t* outID, uint32_t count) { - glCreateTextures(TextureTarget(multisampled), count, outID); + // glCreateTextures is 4.5 DSA; macOS caps at 4.1. Callers bind each + // texture (with the correct target) before use. + glGenTextures(count, outID); } static void AttachColorTexture(uint32_t id, int samples, GLenum internalFormat, GLenum format, uint32_t width, uint32_t height, int index) @@ -31,7 +33,10 @@ namespace Donut } else { - glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, GL_UNSIGNED_BYTE, nullptr); + // Integer color formats require an integer pixel type even when + // data is null, or macOS's strict core profile rejects the call. + GLenum type = (format == GL_RED_INTEGER) ? GL_INT : GL_UNSIGNED_BYTE; + glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, type, nullptr); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); @@ -52,7 +57,10 @@ namespace Donut } else { - glTexStorage2D(GL_TEXTURE_2D, 1, format, width, height); + // glTexStorage2D is 4.2; use mutable storage for macOS (4.1). + GLenum depthFormat = (format == GL_DEPTH24_STENCIL8) ? GL_DEPTH_STENCIL : GL_DEPTH_COMPONENT; + GLenum depthType = (format == GL_DEPTH24_STENCIL8) ? GL_UNSIGNED_INT_24_8 : GL_FLOAT; + glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, depthFormat, depthType, nullptr); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); @@ -118,7 +126,7 @@ namespace Donut m_DepthAttachment = 0; } - glCreateFramebuffers(1, &m_RendererID); + glGenFramebuffers(1, &m_RendererID); // glCreateFramebuffers is 4.5 DSA; unavailable on macOS 4.1 glBindFramebuffer(GL_FRAMEBUFFER, m_RendererID); bool multisample = m_Specification.Samples > 1; @@ -230,8 +238,9 @@ namespace Donut void OpenGLFramebuffer::ClearAttachment(uint32_t attachmentIndex, int value) { - auto& spec = m_ColorAttachmentSpecifications[attachmentIndex]; - glClearTexImage(m_ColorAttachments[attachmentIndex], 0, - Utils::DonutFBTextureFormatToGL(spec.TextureFormat), GL_INT, &value); + // glClearTexImage is 4.4 and unavailable on macOS. Clear the integer + // attachment by binding this framebuffer and clearing its draw buffer. + glBindFramebuffer(GL_FRAMEBUFFER, m_RendererID); + glClearBufferiv(GL_COLOR, static_cast(attachmentIndex), &value); } }; diff --git a/src/Platform/OpenGL/OpenGLIndexBuffer.cpp b/src/Platform/OpenGL/OpenGLIndexBuffer.cpp index 7faee62..668a898 100644 --- a/src/Platform/OpenGL/OpenGLIndexBuffer.cpp +++ b/src/Platform/OpenGL/OpenGLIndexBuffer.cpp @@ -6,7 +6,7 @@ namespace Donut OpenGLIndexBuffer::OpenGLIndexBuffer(const uint32_t* indices, uint32_t count) : m_Count(count) { - glCreateBuffers(1, &m_RendererID); + glGenBuffers(1, &m_RendererID); // glCreateBuffers is 4.5 DSA; unavailable on macOS 4.1 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_RendererID); glBufferData(GL_ELEMENT_ARRAY_BUFFER, count * sizeof(uint32_t), indices, GL_STATIC_DRAW); } diff --git a/src/Platform/OpenGL/OpenGLRendererAPI.cpp b/src/Platform/OpenGL/OpenGLRendererAPI.cpp index 230b19b..fd3c491 100644 --- a/src/Platform/OpenGL/OpenGLRendererAPI.cpp +++ b/src/Platform/OpenGL/OpenGLRendererAPI.cpp @@ -103,7 +103,10 @@ namespace Donut void OpenGLRendererAPI::BindImageTexture(uint32_t textureID, uint32_t slot, bool readOnly) { - glBindImageTexture(slot, textureID, 0, GL_FALSE, 0, + // Image load/store is OpenGL 4.2; the pointer is null on macOS (4.1). + if (glBindImageTexture == nullptr) + return; + glBindImageTexture(slot, textureID, 0, GL_FALSE, 0, readOnly ? GL_READ_ONLY : GL_WRITE_ONLY, GL_RGBA8); } diff --git a/src/Platform/OpenGL/OpenGLShader.cpp b/src/Platform/OpenGL/OpenGLShader.cpp index b163cde..2992cdc 100644 --- a/src/Platform/OpenGL/OpenGLShader.cpp +++ b/src/Platform/OpenGL/OpenGLShader.cpp @@ -120,7 +120,15 @@ namespace Donut std::vector infoLog(maxLength); glGetShaderInfoLog(shader, maxLength, &maxLength, &infoLog[0]); glDeleteShader(shader); - std::cout << "Shader compilation failure!" << std::endl << infoLog.data() << std::endl; + for (auto id : glShaderIDs) + glDeleteShader(id); + glDeleteProgram(program); + m_RendererID = 0; + // infoLog.data() is null when the driver returns an empty log + // (e.g. macOS rejecting a compute shader); streaming a null + // char* into std::cout calls strlen(NULL) and crashes. + const char* log = infoLog.empty() ? "" : infoLog.data(); + std::cout << "Shader compilation failure!" << std::endl << log << std::endl; return; } glAttachShader(program, shader); @@ -141,7 +149,9 @@ namespace Donut glDeleteProgram(m_RendererID); for (auto id : glShaderIDs) glDeleteShader(id); - std::cout << "Shader link failure!" << std::endl << infoLog.data() << std::endl; + m_RendererID = 0; + const char* log = infoLog.empty() ? "" : infoLog.data(); + std::cout << "Shader link failure!" << std::endl << log << std::endl; return; } @@ -247,16 +257,25 @@ namespace Donut void OpenGLShader::Dispatch(uint32_t x, uint32_t y, uint32_t z) { + // Compute shaders require OpenGL 4.3+. On drivers that cap out earlier + // (e.g. macOS, which is frozen at 4.1) glDispatchCompute is never + // loaded and the pointer is null. Guard so we no-op instead of crash. + if (m_RendererID == 0 || glDispatchCompute == nullptr) + return; glDispatchCompute(x, y, z); } void OpenGLShader::DispatchIndirect(uint32_t offset) { + if (m_RendererID == 0 || glDispatchComputeIndirect == nullptr) + return; glDispatchComputeIndirect(offset); } void OpenGLShader::MemoryBarrier(uint32_t barriers) { + if (glMemoryBarrier == nullptr) + return; glMemoryBarrier(barriers); } }; diff --git a/src/Platform/OpenGL/OpenGLShader.h b/src/Platform/OpenGL/OpenGLShader.h index 99a150b..72d1d6e 100644 --- a/src/Platform/OpenGL/OpenGLShader.h +++ b/src/Platform/OpenGL/OpenGLShader.h @@ -48,7 +48,7 @@ namespace Donut std::unordered_map PreProcess(const std::string& source); void Compile(const std::unordered_map& shaderSources); private: - uint32_t m_RendererID; + uint32_t m_RendererID = 0; std::string m_Name; }; }; diff --git a/src/Platform/OpenGL/OpenGLTexture.cpp b/src/Platform/OpenGL/OpenGLTexture.cpp index ef5bdaa..1895575 100644 --- a/src/Platform/OpenGL/OpenGLTexture.cpp +++ b/src/Platform/OpenGL/OpenGLTexture.cpp @@ -8,6 +8,11 @@ #include #include +// NOTE: This file targets OpenGL 4.1 (the maximum macOS exposes). It uses the +// classic bind-based texture API rather than 4.5 Direct State Access +// (glCreateTextures / glTextureStorage2D / glTextureParameteri / glBindTextureUnit), +// none of which exist on macOS. + namespace Donut { OpenGLTexture2D::OpenGLTexture2D(uint32_t width, uint32_t height) @@ -16,14 +21,14 @@ namespace Donut m_InternalFormat = GL_RGBA8; m_DataFormat = GL_RGBA; - glCreateTextures(GL_TEXTURE_2D, 1, &m_RendererID); - glTextureStorage2D(m_RendererID, 1, m_InternalFormat, m_Width, m_Height); - - glTextureParameteri(m_RendererID, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTextureParameteri(m_RendererID, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glGenTextures(1, &m_RendererID); + glBindTexture(GL_TEXTURE_2D, m_RendererID); + glTexImage2D(GL_TEXTURE_2D, 0, m_InternalFormat, m_Width, m_Height, 0, m_DataFormat, GL_UNSIGNED_BYTE, nullptr); - glTextureParameteri(m_RendererID, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTextureParameteri(m_RendererID, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); } OpenGLTexture2D::OpenGLTexture2D(const std::string& path) @@ -34,17 +39,17 @@ namespace Donut m_InternalFormat = GL_RGBA8; m_DataFormat = GL_RGBA; - glCreateTextures(GL_TEXTURE_2D, 1, &m_RendererID); - glTextureStorage2D(m_RendererID, 1, m_InternalFormat, m_Width, m_Height); + glGenTextures(1, &m_RendererID); + glBindTexture(GL_TEXTURE_2D, m_RendererID); + glTexImage2D(GL_TEXTURE_2D, 0, m_InternalFormat, m_Width, m_Height, 0, m_DataFormat, GL_UNSIGNED_BYTE, nullptr); - glTextureParameteri(m_RendererID, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTextureParameteri(m_RendererID, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - glTextureParameteri(m_RendererID, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTextureParameteri(m_RendererID, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); uint32_t whitePixel = 0xFFFFFFFF; - glTextureSubImage2D(m_RendererID, 0, 0, 0, m_Width, m_Height, m_DataFormat, GL_UNSIGNED_BYTE, &whitePixel); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_Width, m_Height, m_DataFormat, GL_UNSIGNED_BYTE, &whitePixel); DONUT_INFO("Created default texture (stb_image not available for loading: ", path, ")"); } @@ -62,17 +67,23 @@ namespace Donut DONUT_ERROR("Data must be entire texture!"); return; } - - glTextureSubImage2D(m_RendererID, 0, 0, 0, m_Width, m_Height, m_DataFormat, GL_UNSIGNED_BYTE, data); + + glBindTexture(GL_TEXTURE_2D, m_RendererID); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_Width, m_Height, m_DataFormat, GL_UNSIGNED_BYTE, data); } void OpenGLTexture2D::Bind(uint32_t slot) const { - glBindTextureUnit(slot, m_RendererID); + glActiveTexture(GL_TEXTURE0 + slot); + glBindTexture(GL_TEXTURE_2D, m_RendererID); } void OpenGLTexture2D::BindAsImage(uint32_t slot, bool readOnly) const { + // Image load/store is OpenGL 4.2 and unavailable on macOS. Guard the + // function pointer so this degrades to a no-op instead of crashing. + if (glBindImageTexture == nullptr) + return; GLenum access = readOnly ? GL_READ_ONLY : GL_WRITE_ONLY; glBindImageTexture(slot, m_RendererID, 0, GL_FALSE, 0, access, m_InternalFormat); } @@ -80,17 +91,19 @@ namespace Donut OpenGLCubemapTexture::OpenGLCubemapTexture(uint32_t width, uint32_t height) : m_Width(width), m_Height(height) { - m_InternalFormat = GL_RGB16F; - m_DataFormat = GL_RGB; + m_InternalFormat = GL_RGBA16F; + m_DataFormat = GL_RGBA; - glCreateTextures(GL_TEXTURE_CUBE_MAP, 1, &m_RendererID); - glTextureStorage2D(m_RendererID, 1, m_InternalFormat, m_Width, m_Height); + glGenTextures(1, &m_RendererID); + glBindTexture(GL_TEXTURE_CUBE_MAP, m_RendererID); + for (uint32_t i = 0; i < 6; ++i) + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, m_InternalFormat, m_Width, m_Height, 0, m_DataFormat, GL_FLOAT, nullptr); - glTextureParameteri(m_RendererID, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTextureParameteri(m_RendererID, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTextureParameteri(m_RendererID, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTextureParameteri(m_RendererID, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTextureParameteri(m_RendererID, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); } OpenGLCubemapTexture::OpenGLCubemapTexture(const std::string& path) @@ -98,17 +111,19 @@ namespace Donut { m_Width = 1024; m_Height = 1024; - m_InternalFormat = GL_RGB16F; - m_DataFormat = GL_RGB; + m_InternalFormat = GL_RGBA16F; + m_DataFormat = GL_RGBA; - glCreateTextures(GL_TEXTURE_CUBE_MAP, 1, &m_RendererID); - glTextureStorage2D(m_RendererID, 1, m_InternalFormat, m_Width, m_Height); + glGenTextures(1, &m_RendererID); + glBindTexture(GL_TEXTURE_CUBE_MAP, m_RendererID); + for (uint32_t i = 0; i < 6; ++i) + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, m_InternalFormat, m_Width, m_Height, 0, m_DataFormat, GL_FLOAT, nullptr); - glTextureParameteri(m_RendererID, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTextureParameteri(m_RendererID, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTextureParameteri(m_RendererID, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTextureParameteri(m_RendererID, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTextureParameteri(m_RendererID, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); LoadHDRI(path); } @@ -123,11 +138,11 @@ namespace Donut stbi_set_flip_vertically_on_load(true); int width, height, channels; float* hdrData = stbi_loadf(path.c_str(), &width, &height, &channels, 3); - + if (!hdrData) { DONUT_ERROR("Failed to load HDRI: {}", path); - float defaultSky[6 * 4] = + float defaultSky[6 * 4] = { 0.5f, 0.7f, 1.0f, 1.0f, // Right 0.5f, 0.7f, 1.0f, 1.0f, // Left @@ -136,15 +151,16 @@ namespace Donut 0.5f, 0.7f, 1.0f, 1.0f, // Front 0.5f, 0.7f, 1.0f, 1.0f // Back }; - + + glBindTexture(GL_TEXTURE_CUBE_MAP, m_RendererID); for (int i = 0; i < 6; ++i) - glTextureSubImage3D(m_RendererID, 0, 0, 0, i, 1, 1, 1, GL_RGBA, GL_FLOAT, &defaultSky[i * 4]); + glTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 0, 0, 1, 1, GL_RGBA, GL_FLOAT, &defaultSky[i * 4]); return; } ConvertEquirectangularToCubemap(hdrData, width, height); stbi_image_free(hdrData); - + DONUT_INFO("Successfully loaded HDRI: {} ({}x{})", path, width, height); } @@ -174,10 +190,10 @@ namespace Donut DONUT_ERROR("Failed to create equirectangular to cubemap shader"); return; } - + uint32_t shaderProgram = equirectShader->GetRendererID(); - float vertices[] = + float vertices[] = { -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, @@ -197,7 +213,7 @@ namespace Donut glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); glm::mat4 captureProjection = glm::perspective(glm::radians(90.0f), 1.0f, 0.1f, 10.0f); - glm::mat4 captureViews[] = + glm::mat4 captureViews[] = { glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3( 1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)), glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(-1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)), @@ -224,10 +240,10 @@ namespace Donut glDrawArrays(GL_TRIANGLES, 0, 36); } glBindVertexArray(0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); glDeleteVertexArrays(1, &cubeVAO); glDeleteBuffers(1, &cubeVBO); - glDeleteProgram(shaderProgram); glDeleteTextures(1, &hdrTexture); glDeleteFramebuffers(1, &captureFBO); glDeleteRenderbuffers(1, &captureRBO); @@ -240,12 +256,15 @@ namespace Donut void OpenGLCubemapTexture::Bind(uint32_t slot) const { - glBindTextureUnit(slot, m_RendererID); + glActiveTexture(GL_TEXTURE0 + slot); + glBindTexture(GL_TEXTURE_CUBE_MAP, m_RendererID); } void OpenGLCubemapTexture::BindAsImage(uint32_t slot, bool readOnly) const { + if (glBindImageTexture == nullptr) + return; GLenum access = readOnly ? GL_READ_ONLY : GL_WRITE_ONLY; glBindImageTexture(slot, m_RendererID, 0, GL_TRUE, 0, access, m_InternalFormat); } -}; \ No newline at end of file +}; diff --git a/src/Platform/OpenGL/OpenGLVertexArray.cpp b/src/Platform/OpenGL/OpenGLVertexArray.cpp index 6019287..afe5fe2 100644 --- a/src/Platform/OpenGL/OpenGLVertexArray.cpp +++ b/src/Platform/OpenGL/OpenGLVertexArray.cpp @@ -6,9 +6,11 @@ namespace Donut { - OpenGLVertexArray::OpenGLVertexArray() + OpenGLVertexArray::OpenGLVertexArray() { - glCreateVertexArrays(1, &m_RendererID); + // glCreateVertexArrays is 4.5 DSA; macOS caps at 4.1. glGenVertexArrays + // reserves the name and the VAO is created on first bind (done below). + glGenVertexArrays(1, &m_RendererID); } OpenGLVertexArray::~OpenGLVertexArray() diff --git a/src/Platform/OpenGL/OpenGLVertexBuffer.cpp b/src/Platform/OpenGL/OpenGLVertexBuffer.cpp index 21f152c..4f5e48f 100644 --- a/src/Platform/OpenGL/OpenGLVertexBuffer.cpp +++ b/src/Platform/OpenGL/OpenGLVertexBuffer.cpp @@ -7,7 +7,7 @@ namespace Donut { OpenGLVertexBuffer::OpenGLVertexBuffer(const void* data, uint32_t size) { - glCreateBuffers(1, &m_RendererID); + glGenBuffers(1, &m_RendererID); // glCreateBuffers is 4.5 DSA; unavailable on macOS 4.1 glBindBuffer(GL_ARRAY_BUFFER, m_RendererID); glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW); } -- cgit v1.3