|
| 1 | +// SPDX-License-Identifier: LGPL-3.0-or-later |
| 2 | + |
| 3 | +#include "cputexturemanager.h" |
| 4 | +#include "texture.h" |
| 5 | + |
| 6 | +using namespace scratchcpprender; |
| 7 | + |
| 8 | +CpuTextureManager::CpuTextureManager() |
| 9 | +{ |
| 10 | +} |
| 11 | + |
| 12 | +CpuTextureManager::~CpuTextureManager() |
| 13 | +{ |
| 14 | + for (const auto &[handle, data] : m_textureData) |
| 15 | + delete[] data; |
| 16 | +} |
| 17 | + |
| 18 | +GLubyte *CpuTextureManager::getTextureData(const Texture &texture) |
| 19 | +{ |
| 20 | + if (!texture.isValid()) |
| 21 | + return nullptr; |
| 22 | + |
| 23 | + const GLuint handle = texture.handle(); |
| 24 | + auto it = m_textureData.find(handle); |
| 25 | + |
| 26 | + if (it == m_textureData.cend()) { |
| 27 | + if (addTexture(texture)) |
| 28 | + return m_textureData[handle]; |
| 29 | + else |
| 30 | + return nullptr; |
| 31 | + } else |
| 32 | + return it->second; |
| 33 | +} |
| 34 | + |
| 35 | +const std::vector<QPoint> &CpuTextureManager::getTextureConvexHullPoints(const Texture &texture) |
| 36 | +{ |
| 37 | + static const std::vector<QPoint> empty; |
| 38 | + |
| 39 | + if (!texture.isValid()) |
| 40 | + return empty; |
| 41 | + |
| 42 | + const GLuint handle = texture.handle(); |
| 43 | + auto it = m_convexHullPoints.find(handle); |
| 44 | + |
| 45 | + if (it == m_convexHullPoints.cend()) { |
| 46 | + if (addTexture(texture)) |
| 47 | + return m_convexHullPoints[handle]; |
| 48 | + else |
| 49 | + return empty; |
| 50 | + } else |
| 51 | + return it->second; |
| 52 | +} |
| 53 | + |
| 54 | +bool CpuTextureManager::addTexture(const Texture &texture) |
| 55 | +{ |
| 56 | + if (!texture.isValid()) |
| 57 | + return false; |
| 58 | + |
| 59 | + const GLuint handle = texture.handle(); |
| 60 | + const int width = texture.width(); |
| 61 | + const int height = texture.height(); |
| 62 | + |
| 63 | + QOpenGLFunctions glF; |
| 64 | + glF.initializeOpenGLFunctions(); |
| 65 | + |
| 66 | + // Create a FBO for the texture |
| 67 | + unsigned int fbo; |
| 68 | + glF.glGenFramebuffers(1, &fbo); |
| 69 | + glF.glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| 70 | + glF.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, handle, 0); |
| 71 | + |
| 72 | + if (glF.glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { |
| 73 | + qWarning() << "error: framebuffer incomplete (CpuTextureManager)"; |
| 74 | + glF.glDeleteFramebuffers(1, &fbo); |
| 75 | + return false; |
| 76 | + } |
| 77 | + |
| 78 | + // Read pixels |
| 79 | + GLubyte *pixels = new GLubyte[width * height * 4]; // 4 channels (RGBA) |
| 80 | + glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); |
| 81 | + |
| 82 | + // Flip vertically |
| 83 | + int rowSize = width * 4; |
| 84 | + GLubyte *tempRow = new GLubyte[rowSize]; |
| 85 | + |
| 86 | + for (size_t i = 0; i < height / 2; ++i) { |
| 87 | + size_t topRowIndex = i * rowSize; |
| 88 | + size_t bottomRowIndex = (height - 1 - i) * rowSize; |
| 89 | + |
| 90 | + // Swap rows |
| 91 | + memcpy(tempRow, &pixels[topRowIndex], rowSize); |
| 92 | + memcpy(&pixels[topRowIndex], &pixels[bottomRowIndex], rowSize); |
| 93 | + memcpy(&pixels[bottomRowIndex], tempRow, rowSize); |
| 94 | + } |
| 95 | + |
| 96 | + delete[] tempRow; |
| 97 | + |
| 98 | + m_textureData[handle] = pixels; |
| 99 | + m_convexHullPoints[handle] = {}; |
| 100 | + std::vector<QPoint> &hullPoints = m_convexHullPoints[handle]; |
| 101 | + |
| 102 | + // Get convex hull points |
| 103 | + for (int y = 0; y < height; y++) { |
| 104 | + for (int x = 0; x < width; x++) { |
| 105 | + int index = (y * width + x) * 4; // 4 channels (RGBA) |
| 106 | + |
| 107 | + // Check alpha channel |
| 108 | + if (pixels[index + 3] > 0) |
| 109 | + hullPoints.push_back(QPoint(x, y)); |
| 110 | + } |
| 111 | + } |
| 112 | + |
| 113 | + // Cleanup |
| 114 | + glF.glBindFramebuffer(GL_FRAMEBUFFER, 0); |
| 115 | + glF.glDeleteFramebuffers(1, &fbo); |
| 116 | + |
| 117 | + return true; |
| 118 | +} |
0 commit comments