pcbjam/wasm/shims/gl_immediate_shim.js
Viktor Vaczi 6c2cf85177 feat(webgl): Fix GL initialization and add GLSL ES shader conversion
Progress on WEBGL_GAL rendering:

- Fix GLImmediateShim initialization by adding GL function dependencies
  (glBegin, glEnd, glVertex2f, etc.) to $GLImmediateShim__deps
- Add COLOR4D(EDA_COLOR_T) constructor stub to wasm_stubs.cpp
- Fix GAL context locking - add LockContext/UnlockContext calls
- Add exception catching to build (-sNO_DISABLE_EXCEPTION_CATCHING)
- Create GLSL ES 1.00 shader converter in generate_shaders.py:
  - Remove #version 120 directive (ES 1.00 default)
  - Add precision highp float/int qualifiers
  - Convert int * float to float literals (2 * x -> 2.0 * x)
- Update build script to clean output files for linker flag changes
- Add console capture to test spec for debugging

Current status:
- WASM builds and loads successfully
- GLImmediateShim initializes correctly
- WEBGL_GAL creates successfully
- Shader compilation fails due to Emscripten LEGACY_GL_EMULATION
  prepending code that conflicts with custom shader precision

Next: Investigate shader compilation with LEGACY_GL_EMULATION or
consider alternative approaches for GL compatibility.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-07 21:59:21 +01:00

178 lines
5.3 KiB
JavaScript

/**
* gl_immediate_shim.js
*
* Custom OpenGL immediate mode shims for KiCad WASM port.
* Fixes Emscripten LEGACY_GL_EMULATION issues:
* 1. Color-per-vertex requirement - injects color before each vertex automatically
* 2. Missing double-precision functions (glVertex2d, glVertex3d, glColor3d, glColor4d)
*
* Usage: emcc ... --js-library=lib/gl_immediate_shim.js
*/
addToLibrary({
// ==================================================================
// GLImmediateShim - State tracking and function wrapping
// ==================================================================
$GLImmediateShim__deps: ['$GLImmediate', 'glBegin', 'glEnd', 'glVertex2f', 'glVertex3f', 'glColor3f', 'glColor4f'],
$GLImmediateShim__postset: 'GLImmediateShim.init();',
$GLImmediateShim: {
// Current color state (persistent across vertices)
currentColor: null,
// Track if we're inside glBegin/glEnd block
inBeginEnd: false,
// Track if color was called since the last vertex
// This prevents double-injection when code already calls color per vertex
colorCalledSinceLastVertex: false,
// Original functions we're wrapping
origFns: {},
// Initialization flag
initialized: false,
init: function() {
if (GLImmediateShim.initialized) return;
if (typeof GLImmediate === 'undefined') {
// GLImmediate not ready yet, will be called again
console.log('[GLImmediateShim] Waiting for GLImmediate...');
return;
}
console.log('[GLImmediateShim] Initializing OpenGL immediate mode shims');
// Initialize current color to white (OpenGL default)
GLImmediateShim.currentColor = new Float32Array([1.0, 1.0, 1.0, 1.0]);
// Store original functions
GLImmediateShim.origFns = {
glBegin: _glBegin,
glEnd: _glEnd,
glVertex2f: _glVertex2f,
glVertex3f: _glVertex3f,
glColor3f: _glColor3f,
glColor4f: _glColor4f,
};
// Install shims
_glBegin = GLImmediateShim.shimBegin;
_glEnd = GLImmediateShim.shimEnd;
_glVertex2f = GLImmediateShim.shimVertex2f;
_glVertex3f = GLImmediateShim.shimVertex3f;
_glColor3f = GLImmediateShim.shimColor3f;
_glColor4f = GLImmediateShim.shimColor4f;
GLImmediateShim.initialized = true;
console.log('[GLImmediateShim] Initialized successfully');
},
// ==================================================================
// Shim implementations
// ==================================================================
shimBegin: function(mode) {
GLImmediateShim.inBeginEnd = true;
GLImmediateShim.colorCalledSinceLastVertex = false;
GLImmediateShim.origFns.glBegin(mode);
},
shimEnd: function() {
GLImmediateShim.inBeginEnd = false;
GLImmediateShim.origFns.glEnd();
},
shimColor3f: function(r, g, b) {
var c = GLImmediateShim.currentColor;
c[0] = r;
c[1] = g;
c[2] = b;
c[3] = 1.0;
if (GLImmediateShim.inBeginEnd) {
// Mark that color was explicitly called for this vertex
GLImmediateShim.colorCalledSinceLastVertex = true;
}
GLImmediateShim.origFns.glColor3f(r, g, b);
},
shimColor4f: function(r, g, b, a) {
var c = GLImmediateShim.currentColor;
c[0] = r;
c[1] = g;
c[2] = b;
c[3] = a;
if (GLImmediateShim.inBeginEnd) {
// Mark that color was explicitly called for this vertex
GLImmediateShim.colorCalledSinceLastVertex = true;
}
GLImmediateShim.origFns.glColor4f(r, g, b, a);
},
// Inject current color before each vertex (only if not already called)
injectColor: function() {
if (!GLImmediateShim.inBeginEnd) return;
// Only inject color if it wasn't already called for this vertex
if (!GLImmediateShim.colorCalledSinceLastVertex) {
var c = GLImmediateShim.currentColor;
GLImmediateShim.origFns.glColor4f(c[0], c[1], c[2], c[3]);
}
// Reset the flag for the next vertex
GLImmediateShim.colorCalledSinceLastVertex = false;
},
shimVertex2f: function(x, y) {
GLImmediateShim.injectColor();
GLImmediateShim.origFns.glVertex2f(x, y);
},
shimVertex3f: function(x, y, z) {
GLImmediateShim.injectColor();
GLImmediateShim.origFns.glVertex3f(x, y, z);
},
},
// ==================================================================
// Double-precision vertex functions (missing in Emscripten)
// ==================================================================
glVertex2d__deps: ['glVertex2f'],
glVertex2d: function(x, y) {
_glVertex2f(x, y);
},
glVertex3d__deps: ['glVertex3f'],
glVertex3d: function(x, y, z) {
_glVertex3f(x, y, z);
},
glVertex4d__deps: ['glVertex4f'],
glVertex4d: function(x, y, z, w) {
_glVertex4f(x, y, z, w);
},
// ==================================================================
// Double-precision color functions
// ==================================================================
glColor3d__deps: ['glColor3f'],
glColor3d: function(r, g, b) {
_glColor3f(r, g, b);
},
glColor4d__deps: ['glColor4f'],
glColor4d: function(r, g, b, a) {
_glColor4f(r, g, b, a);
},
});
// Ensure GLImmediateShim is included in the build
if (typeof extraLibraryFuncs !== 'undefined') {
extraLibraryFuncs.push('$GLImmediateShim');
}