- Add wasm_stubs.cpp with WASM-specific stub implementations for COLOR4D::BLACK/WHITE, GLU tesselator, PGM_BASE, and other KiCad dependencies - Update Makefile to include KiCad sources (GAL base class, display options, HiDPI canvas) and test scenarios - Fix kiglew.h to define GLEW guard (__glew_h__) preventing conflicts with Emscripten's GLEW header - Update test HTML to create canvas before module load (MODULARIZE requires passing canvas in Module config, not preRun) - Update Playwright tests to find canvas elements correctly - Add #window-container for wxWidgets GL canvas support Build produces 8.4MB WASM with full WEBGL_GAL implementation. Tests pass but rendering still shows dark output (debugging in progress). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
342 lines
9 KiB
C++
342 lines
9 KiB
C++
/**
|
|
* WASM stubs for GAL WebGL test
|
|
*
|
|
* Provides implementations for symbols needed by WEBGL_GAL but not
|
|
* provided by the minimal test harness.
|
|
*/
|
|
|
|
// Include kiglew.h first to prevent GLEW conflicts
|
|
#include "webgl/kiglew.h"
|
|
|
|
#include <wx/wx.h>
|
|
#include <wx/snglinst.h>
|
|
|
|
// Forward declarations to avoid including heavy headers
|
|
namespace KIGFX { class GAL; }
|
|
|
|
// Include minimal headers
|
|
#include <gal/color4d.h>
|
|
#include <kiid.h>
|
|
#include <gal/hidpi_gl_canvas.h>
|
|
#include <gal/graphics_abstraction_layer.h>
|
|
|
|
//=============================================================================
|
|
// COLOR4D static constants
|
|
//=============================================================================
|
|
|
|
namespace KIGFX {
|
|
|
|
const COLOR4D COLOR4D::BLACK( 0, 0, 0, 1 );
|
|
const COLOR4D COLOR4D::WHITE( 1, 1, 1, 1 );
|
|
const COLOR4D COLOR4D::UNSPECIFIED( 0, 0, 0, 0 );
|
|
const COLOR4D COLOR4D::CLEAR( 0, 0, 0, 0 );
|
|
|
|
} // namespace KIGFX
|
|
|
|
//=============================================================================
|
|
// KIID
|
|
//=============================================================================
|
|
|
|
KIID niluuid;
|
|
|
|
// Note: GAL class is provided by graphics_abstraction_layer.cpp
|
|
|
|
//=============================================================================
|
|
// GLU tesselator stubs (needed for polygon rendering)
|
|
// These are no-op stubs - polygons won't render correctly until
|
|
// we add a real tesselator implementation
|
|
//=============================================================================
|
|
|
|
extern "C" {
|
|
|
|
struct GLUtesselator {};
|
|
|
|
GLUtesselator* gluNewTess() { return new GLUtesselator(); }
|
|
void gluDeleteTess(GLUtesselator* tess) { delete tess; }
|
|
void gluTessProperty(GLUtesselator*, GLenum, GLdouble) {}
|
|
void gluTessCallback(GLUtesselator*, GLenum, void(*)()) {}
|
|
void gluTessBeginPolygon(GLUtesselator*, void*) {}
|
|
void gluTessEndPolygon(GLUtesselator*) {}
|
|
void gluTessBeginContour(GLUtesselator*) {}
|
|
void gluTessEndContour(GLUtesselator*) {}
|
|
void gluTessVertex(GLUtesselator*, GLdouble*, void*) {}
|
|
|
|
}
|
|
|
|
//=============================================================================
|
|
// Additional stubs from kicad_stubs.cpp that are needed
|
|
//=============================================================================
|
|
|
|
#include <core/observable.h>
|
|
|
|
namespace UTIL {
|
|
namespace DETAIL {
|
|
|
|
OBSERVABLE_BASE::OBSERVABLE_BASE() {}
|
|
OBSERVABLE_BASE::~OBSERVABLE_BASE() {}
|
|
void OBSERVABLE_BASE::on_observers_empty() {}
|
|
void OBSERVABLE_BASE::enter_iteration() {}
|
|
void OBSERVABLE_BASE::leave_iteration() {}
|
|
void OBSERVABLE_BASE::add_observer(void*) {}
|
|
void OBSERVABLE_BASE::remove_observer(void*) {}
|
|
|
|
} // namespace DETAIL
|
|
} // namespace UTIL
|
|
|
|
// UTIL::LINK stubs
|
|
namespace UTIL {
|
|
LINK::LINK() : token_(nullptr), observer_(nullptr) {}
|
|
LINK::LINK(std::shared_ptr<DETAIL::OBSERVABLE_BASE::IMPL> token, void* observer)
|
|
: token_(token), observer_(observer) {}
|
|
LINK::LINK(LINK&& other) : token_(std::move(other.token_)), observer_(other.observer_) {
|
|
other.observer_ = nullptr;
|
|
}
|
|
LINK::~LINK() {}
|
|
LINK& LINK::operator=(LINK&& other) {
|
|
token_ = std::move(other.token_);
|
|
observer_ = other.observer_;
|
|
other.observer_ = nullptr;
|
|
return *this;
|
|
}
|
|
void LINK::reset() { token_.reset(); observer_ = nullptr; }
|
|
LINK::operator bool() const { return token_ != nullptr; }
|
|
}
|
|
|
|
// UI dialog stubs
|
|
void DisplayError(wxWindow*, const wxString&) {}
|
|
void DisplayErrorMessage(wxWindow*, const wxString&, const wxString&) {}
|
|
|
|
// OpenGL info stub
|
|
void SetOpenGLInfo(const char*, const char*, const char*) {}
|
|
|
|
// Math logging stub
|
|
void kimathLogOverflow(double, const char*) {}
|
|
|
|
// Arc geometry stub
|
|
#include <geometry/eda_angle.h>
|
|
int GetArcToSegmentCount(int aRadius, int aArcError, const EDA_ANGLE& aArcAngle) {
|
|
double degrees = std::abs(aArcAngle.AsDegrees());
|
|
return std::max(1, (int)(degrees / 10.0));
|
|
}
|
|
|
|
// DPI scaling stub
|
|
#include <dpi_scaling.h>
|
|
double DPI_SCALING::GetDefaultScaleFactor() { return 1.0; }
|
|
|
|
// Cursor store stub
|
|
#include <gal/cursors.h>
|
|
const WX_CURSOR_TYPE CURSOR_STORE::GetCursor(KICURSOR aCursor, bool aHiDPI) {
|
|
return wxCursor(wxCURSOR_ARROW);
|
|
}
|
|
|
|
// VC_SETTINGS::Reset stub
|
|
#include <view/view_controls.h>
|
|
namespace KIGFX {
|
|
void VC_SETTINGS::Reset() {}
|
|
}
|
|
|
|
// KIID constructors
|
|
KIID::KIID() {}
|
|
KIID::KIID(int aValue) {}
|
|
|
|
// UTF8 stubs
|
|
#include <core/utf8.h>
|
|
UTF8::UTF8(const wxString& s) : m_s(s.ToUTF8().data()) {}
|
|
int UTF8::uni_forward(const unsigned char* aSequence, unsigned* aResult) {
|
|
if (aSequence && *aSequence) {
|
|
if (aResult) *aResult = (unsigned)*aSequence;
|
|
return 1;
|
|
}
|
|
if (aResult) *aResult = 0;
|
|
return 0;
|
|
}
|
|
|
|
// TEXT_ATTRIBUTES constructor
|
|
#include <font/text_attributes.h>
|
|
TEXT_ATTRIBUTES::TEXT_ATTRIBUTES(KIFONT::FONT* aFont) {}
|
|
|
|
// KIFONT stubs
|
|
#include <font/font.h>
|
|
|
|
namespace KIFONT {
|
|
|
|
FONT* FONT::GetFont(const wxString&, bool, bool, const std::vector<wxString>*, bool) {
|
|
return nullptr;
|
|
}
|
|
|
|
const METRICS& METRICS::Default() {
|
|
static METRICS m;
|
|
return m;
|
|
}
|
|
|
|
void OUTLINE_GLYPH::Triangulate(std::function<void(const VECTOR2I&, const VECTOR2I&, const VECTOR2I&)>) const {}
|
|
|
|
void FONT::Draw(KIGFX::GAL*, const wxString&, const VECTOR2I&, const VECTOR2I&,
|
|
const TEXT_ATTRIBUTES&, const METRICS&) const {}
|
|
|
|
// STROKE_GLYPH stubs
|
|
STROKE_GLYPH::STROKE_GLYPH( const STROKE_GLYPH& aGlyph )
|
|
{
|
|
reserve( aGlyph.size() );
|
|
for( const std::vector<VECTOR2D>& pointList : aGlyph )
|
|
push_back( pointList );
|
|
m_boundingBox = aGlyph.m_boundingBox;
|
|
m_penIsDown = false;
|
|
}
|
|
|
|
void STROKE_GLYPH::AddPoint( const VECTOR2D& aPoint )
|
|
{
|
|
if( !m_penIsDown )
|
|
{
|
|
emplace_back();
|
|
back().reserve( 16 );
|
|
m_penIsDown = true;
|
|
}
|
|
back().push_back( aPoint );
|
|
}
|
|
|
|
void STROKE_GLYPH::RaisePen()
|
|
{
|
|
m_penIsDown = false;
|
|
}
|
|
|
|
void STROKE_GLYPH::Finalize()
|
|
{
|
|
}
|
|
|
|
} // namespace KIFONT
|
|
|
|
// SHAPE_POLY_SET stub
|
|
#include <geometry/shape_poly_set.h>
|
|
bool SHAPE_POLY_SET::IsTriangulationUpToDate() const {
|
|
return false;
|
|
}
|
|
|
|
// Bezier curve stub
|
|
#include <bezier_curves.h>
|
|
void BEZIER_POLY::GetPoly(std::vector<VECTOR2D>& aOutput, double aMinSegLen) {
|
|
if (!m_ctrlPts.empty()) {
|
|
aOutput.push_back(m_ctrlPts.front());
|
|
aOutput.push_back(m_ctrlPts.back());
|
|
}
|
|
}
|
|
|
|
// BITMAP_BASE stubs
|
|
#include <bitmap_base.h>
|
|
|
|
BITMAP_BASE::BITMAP_BASE( const VECTOR2I& pos )
|
|
{
|
|
m_scale = 1.0;
|
|
m_imageType = wxBITMAP_TYPE_PNG;
|
|
m_bitmap = nullptr;
|
|
m_image = nullptr;
|
|
m_originalImage = nullptr;
|
|
m_ppi = 91;
|
|
m_pixelSizeIu = 254000.0 / m_ppi;
|
|
m_isMirroredX = false;
|
|
m_isMirroredY = false;
|
|
m_rotation = ANGLE_0;
|
|
}
|
|
|
|
bool BITMAP_BASE::SetImage( const wxImage& aImage )
|
|
{
|
|
delete m_image;
|
|
delete m_originalImage;
|
|
delete m_bitmap;
|
|
|
|
m_image = new wxImage( aImage );
|
|
m_originalImage = new wxImage( aImage );
|
|
m_bitmap = new wxBitmap( *m_image );
|
|
m_imageType = wxBITMAP_TYPE_PNG;
|
|
return true;
|
|
}
|
|
|
|
//=============================================================================
|
|
// PGM_BASE and related stubs (minimal for GL_CONTEXT_MANAGER)
|
|
//=============================================================================
|
|
|
|
// Forward-declared types
|
|
class SETTINGS_MANAGER {};
|
|
class LIBRARY_MANAGER {};
|
|
class BACKGROUND_JOBS_MONITOR {};
|
|
class NOTIFICATIONS_MANAGER {};
|
|
|
|
#include <pgm_base.h>
|
|
#include <advanced_config.h>
|
|
#include <settings/environment.h>
|
|
|
|
// Minimal PGM_BASE subclass
|
|
class PGM_BASE_TEST : public PGM_BASE {
|
|
public:
|
|
PGM_BASE_TEST() : PGM_BASE() {}
|
|
void MacOpenFile(const wxString& aFileName) override {}
|
|
};
|
|
|
|
static PGM_BASE_TEST* s_pgmInstance = nullptr;
|
|
|
|
PGM_BASE& Pgm() {
|
|
if (!s_pgmInstance) {
|
|
s_pgmInstance = new PGM_BASE_TEST();
|
|
}
|
|
return *s_pgmInstance;
|
|
}
|
|
|
|
const ADVANCED_CFG& ADVANCED_CFG::GetCfg() {
|
|
static ADVANCED_CFG instance;
|
|
return instance;
|
|
}
|
|
|
|
ADVANCED_CFG::ADVANCED_CFG() {
|
|
m_ScreenDPI = 91;
|
|
}
|
|
|
|
const char* GetBuildVersion() {
|
|
return "8.0.0-wasm-test";
|
|
}
|
|
|
|
wxApp& PGM_BASE::App() {
|
|
return *wxTheApp;
|
|
}
|
|
|
|
COMMON_SETTINGS* PGM_BASE::GetCommonSettings() const {
|
|
return nullptr;
|
|
}
|
|
|
|
const wxString& PGM_BASE::GetExecutablePath() const {
|
|
static wxString empty;
|
|
return empty;
|
|
}
|
|
|
|
ENV_VAR_MAP& PGM_BASE::GetLocalEnvVariables() const {
|
|
static ENV_VAR_MAP empty;
|
|
return empty;
|
|
}
|
|
|
|
bool PGM_BASE::SetLanguage(wxString&, bool) { return false; }
|
|
const wxString& PGM_BASE::GetTextEditor(bool) { static wxString s; return s; }
|
|
void PGM_BASE::SetTextEditor(const wxString&) {}
|
|
wxString PGM_BASE::GetLanguageTag() { return wxString(); }
|
|
void PGM_BASE::SetLanguagePath() {}
|
|
void PGM_BASE::ReadPdfBrowserInfos() {}
|
|
bool PGM_BASE::SetLocalEnvVariable(const wxString&, const wxString&) { return false; }
|
|
void PGM_BASE::SetLocalEnvVariables() {}
|
|
void PGM_BASE::WritePdfBrowserInfos() {}
|
|
void PGM_BASE::SetLanguageIdentifier(int) {}
|
|
const wxString PGM_BASE::AskUserForPreferredEditor(const wxString&) { return wxString(); }
|
|
|
|
PGM_BASE::PGM_BASE() {
|
|
m_singleton.Init();
|
|
}
|
|
PGM_BASE::~PGM_BASE() {}
|
|
|
|
// Singleton init
|
|
#include <singleton.h>
|
|
#include "webgl/gl_context_mgr.h"
|
|
|
|
void KICAD_SINGLETON::Init() {
|
|
m_GLContextManager = new GL_CONTEXT_MANAGER();
|
|
}
|
|
KICAD_SINGLETON::~KICAD_SINGLETON() {
|
|
delete m_GLContextManager;
|
|
m_GLContextManager = nullptr;
|
|
}
|