feat(3d): gl1 shim M0-M2 — FFP-on-WebGL2 substrate + lighting; 12 scenarios truly green
wasm/gl1: the GL1.x fixed-function emulation layer replacing the
gl_ffp_stub.c no-ops in the 3d-regression harness link. This batch:
- symbol split: 52 FFP-only entry points implemented; 10 Emscripten-owned
names intercepted via wasm-ld --wrap (sources.txt/wrapped_symbols.txt are
the shared manifests for both link sites; production hookup lands in M7)
- matrix stacks (MODELVIEW/PROJECTION, glGetFloatv readback), immediate
mode with all 8 GL1 primitive conversions, GL1-default state mirror
- full GL 1.5 Gouraud lighting uber-shader (eye-space light capture at
glLightfv time, color-material, two-side, COMBINE evaluator + alpha test
wired but inert until M3/M5)
- draw routing: FFP traffic identified by GL_VERTEX_ARRAY client state;
blit/2D-GAL draws pass through untouched
- display lists: correct glGenLists/glIsList existing-empty semantics;
recorder itself is M3 (recorded commands drop with a one-time warning)
Parity: 20/47 under the 0.02 floor, of which 12 verified genuinely
rendering (bg-gradient x2, bounding-box, half-open-cylinder, segment x2,
material x3, light x3 — eyeballed against baselines); the other 8 are
small-geometry scenarios whose missing GLU/display-list content sits under
the floor (become real in M3/M4).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 11:37:51 +02:00
|
|
|
/*
|
|
|
|
|
* gl1_entry_wrapped — interceptors for the Emscripten-owned GL names the
|
|
|
|
|
* emulator must observe. The ONLY mechanism-aware TU: both link sites pass
|
|
|
|
|
* -Wl,--wrap=<sym> for every name in ../wrapped_symbols.txt, so references
|
|
|
|
|
* land on __wrap_* here and __real_* resolves back to the WebGL JS library.
|
|
|
|
|
* (Fallback if --wrap ever breaks: macro-remap in gal/opengl/kiglew.h — only
|
|
|
|
|
* this file would change.)
|
|
|
|
|
*
|
|
|
|
|
* Draw routing: a glDrawArrays/glDrawElements call belongs to the FFP
|
|
|
|
|
* pipeline iff GL_VERTEX_ARRAY client state is enabled — only GL1 code uses
|
|
|
|
|
* glEnableClientState, while the raytracer blit and the 2D WebGL GAL drive
|
|
|
|
|
* their own GLSL programs with glVertexAttribPointer and never touch client
|
|
|
|
|
* state. Their draws pass through untouched.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "gl1_shim.h"
|
|
|
|
|
|
|
|
|
|
#include <glm/gtc/type_ptr.hpp>
|
|
|
|
|
|
|
|
|
|
#include <cstring>
|
|
|
|
|
|
|
|
|
|
using namespace gl1;
|
|
|
|
|
|
|
|
|
|
extern "C"
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
void __wrap_glEnable( GLenum cap )
|
|
|
|
|
{
|
|
|
|
|
if( dlistRecording() )
|
|
|
|
|
{
|
|
|
|
|
dlistRecordEnable( cap, true );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-03 11:48:22 +02:00
|
|
|
stateEnable( cap, true );
|
feat(3d): gl1 shim M0-M2 — FFP-on-WebGL2 substrate + lighting; 12 scenarios truly green
wasm/gl1: the GL1.x fixed-function emulation layer replacing the
gl_ffp_stub.c no-ops in the 3d-regression harness link. This batch:
- symbol split: 52 FFP-only entry points implemented; 10 Emscripten-owned
names intercepted via wasm-ld --wrap (sources.txt/wrapped_symbols.txt are
the shared manifests for both link sites; production hookup lands in M7)
- matrix stacks (MODELVIEW/PROJECTION, glGetFloatv readback), immediate
mode with all 8 GL1 primitive conversions, GL1-default state mirror
- full GL 1.5 Gouraud lighting uber-shader (eye-space light capture at
glLightfv time, color-material, two-side, COMBINE evaluator + alpha test
wired but inert until M3/M5)
- draw routing: FFP traffic identified by GL_VERTEX_ARRAY client state;
blit/2D-GAL draws pass through untouched
- display lists: correct glGenLists/glIsList existing-empty semantics;
recorder itself is M3 (recorded commands drop with a one-time warning)
Parity: 20/47 under the 0.02 floor, of which 12 verified genuinely
rendering (bg-gradient x2, bounding-box, half-open-cylinder, segment x2,
material x3, light x3 — eyeballed against baselines); the other 8 are
small-geometry scenarios whose missing GLU/display-list content sits under
the floor (become real in M3/M4).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 11:37:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void __wrap_glDisable( GLenum cap )
|
|
|
|
|
{
|
|
|
|
|
if( dlistRecording() )
|
|
|
|
|
{
|
|
|
|
|
dlistRecordEnable( cap, false );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-03 11:48:22 +02:00
|
|
|
stateEnable( cap, false );
|
feat(3d): gl1 shim M0-M2 — FFP-on-WebGL2 substrate + lighting; 12 scenarios truly green
wasm/gl1: the GL1.x fixed-function emulation layer replacing the
gl_ffp_stub.c no-ops in the 3d-regression harness link. This batch:
- symbol split: 52 FFP-only entry points implemented; 10 Emscripten-owned
names intercepted via wasm-ld --wrap (sources.txt/wrapped_symbols.txt are
the shared manifests for both link sites; production hookup lands in M7)
- matrix stacks (MODELVIEW/PROJECTION, glGetFloatv readback), immediate
mode with all 8 GL1 primitive conversions, GL1-default state mirror
- full GL 1.5 Gouraud lighting uber-shader (eye-space light capture at
glLightfv time, color-material, two-side, COMBINE evaluator + alpha test
wired but inert until M3/M5)
- draw routing: FFP traffic identified by GL_VERTEX_ARRAY client state;
blit/2D-GAL draws pass through untouched
- display lists: correct glGenLists/glIsList existing-empty semantics;
recorder itself is M3 (recorded commands drop with a one-time warning)
Parity: 20/47 under the 0.02 floor, of which 12 verified genuinely
rendering (bg-gradient x2, bounding-box, half-open-cylinder, segment x2,
material x3, light x3 — eyeballed against baselines); the other 8 are
small-geometry scenarios whose missing GLU/display-list content sits under
the floor (become real in M3/M4).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 11:37:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
GLboolean __wrap_glIsEnabled( GLenum cap )
|
|
|
|
|
{
|
|
|
|
|
// glGet-class queries execute even during display-list recording.
|
|
|
|
|
if( bool* slot = ffpCapSlot( cap ) )
|
|
|
|
|
return *slot ? GL_TRUE : GL_FALSE;
|
|
|
|
|
|
|
|
|
|
return __real_glIsEnabled( cap );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void __wrap_glGetFloatv( GLenum pname, GLfloat* params )
|
|
|
|
|
{
|
|
|
|
|
if( pname == GL_MODELVIEW_MATRIX )
|
|
|
|
|
{
|
|
|
|
|
std::memcpy( params, glm::value_ptr( S().mv.back() ), 16 * sizeof( GLfloat ) );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( pname == GL_PROJECTION_MATRIX )
|
|
|
|
|
{
|
|
|
|
|
std::memcpy( params, glm::value_ptr( S().proj.back() ), 16 * sizeof( GLfloat ) );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
__real_glGetFloatv( pname, params );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void __wrap_glDrawArrays( GLenum mode, GLint first, GLsizei count )
|
|
|
|
|
{
|
|
|
|
|
if( dlistRecording() )
|
|
|
|
|
{
|
|
|
|
|
dlistRecordDrawArrays( mode, first, count );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( !S().clientArrays[CA_VERTEX].enabled )
|
|
|
|
|
{
|
|
|
|
|
// Modern-GL consumer (raytracer blit, 2D GAL, the shim itself never
|
|
|
|
|
// reaches here) — pass through untouched.
|
|
|
|
|
__real_glDrawArrays( mode, first, count );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
drawClientArrays( mode, first, count );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void __wrap_glDrawElements( GLenum mode, GLsizei count, GLenum type, const GLvoid* indices )
|
|
|
|
|
{
|
|
|
|
|
if( dlistRecording() )
|
|
|
|
|
{
|
|
|
|
|
GL1_WARN_ONCE( "glDrawElements inside glNewList is not supported — dropped" );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( !S().clientArrays[CA_VERTEX].enabled )
|
|
|
|
|
{
|
|
|
|
|
__real_glDrawElements( mode, count, type, indices );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
drawClientElements( mode, count, type, indices );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void __wrap_glBindTexture( GLenum target, GLuint texture )
|
|
|
|
|
{
|
|
|
|
|
if( dlistRecording() )
|
|
|
|
|
{
|
|
|
|
|
dlistRecordBindTexture( target, texture );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-03 11:48:22 +02:00
|
|
|
stateBindTexture( target, texture );
|
feat(3d): gl1 shim M0-M2 — FFP-on-WebGL2 substrate + lighting; 12 scenarios truly green
wasm/gl1: the GL1.x fixed-function emulation layer replacing the
gl_ffp_stub.c no-ops in the 3d-regression harness link. This batch:
- symbol split: 52 FFP-only entry points implemented; 10 Emscripten-owned
names intercepted via wasm-ld --wrap (sources.txt/wrapped_symbols.txt are
the shared manifests for both link sites; production hookup lands in M7)
- matrix stacks (MODELVIEW/PROJECTION, glGetFloatv readback), immediate
mode with all 8 GL1 primitive conversions, GL1-default state mirror
- full GL 1.5 Gouraud lighting uber-shader (eye-space light capture at
glLightfv time, color-material, two-side, COMBINE evaluator + alpha test
wired but inert until M3/M5)
- draw routing: FFP traffic identified by GL_VERTEX_ARRAY client state;
blit/2D-GAL draws pass through untouched
- display lists: correct glGenLists/glIsList existing-empty semantics;
recorder itself is M3 (recorded commands drop with a one-time warning)
Parity: 20/47 under the 0.02 floor, of which 12 verified genuinely
rendering (bg-gradient x2, bounding-box, half-open-cylinder, segment x2,
material x3, light x3 — eyeballed against baselines); the other 8 are
small-geometry scenarios whose missing GLU/display-list content sits under
the floor (become real in M3/M4).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 11:37:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void __wrap_glBlendFunc( GLenum sfactor, GLenum dfactor )
|
|
|
|
|
{
|
|
|
|
|
if( dlistRecording() )
|
|
|
|
|
{
|
|
|
|
|
dlistRecordBlendFunc( sfactor, dfactor );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-03 11:48:22 +02:00
|
|
|
stateBlendFunc( sfactor, dfactor );
|
feat(3d): gl1 shim M0-M2 — FFP-on-WebGL2 substrate + lighting; 12 scenarios truly green
wasm/gl1: the GL1.x fixed-function emulation layer replacing the
gl_ffp_stub.c no-ops in the 3d-regression harness link. This batch:
- symbol split: 52 FFP-only entry points implemented; 10 Emscripten-owned
names intercepted via wasm-ld --wrap (sources.txt/wrapped_symbols.txt are
the shared manifests for both link sites; production hookup lands in M7)
- matrix stacks (MODELVIEW/PROJECTION, glGetFloatv readback), immediate
mode with all 8 GL1 primitive conversions, GL1-default state mirror
- full GL 1.5 Gouraud lighting uber-shader (eye-space light capture at
glLightfv time, color-material, two-side, COMBINE evaluator + alpha test
wired but inert until M3/M5)
- draw routing: FFP traffic identified by GL_VERTEX_ARRAY client state;
blit/2D-GAL draws pass through untouched
- display lists: correct glGenLists/glIsList existing-empty semantics;
recorder itself is M3 (recorded commands drop with a one-time warning)
Parity: 20/47 under the 0.02 floor, of which 12 verified genuinely
rendering (bg-gradient x2, bounding-box, half-open-cylinder, segment x2,
material x3, light x3 — eyeballed against baselines); the other 8 are
small-geometry scenarios whose missing GLU/display-list content sits under
the floor (become real in M3/M4).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 11:37:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void __wrap_glLineWidth( GLfloat width )
|
|
|
|
|
{
|
|
|
|
|
if( dlistRecording() )
|
|
|
|
|
{
|
|
|
|
|
dlistRecordLineWidth( width );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-03 11:48:22 +02:00
|
|
|
stateLineWidth( width );
|
feat(3d): gl1 shim M0-M2 — FFP-on-WebGL2 substrate + lighting; 12 scenarios truly green
wasm/gl1: the GL1.x fixed-function emulation layer replacing the
gl_ffp_stub.c no-ops in the 3d-regression harness link. This batch:
- symbol split: 52 FFP-only entry points implemented; 10 Emscripten-owned
names intercepted via wasm-ld --wrap (sources.txt/wrapped_symbols.txt are
the shared manifests for both link sites; production hookup lands in M7)
- matrix stacks (MODELVIEW/PROJECTION, glGetFloatv readback), immediate
mode with all 8 GL1 primitive conversions, GL1-default state mirror
- full GL 1.5 Gouraud lighting uber-shader (eye-space light capture at
glLightfv time, color-material, two-side, COMBINE evaluator + alpha test
wired but inert until M3/M5)
- draw routing: FFP traffic identified by GL_VERTEX_ARRAY client state;
blit/2D-GAL draws pass through untouched
- display lists: correct glGenLists/glIsList existing-empty semantics;
recorder itself is M3 (recorded commands drop with a one-time warning)
Parity: 20/47 under the 0.02 floor, of which 12 verified genuinely
rendering (bg-gradient x2, bounding-box, half-open-cylinder, segment x2,
material x3, light x3 — eyeballed against baselines); the other 8 are
small-geometry scenarios whose missing GLU/display-list content sits under
the floor (become real in M3/M4).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 11:37:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void __wrap_glHint( GLenum target, GLenum mode )
|
|
|
|
|
{
|
|
|
|
|
// Only the two WebGL2-legal hints pass through; the FFP hints
|
|
|
|
|
// (LINE_SMOOTH_HINT, PERSPECTIVE_CORRECTION_HINT...) would raise
|
|
|
|
|
// INVALID_ENUM and are swallowed.
|
|
|
|
|
if( target == GL_GENERATE_MIPMAP_HINT || target == GL_FRAGMENT_SHADER_DERIVATIVE_HINT )
|
|
|
|
|
__real_glHint( target, mode );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // extern "C"
|