From 898e079ef20dab2656494aa47090503eb17bd80a Mon Sep 17 00:00:00 2001 From: Viktor Vaczi Date: Sun, 21 Dec 2025 14:21:29 +0100 Subject: [PATCH] Enable 3D viewer in KiCad WASM build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Build the 3D viewer code for WASM instead of stubbing it out. This is simpler to maintain than complex header stubs. Changes: - Enable KICAD_BUILD_3D_VIEWER_WASM=ON in build script - Remove -gsource-map to avoid OOM in wasm-emscripten-finalize - Add OpenGL stubs for fixed-function pipeline (WebGL ES 2.0 only) - Add GLU stub for gluErrorString - Add NNG stub for IPC API (sockets don't work in WASM) - Add PCBnew scripting stub - Expand curl and libgit2 stubs The 3D viewer code compiles but won't render at runtime since OpenGL GAL is disabled and Cairo GAL is used instead. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- kicad | 2 +- scripts/kicad/build-pcbnew.sh | 29 +- wasm/stubs/curl_stub.c | 85 +++++ wasm/stubs/gl_canvas_stub.cpp | 509 ++++++++++++++++++++++++++ wasm/stubs/glu_stub.c | 44 +++ wasm/stubs/libgit2_stub.c | 210 +++++++++++ wasm/stubs/nng/nng.h | 47 +++ wasm/stubs/nng/protocol/reqrep0/rep.h | 12 + wasm/stubs/nng_stub.c | 66 ++++ wasm/stubs/pcbnew_scripting_stub.cpp | 20 + 10 files changed, 1017 insertions(+), 7 deletions(-) create mode 100644 wasm/stubs/gl_canvas_stub.cpp create mode 100644 wasm/stubs/glu_stub.c create mode 100644 wasm/stubs/nng/nng.h create mode 100644 wasm/stubs/nng/protocol/reqrep0/rep.h create mode 100644 wasm/stubs/nng_stub.c create mode 100644 wasm/stubs/pcbnew_scripting_stub.cpp diff --git a/kicad b/kicad index e6a59ab..46bb16e 160000 --- a/kicad +++ b/kicad @@ -1 +1 @@ -Subproject commit e6a59ab94a325f5df44bca6f8b7b7aa9d75fbf03 +Subproject commit 46bb16e86bb7085578298bcc72a261f612dd8196 diff --git a/scripts/kicad/build-pcbnew.sh b/scripts/kicad/build-pcbnew.sh index 9dbca15..ba3c3fa 100755 --- a/scripts/kicad/build-pcbnew.sh +++ b/scripts/kicad/build-pcbnew.sh @@ -128,8 +128,10 @@ if [ "${DEBUG_BUILD:-0}" = "1" ] || [ $DEBUG -eq 1 ]; then BUILD_TYPE="Debug" EXTRA_FLAGS="-g -O1 -fexceptions -matomics -mbulk-memory" # -O0 at link time skips wasm-opt (which can OOM on large WASM with debug symbols) - LINKER_DEBUG_FLAGS="-O0 -g -gsource-map -fexceptions" - log_info "Building KiCad in DEBUG mode (with source maps, -O1 for WASM compatibility)" + # NOTE: -gsource-map removed because wasm-emscripten-finalize OOMs on large WASM + # with source maps enabled. Keep -g for debug symbols in the WASM. + LINKER_DEBUG_FLAGS="-O0 -g -fexceptions" + log_info "Building KiCad in DEBUG mode (debug symbols, no source maps due to memory)" else BUILD_TYPE="Release" EXTRA_FLAGS="-O2 -fexceptions -matomics -mbulk-memory" @@ -157,6 +159,19 @@ emar rcs "${STUBS_BUILD}/libgit2_stub.a" "${STUBS_BUILD}/libgit2_stub.o" emcc -c "${STUBS_DIR}/curl_stub.c" -o "${STUBS_BUILD}/curl_stub.o" emar rcs "${STUBS_BUILD}/libcurl_stub.a" "${STUBS_BUILD}/curl_stub.o" +# Compile GLU stub (for 3D viewer) +emcc -c "${STUBS_DIR}/glu_stub.c" -o "${STUBS_BUILD}/glu_stub.o" +emar rcs "${STUBS_BUILD}/libglu_stub.a" "${STUBS_BUILD}/glu_stub.o" + +# Compile PCBnew scripting stub (requires wxWidgets headers) +WX_CXXFLAGS=$("${WX_BUILD}/wx-config" --cxxflags 2>/dev/null || echo "-I${WX_BUILD}/lib/wx/include/emscripten-unicode-static-3.2 -I${PROJECT_ROOT}/wxwidgets/include") +em++ -c ${WX_CXXFLAGS} "${STUBS_DIR}/pcbnew_scripting_stub.cpp" -o "${STUBS_BUILD}/pcbnew_scripting_stub.o" +emar rcs "${STUBS_BUILD}/libpcbnew_scripting_stub.a" "${STUBS_BUILD}/pcbnew_scripting_stub.o" + +# Compile NNG stub (IPC API requires NNG but sockets don't work in WASM) +emcc -c -I"${STUBS_DIR}" "${STUBS_DIR}/nng_stub.c" -o "${STUBS_BUILD}/nng_stub.o" +emar rcs "${STUBS_BUILD}/libnng_stub.a" "${STUBS_BUILD}/nng_stub.o" + log_info "Stub libraries built" # Step 6.2: Replace Emscripten's wasm-opt with stub to bypass asyncify transformation @@ -197,9 +212,9 @@ emcmake cmake "${KICAD_DIR}" \ -DCMAKE_MODULE_PATH="${WASM_LAYER}/cmake" \ -DSYSROOT="${SYSROOT}" \ -DCMAKE_POLICY_VERSION_MINIMUM=3.5 \ - -DCMAKE_CXX_FLAGS="${EXTRA_FLAGS} -pthread -sUSE_ZLIB=1 -DKICAD_USE_PLATFORM_WASM=1 -I${SYSROOT}/include" \ - -DCMAKE_C_FLAGS="${EXTRA_FLAGS} -pthread -sUSE_ZLIB=1 -I${SYSROOT}/include" \ - -DCMAKE_EXE_LINKER_FLAGS="${LINKER_DEBUG_FLAGS} -pthread -sUSE_ZLIB=1 -sASYNCIFY=1 -sASYNCIFY_STACK_SIZE=65536 -sUSE_PTHREADS=1 -sPTHREAD_POOL_SIZE='navigator.hardwareConcurrency' -sPTHREAD_POOL_SIZE_STRICT=0 -sALLOW_MEMORY_GROWTH=1 -sINITIAL_MEMORY=256MB -sMAXIMUM_MEMORY=4GB -sEXPORTED_RUNTIME_METHODS=['ccall','cwrap','UTF8ToString','stringToUTF8','lengthBytesUTF8'] -L${SYSROOT}/lib ${STUBS_BUILD}/libgit2_stub.a ${STUBS_BUILD}/libcurl_stub.a" \ + -DCMAKE_CXX_FLAGS="${EXTRA_FLAGS} -pthread -sUSE_ZLIB=1 -DKICAD_USE_PLATFORM_WASM=1 -I${SYSROOT}/include -I${STUBS_DIR}" \ + -DCMAKE_C_FLAGS="${EXTRA_FLAGS} -pthread -sUSE_ZLIB=1 -I${SYSROOT}/include -I${STUBS_DIR}" \ + -DCMAKE_EXE_LINKER_FLAGS="${LINKER_DEBUG_FLAGS} -pthread -sUSE_ZLIB=1 -sASYNCIFY=1 -sASYNCIFY_STACK_SIZE=65536 -sUSE_PTHREADS=1 -sPTHREAD_POOL_SIZE='navigator.hardwareConcurrency' -sPTHREAD_POOL_SIZE_STRICT=0 -sALLOW_MEMORY_GROWTH=1 -sINITIAL_MEMORY=256MB -sMAXIMUM_MEMORY=4GB -sEXPORTED_RUNTIME_METHODS=['ccall','cwrap','UTF8ToString','stringToUTF8','lengthBytesUTF8'] -L${SYSROOT}/lib ${STUBS_BUILD}/libgit2_stub.a ${STUBS_BUILD}/libcurl_stub.a ${STUBS_BUILD}/libglu_stub.a ${STUBS_BUILD}/libpcbnew_scripting_stub.a ${STUBS_BUILD}/libnng_stub.a" \ -DCMAKE_PREFIX_PATH="${SYSROOT};${WX_BUILD}" \ -DwxWidgets_CONFIG_EXECUTABLE="${WX_BUILD}/wx-config" \ \ @@ -207,6 +222,8 @@ emcmake cmake "${KICAD_DIR}" \ -DKICAD_SPICE=OFF \ -DKICAD_USE_EGL=OFF \ -DKICAD_USE_BUNDLED_GLEW=ON \ + -DKICAD_BUILD_3D_VIEWER_WASM=ON \ + -DKICAD_IPC_API=ON \ \ -DZSTD_ROOT="${SYSROOT}" \ -DZSTD_INCLUDE_DIR="${SYSROOT}/include" \ @@ -227,6 +244,7 @@ emcmake cmake "${KICAD_DIR}" \ -DProtobuf_INCLUDE_DIR="${SYSROOT}/include" \ -DProtobuf_LIBRARY="${SYSROOT}/lib/libprotobuf.a" \ -DProtobuf_LITE_LIBRARY="${SYSROOT}/lib/libprotobuf-lite.a" \ + -DProtobuf_PROTOC_EXECUTABLE="${SYSROOT}/bin/protoc" \ -DODBC_CONFIG:STRING="stub-for-wasm" \ -DODBCLIB:STRING="" \ -DODBC_CFLAGS:STRING="" \ @@ -238,7 +256,6 @@ emcmake cmake "${KICAD_DIR}" \ # Step 8: Build pcbnew target log_info "Building pcbnew..." -# JOBS is set in env.sh (default: 1 for sequential builds, use -j N to override) emmake make -j${JOBS} pcbnew # Step 9: Create stamp file diff --git a/wasm/stubs/curl_stub.c b/wasm/stubs/curl_stub.c index dee1af8..2118afe 100644 --- a/wasm/stubs/curl_stub.c +++ b/wasm/stubs/curl_stub.c @@ -2,8 +2,68 @@ * Network operations need to go through JavaScript fetch API */ +#include +#include + +typedef void CURL; +typedef void CURLM; typedef int CURLcode; +typedef int CURLoption; +typedef int CURLINFO; + #define CURLE_OK 0 +#define CURLE_UNSUPPORTED_PROTOCOL 1 + +/* Version info */ +const char* curl_version(void) { + return "stub-wasm/0.0 (no network in browser)"; +} + +/* Easy interface */ +CURL* curl_easy_init(void) { + return NULL; /* No curl in WASM */ +} + +void curl_easy_cleanup(CURL *curl) { + (void)curl; +} + +CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...) { + (void)curl; + (void)option; + return CURLE_OK; +} + +CURLcode curl_easy_perform(CURL *curl) { + (void)curl; + return CURLE_UNSUPPORTED_PROTOCOL; +} + +CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...) { + (void)curl; + (void)info; + return CURLE_OK; +} + +const char* curl_easy_strerror(CURLcode code) { + (void)code; + return "Network operations not available in browser"; +} + +void curl_easy_reset(CURL *curl) { + (void)curl; +} + +char* curl_easy_escape(CURL *curl, const char *string, int length) { + (void)curl; + (void)string; + (void)length; + return NULL; +} + +void curl_free(void *p) { + (void)p; +} CURLcode curl_global_init(long flags) { (void)flags; @@ -13,3 +73,28 @@ CURLcode curl_global_init(long flags) { void curl_global_cleanup(void) { /* Nothing to clean up */ } + +/* Multi interface (for async) */ +CURLM* curl_multi_init(void) { + return NULL; +} + +void curl_multi_cleanup(CURLM *multi) { + (void)multi; +} + +/* Slist */ +struct curl_slist { + char *data; + struct curl_slist *next; +}; + +struct curl_slist* curl_slist_append(struct curl_slist *list, const char *string) { + (void)list; + (void)string; + return NULL; +} + +void curl_slist_free_all(struct curl_slist *list) { + (void)list; +} diff --git a/wasm/stubs/gl_canvas_stub.cpp b/wasm/stubs/gl_canvas_stub.cpp new file mode 100644 index 0000000..14e54b5 --- /dev/null +++ b/wasm/stubs/gl_canvas_stub.cpp @@ -0,0 +1,509 @@ +/* + * OpenGL Canvas stubs for KiCad WASM build + * OpenGL GAL is not available in WASM (uses Cairo only). + * This stub provides typeinfo and methods for dynamic_cast to work. + */ + +#include +#include +#include <3d_rendering/raytracing/render_3d_raytrace_gl.h> + +//============================================================================= +// Fixed-function OpenGL stubs for WebGL compatibility +// WebGL only supports OpenGL ES 2.0/3.0 which doesn't have these functions +//============================================================================= + +extern "C" { + +void glLoadMatrixf( const float* m ) +{ + (void)m; + // Fixed-function pipeline not available in WebGL +} + +void glPushMatrix() +{ + // Fixed-function pipeline not available in WebGL +} + +void glPopMatrix() +{ + // Fixed-function pipeline not available in WebGL +} + +void glColor4f( float r, float g, float b, float a ) +{ + (void)r; (void)g; (void)b; (void)a; + // Fixed-function pipeline not available in WebGL +} + +void glTranslatef( float x, float y, float z ) +{ + (void)x; (void)y; (void)z; + // Fixed-function pipeline not available in WebGL +} + +void glScalef( float x, float y, float z ) +{ + (void)x; (void)y; (void)z; + // Fixed-function pipeline not available in WebGL +} + +void glRotatef( float angle, float x, float y, float z ) +{ + (void)angle; (void)x; (void)y; (void)z; + // Fixed-function pipeline not available in WebGL +} + +void glEnableClientState( unsigned int cap ) +{ + (void)cap; + // Fixed-function pipeline not available in WebGL +} + +void glDisableClientState( unsigned int cap ) +{ + (void)cap; + // Fixed-function pipeline not available in WebGL +} + +void glPointSize( float size ) +{ + (void)size; + // Fixed-function pipeline not available in WebGL +} + +void glVertex3f( float x, float y, float z ) +{ + (void)x; (void)y; (void)z; + // Immediate mode not available in WebGL +} + +void glBegin( unsigned int mode ) +{ + (void)mode; + // Immediate mode not available in WebGL +} + +void glEnd() +{ + // Immediate mode not available in WebGL +} + +void glColorMaterial( unsigned int face, unsigned int mode ) +{ + (void)face; (void)mode; + // Fixed-function pipeline not available in WebGL +} + +void glNormalPointer( unsigned int type, int stride, const void* pointer ) +{ + (void)type; (void)stride; (void)pointer; + // Fixed-function pipeline not available in WebGL +} + +void glColorPointer( int size, unsigned int type, int stride, const void* pointer ) +{ + (void)size; (void)type; (void)stride; (void)pointer; + // Fixed-function pipeline not available in WebGL +} + +void glTexCoordPointer( int size, unsigned int type, int stride, const void* pointer ) +{ + (void)size; (void)type; (void)stride; (void)pointer; + // Fixed-function pipeline not available in WebGL +} + +void glVertexPointer( int size, unsigned int type, int stride, const void* pointer ) +{ + (void)size; (void)type; (void)stride; (void)pointer; + // Fixed-function pipeline not available in WebGL +} + +void glMaterialfv( unsigned int face, unsigned int pname, const float* params ) +{ + (void)face; (void)pname; (void)params; + // Fixed-function pipeline not available in WebGL +} + +void glMaterialf( unsigned int face, unsigned int pname, float param ) +{ + (void)face; (void)pname; (void)param; + // Fixed-function pipeline not available in WebGL +} + +void glLightfv( unsigned int light, unsigned int pname, const float* params ) +{ + (void)light; (void)pname; (void)params; + // Fixed-function pipeline not available in WebGL +} + +void glLightModelfv( unsigned int pname, const float* params ) +{ + (void)pname; (void)params; + // Fixed-function pipeline not available in WebGL +} + +void glNormal3f( float nx, float ny, float nz ) +{ + (void)nx; (void)ny; (void)nz; + // Fixed-function pipeline not available in WebGL +} + +void glTexCoord2f( float s, float t ) +{ + (void)s; (void)t; + // Fixed-function pipeline not available in WebGL +} + +void glMatrixMode( unsigned int mode ) +{ + (void)mode; + // Fixed-function pipeline not available in WebGL +} + +void glLoadIdentity() +{ + // Fixed-function pipeline not available in WebGL +} + +void glOrtho( double left, double right, double bottom, double top, double nearVal, double farVal ) +{ + (void)left; (void)right; (void)bottom; (void)top; (void)nearVal; (void)farVal; + // Fixed-function pipeline not available in WebGL +} + +void glFrustum( double left, double right, double bottom, double top, double nearVal, double farVal ) +{ + (void)left; (void)right; (void)bottom; (void)top; (void)nearVal; (void)farVal; + // Fixed-function pipeline not available in WebGL +} + +void glMultMatrixf( const float* m ) +{ + (void)m; + // Fixed-function pipeline not available in WebGL +} + +void glShadeModel( unsigned int mode ) +{ + (void)mode; + // Fixed-function pipeline not available in WebGL +} + +void glTexEnvfv( unsigned int target, unsigned int pname, const float* params ) +{ + (void)target; (void)pname; (void)params; + // Fixed-function pipeline not available in WebGL +} + +void glTexEnvf( unsigned int target, unsigned int pname, float param ) +{ + (void)target; (void)pname; (void)param; + // Fixed-function pipeline not available in WebGL +} + +void glTexEnvi( unsigned int target, unsigned int pname, int param ) +{ + (void)target; (void)pname; (void)param; + // Fixed-function pipeline not available in WebGL +} + +void glLightModeli( unsigned int pname, int param ) +{ + (void)pname; (void)param; + // Fixed-function pipeline not available in WebGL +} + +// Display lists - not available in WebGL +unsigned char glIsList( unsigned int list ) +{ + (void)list; + return 0; // Always return false - no display lists in WebGL +} + +void glDeleteLists( unsigned int list, int range ) +{ + (void)list; (void)range; + // Display lists not available in WebGL +} + +unsigned int glGenLists( int range ) +{ + (void)range; + return 0; // Return 0 to indicate failure - no display lists in WebGL +} + +void glNewList( unsigned int list, unsigned int mode ) +{ + (void)list; (void)mode; + // Display lists not available in WebGL +} + +void glEndList() +{ + // Display lists not available in WebGL +} + +void glCallList( unsigned int list ) +{ + (void)list; + // Display lists not available in WebGL +} + +void glCallLists( int n, unsigned int type, const void* lists ) +{ + (void)n; (void)type; (void)lists; + // Display lists not available in WebGL +} + +// More fixed-function pipeline functions +void glColor3f( float r, float g, float b ) +{ + (void)r; (void)g; (void)b; + // Fixed-function pipeline not available in WebGL +} + +void glColor3fv( const float* v ) +{ + (void)v; + // Fixed-function pipeline not available in WebGL +} + +void glColor4fv( const float* v ) +{ + (void)v; + // Fixed-function pipeline not available in WebGL +} + +void glVertex2f( float x, float y ) +{ + (void)x; (void)y; + // Immediate mode not available in WebGL +} + +void glVertex3fv( const float* v ) +{ + (void)v; + // Immediate mode not available in WebGL +} + +void glNormal3fv( const float* v ) +{ + (void)v; + // Fixed-function pipeline not available in WebGL +} + +void glRectf( float x1, float y1, float x2, float y2 ) +{ + (void)x1; (void)y1; (void)x2; (void)y2; + // Immediate mode not available in WebGL +} + +void glLineWidth( float width ) +{ + (void)width; + // Note: WebGL has limited line width support +} + +void glAlphaFunc( unsigned int func, float ref ) +{ + (void)func; (void)ref; + // Fixed-function pipeline not available in WebGL +} + +void glClientActiveTexture( unsigned int texture ) +{ + (void)texture; + // Fixed-function pipeline not available in WebGL +} + +void glScaled( double x, double y, double z ) +{ + (void)x; (void)y; (void)z; + // Fixed-function pipeline not available in WebGL +} + +void glPolygonMode( unsigned int face, unsigned int mode ) +{ + (void)face; (void)mode; + // Not available in WebGL ES +} + +void glClipPlane( unsigned int plane, const double* equation ) +{ + (void)plane; (void)equation; + // Fixed-function pipeline not available in WebGL +} + +void glFogf( unsigned int pname, float param ) +{ + (void)pname; (void)param; + // Fixed-function pipeline not available in WebGL +} + +void glFogfv( unsigned int pname, const float* params ) +{ + (void)pname; (void)params; + // Fixed-function pipeline not available in WebGL +} + +void glFogi( unsigned int pname, int param ) +{ + (void)pname; (void)param; + // Fixed-function pipeline not available in WebGL +} + +} // extern "C" + +//============================================================================= +// HIDPI_GL_CANVAS stub implementation +//============================================================================= + +HIDPI_GL_CANVAS::HIDPI_GL_CANVAS( const KIGFX::VC_SETTINGS& aSettings, wxWindow* aParent, + const wxGLAttributes& aGLAttribs, wxWindowID aId, + const wxPoint& aPos, const wxSize& aSize, long aStyle, + const wxString& aName, const wxPalette& aPalette ) : + wxGLCanvas( aParent, aGLAttribs, aId, aPos, aSize, aStyle, aName, aPalette ), + m_settings( aSettings ) +{ + // Not used in WASM - OpenGL is disabled +} + +wxSize HIDPI_GL_CANVAS::GetNativePixelSize() const +{ + return wxSize( 0, 0 ); +} + +wxPoint HIDPI_GL_CANVAS::GetNativePosition( const wxPoint& aPoint ) const +{ + return aPoint; +} + +double HIDPI_GL_CANVAS::GetScaleFactor() const +{ + return 1.0; // No HiDPI scaling in WASM stub +} + +//============================================================================= +// HIDPI_GL_3D_CANVAS stub implementation +//============================================================================= + +const float HIDPI_GL_3D_CANVAS::m_delta_move_step_factor = 0.7f; + +HIDPI_GL_3D_CANVAS::HIDPI_GL_3D_CANVAS( const KIGFX::VC_SETTINGS& aVcSettings, CAMERA& aCamera, + wxWindow* aParent, const wxGLAttributes& aGLAttribs, + wxWindowID aId, const wxPoint& aPos, const wxSize& aSize, + long aStyle, const wxString& aName, + const wxPalette& aPalette ) : + HIDPI_GL_CANVAS( aVcSettings, aParent, aGLAttribs, aId, aPos, aSize, aStyle, aName, aPalette ), + m_camera( aCamera ) +{ + m_mouse_is_moving = false; + m_mouse_was_moved = false; + m_camera_is_moving = false; + // Not used in WASM - 3D viewer uses RAM raytracer +} + +void HIDPI_GL_3D_CANVAS::OnMouseMoveCamera( wxMouseEvent& event ) +{ + (void)event; + // Not used in WASM +} + +void HIDPI_GL_3D_CANVAS::OnMouseWheelCamera( wxMouseEvent& event, bool aPan ) +{ + (void)event; + (void)aPan; + // Not used in WASM +} + +//============================================================================= +// RENDER_3D_RAYTRACE_GL stub implementation +//============================================================================= + +RENDER_3D_RAYTRACE_GL::RENDER_3D_RAYTRACE_GL( EDA_3D_CANVAS* aCanvas, BOARD_ADAPTER& aAdapter, + CAMERA& aCamera ) : + RENDER_3D_RAYTRACE_BASE( aAdapter, aCamera ) +{ + (void)aCanvas; + m_openglSupportsVertexBufferObjects = false; + m_pboId = 0; + m_pboDataSize = 0; + // Not used in WASM - uses RAM raytracer instead +} + +RENDER_3D_RAYTRACE_GL::~RENDER_3D_RAYTRACE_GL() +{ +} + +void RENDER_3D_RAYTRACE_GL::SetCurWindowSize( const wxSize& aSize ) +{ + (void)aSize; + // Not used in WASM +} + +bool RENDER_3D_RAYTRACE_GL::Redraw( bool aIsMoving, REPORTER* aStatusReporter, + REPORTER* aWarningReporter ) +{ + (void)aIsMoving; + (void)aStatusReporter; + (void)aWarningReporter; + return false; // Not used in WASM +} + +void RENDER_3D_RAYTRACE_GL::initPbo() +{ + // Not used in WASM +} + +void RENDER_3D_RAYTRACE_GL::deletePbo() +{ + // Not used in WASM +} + +//============================================================================= +// NavLib/3DConnexion SpaceMouse plugin stubs +// These are for 3D mouse support which is not available in WASM +//============================================================================= + +// Define empty implementation classes to satisfy unique_ptr +class NL_3D_VIEWER_PLUGIN_IMPL {}; +class NL_FOOTPRINT_PROPERTIES_PLUGIN_IMPL {}; + +#include <3d_navlib/nl_3d_viewer_plugin.h> +#include <3d_navlib/nl_footprint_properties_plugin.h> + +NL_3D_VIEWER_PLUGIN::NL_3D_VIEWER_PLUGIN( EDA_3D_CANVAS* aViewport ) : + m_impl( nullptr ) +{ + (void)aViewport; + // SpaceMouse not available in WASM +} + +NL_3D_VIEWER_PLUGIN::~NL_3D_VIEWER_PLUGIN() +{ +} + +void NL_3D_VIEWER_PLUGIN::SetFocus( bool aFocus ) +{ + (void)aFocus; + // SpaceMouse not available in WASM +} + +NL_FOOTPRINT_PROPERTIES_PLUGIN::NL_FOOTPRINT_PROPERTIES_PLUGIN( EDA_3D_CANVAS* aViewport ) : + m_impl( nullptr ) +{ + (void)aViewport; + // SpaceMouse not available in WASM +} + +NL_FOOTPRINT_PROPERTIES_PLUGIN::~NL_FOOTPRINT_PROPERTIES_PLUGIN() +{ +} + +void NL_FOOTPRINT_PROPERTIES_PLUGIN::SetFocus( bool aFocus ) +{ + (void)aFocus; + // SpaceMouse not available in WASM +} diff --git a/wasm/stubs/glu_stub.c b/wasm/stubs/glu_stub.c new file mode 100644 index 0000000..82e0e60 --- /dev/null +++ b/wasm/stubs/glu_stub.c @@ -0,0 +1,44 @@ +/* GLU stubs for WebAssembly builds + * GLU is not available in WebGL, these stubs prevent link errors. + * The gizmo won't render but the 3D view should work with LEGACY_GL_EMULATION. + */ + +typedef struct GLUquadric GLUquadric; +typedef struct GLUtesselator GLUtesselator; +typedef double GLdouble; +typedef void (*_GLUfuncptr)(void); + +/* Quadric stubs */ +GLUquadric* gluNewQuadric(void) { return (GLUquadric*)0; } +void gluDeleteQuadric(GLUquadric* q) { (void)q; } +void gluQuadricDrawStyle(GLUquadric* q, int s) { (void)q; (void)s; } +void gluQuadricNormals(GLUquadric* q, int n) { (void)q; (void)n; } +void gluCylinder(GLUquadric* q, double b, double t, double h, int sl, int st) { + (void)q; (void)b; (void)t; (void)h; (void)sl; (void)st; +} +void gluDisk(GLUquadric* q, double i, double o, int sl, int lp) { + (void)q; (void)i; (void)o; (void)sl; (void)lp; +} +void gluSphere(GLUquadric* q, double r, int sl, int st) { + (void)q; (void)r; (void)sl; (void)st; +} +void gluPerspective(double fovy, double aspect, double zNear, double zFar) { + (void)fovy; (void)aspect; (void)zNear; (void)zFar; +} + +/* Tessellation stubs */ +GLUtesselator* gluNewTess(void) { return (GLUtesselator*)0; } +void gluDeleteTess(GLUtesselator* t) { (void)t; } +void gluTessBeginPolygon(GLUtesselator* t, void* d) { (void)t; (void)d; } +void gluTessEndPolygon(GLUtesselator* t) { (void)t; } +void gluTessBeginContour(GLUtesselator* t) { (void)t; } +void gluTessEndContour(GLUtesselator* t) { (void)t; } +void gluTessVertex(GLUtesselator* t, GLdouble* l, void* d) { (void)t; (void)l; (void)d; } +void gluTessNormal(GLUtesselator* t, GLdouble x, GLdouble y, GLdouble z) { (void)t; (void)x; (void)y; (void)z; } +void gluTessCallback(GLUtesselator* t, unsigned int w, _GLUfuncptr f) { (void)t; (void)w; (void)f; } +void gluTessProperty(GLUtesselator* t, unsigned int w, GLdouble v) { (void)t; (void)w; (void)v; } +void gluGetTessProperty(GLUtesselator* t, unsigned int w, GLdouble* d) { (void)t; (void)w; (void)d; } + +/* Error string stub */ +static const unsigned char glu_error_str[] = "GLU stub error"; +const unsigned char* gluErrorString(unsigned int e) { (void)e; return glu_error_str; } diff --git a/wasm/stubs/libgit2_stub.c b/wasm/stubs/libgit2_stub.c index fb39c55..2688808 100644 --- a/wasm/stubs/libgit2_stub.c +++ b/wasm/stubs/libgit2_stub.c @@ -62,3 +62,213 @@ int git_oid_cmp(const void *a, const void *b) { (void)b; return 0; } + +/* Index operations */ +int git_repository_index(void **out, void *repo) { + (void)repo; + *out = NULL; + return -1; +} + +int git_index_add_bypath(void *index, const char *path) { + (void)index; + (void)path; + return -1; +} + +int git_index_write(void *index) { + (void)index; + return -1; +} + +int git_index_write_tree(void *out, void *index) { + (void)out; + (void)index; + return -1; +} + +void git_index_free(void *index) { + (void)index; +} + +/* Reference name to ID */ +int git_reference_name_to_id(void *out, void *repo, const char *name) { + (void)out; + (void)repo; + (void)name; + return -1; +} + +/* Commit operations */ +int git_commit_lookup(void **out, void *repo, const void *id) { + (void)repo; + (void)id; + *out = NULL; + return -1; +} + +int git_commit_tree(void **out, const void *commit) { + (void)commit; + *out = NULL; + return -1; +} + +int git_commit_create(void *id, void *repo, const char *update_ref, + const void *author, const void *committer, + const char *encoding, const char *message, + const void *tree, size_t parent_count, const void **parents) { + (void)id; (void)repo; (void)update_ref; + (void)author; (void)committer; + (void)encoding; (void)message; + (void)tree; (void)parent_count; (void)parents; + return -1; +} + +void git_commit_free(void *commit) { + (void)commit; +} + +/* Tree operations */ +int git_tree_lookup(void **out, void *repo, const void *id) { + (void)repo; + (void)id; + *out = NULL; + return -1; +} + +void git_tree_free(void *tree) { + (void)tree; +} + +/* Diff operations */ +int git_diff_tree_to_tree(void **diff, void *repo, void *old_tree, void *new_tree, const void *opts) { + (void)repo; + (void)old_tree; + (void)new_tree; + (void)opts; + *diff = NULL; + return -1; +} + +size_t git_diff_num_deltas(const void *diff) { + (void)diff; + return 0; +} + +void git_diff_free(void *diff) { + (void)diff; +} + +/* Signature operations */ +int git_signature_now(void **out, const char *name, const char *email) { + (void)name; + (void)email; + *out = NULL; + return -1; +} + +void git_signature_free(void *sig) { + (void)sig; +} + +/* Additional functions needed by local_history.cpp */ + +char* git_oid_tostr_s(const void *oid) { + (void)oid; + return ""; /* Return empty string - static buffer not needed for stub */ +} + +int git_diff_tree_to_index(void **diff, void *repo, void *old_tree, void *index, const void *opts) { + (void)repo; + (void)old_tree; + (void)index; + (void)opts; + *diff = NULL; + return -1; +} + +const void* git_diff_get_delta(const void *diff, size_t idx) { + (void)diff; + (void)idx; + return NULL; +} + +int git_patch_from_diff(void **out, void *diff, size_t idx) { + (void)diff; + (void)idx; + *out = NULL; + return -1; +} + +int git_patch_line_stats(size_t *total_context, size_t *total_additions, size_t *total_deletions, const void *patch) { + (void)patch; + if (total_context) *total_context = 0; + if (total_additions) *total_additions = 0; + if (total_deletions) *total_deletions = 0; + return 0; +} + +void git_patch_free(void *patch) { + (void)patch; +} + +int git_repository_init(void **out, const char *path, unsigned int is_bare) { + (void)path; + (void)is_bare; + *out = NULL; + return -1; +} + +int git_reference_lookup(void **out, void *repo, const char *name) { + (void)repo; + (void)name; + *out = NULL; + return -1; +} + +int git_object_lookup(void **out, void *repo, const void *id, int type) { + (void)repo; + (void)id; + (void)type; + *out = NULL; + return -1; +} + +int git_tag_create_lightweight(void *oid, void *repo, const char *tag_name, const void *target, int force) { + (void)oid; + (void)repo; + (void)tag_name; + (void)target; + (void)force; + return -1; +} + +void git_object_free(void *object) { + (void)object; +} + +int git_reference_delete(void *ref) { + (void)ref; + return -1; +} + +/* Git config operations */ +int git_config_open_default(void **out) { + *out = NULL; + return -1; +} + +int git_config_get_entry(void **out, const void *cfg, const char *name) { + (void)cfg; + (void)name; + *out = NULL; + return -1; +} + +void git_config_entry_free(void *entry) { + (void)entry; +} + +void git_config_free(void *cfg) { + (void)cfg; +} diff --git a/wasm/stubs/nng/nng.h b/wasm/stubs/nng/nng.h new file mode 100644 index 0000000..21b1b33 --- /dev/null +++ b/wasm/stubs/nng/nng.h @@ -0,0 +1,47 @@ +/* + * NNG stub header for KiCad WASM build + * Socket-based IPC is not supported in browsers, so we provide stub implementations + * that compile but don't do anything. + */ + +#ifndef NNG_NNG_H +#define NNG_NNG_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// Error codes +#define NNG_ETIMEDOUT 5 +#define NNG_ECLOSED 6 +#define NNG_ENOENT 7 + +// Options +#define NNG_OPT_RECVTIMEO "recv-timeout" + +// Flags +#define NNG_FLAG_ALLOC 1 + +// Opaque types +typedef struct nng_socket_s { int id; } nng_socket; +typedef struct nng_listener_s { int id; } nng_listener; +typedef int nng_duration; + +// NNG function stubs - all return error codes indicating "not supported" +int nng_rep0_open(nng_socket *s); +int nng_listener_create(nng_listener *l, nng_socket s, const char *url); +int nng_socket_set_ms(nng_socket s, const char *opt, nng_duration dur); +int nng_listener_start(nng_listener l, int flags); +int nng_recv(nng_socket s, void *data, size_t *sizep, int flags); +int nng_send(nng_socket s, void *data, size_t size, int flags); +int nng_close(nng_socket s); +void nng_free(void *ptr, size_t size); + +#ifdef __cplusplus +} +#endif + +#endif // NNG_NNG_H diff --git a/wasm/stubs/nng/protocol/reqrep0/rep.h b/wasm/stubs/nng/protocol/reqrep0/rep.h new file mode 100644 index 0000000..0df73b4 --- /dev/null +++ b/wasm/stubs/nng/protocol/reqrep0/rep.h @@ -0,0 +1,12 @@ +/* + * NNG REP protocol stub header for KiCad WASM build + */ + +#ifndef NNG_PROTOCOL_REQREP0_REP_H +#define NNG_PROTOCOL_REQREP0_REP_H + +#include "../../nng.h" + +// nng_rep0_open is already declared in nng.h + +#endif // NNG_PROTOCOL_REQREP0_REP_H diff --git a/wasm/stubs/nng_stub.c b/wasm/stubs/nng_stub.c new file mode 100644 index 0000000..ffc4c7e --- /dev/null +++ b/wasm/stubs/nng_stub.c @@ -0,0 +1,66 @@ +/* + * NNG stub implementation for KiCad WASM build + * Socket-based IPC is not supported in browsers. + * These stubs allow the code to compile but return errors indicating unsupported. + */ + +#include "nng/nng.h" + +// All NNG operations fail in WASM since sockets aren't available +// Using NNG_ENOENT as a generic "not available" error + +int nng_rep0_open(nng_socket *s) { + if (s) { + s->id = -1; + } + return NNG_ENOENT; +} + +int nng_listener_create(nng_listener *l, nng_socket s, const char *url) { + (void)s; + (void)url; + if (l) { + l->id = -1; + } + return NNG_ENOENT; +} + +int nng_socket_set_ms(nng_socket s, const char *opt, nng_duration dur) { + (void)s; + (void)opt; + (void)dur; + return NNG_ENOENT; +} + +int nng_listener_start(nng_listener l, int flags) { + (void)l; + (void)flags; + return NNG_ENOENT; +} + +int nng_recv(nng_socket s, void *data, size_t *sizep, int flags) { + (void)s; + (void)data; + (void)sizep; + (void)flags; + return NNG_ENOENT; +} + +int nng_send(nng_socket s, void *data, size_t size, int flags) { + (void)s; + (void)data; + (void)size; + (void)flags; + return NNG_ENOENT; +} + +int nng_close(nng_socket s) { + (void)s; + return 0; // Close always succeeds +} + +void nng_free(void *ptr, size_t size) { + (void)ptr; + (void)size; + // Nothing to free in stub +} diff --git a/wasm/stubs/pcbnew_scripting_stub.cpp b/wasm/stubs/pcbnew_scripting_stub.cpp new file mode 100644 index 0000000..e8c9437 --- /dev/null +++ b/wasm/stubs/pcbnew_scripting_stub.cpp @@ -0,0 +1,20 @@ +/* PCBnew scripting stubs for WebAssembly builds + * Python scripting is disabled in WASM, these stubs prevent link errors. + */ + +#include + +void pcbnewGetScriptsSearchPaths( wxString& aNames ) +{ + aNames = wxT("(Scripting disabled in WASM build)"); +} + +void pcbnewGetUnloadableScriptNames( wxString& aNames ) +{ + aNames = wxEmptyString; +} + +void pcbnewGetWizardsBackTrace( wxString& aTrace ) +{ + aTrace = wxEmptyString; +}