1012 lines
35 KiB
C
1012 lines
35 KiB
C
#define SOKOL_GFX_IMPL
|
|
#include "sokol/sokol_gfx.h"
|
|
#include "cell.h"
|
|
|
|
// Helper macros for enum mapping (same pattern as sdl/gpu.c)
|
|
#define ENUM_MAPPING_TABLE(ENUM) \
|
|
static const struct { int value; const char *name; } ENUM##_mapping[]
|
|
|
|
#define JS2ENUM(NAME) \
|
|
int js2##NAME(JSContext *js, JSValue v) { \
|
|
if (JS_IsNull(v)) return 0; \
|
|
const char *str = JS_ToCString(js, v); \
|
|
if (!str) return 0; \
|
|
for(int i = 0; i < sizeof(NAME##_mapping)/sizeof(NAME##_mapping[0]); i++) \
|
|
if(!strcmp(NAME##_mapping[i].name, str)) { \
|
|
JS_FreeCString(js, str); \
|
|
return NAME##_mapping[i].value; \
|
|
} \
|
|
JS_FreeCString(js, str); \
|
|
return 0; \
|
|
} \
|
|
JSValue NAME##2js(JSContext *js, int enumval) { \
|
|
for(int i = 0; i < sizeof(NAME##_mapping)/sizeof(NAME##_mapping[0]); i++) \
|
|
if(NAME##_mapping[i].value == enumval) \
|
|
return JS_NewString(js, NAME##_mapping[i].name); \
|
|
return JS_NULL; \
|
|
}
|
|
|
|
// Backend enum
|
|
ENUM_MAPPING_TABLE(sg_backend) = {
|
|
{SG_BACKEND_GLCORE, "glcore"},
|
|
{SG_BACKEND_GLES3, "gles3"},
|
|
{SG_BACKEND_D3D11, "d3d11"},
|
|
{SG_BACKEND_METAL_IOS, "metal_ios"},
|
|
{SG_BACKEND_METAL_MACOS, "metal_macos"},
|
|
{SG_BACKEND_METAL_SIMULATOR, "metal_simulator"},
|
|
{SG_BACKEND_WGPU, "wgpu"},
|
|
{SG_BACKEND_VULKAN, "vulkan"},
|
|
{SG_BACKEND_DUMMY, "dummy"},
|
|
};
|
|
JS2ENUM(sg_backend)
|
|
|
|
// Pixel format enum
|
|
ENUM_MAPPING_TABLE(sg_pixel_format) = {
|
|
{SG_PIXELFORMAT_NONE, "none"},
|
|
{SG_PIXELFORMAT_R8, "r8"},
|
|
{SG_PIXELFORMAT_R8SN, "r8sn"},
|
|
{SG_PIXELFORMAT_R8UI, "r8ui"},
|
|
{SG_PIXELFORMAT_R8SI, "r8si"},
|
|
{SG_PIXELFORMAT_R16, "r16"},
|
|
{SG_PIXELFORMAT_R16SN, "r16sn"},
|
|
{SG_PIXELFORMAT_R16UI, "r16ui"},
|
|
{SG_PIXELFORMAT_R16SI, "r16si"},
|
|
{SG_PIXELFORMAT_R16F, "r16f"},
|
|
{SG_PIXELFORMAT_RG8, "rg8"},
|
|
{SG_PIXELFORMAT_RG8SN, "rg8sn"},
|
|
{SG_PIXELFORMAT_RG8UI, "rg8ui"},
|
|
{SG_PIXELFORMAT_RG8SI, "rg8si"},
|
|
{SG_PIXELFORMAT_R32UI, "r32ui"},
|
|
{SG_PIXELFORMAT_R32SI, "r32si"},
|
|
{SG_PIXELFORMAT_R32F, "r32f"},
|
|
{SG_PIXELFORMAT_RG16, "rg16"},
|
|
{SG_PIXELFORMAT_RG16SN, "rg16sn"},
|
|
{SG_PIXELFORMAT_RG16UI, "rg16ui"},
|
|
{SG_PIXELFORMAT_RG16SI, "rg16si"},
|
|
{SG_PIXELFORMAT_RG16F, "rg16f"},
|
|
{SG_PIXELFORMAT_RGBA8, "rgba8"},
|
|
{SG_PIXELFORMAT_SRGB8A8, "srgba8"},
|
|
{SG_PIXELFORMAT_RGBA8SN, "rgba8sn"},
|
|
{SG_PIXELFORMAT_RGBA8UI, "rgba8ui"},
|
|
{SG_PIXELFORMAT_RGBA8SI, "rgba8si"},
|
|
{SG_PIXELFORMAT_BGRA8, "bgra8"},
|
|
{SG_PIXELFORMAT_RGB10A2, "rgb10a2"},
|
|
{SG_PIXELFORMAT_RG11B10F, "rg11b10f"},
|
|
{SG_PIXELFORMAT_RG32UI, "rg32ui"},
|
|
{SG_PIXELFORMAT_RG32SI, "rg32si"},
|
|
{SG_PIXELFORMAT_RG32F, "rg32f"},
|
|
{SG_PIXELFORMAT_RGBA16, "rgba16"},
|
|
{SG_PIXELFORMAT_RGBA16SN, "rgba16sn"},
|
|
{SG_PIXELFORMAT_RGBA16UI, "rgba16ui"},
|
|
{SG_PIXELFORMAT_RGBA16SI, "rgba16si"},
|
|
{SG_PIXELFORMAT_RGBA16F, "rgba16f"},
|
|
{SG_PIXELFORMAT_RGBA32UI, "rgba32ui"},
|
|
{SG_PIXELFORMAT_RGBA32SI, "rgba32si"},
|
|
{SG_PIXELFORMAT_RGBA32F, "rgba32f"},
|
|
{SG_PIXELFORMAT_DEPTH, "depth"},
|
|
{SG_PIXELFORMAT_DEPTH_STENCIL, "depth_stencil"},
|
|
};
|
|
JS2ENUM(sg_pixel_format)
|
|
|
|
// Primitive type
|
|
ENUM_MAPPING_TABLE(sg_primitive_type) = {
|
|
{SG_PRIMITIVETYPE_POINTS, "points"},
|
|
{SG_PRIMITIVETYPE_LINES, "lines"},
|
|
{SG_PRIMITIVETYPE_LINE_STRIP, "line_strip"},
|
|
{SG_PRIMITIVETYPE_TRIANGLES, "triangles"},
|
|
{SG_PRIMITIVETYPE_TRIANGLE_STRIP, "triangle_strip"},
|
|
};
|
|
JS2ENUM(sg_primitive_type)
|
|
|
|
// Index type
|
|
ENUM_MAPPING_TABLE(sg_index_type) = {
|
|
{SG_INDEXTYPE_NONE, "none"},
|
|
{SG_INDEXTYPE_UINT16, "uint16"},
|
|
{SG_INDEXTYPE_UINT32, "uint32"},
|
|
};
|
|
JS2ENUM(sg_index_type)
|
|
|
|
// Image type
|
|
ENUM_MAPPING_TABLE(sg_image_type) = {
|
|
{SG_IMAGETYPE_2D, "2d"},
|
|
{SG_IMAGETYPE_CUBE, "cube"},
|
|
{SG_IMAGETYPE_3D, "3d"},
|
|
{SG_IMAGETYPE_ARRAY, "array"},
|
|
};
|
|
JS2ENUM(sg_image_type)
|
|
|
|
// Filter
|
|
ENUM_MAPPING_TABLE(sg_filter) = {
|
|
{SG_FILTER_NEAREST, "nearest"},
|
|
{SG_FILTER_LINEAR, "linear"},
|
|
};
|
|
JS2ENUM(sg_filter)
|
|
|
|
// Wrap mode
|
|
ENUM_MAPPING_TABLE(sg_wrap) = {
|
|
{SG_WRAP_REPEAT, "repeat"},
|
|
{SG_WRAP_CLAMP_TO_EDGE, "clamp"},
|
|
{SG_WRAP_CLAMP_TO_BORDER, "border"},
|
|
{SG_WRAP_MIRRORED_REPEAT, "mirror"},
|
|
};
|
|
JS2ENUM(sg_wrap)
|
|
|
|
// Compare function
|
|
ENUM_MAPPING_TABLE(sg_compare_func) = {
|
|
{SG_COMPAREFUNC_NEVER, "never"},
|
|
{SG_COMPAREFUNC_LESS, "less"},
|
|
{SG_COMPAREFUNC_EQUAL, "equal"},
|
|
{SG_COMPAREFUNC_LESS_EQUAL, "less_equal"},
|
|
{SG_COMPAREFUNC_GREATER, "greater"},
|
|
{SG_COMPAREFUNC_NOT_EQUAL, "not_equal"},
|
|
{SG_COMPAREFUNC_GREATER_EQUAL, "greater_equal"},
|
|
{SG_COMPAREFUNC_ALWAYS, "always"},
|
|
};
|
|
JS2ENUM(sg_compare_func)
|
|
|
|
// Stencil op
|
|
ENUM_MAPPING_TABLE(sg_stencil_op) = {
|
|
{SG_STENCILOP_KEEP, "keep"},
|
|
{SG_STENCILOP_ZERO, "zero"},
|
|
{SG_STENCILOP_REPLACE, "replace"},
|
|
{SG_STENCILOP_INCR_CLAMP, "incr_clamp"},
|
|
{SG_STENCILOP_DECR_CLAMP, "decr_clamp"},
|
|
{SG_STENCILOP_INVERT, "invert"},
|
|
{SG_STENCILOP_INCR_WRAP, "incr_wrap"},
|
|
{SG_STENCILOP_DECR_WRAP, "decr_wrap"},
|
|
};
|
|
JS2ENUM(sg_stencil_op)
|
|
|
|
// Blend factor
|
|
ENUM_MAPPING_TABLE(sg_blend_factor) = {
|
|
{SG_BLENDFACTOR_ZERO, "zero"},
|
|
{SG_BLENDFACTOR_ONE, "one"},
|
|
{SG_BLENDFACTOR_SRC_COLOR, "src_color"},
|
|
{SG_BLENDFACTOR_ONE_MINUS_SRC_COLOR, "one_minus_src_color"},
|
|
{SG_BLENDFACTOR_SRC_ALPHA, "src_alpha"},
|
|
{SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, "one_minus_src_alpha"},
|
|
{SG_BLENDFACTOR_DST_COLOR, "dst_color"},
|
|
{SG_BLENDFACTOR_ONE_MINUS_DST_COLOR, "one_minus_dst_color"},
|
|
{SG_BLENDFACTOR_DST_ALPHA, "dst_alpha"},
|
|
{SG_BLENDFACTOR_ONE_MINUS_DST_ALPHA, "one_minus_dst_alpha"},
|
|
{SG_BLENDFACTOR_SRC_ALPHA_SATURATED, "src_alpha_saturated"},
|
|
{SG_BLENDFACTOR_BLEND_COLOR, "blend_color"},
|
|
{SG_BLENDFACTOR_ONE_MINUS_BLEND_COLOR, "one_minus_blend_color"},
|
|
};
|
|
JS2ENUM(sg_blend_factor)
|
|
|
|
// Blend op
|
|
ENUM_MAPPING_TABLE(sg_blend_op) = {
|
|
{SG_BLENDOP_ADD, "add"},
|
|
{SG_BLENDOP_SUBTRACT, "subtract"},
|
|
{SG_BLENDOP_REVERSE_SUBTRACT, "reverse_subtract"},
|
|
{SG_BLENDOP_MIN, "min"},
|
|
{SG_BLENDOP_MAX, "max"},
|
|
};
|
|
JS2ENUM(sg_blend_op)
|
|
|
|
// Cull mode
|
|
ENUM_MAPPING_TABLE(sg_cull_mode) = {
|
|
{SG_CULLMODE_NONE, "none"},
|
|
{SG_CULLMODE_FRONT, "front"},
|
|
{SG_CULLMODE_BACK, "back"},
|
|
};
|
|
JS2ENUM(sg_cull_mode)
|
|
|
|
// Face winding
|
|
ENUM_MAPPING_TABLE(sg_face_winding) = {
|
|
{SG_FACEWINDING_CCW, "ccw"},
|
|
{SG_FACEWINDING_CW, "cw"},
|
|
};
|
|
JS2ENUM(sg_face_winding)
|
|
|
|
// Vertex format
|
|
ENUM_MAPPING_TABLE(sg_vertex_format) = {
|
|
{SG_VERTEXFORMAT_FLOAT, "float"},
|
|
{SG_VERTEXFORMAT_FLOAT2, "float2"},
|
|
{SG_VERTEXFORMAT_FLOAT3, "float3"},
|
|
{SG_VERTEXFORMAT_FLOAT4, "float4"},
|
|
{SG_VERTEXFORMAT_INT, "int"},
|
|
{SG_VERTEXFORMAT_INT2, "int2"},
|
|
{SG_VERTEXFORMAT_INT3, "int3"},
|
|
{SG_VERTEXFORMAT_INT4, "int4"},
|
|
{SG_VERTEXFORMAT_UINT, "uint"},
|
|
{SG_VERTEXFORMAT_UINT2, "uint2"},
|
|
{SG_VERTEXFORMAT_UINT3, "uint3"},
|
|
{SG_VERTEXFORMAT_UINT4, "uint4"},
|
|
{SG_VERTEXFORMAT_BYTE4, "byte4"},
|
|
{SG_VERTEXFORMAT_BYTE4N, "byte4n"},
|
|
{SG_VERTEXFORMAT_UBYTE4, "ubyte4"},
|
|
{SG_VERTEXFORMAT_UBYTE4N, "ubyte4n"},
|
|
{SG_VERTEXFORMAT_SHORT2, "short2"},
|
|
{SG_VERTEXFORMAT_SHORT2N, "short2n"},
|
|
{SG_VERTEXFORMAT_USHORT2, "ushort2"},
|
|
{SG_VERTEXFORMAT_USHORT2N, "ushort2n"},
|
|
{SG_VERTEXFORMAT_SHORT4, "short4"},
|
|
{SG_VERTEXFORMAT_SHORT4N, "short4n"},
|
|
{SG_VERTEXFORMAT_USHORT4, "ushort4"},
|
|
{SG_VERTEXFORMAT_USHORT4N, "ushort4n"},
|
|
{SG_VERTEXFORMAT_HALF2, "half2"},
|
|
{SG_VERTEXFORMAT_HALF4, "half4"},
|
|
};
|
|
JS2ENUM(sg_vertex_format)
|
|
|
|
// Load action
|
|
ENUM_MAPPING_TABLE(sg_load_action) = {
|
|
{SG_LOADACTION_CLEAR, "clear"},
|
|
{SG_LOADACTION_LOAD, "load"},
|
|
{SG_LOADACTION_DONTCARE, "dontcare"},
|
|
};
|
|
JS2ENUM(sg_load_action)
|
|
|
|
// Store action
|
|
ENUM_MAPPING_TABLE(sg_store_action) = {
|
|
{SG_STOREACTION_STORE, "store"},
|
|
{SG_STOREACTION_DONTCARE, "dontcare"},
|
|
};
|
|
JS2ENUM(sg_store_action)
|
|
|
|
// Uniform type
|
|
ENUM_MAPPING_TABLE(sg_uniform_type) = {
|
|
{SG_UNIFORMTYPE_FLOAT, "float"},
|
|
{SG_UNIFORMTYPE_FLOAT2, "float2"},
|
|
{SG_UNIFORMTYPE_FLOAT3, "float3"},
|
|
{SG_UNIFORMTYPE_FLOAT4, "float4"},
|
|
{SG_UNIFORMTYPE_INT, "int"},
|
|
{SG_UNIFORMTYPE_INT2, "int2"},
|
|
{SG_UNIFORMTYPE_INT3, "int3"},
|
|
{SG_UNIFORMTYPE_INT4, "int4"},
|
|
{SG_UNIFORMTYPE_MAT4, "mat4"},
|
|
};
|
|
JS2ENUM(sg_uniform_type)
|
|
|
|
// Helper to check bool property
|
|
static int JS_GETBOOL(JSContext *js, JSValue obj, const char *prop) {
|
|
JSValue v = JS_GetPropertyStr(js, obj, prop);
|
|
int ret = JS_ToBool(js, v);
|
|
JS_FreeValue(js, v);
|
|
return ret;
|
|
}
|
|
|
|
// Color conversion
|
|
static sg_color js2sg_color(JSContext *js, JSValue v) {
|
|
sg_color c = {0};
|
|
if (JS_IsArray(js, v)) {
|
|
JSValue r = JS_GetPropertyUint32(js, v, 0);
|
|
JSValue g = JS_GetPropertyUint32(js, v, 1);
|
|
JSValue b = JS_GetPropertyUint32(js, v, 2);
|
|
JSValue a = JS_GetPropertyUint32(js, v, 3);
|
|
c.r = js2number(js, r);
|
|
c.g = js2number(js, g);
|
|
c.b = js2number(js, b);
|
|
c.a = JS_IsNull(a) ? 1.0f : js2number(js, a);
|
|
JS_FreeValue(js, r);
|
|
JS_FreeValue(js, g);
|
|
JS_FreeValue(js, b);
|
|
JS_FreeValue(js, a);
|
|
} else if (JS_IsObject(v)) {
|
|
JS_GETPROP(js, c.r, v, r, number);
|
|
JS_GETPROP(js, c.g, v, g, number);
|
|
JS_GETPROP(js, c.b, v, b, number);
|
|
c.a = 1.0f;
|
|
JS_GETPROP(js, c.a, v, a, number);
|
|
}
|
|
return c;
|
|
}
|
|
|
|
// ============================================================================
|
|
// SETUP / SHUTDOWN
|
|
// ============================================================================
|
|
|
|
// gfx.setup(desc) - Initialize sokol_gfx
|
|
JSC_CCALL(gfx_setup,
|
|
sg_desc desc = {0};
|
|
if (argc > 0 && JS_IsObject(argv[0])) {
|
|
JSValue cfg = argv[0];
|
|
JSValue env = JS_GetPropertyStr(js, cfg, "environment");
|
|
if (!JS_IsNull(env)) {
|
|
// Environment settings would be set here
|
|
// For now, use defaults from sokol_glue
|
|
}
|
|
JS_FreeValue(js, env);
|
|
}
|
|
sg_setup(&desc);
|
|
)
|
|
|
|
// gfx.shutdown() - Shutdown sokol_gfx
|
|
JSC_CCALL(gfx_shutdown,
|
|
sg_shutdown();
|
|
)
|
|
|
|
// gfx.is_valid() - Check if sokol_gfx is initialized
|
|
JSC_CCALL(gfx_is_valid,
|
|
return JS_NewBool(js, sg_isvalid());
|
|
)
|
|
|
|
// gfx.backend() - Get current backend as string
|
|
JSC_CCALL(gfx_backend,
|
|
return sg_backend2js(js, sg_query_backend());
|
|
)
|
|
|
|
// gfx.commit() - Commit the current frame
|
|
JSC_CCALL(gfx_commit,
|
|
sg_commit();
|
|
)
|
|
|
|
// gfx.reset_state_cache() - Reset internal state cache
|
|
JSC_CCALL(gfx_reset_state_cache,
|
|
sg_reset_state_cache();
|
|
)
|
|
|
|
// ============================================================================
|
|
// BUFFER
|
|
// ============================================================================
|
|
|
|
// gfx.make_buffer(desc) - Create a buffer
|
|
// desc: { size, data, vertex, index, storage, immutable, dynamic, stream, label }
|
|
JSC_CCALL(gfx_make_buffer,
|
|
sg_buffer_desc desc = {0};
|
|
JSValue cfg = argv[0];
|
|
|
|
JS_GETPROP(js, desc.size, cfg, size, number);
|
|
|
|
// Usage flags
|
|
desc.usage.vertex_buffer = JS_GETBOOL(js, cfg, "vertex");
|
|
desc.usage.index_buffer = JS_GETBOOL(js, cfg, "index");
|
|
desc.usage.storage_buffer = JS_GETBOOL(js, cfg, "storage");
|
|
desc.usage.immutable = !JS_GETBOOL(js, cfg, "dynamic") && !JS_GETBOOL(js, cfg, "stream");
|
|
desc.usage.dynamic_update = JS_GETBOOL(js, cfg, "dynamic");
|
|
desc.usage.stream_update = JS_GETBOOL(js, cfg, "stream");
|
|
|
|
// Default to vertex buffer if nothing specified
|
|
if (!desc.usage.vertex_buffer && !desc.usage.index_buffer && !desc.usage.storage_buffer)
|
|
desc.usage.vertex_buffer = true;
|
|
|
|
// Initial data
|
|
JSValue data_val = JS_GetPropertyStr(js, cfg, "data");
|
|
if (!JS_IsNull(data_val)) {
|
|
size_t data_size;
|
|
void *data_ptr = js_get_blob_data(js, &data_size, data_val);
|
|
if (data_ptr && data_ptr != (void*)-1) {
|
|
desc.data.ptr = data_ptr;
|
|
desc.data.size = data_size;
|
|
if (desc.size == 0) desc.size = data_size;
|
|
}
|
|
}
|
|
JS_FreeValue(js, data_val);
|
|
|
|
// Label
|
|
JSValue label_val = JS_GetPropertyStr(js, cfg, "label");
|
|
if (JS_IsString(label_val)) {
|
|
desc.label = JS_ToCString(js, label_val);
|
|
}
|
|
JS_FreeValue(js, label_val);
|
|
|
|
sg_buffer buf = sg_make_buffer(&desc);
|
|
|
|
if (desc.label) JS_FreeCString(js, desc.label);
|
|
|
|
return JS_NewInt32(js, buf.id);
|
|
)
|
|
|
|
// gfx.destroy_buffer(buf_id)
|
|
JSC_CCALL(gfx_destroy_buffer,
|
|
sg_buffer buf = { .id = js2number(js, argv[0]) };
|
|
sg_destroy_buffer(buf);
|
|
)
|
|
|
|
// gfx.update_buffer(buf_id, data)
|
|
JSC_CCALL(gfx_update_buffer,
|
|
sg_buffer buf = { .id = js2number(js, argv[0]) };
|
|
size_t data_size;
|
|
void *data_ptr = js_get_blob_data(js, &data_size, argv[1]);
|
|
if (data_ptr && data_ptr != (void*)-1) {
|
|
sg_update_buffer(buf, &(sg_range){ .ptr = data_ptr, .size = data_size });
|
|
}
|
|
)
|
|
|
|
// gfx.append_buffer(buf_id, data) -> offset
|
|
JSC_CCALL(gfx_append_buffer,
|
|
sg_buffer buf = { .id = js2number(js, argv[0]) };
|
|
size_t data_size;
|
|
void *data_ptr = js_get_blob_data(js, &data_size, argv[1]);
|
|
if (data_ptr && data_ptr != (void*)-1) {
|
|
int offset = sg_append_buffer(buf, &(sg_range){ .ptr = data_ptr, .size = data_size });
|
|
return JS_NewInt32(js, offset);
|
|
}
|
|
return JS_NewInt32(js, -1);
|
|
)
|
|
|
|
// ============================================================================
|
|
// IMAGE
|
|
// ============================================================================
|
|
|
|
// gfx.make_image(desc) - Create an image
|
|
// desc: { width, height, type, format, mip_levels, samples, storage, color_target, depth_target, ... }
|
|
JSC_CCALL(gfx_make_image,
|
|
sg_image_desc desc = {0};
|
|
JSValue cfg = argv[0];
|
|
|
|
JS_GETPROP(js, desc.width, cfg, width, number);
|
|
JS_GETPROP(js, desc.height, cfg, height, number);
|
|
JS_GETPROP(js, desc.num_slices, cfg, slices, number);
|
|
JS_GETPROP(js, desc.num_mipmaps, cfg, mip_levels, number);
|
|
JS_GETPROP(js, desc.type, cfg, type, sg_image_type);
|
|
JS_GETPROP(js, desc.pixel_format, cfg, format, sg_pixel_format);
|
|
JS_GETPROP(js, desc.sample_count, cfg, samples, number);
|
|
|
|
// Usage flags
|
|
desc.usage.storage_image = JS_GETBOOL(js, cfg, "storage");
|
|
desc.usage.color_attachment = JS_GETBOOL(js, cfg, "color_target");
|
|
desc.usage.resolve_attachment = JS_GETBOOL(js, cfg, "resolve_target");
|
|
desc.usage.depth_stencil_attachment = JS_GETBOOL(js, cfg, "depth_target");
|
|
desc.usage.immutable = !JS_GETBOOL(js, cfg, "dynamic") && !JS_GETBOOL(js, cfg, "stream");
|
|
desc.usage.dynamic_update = JS_GETBOOL(js, cfg, "dynamic");
|
|
desc.usage.stream_update = JS_GETBOOL(js, cfg, "stream");
|
|
|
|
// Initial data for mip 0, face 0
|
|
JSValue data_val = JS_GetPropertyStr(js, cfg, "data");
|
|
if (!JS_IsNull(data_val)) {
|
|
size_t data_size;
|
|
void *data_ptr = js_get_blob_data(js, &data_size, data_val);
|
|
if (data_ptr && data_ptr != (void*)-1) {
|
|
desc.data.mip_levels[0].ptr = data_ptr;
|
|
desc.data.mip_levels[0].size = data_size;
|
|
}
|
|
}
|
|
JS_FreeValue(js, data_val);
|
|
|
|
sg_image img = sg_make_image(&desc);
|
|
return JS_NewInt32(js, img.id);
|
|
)
|
|
|
|
// gfx.destroy_image(img_id)
|
|
JSC_CCALL(gfx_destroy_image,
|
|
sg_image img = { .id = js2number(js, argv[0]) };
|
|
sg_destroy_image(img);
|
|
)
|
|
|
|
// gfx.update_image(img_id, data)
|
|
JSC_CCALL(gfx_update_image,
|
|
sg_image img = { .id = js2number(js, argv[0]) };
|
|
sg_image_data data = {0};
|
|
|
|
size_t data_size;
|
|
void *data_ptr = js_get_blob_data(js, &data_size, argv[1]);
|
|
if (data_ptr && data_ptr != (void*)-1) {
|
|
data.mip_levels[0].ptr = data_ptr;
|
|
data.mip_levels[0].size = data_size;
|
|
sg_update_image(img, &data);
|
|
}
|
|
)
|
|
|
|
// ============================================================================
|
|
// SAMPLER
|
|
// ============================================================================
|
|
|
|
// gfx.make_sampler(desc) - Create a sampler
|
|
// desc: { min_filter, mag_filter, mipmap_filter, wrap_u, wrap_v, wrap_w, ... }
|
|
JSC_CCALL(gfx_make_sampler,
|
|
sg_sampler_desc desc = {0};
|
|
JSValue cfg = argv[0];
|
|
|
|
JS_GETPROP(js, desc.min_filter, cfg, min_filter, sg_filter);
|
|
JS_GETPROP(js, desc.mag_filter, cfg, mag_filter, sg_filter);
|
|
JS_GETPROP(js, desc.mipmap_filter, cfg, mipmap_filter, sg_filter);
|
|
JS_GETPROP(js, desc.wrap_u, cfg, wrap_u, sg_wrap);
|
|
JS_GETPROP(js, desc.wrap_v, cfg, wrap_v, sg_wrap);
|
|
JS_GETPROP(js, desc.wrap_w, cfg, wrap_w, sg_wrap);
|
|
JS_GETPROP(js, desc.min_lod, cfg, min_lod, number);
|
|
JS_GETPROP(js, desc.max_lod, cfg, max_lod, number);
|
|
JS_GETPROP(js, desc.max_anisotropy, cfg, max_anisotropy, number);
|
|
JS_GETPROP(js, desc.compare, cfg, compare, sg_compare_func);
|
|
|
|
sg_sampler smp = sg_make_sampler(&desc);
|
|
return JS_NewInt32(js, smp.id);
|
|
)
|
|
|
|
// gfx.destroy_sampler(smp_id)
|
|
JSC_CCALL(gfx_destroy_sampler,
|
|
sg_sampler smp = { .id = js2number(js, argv[0]) };
|
|
sg_destroy_sampler(smp);
|
|
)
|
|
|
|
// ============================================================================
|
|
// SHADER
|
|
// ============================================================================
|
|
|
|
// gfx.make_shader(desc) - Create a shader
|
|
// This is complex; for now support basic vertex/fragment with uniform blocks
|
|
JSC_CCALL(gfx_make_shader,
|
|
sg_shader_desc desc = {0};
|
|
JSValue cfg = argv[0];
|
|
|
|
// Vertex shader source
|
|
JSValue vs_val = JS_GetPropertyStr(js, cfg, "vs");
|
|
if (JS_IsObject(vs_val)) {
|
|
JSValue src = JS_GetPropertyStr(js, vs_val, "source");
|
|
if (JS_IsString(src)) {
|
|
desc.vertex_func.source = JS_ToCString(js, src);
|
|
}
|
|
JS_FreeValue(js, src);
|
|
|
|
JSValue entry = JS_GetPropertyStr(js, vs_val, "entry");
|
|
if (JS_IsString(entry)) {
|
|
desc.vertex_func.entry = JS_ToCString(js, entry);
|
|
}
|
|
JS_FreeValue(js, entry);
|
|
}
|
|
JS_FreeValue(js, vs_val);
|
|
|
|
// Fragment shader source
|
|
JSValue fs_val = JS_GetPropertyStr(js, cfg, "fs");
|
|
if (JS_IsObject(fs_val)) {
|
|
JSValue src = JS_GetPropertyStr(js, fs_val, "source");
|
|
if (JS_IsString(src)) {
|
|
desc.fragment_func.source = JS_ToCString(js, src);
|
|
}
|
|
JS_FreeValue(js, src);
|
|
|
|
JSValue entry = JS_GetPropertyStr(js, fs_val, "entry");
|
|
if (JS_IsString(entry)) {
|
|
desc.fragment_func.entry = JS_ToCString(js, entry);
|
|
}
|
|
JS_FreeValue(js, entry);
|
|
}
|
|
JS_FreeValue(js, fs_val);
|
|
|
|
sg_shader shd = sg_make_shader(&desc);
|
|
|
|
// Free strings
|
|
if (desc.vertex_func.source) JS_FreeCString(js, desc.vertex_func.source);
|
|
if (desc.vertex_func.entry) JS_FreeCString(js, desc.vertex_func.entry);
|
|
if (desc.fragment_func.source) JS_FreeCString(js, desc.fragment_func.source);
|
|
if (desc.fragment_func.entry) JS_FreeCString(js, desc.fragment_func.entry);
|
|
|
|
return JS_NewInt32(js, shd.id);
|
|
)
|
|
|
|
// gfx.destroy_shader(shd_id)
|
|
JSC_CCALL(gfx_destroy_shader,
|
|
sg_shader shd = { .id = js2number(js, argv[0]) };
|
|
sg_destroy_shader(shd);
|
|
)
|
|
|
|
// ============================================================================
|
|
// PIPELINE
|
|
// ============================================================================
|
|
|
|
// gfx.make_pipeline(desc) - Create a pipeline
|
|
JSC_CCALL(gfx_make_pipeline,
|
|
sg_pipeline_desc desc = {0};
|
|
JSValue cfg = argv[0];
|
|
|
|
// Shader
|
|
JSValue shd_val = JS_GetPropertyStr(js, cfg, "shader");
|
|
desc.shader.id = js2number(js, shd_val);
|
|
JS_FreeValue(js, shd_val);
|
|
|
|
// Vertex layout
|
|
JSValue layout_val = JS_GetPropertyStr(js, cfg, "layout");
|
|
if (JS_IsObject(layout_val)) {
|
|
// Buffers
|
|
JSValue buffers_val = JS_GetPropertyStr(js, layout_val, "buffers");
|
|
if (JS_IsArray(js, buffers_val)) {
|
|
int len = 0;
|
|
JSValue len_val = JS_GetPropertyStr(js, buffers_val, "length");
|
|
JS_ToInt32(js, &len, len_val);
|
|
JS_FreeValue(js, len_val);
|
|
|
|
for (int i = 0; i < len && i < SG_MAX_VERTEXBUFFER_BINDSLOTS; i++) {
|
|
JSValue buf = JS_GetPropertyUint32(js, buffers_val, i);
|
|
if (JS_IsObject(buf)) {
|
|
JS_GETPROP(js, desc.layout.buffers[i].stride, buf, stride, number);
|
|
JSValue step_val = JS_GetPropertyStr(js, buf, "step");
|
|
if (!JS_IsNull(step_val)) {
|
|
const char *step_str = JS_ToCString(js, step_val);
|
|
if (step_str) {
|
|
if (!strcmp(step_str, "instance"))
|
|
desc.layout.buffers[i].step_func = SG_VERTEXSTEP_PER_INSTANCE;
|
|
JS_FreeCString(js, step_str);
|
|
}
|
|
}
|
|
JS_FreeValue(js, step_val);
|
|
JS_GETPROP(js, desc.layout.buffers[i].step_rate, buf, step_rate, number);
|
|
}
|
|
JS_FreeValue(js, buf);
|
|
}
|
|
}
|
|
JS_FreeValue(js, buffers_val);
|
|
|
|
// Attributes
|
|
JSValue attrs_val = JS_GetPropertyStr(js, layout_val, "attrs");
|
|
if (JS_IsArray(js, attrs_val)) {
|
|
int len = 0;
|
|
JSValue len_val = JS_GetPropertyStr(js, attrs_val, "length");
|
|
JS_ToInt32(js, &len, len_val);
|
|
JS_FreeValue(js, len_val);
|
|
|
|
for (int i = 0; i < len && i < SG_MAX_VERTEX_ATTRIBUTES; i++) {
|
|
JSValue attr = JS_GetPropertyUint32(js, attrs_val, i);
|
|
if (JS_IsObject(attr)) {
|
|
JS_GETPROP(js, desc.layout.attrs[i].format, attr, format, sg_vertex_format);
|
|
JS_GETPROP(js, desc.layout.attrs[i].offset, attr, offset, number);
|
|
JS_GETPROP(js, desc.layout.attrs[i].buffer_index, attr, buffer, number);
|
|
}
|
|
JS_FreeValue(js, attr);
|
|
}
|
|
}
|
|
JS_FreeValue(js, attrs_val);
|
|
}
|
|
JS_FreeValue(js, layout_val);
|
|
|
|
// Primitive type
|
|
JS_GETPROP(js, desc.primitive_type, cfg, primitive, sg_primitive_type);
|
|
|
|
// Index type
|
|
JS_GETPROP(js, desc.index_type, cfg, index_type, sg_index_type);
|
|
|
|
// Cull mode
|
|
JS_GETPROP(js, desc.cull_mode, cfg, cull, sg_cull_mode);
|
|
|
|
// Face winding
|
|
JS_GETPROP(js, desc.face_winding, cfg, winding, sg_face_winding);
|
|
|
|
// Depth state
|
|
JSValue depth_val = JS_GetPropertyStr(js, cfg, "depth");
|
|
if (JS_IsObject(depth_val)) {
|
|
JS_GETPROP(js, desc.depth.pixel_format, depth_val, format, sg_pixel_format);
|
|
JS_GETPROP(js, desc.depth.compare, depth_val, compare, sg_compare_func);
|
|
desc.depth.write_enabled = JS_GETBOOL(js, depth_val, "write");
|
|
JS_GETPROP(js, desc.depth.bias, depth_val, bias, number);
|
|
JS_GETPROP(js, desc.depth.bias_slope_scale, depth_val, bias_slope, number);
|
|
JS_GETPROP(js, desc.depth.bias_clamp, depth_val, bias_clamp, number);
|
|
}
|
|
JS_FreeValue(js, depth_val);
|
|
|
|
// Stencil state
|
|
JSValue stencil_val = JS_GetPropertyStr(js, cfg, "stencil");
|
|
if (JS_IsObject(stencil_val)) {
|
|
desc.stencil.enabled = JS_GETBOOL(js, stencil_val, "enabled");
|
|
JS_GETPROP(js, desc.stencil.read_mask, stencil_val, read_mask, number);
|
|
JS_GETPROP(js, desc.stencil.write_mask, stencil_val, write_mask, number);
|
|
JS_GETPROP(js, desc.stencil.ref, stencil_val, ref, number);
|
|
|
|
JSValue front_val = JS_GetPropertyStr(js, stencil_val, "front");
|
|
if (JS_IsObject(front_val)) {
|
|
JS_GETPROP(js, desc.stencil.front.compare, front_val, compare, sg_compare_func);
|
|
JS_GETPROP(js, desc.stencil.front.fail_op, front_val, fail, sg_stencil_op);
|
|
JS_GETPROP(js, desc.stencil.front.depth_fail_op, front_val, depth_fail, sg_stencil_op);
|
|
JS_GETPROP(js, desc.stencil.front.pass_op, front_val, pass, sg_stencil_op);
|
|
}
|
|
JS_FreeValue(js, front_val);
|
|
|
|
JSValue back_val = JS_GetPropertyStr(js, stencil_val, "back");
|
|
if (JS_IsObject(back_val)) {
|
|
JS_GETPROP(js, desc.stencil.back.compare, back_val, compare, sg_compare_func);
|
|
JS_GETPROP(js, desc.stencil.back.fail_op, back_val, fail, sg_stencil_op);
|
|
JS_GETPROP(js, desc.stencil.back.depth_fail_op, back_val, depth_fail, sg_stencil_op);
|
|
JS_GETPROP(js, desc.stencil.back.pass_op, back_val, pass, sg_stencil_op);
|
|
}
|
|
JS_FreeValue(js, back_val);
|
|
}
|
|
JS_FreeValue(js, stencil_val);
|
|
|
|
// Color targets
|
|
JSValue colors_val = JS_GetPropertyStr(js, cfg, "colors");
|
|
if (JS_IsArray(js, colors_val)) {
|
|
int len = 0;
|
|
JSValue len_val = JS_GetPropertyStr(js, colors_val, "length");
|
|
JS_ToInt32(js, &len, len_val);
|
|
JS_FreeValue(js, len_val);
|
|
|
|
for (int i = 0; i < len && i < SG_MAX_COLOR_ATTACHMENTS; i++) {
|
|
JSValue col = JS_GetPropertyUint32(js, colors_val, i);
|
|
if (JS_IsObject(col)) {
|
|
JS_GETPROP(js, desc.colors[i].pixel_format, col, format, sg_pixel_format);
|
|
|
|
JSValue blend_val = JS_GetPropertyStr(js, col, "blend");
|
|
if (JS_IsObject(blend_val)) {
|
|
desc.colors[i].blend.enabled = JS_GETBOOL(js, blend_val, "enabled");
|
|
JS_GETPROP(js, desc.colors[i].blend.src_factor_rgb, blend_val, src_rgb, sg_blend_factor);
|
|
JS_GETPROP(js, desc.colors[i].blend.dst_factor_rgb, blend_val, dst_rgb, sg_blend_factor);
|
|
JS_GETPROP(js, desc.colors[i].blend.op_rgb, blend_val, op_rgb, sg_blend_op);
|
|
JS_GETPROP(js, desc.colors[i].blend.src_factor_alpha, blend_val, src_alpha, sg_blend_factor);
|
|
JS_GETPROP(js, desc.colors[i].blend.dst_factor_alpha, blend_val, dst_alpha, sg_blend_factor);
|
|
JS_GETPROP(js, desc.colors[i].blend.op_alpha, blend_val, op_alpha, sg_blend_op);
|
|
}
|
|
JS_FreeValue(js, blend_val);
|
|
}
|
|
JS_FreeValue(js, col);
|
|
}
|
|
}
|
|
JS_FreeValue(js, colors_val);
|
|
|
|
// Sample count
|
|
JS_GETPROP(js, desc.sample_count, cfg, samples, number);
|
|
|
|
sg_pipeline pip = sg_make_pipeline(&desc);
|
|
return JS_NewInt32(js, pip.id);
|
|
)
|
|
|
|
// gfx.destroy_pipeline(pip_id)
|
|
JSC_CCALL(gfx_destroy_pipeline,
|
|
sg_pipeline pip = { .id = js2number(js, argv[0]) };
|
|
sg_destroy_pipeline(pip);
|
|
)
|
|
|
|
// ============================================================================
|
|
// PASS / RENDERING
|
|
// ============================================================================
|
|
|
|
// gfx.begin_pass(desc) - Begin a render pass
|
|
// desc: { action: { colors: [{load, store, clear}], depth: {...}, stencil: {...} }, swapchain: {...} }
|
|
JSC_CCALL(gfx_begin_pass,
|
|
sg_pass pass = {0};
|
|
|
|
if (argc > 0 && JS_IsObject(argv[0])) {
|
|
JSValue cfg = argv[0];
|
|
|
|
// Pass action
|
|
JSValue action_val = JS_GetPropertyStr(js, cfg, "action");
|
|
if (JS_IsObject(action_val)) {
|
|
// Color attachments
|
|
JSValue colors_val = JS_GetPropertyStr(js, action_val, "colors");
|
|
if (JS_IsArray(js, colors_val)) {
|
|
int len = 0;
|
|
JSValue len_val = JS_GetPropertyStr(js, colors_val, "length");
|
|
JS_ToInt32(js, &len, len_val);
|
|
JS_FreeValue(js, len_val);
|
|
|
|
for (int i = 0; i < len && i < SG_MAX_COLOR_ATTACHMENTS; i++) {
|
|
JSValue col = JS_GetPropertyUint32(js, colors_val, i);
|
|
if (JS_IsObject(col)) {
|
|
JS_GETPROP(js, pass.action.colors[i].load_action, col, load, sg_load_action);
|
|
JS_GETPROP(js, pass.action.colors[i].store_action, col, store, sg_store_action);
|
|
|
|
JSValue clear_val = JS_GetPropertyStr(js, col, "clear");
|
|
if (!JS_IsNull(clear_val)) {
|
|
pass.action.colors[i].clear_value = js2sg_color(js, clear_val);
|
|
}
|
|
JS_FreeValue(js, clear_val);
|
|
}
|
|
JS_FreeValue(js, col);
|
|
}
|
|
}
|
|
JS_FreeValue(js, colors_val);
|
|
|
|
// Depth
|
|
JSValue depth_val = JS_GetPropertyStr(js, action_val, "depth");
|
|
if (JS_IsObject(depth_val)) {
|
|
JS_GETPROP(js, pass.action.depth.load_action, depth_val, load, sg_load_action);
|
|
JS_GETPROP(js, pass.action.depth.store_action, depth_val, store, sg_store_action);
|
|
JS_GETPROP(js, pass.action.depth.clear_value, depth_val, clear, number);
|
|
}
|
|
JS_FreeValue(js, depth_val);
|
|
|
|
// Stencil
|
|
JSValue stencil_val = JS_GetPropertyStr(js, action_val, "stencil");
|
|
if (JS_IsObject(stencil_val)) {
|
|
JS_GETPROP(js, pass.action.stencil.load_action, stencil_val, load, sg_load_action);
|
|
JS_GETPROP(js, pass.action.stencil.store_action, stencil_val, store, sg_store_action);
|
|
JS_GETPROP(js, pass.action.stencil.clear_value, stencil_val, clear, number);
|
|
}
|
|
JS_FreeValue(js, stencil_val);
|
|
}
|
|
JS_FreeValue(js, action_val);
|
|
|
|
// Swapchain
|
|
JSValue swapchain_val = JS_GetPropertyStr(js, cfg, "swapchain");
|
|
if (JS_IsObject(swapchain_val)) {
|
|
JS_GETPROP(js, pass.swapchain.width, swapchain_val, width, number);
|
|
JS_GETPROP(js, pass.swapchain.height, swapchain_val, height, number);
|
|
JS_GETPROP(js, pass.swapchain.sample_count, swapchain_val, samples, number);
|
|
JS_GETPROP(js, pass.swapchain.color_format, swapchain_val, color_format, sg_pixel_format);
|
|
JS_GETPROP(js, pass.swapchain.depth_format, swapchain_val, depth_format, sg_pixel_format);
|
|
}
|
|
JS_FreeValue(js, swapchain_val);
|
|
|
|
// Compute pass
|
|
pass.compute = JS_GETBOOL(js, cfg, "compute");
|
|
}
|
|
|
|
sg_begin_pass(&pass);
|
|
)
|
|
|
|
// gfx.end_pass()
|
|
JSC_CCALL(gfx_end_pass,
|
|
sg_end_pass();
|
|
)
|
|
|
|
// gfx.apply_pipeline(pip_id)
|
|
JSC_CCALL(gfx_apply_pipeline,
|
|
sg_pipeline pip = { .id = js2number(js, argv[0]) };
|
|
sg_apply_pipeline(pip);
|
|
)
|
|
|
|
// gfx.apply_bindings(bindings)
|
|
// bindings: { vertex_buffers: [{buffer, offset}], index_buffer: {buffer, offset}, samplers: [...] }
|
|
JSC_CCALL(gfx_apply_bindings,
|
|
sg_bindings bind = {0};
|
|
JSValue cfg = argv[0];
|
|
|
|
// Vertex buffers
|
|
JSValue vb_val = JS_GetPropertyStr(js, cfg, "vertex_buffers");
|
|
if (JS_IsArray(js, vb_val)) {
|
|
int len = 0;
|
|
JSValue len_val = JS_GetPropertyStr(js, vb_val, "length");
|
|
JS_ToInt32(js, &len, len_val);
|
|
JS_FreeValue(js, len_val);
|
|
|
|
for (int i = 0; i < len && i < SG_MAX_VERTEXBUFFER_BINDSLOTS; i++) {
|
|
JSValue vb = JS_GetPropertyUint32(js, vb_val, i);
|
|
if (JS_IsNumber(vb)) {
|
|
bind.vertex_buffers[i].id = js2number(js, vb);
|
|
} else if (JS_IsObject(vb)) {
|
|
JSValue buf_val = JS_GetPropertyStr(js, vb, "buffer");
|
|
bind.vertex_buffers[i].id = js2number(js, buf_val);
|
|
JS_FreeValue(js, buf_val);
|
|
JS_GETPROP(js, bind.vertex_buffer_offsets[i], vb, offset, number);
|
|
}
|
|
JS_FreeValue(js, vb);
|
|
}
|
|
}
|
|
JS_FreeValue(js, vb_val);
|
|
|
|
// Index buffer
|
|
JSValue ib_val = JS_GetPropertyStr(js, cfg, "index_buffer");
|
|
if (JS_IsNumber(ib_val)) {
|
|
bind.index_buffer.id = js2number(js, ib_val);
|
|
} else if (JS_IsObject(ib_val)) {
|
|
JSValue buf_val = JS_GetPropertyStr(js, ib_val, "buffer");
|
|
bind.index_buffer.id = js2number(js, buf_val);
|
|
JS_FreeValue(js, buf_val);
|
|
JS_GETPROP(js, bind.index_buffer_offset, ib_val, offset, number);
|
|
}
|
|
JS_FreeValue(js, ib_val);
|
|
|
|
// Samplers
|
|
JSValue smp_val = JS_GetPropertyStr(js, cfg, "samplers");
|
|
if (JS_IsArray(js, smp_val)) {
|
|
int len = 0;
|
|
JSValue len_val = JS_GetPropertyStr(js, smp_val, "length");
|
|
JS_ToInt32(js, &len, len_val);
|
|
JS_FreeValue(js, len_val);
|
|
|
|
for (int i = 0; i < len && i < SG_MAX_SAMPLER_BINDSLOTS; i++) {
|
|
JSValue s = JS_GetPropertyUint32(js, smp_val, i);
|
|
bind.samplers[i].id = js2number(js, s);
|
|
JS_FreeValue(js, s);
|
|
}
|
|
}
|
|
JS_FreeValue(js, smp_val);
|
|
|
|
sg_apply_bindings(&bind);
|
|
)
|
|
|
|
// gfx.apply_uniforms(stage, slot, data)
|
|
// stage: "vertex" or "fragment"
|
|
JSC_CCALL(gfx_apply_uniforms,
|
|
int slot = js2number(js, argv[0]);
|
|
|
|
size_t data_size;
|
|
void *data_ptr = js_get_blob_data(js, &data_size, argv[1]);
|
|
if (data_ptr && data_ptr != (void*)-1) {
|
|
sg_apply_uniforms(slot, &(sg_range){ .ptr = data_ptr, .size = data_size });
|
|
}
|
|
)
|
|
|
|
// gfx.apply_viewport(x, y, w, h, origin_top_left)
|
|
JSC_CCALL(gfx_apply_viewport,
|
|
int x = js2number(js, argv[0]);
|
|
int y = js2number(js, argv[1]);
|
|
int w = js2number(js, argv[2]);
|
|
int h = js2number(js, argv[3]);
|
|
int origin_top_left = argc > 4 ? js2bool(js, argv[4]) : true;
|
|
sg_apply_viewport(x, y, w, h, origin_top_left);
|
|
)
|
|
|
|
// gfx.apply_scissor_rect(x, y, w, h, origin_top_left)
|
|
JSC_CCALL(gfx_apply_scissor_rect,
|
|
int x = js2number(js, argv[0]);
|
|
int y = js2number(js, argv[1]);
|
|
int w = js2number(js, argv[2]);
|
|
int h = js2number(js, argv[3]);
|
|
int origin_top_left = argc > 4 ? js2bool(js, argv[4]) : true;
|
|
sg_apply_scissor_rect(x, y, w, h, origin_top_left);
|
|
)
|
|
|
|
// gfx.draw(base_element, num_elements, num_instances)
|
|
JSC_CCALL(gfx_draw,
|
|
int base = js2number(js, argv[0]);
|
|
int num = js2number(js, argv[1]);
|
|
int instances = argc > 2 ? js2number(js, argv[2]) : 1;
|
|
sg_draw(base, num, instances);
|
|
)
|
|
|
|
// gfx.dispatch(x, y, z) - For compute passes
|
|
JSC_CCALL(gfx_dispatch,
|
|
int x = js2number(js, argv[0]);
|
|
int y = argc > 1 ? js2number(js, argv[1]) : 1;
|
|
int z = argc > 2 ? js2number(js, argv[2]) : 1;
|
|
sg_dispatch(x, y, z);
|
|
)
|
|
|
|
// ============================================================================
|
|
// QUERY
|
|
// ============================================================================
|
|
|
|
// gfx.query_features() -> object
|
|
JSC_CCALL(gfx_query_features,
|
|
sg_features f = sg_query_features();
|
|
JSValue obj = JS_NewObject(js);
|
|
JS_SetPropertyStr(js, obj, "origin_top_left", JS_NewBool(js, f.origin_top_left));
|
|
JS_SetPropertyStr(js, obj, "image_clamp_to_border", JS_NewBool(js, f.image_clamp_to_border));
|
|
JS_SetPropertyStr(js, obj, "mrt_independent_blend_state", JS_NewBool(js, f.mrt_independent_blend_state));
|
|
JS_SetPropertyStr(js, obj, "mrt_independent_write_mask", JS_NewBool(js, f.mrt_independent_write_mask));
|
|
JS_SetPropertyStr(js, obj, "compute", JS_NewBool(js, f.compute));
|
|
return obj;
|
|
)
|
|
|
|
// gfx.query_limits() -> object
|
|
JSC_CCALL(gfx_query_limits,
|
|
sg_limits l = sg_query_limits();
|
|
JSValue obj = JS_NewObject(js);
|
|
JS_SetPropertyStr(js, obj, "max_image_size_2d", JS_NewInt32(js, l.max_image_size_2d));
|
|
JS_SetPropertyStr(js, obj, "max_image_size_cube", JS_NewInt32(js, l.max_image_size_cube));
|
|
JS_SetPropertyStr(js, obj, "max_image_size_3d", JS_NewInt32(js, l.max_image_size_3d));
|
|
JS_SetPropertyStr(js, obj, "max_image_size_array", JS_NewInt32(js, l.max_image_size_array));
|
|
JS_SetPropertyStr(js, obj, "max_image_array_layers", JS_NewInt32(js, l.max_image_array_layers));
|
|
JS_SetPropertyStr(js, obj, "max_vertex_attrs", JS_NewInt32(js, l.max_vertex_attrs));
|
|
return obj;
|
|
)
|
|
|
|
// ============================================================================
|
|
// MODULE INIT
|
|
// ============================================================================
|
|
|
|
static const JSCFunctionListEntry js_gfx_funcs[] = {
|
|
JS_CFUNC_DEF("setup", 1, js_gfx_setup),
|
|
JS_CFUNC_DEF("shutdown", 0, js_gfx_shutdown),
|
|
JS_CFUNC_DEF("is_valid", 0, js_gfx_is_valid),
|
|
JS_CFUNC_DEF("backend", 0, js_gfx_backend),
|
|
JS_CFUNC_DEF("commit", 0, js_gfx_commit),
|
|
JS_CFUNC_DEF("reset_state_cache", 0, js_gfx_reset_state_cache),
|
|
|
|
JS_CFUNC_DEF("make_buffer", 1, js_gfx_make_buffer),
|
|
JS_CFUNC_DEF("destroy_buffer", 1, js_gfx_destroy_buffer),
|
|
JS_CFUNC_DEF("update_buffer", 2, js_gfx_update_buffer),
|
|
JS_CFUNC_DEF("append_buffer", 2, js_gfx_append_buffer),
|
|
|
|
JS_CFUNC_DEF("make_image", 1, js_gfx_make_image),
|
|
JS_CFUNC_DEF("destroy_image", 1, js_gfx_destroy_image),
|
|
JS_CFUNC_DEF("update_image", 2, js_gfx_update_image),
|
|
|
|
JS_CFUNC_DEF("make_sampler", 1, js_gfx_make_sampler),
|
|
JS_CFUNC_DEF("destroy_sampler", 1, js_gfx_destroy_sampler),
|
|
|
|
JS_CFUNC_DEF("make_shader", 1, js_gfx_make_shader),
|
|
JS_CFUNC_DEF("destroy_shader", 1, js_gfx_destroy_shader),
|
|
|
|
JS_CFUNC_DEF("make_pipeline", 1, js_gfx_make_pipeline),
|
|
JS_CFUNC_DEF("destroy_pipeline", 1, js_gfx_destroy_pipeline),
|
|
|
|
JS_CFUNC_DEF("begin_pass", 1, js_gfx_begin_pass),
|
|
JS_CFUNC_DEF("end_pass", 0, js_gfx_end_pass),
|
|
JS_CFUNC_DEF("apply_pipeline", 1, js_gfx_apply_pipeline),
|
|
JS_CFUNC_DEF("apply_bindings", 1, js_gfx_apply_bindings),
|
|
JS_CFUNC_DEF("apply_uniforms", 2, js_gfx_apply_uniforms),
|
|
JS_CFUNC_DEF("apply_viewport", 5, js_gfx_apply_viewport),
|
|
JS_CFUNC_DEF("apply_scissor_rect", 5, js_gfx_apply_scissor_rect),
|
|
JS_CFUNC_DEF("draw", 3, js_gfx_draw),
|
|
JS_CFUNC_DEF("dispatch", 3, js_gfx_dispatch),
|
|
|
|
JS_CFUNC_DEF("query_features", 0, js_gfx_query_features),
|
|
JS_CFUNC_DEF("query_limits", 0, js_gfx_query_limits),
|
|
};
|
|
|
|
CELL_USE_INIT(
|
|
JSValue gfx = JS_NewObject(js);
|
|
JS_SetPropertyFunctionList(js, gfx, js_gfx_funcs, sizeof(js_gfx_funcs)/sizeof(js_gfx_funcs[0]));
|
|
return gfx;
|
|
) |