///|
extern "js" fn webgpu_pop_clip_rect() -> Unit =
#| () => {
#| const rt = globalThis.__selene_webgpu_runtime;
#| if (rt) {
#| rt.popClip2d();
#| }
#| }
///|
extern "js" fn webgpu_reset_clip_stack() -> Unit =
#| () => {
#| const rt = globalThis.__selene_webgpu_runtime;
#| if (rt) {
#| rt.resetClip2d();
#| }
#| }
///|
extern "js" fn webgpu_push_color_vertices_2d(
vertices : Array[Double],
pipeline_code : Int,
) -> Unit =
#| (vertices, pipelineCode) => {
#| const rt = globalThis.__selene_webgpu_runtime;
#| if (rt) {
#| rt.pushColor2d(new Float32Array(vertices), pipelineCode);
#| }
#| }
///|
extern "js" fn webgpu_push_cached_color_vertices_2d(
cache_id : Int,
vertices : Array[Double],
pipeline_code : Int,
) -> Unit =
#| (cacheId, vertices, pipelineCode) => {
#| const rt = globalThis.__selene_webgpu_runtime;
#| if (!rt) return;
#| const cache = rt.colorVertexCache2d ??= new Map();
#| let packed = cache.get(cacheId);
#| if (packed) {
#| if (rt.currentFrameStats2d) rt.currentFrameStats2d.colorVertexCacheHits += 1;
#| } else {
#| packed = new Float32Array(vertices);
#| cache.set(cacheId, packed);
#| if (rt.currentFrameStats2d) rt.currentFrameStats2d.colorVertexCacheMisses += 1;
#| }
#| rt.pushColor2d(packed, pipelineCode);
#| }
///|
extern "js" fn webgpu_release_cached_color_vertices_2d(cache_id : Int) -> Unit =
#| (cacheId) => {
#| const rt = globalThis.__selene_webgpu_runtime;
#| rt?.colorVertexCache2d?.delete(cacheId);
#| }
///|
extern "js" fn webgpu_image_dimensions(path : String) -> Array[Double] =
#| (path) => {
#| const rt = globalThis.__selene_webgpu_runtime;
#| if (!rt) return [0, 0, 0];
#| const rec = rt.ensureImage(path);
#| if (!rec || rec.state !== 'ready') return [0, 0, 0];
#| return [1, rec.width, rec.height];
#| }
///|
extern "js" fn webgpu_push_texture_vertices_2d(
path : String,
sampler_code : Int,
filter_code : Int,
vertices : Array[Double],
pipeline_code : Int,
) -> Unit =
#| (path, samplerCode, filterCode, vertices, pipelineCode) => {
#| const rt = globalThis.__selene_webgpu_runtime;
#| if (!rt) return;
#| const rec = rt.ensureImage(path);
#| if (!rec || rec.state !== 'ready') return;
#| rt.pushTex2d(samplerCode, filterCode, rec, new Float32Array(vertices), pipelineCode);
#| }
///|
extern "js" fn webgpu_push_image_material_vertices_2d(
path : String,
filter_code : Int,
vertices : Array[Double],
) -> Unit =
#| (path, filterCode, vertices) => {
#| const rt = globalThis.__selene_webgpu_runtime;
#| if (!rt) return;
#| const rec = rt.ensureImage(path);
#| if (!rec || rec.state !== 'ready') return;
#| rt.pushTex2d(0, filterCode, rec, new Float32Array(vertices), 12, 24);
#| }
///|
extern "js" fn webgpu_text_texture_dimensions(
text : String,
family : String,
size : Double,
weight : Int,
color_r : Double,
color_g : Double,
color_b : Double,
color_a : Double,
) -> Array[Double] =
#| (text, family, size, weight, r, g, bcol, alpha) => {
#| const rt = globalThis.__selene_webgpu_runtime;
#| if (!rt) return [0, 0, 0];
#| const rec = rt.ensureTextTexture(text, family, size, weight, r, g, bcol, alpha);
#| if (!rec) return [0, 0, 0];
#| return [1, rec.logicalWidth, rec.logicalHeight];
#| }
///|
extern "js" fn webgpu_push_text_vertices_2d(
text : String,
family : String,
size : Double,
weight : Int,
color_r : Double,
color_g : Double,
color_b : Double,
color_a : Double,
vertices : Array[Double],
pipeline_code : Int,
) -> Unit =
#| (text, family, size, weight, r, g, bcol, alpha, vertices, pipelineCode) => {
#| const rt = globalThis.__selene_webgpu_runtime;
#| if (!rt) return;
#| const rec = rt.ensureTextTexture(text, family, size, weight, r, g, bcol, alpha);
#| if (!rec) return;
#| rt.pushTex2d(0, 2, rec, new Float32Array(vertices), pipelineCode);
#| }
///|
extern "js" fn webgpu_upload_text_texture(
key : String,
width : Int,
height : Int,
pixels : Array[Int],
) -> Bool =
#| (key, width, height, pixels) => {
#| const rt = globalThis.__selene_webgpu_runtime;
#| if (!rt) return false;
#| try {
#| return !!rt.uploadTextTexture?.(key, width, height, pixels);
#| } catch (_err) {
#| return false;
#| }
#| }
///|
extern "js" fn webgpu_push_cached_text_vertices_2d(
key : String,
vertices : Array[Double],
pipeline_code : Int,
) -> Unit =
#| (key, vertices, pipelineCode) => {
#| const rt = globalThis.__selene_webgpu_runtime;
#| if (!rt) return;
#| const rec = rt.textCache.get(key);
#| if (!rec) return;
#| rt.pushTex2d(0, 2, rec, new Float32Array(vertices), pipelineCode);
#| }