pcbjam/wasm/gl1
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Istvan Matejcsok 27992f4f18 feat(3d): gl1 shim M4+M6+M7 — GLU quadrics, production link, stub retired; 47/47 parity
- gl1_glu: gluCylinder/gluDisk/gluSphere per the SGI GLU reference
  tessellation (sin/cos phase, strip emission order, pole fans — Apple's
  GLU derives from the same source, so vertices match the goldens);
  emission goes through the public glBegin/glVertex entry points so
  quadrics record into display lists
- glLineWidth>1 one-time warning (browsers clamp to 1; affected coverage
  stays under the parity floor — zero floors.json overrides needed)
- production link site: build-kicad-target.sh now compiles wasm/gl1 from
  sources.txt and applies wrapped_symbols.txt --wrap flags (same manifests
  as the test harness); kicad_editor's RENDER_3D_OPENGL links against the
  real emulation layer instead of no-ops
- wasm/stubs/gl_ffp_stub.c deleted (role fully superseded; history in git)
- docs: 3d-regression README port-status section (floor-blind small
  geometry + line-width caveats), harness comments de-red-stated

Parity: 47/47 under the 0.02 floor, zero overrides. Native golden path
byte-identical to bb0e238 (whose gate ran green) — scenarios/, native/,
baseline/, manifest, floors, spec all untouched by the port.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 15:45:58 +02:00
..
include feat(3d): gl1 shim M3+M5 — display-list recorder, client arrays, VBO routing; 44/47 under parity floor 2026-07-03 15:45:58 +02:00
src feat(3d): gl1 shim M4+M6+M7 — GLU quadrics, production link, stub retired; 47/47 parity 2026-07-03 15:45:58 +02:00
README.md feat(3d): gl1 shim M0-M2 — FFP-on-WebGL2 substrate + lighting; 12 scenarios truly green 2026-07-03 15:45:58 +02:00
sources.txt feat(3d): gl1 shim M0-M2 — FFP-on-WebGL2 substrate + lighting; 12 scenarios truly green 2026-07-03 15:45:58 +02:00
wrapped_symbols.txt feat(3d): gl1 shim M0-M2 — FFP-on-WebGL2 substrate + lighting; 12 scenarios truly green 2026-07-03 15:45:58 +02:00

wasm/gl1 — GL 1.x fixed-function pipeline on WebGL2

Emulation layer that lets KiCad's 3D viewer renderer (RENDER_3D_OPENGL, pure GL 1.x fixed-function, compiled unmodified) render in the browser. Supersedes the no-op link stubs of wasm/stubs/gl_ffp_stub.c (git history has the old file): same public surface, real implementations.

TDD harness: tests/3d-regression/ — 47 native-golden scenarios; parity via npm run 3d:check:parity (see that README).

How the symbols resolve

In the WASM build, gl* are plain C functions split between two providers:

  • Emscripten's WebGL library (-sMAX_WEBGL_VERSION=2) owns every modern/WebGL2 name (glClear, glDrawArrays, glTexImage2D, buffers, shaders, stencil...).
  • This shim owns the FFP-only names WebGL2 lacks (glBegin, display lists, matrix stack, glLight*/glMaterial*, client-array pointers, glTexEnv*, glAlphaFunc, GLU quadrics) — see src/gl1_entry_ffp.cpp.

The emulator must also observe a few Emscripten-owned calls (FFP glEnable caps, draws over client arrays, matrix readback, state recorded inside display lists). Those are intercepted with wasm-ld --wrap: every name in wrapped_symbols.txt gets a -Wl,--wrap=<sym> flag at both link sites, the interceptors live in src/gl1_entry_wrapped.cpp, and __real_* forwards to the WebGL library. No kicad/wxwidgets sources are touched.

Link sites (both read sources.txt + wrapped_symbols.txt):

  • tests/3d-regression/wasm/Makefile (the TDD harness)
  • scripts/kicad/build-kicad-target.sh (GL3D_LINK_FLAGS, production kicad_editor)

Draw routing

A glDrawArrays/glDrawElements call is FFP traffic iff GL_VERTEX_ARRAY client state is enabled: only GL1 code calls glEnableClientState, while the raytracer blit (eda_3d_canvas_wasm.cpp) and the 2D WebGL GAL drive their own GLSL programs and never touch client state — their draws pass through untouched.

Invariants that are easy to break (learned from the native goldens)

  • Display lists snapshot client arrays at record time. The renderer sets gl*Pointer, records glDrawArrays inside glNewList, then delete[]s the arrays right after glEndList (layer_triangles.cpp) — a recorder that stores pointers reads freed memory. Copy eagerly at record.
  • Lights live in eye space, captured at glLightfv time. init_lights() runs under an identity modelview → the directional lights are anchored to the camera. Re-deriving light directions at draw time breaks every lit scenario.
  • Do not "fix" mismatched normal counts. generate_middle_triangles rejecting countersink walls (normals ≠ vertices) is upstream KiCad behavior the goldens document; tolerating it would diverge from native.
  • Lighting is per-vertex (Gouraud) to match fixed-function output; per-fragment lighting visibly mismatches speculars on coarse meshes.

Layout

sources.txt / wrapped_symbols.txt   single source of truth for both link sites
include/gl1_shim.h                  internal API + the state mirror
src/gl1_entry_ffp.cpp               the 52 FFP-only public entry points
src/gl1_entry_wrapped.cpp           __wrap_* interceptors (mechanism-aware TU)
src/gl1_state.cpp                   state singleton, capability routing
src/gl1_matrix.cpp                  MODELVIEW/PROJECTION stacks (+readback)
src/gl1_immediate.cpp               glBegin/glEnd + primitive conversion
src/gl1_dlist.cpp                   display-list recorder/replayer
src/gl1_draw.cpp                    draw execution (stream VBO, attrib setup)
src/gl1_shaders.cpp                 the FFP uber-program (ES 3.00) + uniforms
src/gl1_glu.cpp                     GLU quadrics (SGI tessellation) + gluPerspective