- Add comprehensive README documenting all 28 GAL test scenarios - Document known limitation: DrawBitmap uses legacy OpenGL immediate mode (glBegin/glEnd) incompatible with shader-based test harness - Add shader accessor for DrawBitmap workaround attempt - Clean up debug code from bitmap scenario The DrawBitmap limitation is acceptable because: - It's primarily used for reference images in schematics - WebGL port will need its own bitmap rendering implementation - All other 69 GAL methods are fully tested 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
134 lines
4.2 KiB
C++
134 lines
4.2 KiB
C++
/**
|
|
* GAL Test Accessor Implementation
|
|
*
|
|
* Uses a member pointer technique to access private members without
|
|
* the #define private public hack that breaks standard library headers.
|
|
*/
|
|
|
|
#include "gal_test_accessor.h"
|
|
#include "kicad_stubs.h"
|
|
|
|
#include <gal/opengl/opengl_gal.h>
|
|
#include <gal/opengl/opengl_compositor.h>
|
|
#include <gal/opengl/shader.h>
|
|
|
|
// Template-based private member accessor trick
|
|
// See: https://bloglitb.blogspot.com/2010/07/access-to-private-members-thats-easy.html
|
|
|
|
template<typename Tag>
|
|
struct result {
|
|
typedef typename Tag::type type;
|
|
static type ptr;
|
|
};
|
|
|
|
template<typename Tag>
|
|
typename result<Tag>::type result<Tag>::ptr;
|
|
|
|
template<typename Tag, typename Tag::type p>
|
|
struct rob : result<Tag> {
|
|
struct filler {
|
|
filler() { result<Tag>::ptr = p; }
|
|
};
|
|
static filler filler_obj;
|
|
};
|
|
|
|
template<typename Tag, typename Tag::type p>
|
|
typename rob<Tag, p>::filler rob<Tag, p>::filler_obj;
|
|
|
|
// Tags for the private members we need to access
|
|
struct OPENGL_GAL_compositor { typedef KIGFX::OPENGL_COMPOSITOR* KIGFX::OPENGL_GAL::*type; };
|
|
struct OPENGL_GAL_mainBuffer { typedef unsigned int KIGFX::OPENGL_GAL::*type; };
|
|
struct OPENGL_GAL_shader { typedef KIGFX::SHADER* KIGFX::OPENGL_GAL::*type; };
|
|
struct OPENGL_COMPOSITOR_mainFbo { typedef GLuint KIGFX::OPENGL_COMPOSITOR::*type; };
|
|
|
|
// Instantiate the accessors
|
|
template struct rob<OPENGL_GAL_compositor, &KIGFX::OPENGL_GAL::m_compositor>;
|
|
template struct rob<OPENGL_GAL_mainBuffer, &KIGFX::OPENGL_GAL::m_mainBuffer>;
|
|
template struct rob<OPENGL_GAL_shader, &KIGFX::OPENGL_GAL::m_shader>;
|
|
template struct rob<OPENGL_COMPOSITOR_mainFbo, &KIGFX::OPENGL_COMPOSITOR::m_mainFbo>;
|
|
|
|
GLuint GetCompositorMainBufferTexture(KIGFX::OPENGL_GAL* gal) {
|
|
// Get the compositor pointer using the member pointer accessor
|
|
KIGFX::OPENGL_COMPOSITOR* compositor = gal->*result<OPENGL_GAL_compositor>::ptr;
|
|
unsigned int mainBuffer = gal->*result<OPENGL_GAL_mainBuffer>::ptr;
|
|
|
|
if (compositor && mainBuffer > 0) {
|
|
return compositor->GetBufferTexture(mainBuffer);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void GetCompositorBufferSize(KIGFX::OPENGL_GAL* gal, int* width, int* height) {
|
|
KIGFX::OPENGL_COMPOSITOR* compositor = gal->*result<OPENGL_GAL_compositor>::ptr;
|
|
|
|
if (compositor) {
|
|
VECTOR2I size = compositor->GetScreenSize();
|
|
*width = size.x;
|
|
*height = size.y;
|
|
} else {
|
|
*width = 0;
|
|
*height = 0;
|
|
}
|
|
}
|
|
|
|
GLuint GetCompositorMainFBO(KIGFX::OPENGL_GAL* gal) {
|
|
KIGFX::OPENGL_COMPOSITOR* compositor = gal->*result<OPENGL_GAL_compositor>::ptr;
|
|
if (compositor) {
|
|
return compositor->*result<OPENGL_COMPOSITOR_mainFbo>::ptr;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
unsigned int GetMainBufferHandle(KIGFX::OPENGL_GAL* gal) {
|
|
return gal->*result<OPENGL_GAL_mainBuffer>::ptr;
|
|
}
|
|
|
|
bool ReadCompositorFBOPixels(KIGFX::OPENGL_GAL* gal, std::vector<uint8_t>& pixels, int* width, int* height) {
|
|
KIGFX::OPENGL_COMPOSITOR* compositor = gal->*result<OPENGL_GAL_compositor>::ptr;
|
|
unsigned int mainBuffer = gal->*result<OPENGL_GAL_mainBuffer>::ptr;
|
|
|
|
if (!compositor || mainBuffer == 0) {
|
|
return false;
|
|
}
|
|
|
|
GLuint mainFbo = compositor->*result<OPENGL_COMPOSITOR_mainFbo>::ptr;
|
|
|
|
// Get size from compositor
|
|
VECTOR2I size = compositor->GetScreenSize();
|
|
*width = size.x;
|
|
*height = size.y;
|
|
|
|
// Compute attachment point: GL_COLOR_ATTACHMENT0 + (mainBuffer - 1)
|
|
GLenum attachmentPoint = GL_COLOR_ATTACHMENT0_EXT + (mainBuffer - 1);
|
|
|
|
// Bind the FBO for reading
|
|
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mainFbo);
|
|
glReadBuffer(attachmentPoint);
|
|
|
|
// Read pixels
|
|
pixels.resize((*width) * (*height) * 4);
|
|
glReadPixels(0, 0, *width, *height, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
|
|
|
|
// Unbind FBO
|
|
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
|
|
|
return true;
|
|
}
|
|
|
|
KIGFX::SHADER* GetGALShader(KIGFX::OPENGL_GAL* gal) {
|
|
return gal->*result<OPENGL_GAL_shader>::ptr;
|
|
}
|
|
|
|
void DeactivateGALShader(KIGFX::OPENGL_GAL* gal) {
|
|
KIGFX::SHADER* shader = gal->*result<OPENGL_GAL_shader>::ptr;
|
|
if (shader) {
|
|
shader->Deactivate();
|
|
}
|
|
}
|
|
|
|
void ActivateGALShader(KIGFX::OPENGL_GAL* gal) {
|
|
KIGFX::SHADER* shader = gal->*result<OPENGL_GAL_shader>::ptr;
|
|
if (shader) {
|
|
shader->Use();
|
|
}
|
|
}
|