- Update wasm/Makefile to compile ALL scenario files using wildcard - Add conditional compilation to scenario_bitmap.cpp (#ifdef __EMSCRIPTEN__) to handle OpenGL-specific shader workaround code for native only - Change canvas dimensions to 1600x1200 to match native baseline (2x Retina) - Set white background color to match native screenshots - Update gal-webgl.spec.ts to hide UI overlay before taking screenshots - Improve test-gal-regression.sh with better ImageMagick comparison All 28 scenarios now compile and run on both native and WebGL backends. Native vs baseline: PASSED (28/28 matching) WebGL rendering: In progress (primitives not yet visible) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
268 lines
8.5 KiB
HTML
268 lines
8.5 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en-us">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>GAL WebGL Test</title>
|
|
<style>
|
|
body {
|
|
margin: 0;
|
|
padding: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
overflow: hidden;
|
|
background: #1a1a26;
|
|
color: #fff;
|
|
font-family: monospace;
|
|
}
|
|
|
|
/* wxWidgets window styling */
|
|
.window {
|
|
position: absolute;
|
|
pointer-events: none;
|
|
z-index: 10;
|
|
background-color: black;
|
|
overflow: hidden;
|
|
width: 0;
|
|
height: 0;
|
|
}
|
|
|
|
.window-canvas {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
pointer-events: none;
|
|
}
|
|
|
|
/* GL canvas styling */
|
|
.gl-canvas {
|
|
position: absolute;
|
|
z-index: 100;
|
|
pointer-events: none;
|
|
}
|
|
|
|
/* Controls overlay */
|
|
#controls-overlay {
|
|
position: fixed;
|
|
top: 10px;
|
|
left: 10px;
|
|
z-index: 1000;
|
|
background: rgba(0,0,0,0.8);
|
|
padding: 10px;
|
|
border-radius: 4px;
|
|
}
|
|
|
|
#status {
|
|
margin-top: 10px;
|
|
padding: 5px;
|
|
background: #2a2a3a;
|
|
border-radius: 4px;
|
|
}
|
|
|
|
button, select {
|
|
padding: 5px 10px;
|
|
margin-right: 5px;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<!-- wxWidgets main window container -->
|
|
<div id="main-window"></div>
|
|
|
|
<!-- wxWidgets window container (for popups and GL canvases) -->
|
|
<div id="window-container"></div>
|
|
|
|
<!-- Controls overlay -->
|
|
<div id="controls-overlay">
|
|
<select id="scenario-select">
|
|
<option value="-1">Select scenario...</option>
|
|
</select>
|
|
<button id="run-btn" disabled>Run</button>
|
|
<button id="run-all-btn" disabled>All</button>
|
|
<div id="status">Loading WASM...</div>
|
|
</div>
|
|
|
|
<script>
|
|
// Scenario names (matching native test)
|
|
const SCENARIO_NAMES = [
|
|
'basic-lines', // 0
|
|
'line-widths', // 1
|
|
'circles', // 2
|
|
'arcs', // 3
|
|
'rectangles', // 4
|
|
'polygons', // 5
|
|
'alpha-blending', // 6
|
|
'transforms', // 7
|
|
'grid-cursor', // 8
|
|
'segments', // 9
|
|
'complex-scene', // 10
|
|
'bezier-curves', // 11
|
|
'arc-segments', // 12
|
|
'segment-chain', // 13
|
|
'group-caching', // 14
|
|
'polylines-multi', // 15
|
|
'hole-walls', // 16
|
|
'grid-native', // 17
|
|
'cursor-native', // 18
|
|
'render-targets', // 19
|
|
'screen-transform', // 20
|
|
'clear-colors', // 21
|
|
'depth-testing', // 22
|
|
'negative-mode', // 23
|
|
'text-attrs', // 24
|
|
'glyphs', // 25
|
|
'bitmap', // 26
|
|
'transform-api' // 27
|
|
];
|
|
|
|
var wasmModule = null;
|
|
|
|
// Populate scenario dropdown
|
|
function populateScenarios() {
|
|
const select = document.getElementById('scenario-select');
|
|
SCENARIO_NAMES.forEach((name, index) => {
|
|
const option = document.createElement('option');
|
|
option.value = index;
|
|
option.textContent = `${index}: ${name}`;
|
|
select.appendChild(option);
|
|
});
|
|
}
|
|
|
|
// Run a single scenario
|
|
function runScenario(index) {
|
|
console.log('[DEBUG JS] runScenario called with index:', index, 'wasmModule:', !!wasmModule);
|
|
if (!wasmModule) {
|
|
console.log('[DEBUG JS] wasmModule is null, returning early');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
console.log('[DEBUG JS] Calling ccall...');
|
|
const result = wasmModule.ccall('runScenario', 'number', ['number'], [index]);
|
|
console.log('[DEBUG JS] ccall returned:', result);
|
|
if (result === 0) {
|
|
setStatus(`Rendered: ${SCENARIO_NAMES[index]}`);
|
|
} else {
|
|
setStatus(`ERROR: Failed scenario ${index}`);
|
|
}
|
|
} catch (e) {
|
|
console.error('[DEBUG JS] ccall threw error:', e);
|
|
}
|
|
}
|
|
|
|
// Run all scenarios
|
|
async function runAllScenarios() {
|
|
if (!wasmModule) return;
|
|
|
|
const total = wasmModule.ccall('getTotalScenarios', 'number', [], []);
|
|
setStatus(`Running all ${total} scenarios...`);
|
|
|
|
for (let i = 0; i < total; i++) {
|
|
runScenario(i);
|
|
await new Promise(r => setTimeout(r, 100));
|
|
}
|
|
|
|
setStatus(`Completed all ${total} scenarios`);
|
|
}
|
|
|
|
// Update status
|
|
function setStatus(text) {
|
|
document.getElementById('status').textContent = text;
|
|
console.log('[GAL Test]', text);
|
|
}
|
|
|
|
// Get the GL canvas for screenshots
|
|
function getGLCanvas() {
|
|
// wxGLCanvas creates canvases with class 'gl-canvas' or id 'glcanvas-N'
|
|
const glCanvases = document.querySelectorAll('.gl-canvas');
|
|
if (glCanvases.length > 0) {
|
|
return glCanvases[0];
|
|
}
|
|
// Fallback to any canvas in window-container
|
|
const containerCanvases = document.querySelectorAll('#window-container canvas');
|
|
if (containerCanvases.length > 0) {
|
|
return containerCanvases[0];
|
|
}
|
|
// Fallback to main canvas
|
|
return document.getElementById('canvas');
|
|
}
|
|
|
|
// Export for Playwright
|
|
window.galTest = {
|
|
runScenario,
|
|
runAllScenarios,
|
|
getScenarioName: (index) => SCENARIO_NAMES[index],
|
|
getTotalScenarios: () => SCENARIO_NAMES.length,
|
|
getGLCanvas: getGLCanvas,
|
|
isReady: () => wasmModule !== null
|
|
};
|
|
|
|
// Create canvas immediately (before module loads)
|
|
var canvas = document.createElement('canvas');
|
|
canvas.id = 'canvas';
|
|
canvas.style.display = 'block';
|
|
canvas.style.position = 'absolute';
|
|
canvas.style.left = '0';
|
|
canvas.style.top = '0';
|
|
canvas.width = 1600;
|
|
canvas.height = 1200;
|
|
canvas.style.width = '1600px';
|
|
canvas.style.height = '1200px';
|
|
canvas.oncontextmenu = function(e) { e.preventDefault(); };
|
|
canvas.addEventListener("webglcontextlost", function(e) {
|
|
setStatus('WebGL context lost!');
|
|
e.preventDefault();
|
|
}, false);
|
|
document.getElementById('main-window').appendChild(canvas);
|
|
|
|
// Module configuration for MODULARIZE
|
|
var Module = {
|
|
canvas: canvas, // Pass the canvas we created
|
|
print: function(text) {
|
|
console.log(text);
|
|
},
|
|
printErr: function(text) {
|
|
console.error(text);
|
|
},
|
|
setStatus: function(text) {
|
|
setStatus(text || 'Ready');
|
|
},
|
|
onRuntimeInitialized: function() {
|
|
setStatus('WASM initialized');
|
|
}
|
|
};
|
|
|
|
// Setup UI after module loads
|
|
function onModuleReady(module) {
|
|
wasmModule = module;
|
|
setStatus('Ready. Select a scenario.');
|
|
|
|
document.getElementById('run-btn').disabled = false;
|
|
document.getElementById('run-all-btn').disabled = false;
|
|
|
|
document.getElementById('run-btn').onclick = () => {
|
|
const select = document.getElementById('scenario-select');
|
|
const index = parseInt(select.value);
|
|
if (index >= 0) {
|
|
runScenario(index);
|
|
}
|
|
};
|
|
|
|
document.getElementById('run-all-btn').onclick = runAllScenarios;
|
|
|
|
document.getElementById('scenario-select').onchange = (e) => {
|
|
const index = parseInt(e.target.value);
|
|
if (index >= 0) {
|
|
runScenario(index);
|
|
}
|
|
};
|
|
|
|
// Dispatch ready event for Playwright
|
|
window.dispatchEvent(new CustomEvent('gal-test-ready'));
|
|
}
|
|
|
|
// Initialize
|
|
populateScenarios();
|
|
</script>
|
|
<script src="gal_webgl_test.js" onload="createGALTest(Module).then(onModuleReady).catch(e => setStatus('Load error: ' + e.message))"></script>
|
|
</body>
|
|
</html>
|