pcbjam/wasm/gl1/src/gl1_entry_wrapped.cpp
Istvan Matejcsok 3fe4f6fb00 feat(3d): gl1 shim M3+M5 — display-list recorder, client arrays, VBO routing; 44/47 under parity floor
- display lists: literal command replay through the shim state machine
  (state leaks + between-list material changes get GL semantics for free);
  recorded glDrawArrays EAGERLY snapshots enabled client-memory arrays at
  compile time (the renderer frees them right after glEndList) and records
  buffer+offset for VBO-backed pointers
- client-array draws: shared AttribSource path packs client-memory arrays
  into one scratch-VBO upload and binds user VBOs with original offsets
  (GL_BYTE normals / GL_UNSIGNED_BYTE colors normalized per GL1)
- glDrawElements over user VBO/IBO passes indices through untouched
  (ELEMENT_ARRAY_BUFFER never touched by the shim)
- state mutators (enable/bindTexture/blendFunc/lineWidth/alphaFunc) shared
  between the __wrap interceptors and list replay

Parity: 44/47 under the 0.02 floor (was 20). Verified visually: mini-board
Tier-3 composite (mask translucency + stencil-punched TH holes), stencil
hole subtraction, alpha-tested seg-end discs, COMBINE const-alpha model
transparency, and post-machining reproducing the upstream countersink bug
(walls absent, matching the native golden). Remaining 3: camera-* trio
needing the M4 GLU quadrics (+5 small-geometry false-greens they share).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 15:45:58 +02:00

162 lines
3.7 KiB
C++

/*
* 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;
}
stateEnable( cap, true );
}
void __wrap_glDisable( GLenum cap )
{
if( dlistRecording() )
{
dlistRecordEnable( cap, false );
return;
}
stateEnable( cap, false );
}
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;
}
stateBindTexture( target, texture );
}
void __wrap_glBlendFunc( GLenum sfactor, GLenum dfactor )
{
if( dlistRecording() )
{
dlistRecordBlendFunc( sfactor, dfactor );
return;
}
stateBlendFunc( sfactor, dfactor );
}
void __wrap_glLineWidth( GLfloat width )
{
if( dlistRecording() )
{
dlistRecordLineWidth( width );
return;
}
stateLineWidth( width );
}
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"