/* * DISTRHO Plugin Framework (DPF) * 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 * permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifdef _MSC_VER // instantiated template classes whose methods are defined elsewhere # pragma warning(disable:4661) #endif #include "../OpenGL.hpp" #include "../Color.hpp" #include "../ImageWidgets.hpp" // #include "SubWidgetPrivateData.hpp" // #include "TopLevelWidgetPrivateData.hpp" // #include "WidgetPrivateData.hpp" #include "WindowPrivateData.hpp" // templated classes #include "ImageBaseWidgets.cpp" START_NAMESPACE_DGL // -------------------------------------------------------------------------------------------------------------------- // Check for correct build config #ifndef DGL_OPENGL # error Build config error, OpenGL was NOT requested while building OpenGL2 code #endif #ifdef DGL_CAIRO # error Build config error, Cairo requested while building OpenGL2 code #endif #ifdef DGL_VULKAN # error Build config error, Vulkan requested while building OpenGL2 code #endif #ifdef DGL_USE_GLES2 # error Build config error, GLESv2 requested while building OpenGL2 code #endif #ifdef DGL_USE_GLES3 # error Build config error, GLESv3 requested while building OpenGL2 code #endif #ifdef DGL_USE_OPENGL3 # error Build config error, OpenGL3 requested while building OpenGL2 code #endif // -------------------------------------------------------------------------------------------------------------------- // Color void Color::setFor(const GraphicsContext&, const bool includeAlpha) { if (includeAlpha) glColor4f(red, green, blue, alpha); else glColor3f(red, green, blue); } // -------------------------------------------------------------------------------------------------------------------- // Line template static void drawLine(const Point& posStart, const Point& posEnd) { DISTRHO_SAFE_ASSERT_RETURN(posStart != posEnd,); glBegin(GL_LINES); { glVertex2d(posStart.getX(), posStart.getY()); glVertex2d(posEnd.getX(), posEnd.getY()); } glEnd(); } template void Line::draw(const GraphicsContext&, const T width) { DISTRHO_SAFE_ASSERT_RETURN(width != 0,); glLineWidth(static_cast(width)); drawLine(posStart, posEnd); } #if DGL_ALLOW_DEPRECATED_METHODS template void Line::draw() { drawLine(posStart, posEnd); } #endif // -------------------------------------------------------------------------------------------------------------------- // Circle template static void drawCircle(const Point& pos, const uint numSegments, const float size, const float sin, const float cos, const bool outline) { DISTRHO_SAFE_ASSERT_RETURN(numSegments >= 3 && size > 0.0f,); const double origx = static_cast(pos.getX()); const double origy = static_cast(pos.getY()); double t; double x = size; double y = 0.0; glBegin(outline ? GL_LINE_LOOP : GL_POLYGON); for (uint i = 0; i < numSegments; ++i) { glVertex2d(x + origx, y + origy); t = x; x = cos * x - sin * y; y = sin * t + cos * y; } glEnd(); } template static void drawCircle(const GraphicsContext&, const Point& pos, const uint numSegments, const float size, const float sin, const float cos, const bool outline) { drawCircle(pos, numSegments, size, sin, cos, outline); } template void Circle::draw(const GraphicsContext& context) { drawCircle(context, fPos, fNumSegments, fSize, fSin, fCos, false); } template void Circle::drawOutline(const GraphicsContext& context, const T lineWidth) { DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,); glLineWidth(static_cast(lineWidth)); drawCircle(context, fPos, fNumSegments, fSize, fSin, fCos, true); } #if DGL_ALLOW_DEPRECATED_METHODS template void Circle::draw() { drawCircle(fPos, fNumSegments, fSize, fSin, fCos, false); } template void Circle::drawOutline() { drawCircle(fPos, fNumSegments, fSize, fSin, fCos, true); } #endif // -------------------------------------------------------------------------------------------------------------------- // Triangle template static void drawTriangle(const Point& pos1, const Point& pos2, const Point& pos3, const bool outline) { DISTRHO_SAFE_ASSERT_RETURN(pos1 != pos2 && pos1 != pos3,); glBegin(outline ? GL_LINE_LOOP : GL_TRIANGLES); { glVertex2d(pos1.getX(), pos1.getY()); glVertex2d(pos2.getX(), pos2.getY()); glVertex2d(pos3.getX(), pos3.getY()); } glEnd(); } template static void drawTriangle(const GraphicsContext&, const Point& pos1, const Point& pos2, const Point& pos3, const bool outline) { drawTriangle(pos1, pos2, pos3, outline); } template void Triangle::draw(const GraphicsContext&) { drawTriangle(pos1, pos2, pos3, false); } template void Triangle::drawOutline(const GraphicsContext&, const T lineWidth) { DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,); glLineWidth(static_cast(lineWidth)); drawTriangle(pos1, pos2, pos3, true); } #if DGL_ALLOW_DEPRECATED_METHODS template void Triangle::draw() { drawTriangle(pos1, pos2, pos3, false); } template void Triangle::drawOutline() { drawTriangle(pos1, pos2, pos3, true); } #endif // -------------------------------------------------------------------------------------------------------------------- // Rectangle template static void drawRectangle(const Rectangle& rect, const bool outline) { DISTRHO_SAFE_ASSERT_RETURN(rect.isValid(),); glBegin(outline ? GL_LINE_LOOP : GL_QUADS); { const T x = rect.getX(); const T y = rect.getY(); const T w = rect.getWidth(); const T h = rect.getHeight(); glTexCoord2f(0.0f, 0.0f); glVertex2d(x, y); glTexCoord2f(1.0f, 0.0f); glVertex2d(x+w, y); glTexCoord2f(1.0f, 1.0f); glVertex2d(x+w, y+h); glTexCoord2f(0.0f, 1.0f); glVertex2d(x, y+h); } glEnd(); } template void Rectangle::draw(const GraphicsContext&) { drawRectangle(*this, false); } template void Rectangle::drawOutline(const GraphicsContext&, const T lineWidth) { DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,); glLineWidth(static_cast(lineWidth)); drawRectangle(*this, true); } #if DGL_ALLOW_DEPRECATED_METHODS template void Rectangle::draw() { drawRectangle(*this, false); } template void Rectangle::drawOutline() { drawRectangle(*this, true); } #endif // -------------------------------------------------------------------------------------------------------------------- // OpenGLImage static void setupOpenGLImage(const OpenGLImage& image, GLuint textureId) { DISTRHO_SAFE_ASSERT_RETURN(image.isValid(),); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, textureId); 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_CLAMP_TO_BORDER); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); static const float trans[] = { 0.0f, 0.0f, 0.0f, 0.0f }; glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, trans); glPixelStorei(GL_PACK_ALIGNMENT, 1); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, static_cast(image.getWidth()), static_cast(image.getHeight()), 0, asOpenGLImageFormat(image.getFormat()), GL_UNSIGNED_BYTE, image.getRawData()); glBindTexture(GL_TEXTURE_2D, 0); glDisable(GL_TEXTURE_2D); } static void drawOpenGLImage(const OpenGLImage& image, const Point& pos, const GLuint textureId, bool& setupCalled) { if (textureId == 0 || image.isInvalid()) return; if (! setupCalled) { setupOpenGLImage(image, textureId); setupCalled = true; } glColor4f(1.0f, 1.0f, 1.0f, 1.0f); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, textureId); glBegin(GL_QUADS); { const int x = pos.getX(); const int y = pos.getY(); const int w = static_cast(image.getWidth()); const int h = static_cast(image.getHeight()); glTexCoord2f(0.0f, 0.0f); glVertex2d(x, y); glTexCoord2f(1.0f, 0.0f); glVertex2d(x+w, y); glTexCoord2f(1.0f, 1.0f); glVertex2d(x+w, y+h); glTexCoord2f(0.0f, 1.0f); glVertex2d(x, y+h); } glEnd(); glBindTexture(GL_TEXTURE_2D, 0); glDisable(GL_TEXTURE_2D); } void OpenGLImage::drawAt(const GraphicsContext&, const Point& pos) { drawOpenGLImage(*this, pos, textureId, setupCalled); } #if DGL_ALLOW_DEPRECATED_METHODS void OpenGLImage::draw() { drawOpenGLImage(*this, Point(0, 0), textureId, setupCalled); } void OpenGLImage::drawAt(const int x, const int y) { drawOpenGLImage(*this, Point(x, y), textureId, setupCalled); } void OpenGLImage::drawAt(const Point& pos) { drawOpenGLImage(*this, pos, textureId, setupCalled); } #endif // -------------------------------------------------------------------------------------------------------------------- // ImageBaseAboutWindow #if 0 template <> void ImageBaseAboutWindow::onDisplay() { const GraphicsContext& context(getGraphicsContext()); img.draw(context); } #endif template class ImageBaseAboutWindow; // -------------------------------------------------------------------------------------------------------------------- // ImageBaseButton template class ImageBaseButton; // -------------------------------------------------------------------------------------------------------------------- // ImageBaseKnob template <> void ImageBaseKnob::PrivateData::init() { glTextureId = 0; glGenTextures(1, &glTextureId); } template <> void ImageBaseKnob::PrivateData::cleanup() { if (glTextureId == 0) return; glDeleteTextures(1, &glTextureId); glTextureId = 0; } template <> void ImageBaseKnob::onDisplay() { const GraphicsContext& context(getGraphicsContext()); const float normValue = getNormalizedValue(); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, pData->glTextureId); if (! pData->isReady) { 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_CLAMP_TO_BORDER); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); static const float trans[] = { 0.0f, 0.0f, 0.0f, 0.0f }; glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, trans); glPixelStorei(GL_PACK_ALIGNMENT, 1); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); uint imageDataOffset = 0; if (pData->rotationAngle == 0) { DISTRHO_SAFE_ASSERT_RETURN(pData->imgLayerCount > 0,); DISTRHO_SAFE_ASSERT_RETURN(normValue >= 0.0f,); const uint& v1(pData->isImgVertical ? pData->imgLayerWidth : pData->imgLayerHeight); const uint& v2(pData->isImgVertical ? pData->imgLayerHeight : pData->imgLayerWidth); // TODO kImageFormatGreyscale const uint layerDataSize = v1 * v2 * ((pData->image.getFormat() == kImageFormatBGRA || pData->image.getFormat() == kImageFormatRGBA) ? 4 : 3); /* */ imageDataOffset = layerDataSize * uint(normValue * float(pData->imgLayerCount-1)); } glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, static_cast(getWidth()), static_cast(getHeight()), 0, asOpenGLImageFormat(pData->image.getFormat()), GL_UNSIGNED_BYTE, pData->image.getRawData() + imageDataOffset); pData->isReady = true; } const int w = static_cast(getWidth()); const int h = static_cast(getHeight()); if (pData->rotationAngle != 0) { glPushMatrix(); const int w2 = w/2; const int h2 = h/2; glTranslatef(static_cast(w2), static_cast(h2), 0.0f); glRotatef(normValue*static_cast(pData->rotationAngle), 0.0f, 0.0f, 1.0f); Rectangle(-w2, -h2, w, h).draw(context); glPopMatrix(); } else { Rectangle(0, 0, w, h).draw(context); } glBindTexture(GL_TEXTURE_2D, 0); glDisable(GL_TEXTURE_2D); } template class ImageBaseKnob; // -------------------------------------------------------------------------------------------------------------------- // ImageBaseSlider template class ImageBaseSlider; // -------------------------------------------------------------------------------------------------------------------- // ImageBaseSwitch template class ImageBaseSwitch; // -------------------------------------------------------------------------------------------------------------------- void Window::PrivateData::createContextIfNeeded() { } void Window::PrivateData::destroyContext() { } void Window::PrivateData::startContext() { const PuglArea size = puglGetSizeHint(view, PUGL_CURRENT_SIZE); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glViewport(0, 0, static_cast(size.width), static_cast(size.height)); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0.0, static_cast(size.width), static_cast(size.height), 0.0, 0.0, 1.0); glViewport(0, 0, static_cast(size.width), static_cast(size.height)); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void Window::PrivateData::endContext() { } // -------------------------------------------------------------------------------------------------------------------- #ifndef DGL_GEOMETRY_CPP_INCLUDED template class Line; template class Line; template class Line; template class Line; template class Line; template class Line; template class Circle; template class Circle; template class Circle; template class Circle; template class Circle; template class Circle; template class Triangle; template class Triangle; template class Triangle; template class Triangle; template class Triangle; template class Triangle; template class Rectangle; template class Rectangle; template class Rectangle; template class Rectangle; template class Rectangle; template class Rectangle; #endif // -------------------------------------------------------------------------------------------------------------------- END_NAMESPACE_DGL