diff --git a/dgl/src/OpenGL.cpp b/dgl/src/OpenGL.cpp index fa387e41..f351d3e7 100644 --- a/dgl/src/OpenGL.cpp +++ b/dgl/src/OpenGL.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2024 Filipe Coelho + * Copyright (C) 2012-2025 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -33,35 +33,59 @@ START_NAMESPACE_DGL -// ----------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- #ifdef DGL_USE_OPENGL3 +# if defined(DGL_USE_GLES2) && defined(DGL_USE_GLES3) +# error Build config error, both GLESv2 and GLESv3 requested at the same time +# endif + +struct OpenGL3GraphicsContext : GraphicsContext +{ + mutable int prog, color, pos; + mutable uint w, h; +}; + static void notImplemented(const char* const name) { - d_stderr2("OpenGL3 function not implemented: %s", name); + #if defined(DGL_USE_GLES2) + #define DGL_OPENGL3_NAME "GLESv2" + #elif defined(DGL_USE_GLES3) + #define DGL_OPENGL3_NAME "GLESv3" + #else + #define DGL_OPENGL3_NAME "OpenGL3" + #endif + d_stderr2(DGL_OPENGL3_NAME " function not implemented: %s", name); + #undef DGL_OPENGL3_NAME } #else +# if defined(DGL_USE_GLES2) || defined(DGL_USE_GLES3) +# error Build config error, GLES requested while using OpenGL compat mode +# endif # define DGL_USE_COMPAT_OPENGL #endif -// ----------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- // Color -void Color::setFor(const GraphicsContext&, const bool includeAlpha) +void Color::setFor(const GraphicsContext& context, const bool includeAlpha) { -#ifdef DGL_USE_COMPAT_OPENGL + #ifdef DGL_USE_OPENGL3 + const OpenGL3GraphicsContext& gl3context = static_cast(context); + const GLfloat color[4] = { red, green, blue, includeAlpha ? alpha : 1.f }; + glUniform4fv(gl3context.color, 1, color); + #else if (includeAlpha) glColor4f(red, green, blue, alpha); else glColor3f(red, green, blue); -#else - notImplemented("Color::setFor"); + // unused - (void)includeAlpha; -#endif + (void)context; + #endif } -// ----------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- // Line #ifdef DGL_USE_COMPAT_OPENGL @@ -82,16 +106,29 @@ static void drawLine(const Point& posStart, const Point& posEnd) #endif template -void Line::draw(const GraphicsContext&, const T width) +void Line::draw(const GraphicsContext& context, const T width) { -#ifdef DGL_USE_COMPAT_OPENGL DISTRHO_SAFE_ASSERT_RETURN(width != 0,); glLineWidth(static_cast(width)); + + #ifdef DGL_USE_OPENGL3 + const OpenGL3GraphicsContext& gl3context = static_cast(context); + + const GLfloat x1 = (static_cast(posStart.x) / gl3context.w) * 2 - 1; + const GLfloat y1 = (static_cast(posStart.y) / gl3context.h) * -2 + 1; + const GLfloat x2 = (static_cast(posEnd.x) / gl3context.w) * 2 - 1; + const GLfloat y2 = (static_cast(posEnd.y) / gl3context.h) * -2 + 1; + + const GLfloat vertices[] = { x1, y1, x2, y2, }; + glVertexAttribPointer(gl3context.pos, 2, GL_FLOAT, GL_FALSE, 0, vertices); + glEnableVertexAttribArray(gl3context.pos); + + GLubyte order[] = { 0, 1 }; + glDrawElements(GL_LINES, ARRAY_SIZE(order), GL_UNSIGNED_BYTE, order); + #else drawLine(posStart, posEnd); -#else - notImplemented("Line::draw"); -#endif + #endif } // deprecated calls @@ -306,13 +343,27 @@ static void drawRectangle(const Rectangle& rect, const bool outline) #endif template -void Rectangle::draw(const GraphicsContext&) -{ -#ifdef DGL_USE_COMPAT_OPENGL +void Rectangle::draw(const GraphicsContext& context) +{ + #ifdef DGL_USE_OPENGL3 + const OpenGL3GraphicsContext& gl3context = static_cast(context); + const GLfloat x = (static_cast(pos.x) / gl3context.w) * 2 - 1; + const GLfloat y = (static_cast(pos.y) / gl3context.h) * -2 + 1; + const GLfloat w = (static_cast(size.fWidth) / gl3context.w) * 2; + const GLfloat h = (static_cast(size.fHeight) / gl3context.h) * -2; + + GLfloat vertices[] = { x, y, x, y + h, x + w, y + h, x + w, y }; + glVertexAttribPointer(gl3context.pos, 2, GL_FLOAT, GL_FALSE, 0, vertices); + glEnableVertexAttribArray(gl3context.pos); + + GLubyte order[] = { 0, 1, 2, 0, 2, 3 }; + glDrawElements(GL_TRIANGLES, ARRAY_SIZE(order), GL_UNSIGNED_BYTE, order); + #else drawRectangle(*this, false); -#else - notImplemented("Rectangle::draw"); -#endif + + // unused + (void)context; + #endif } template @@ -787,13 +838,96 @@ void Window::PrivateData::renderToPicture(const char* const filename, fclose(f); } -// ----------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- + +#ifdef DGL_USE_OPENGL3 +const GraphicsContext& contextCreationFail(const OpenGL3GraphicsContext& gl3context) +{ + gl3context.prog = -1; + return gl3context; +} +#endif const GraphicsContext& Window::PrivateData::getGraphicsContext() const noexcept { - return (const GraphicsContext&)graphicsContext; + GraphicsContext& context = reinterpret_cast(graphicsContext); + + #ifdef DGL_USE_OPENGL3 + const OpenGL3GraphicsContext& gl3context = static_cast(context); + + // previous context creation failed + if (gl3context.prog == -1) + return context; + + // create new context + if (gl3context.prog == 0) + { + int status; + + const GLuint fragment = glCreateShader(GL_FRAGMENT_SHADER); + DISTRHO_SAFE_ASSERT_RETURN(fragment != 0, contextCreationFail(gl3context)); + + const GLuint vertex = glCreateShader(GL_VERTEX_SHADER); + DISTRHO_SAFE_ASSERT_RETURN(vertex != 0, contextCreationFail(gl3context)); + + const GLuint program = glCreateProgram(); + DISTRHO_SAFE_ASSERT_RETURN(program != 0, contextCreationFail(gl3context)); + + #if defined(DGL_USE_GLES2) + #define DGL_SHADER_HEADER "#version 100\n" + #elif defined(DGL_USE_GLES3) + #define DGL_SHADER_HEADER "#version 300 es\n" + #else + #define DGL_SHADER_HEADER "#version 150 core\n" + #endif + + { + static constexpr const char* const src = DGL_SHADER_HEADER + "precision mediump float;" + "uniform vec4 color;" + "void main() { gl_FragColor = color; }"; + + glShaderSource(fragment, 1, &src, nullptr); + glCompileShader(fragment); + + glGetShaderiv(fragment, GL_COMPILE_STATUS, &status); + DISTRHO_SAFE_ASSERT_RETURN(status != 0, contextCreationFail(gl3context)); + } + + { + static constexpr const char* const src = DGL_SHADER_HEADER + "attribute vec4 pos;" + "void main() { gl_Position = pos; }"; + + glShaderSource(vertex, 1, &src, nullptr); + glCompileShader(vertex); + + glGetShaderiv(vertex, GL_COMPILE_STATUS, &status); + DISTRHO_SAFE_ASSERT_RETURN(status != 0, contextCreationFail(gl3context)); + } + + glAttachShader(program, fragment); + glAttachShader(program, vertex); + glLinkProgram(program); + + glGetProgramiv(program, GL_LINK_STATUS, &status); + DISTRHO_SAFE_ASSERT_RETURN(status != 0, contextCreationFail(gl3context)); + + gl3context.prog = program; + gl3context.color = glGetUniformLocation(program, "color"); + gl3context.pos = glGetAttribLocation(program, "pos"); + } + + const PuglRect rect = puglGetFrame(view); + gl3context.w = static_cast(rect.width + 0.5); + gl3context.h = static_cast(rect.height + 0.5); + + glUseProgram(gl3context.prog); + #endif + + return context; } -// ----------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- END_NAMESPACE_DGL diff --git a/dgl/src/WindowPrivateData.hpp b/dgl/src/WindowPrivateData.hpp index 31b1481a..4abfaf99 100644 --- a/dgl/src/WindowPrivateData.hpp +++ b/dgl/src/WindowPrivateData.hpp @@ -45,7 +45,7 @@ struct Window::PrivateData : IdleCallback { PuglView* view; /** Reserved space for graphics context. */ - mutable uint8_t graphicsContext[sizeof(void*)]; + mutable uint8_t graphicsContext[sizeof(int) * 5]; /** The top-level widgets associated with this Window. */ std::list topLevelWidgets;