update binding generator

This commit is contained in:
Alexander Klingenbeck 2023-05-08 23:37:58 +02:00
parent fd97c55510
commit bdba35dda4
9 changed files with 287 additions and 46 deletions

View File

@ -3,6 +3,7 @@
"sdl.h": "c",
"vs.sc.mtl.bin.h": "c",
"embedded_shader.h": "c",
"common.h": "c"
"common.h": "c",
"raylib.h": "c"
}
}

View File

@ -8,6 +8,14 @@ function main(){
const apiDesc = new ApiDescription(api)
const core_gen = new RayLibHeader("raylib_core", apiDesc)
core_gen.addApiStructByName("Color", {
properties: {
r: { get: true, set: true },
g: { get: true, set: true },
b: { get: true, set: true },
a: { get: true, set: true },
}
})
core_gen.addApiFunctionByName("SetWindowTitle")
core_gen.addApiFunctionByName("SetWindowPosition")
core_gen.addApiFunctionByName("BeginDrawing")
@ -15,7 +23,14 @@ function main(){
core_gen.writeTo("src/bindings/js_raylib_core.h")
const texture_gen = new RayLibHeader("raylib_texture", apiDesc)
texture_gen.addApiStructByName("Image", "UnloadImage", { properties: { width: { get: true } } })
texture_gen.addApiStructByName("Image", {
properties: {
width: { get: true },
height: { get: true }
},
destructor: "UnloadImage"
})
texture_gen.addApiFunctionByName("LoadImage")
texture_gen.writeTo("src/bindings/js_raylib_texture.h")
}

View File

@ -2,8 +2,11 @@ import { writeFileSync } from "fs";
import { ApiFunction } from "./api"
import { CodeGenerator, CodeWriter, GenericCodeGenerator } from "./generation"
export type StructLookup = { [struct: string]: string }
export class QuickJsHeader {
public readonly structLookup: StructLookup = {}
public readonly moduleFunctionList: QuickJsGenerator
public readonly structs: QuickJsGenerator
public readonly functions: QuickJsGenerator
@ -48,6 +51,10 @@ export class QuickJsHeader {
moduleEntryFunc.statement("return m")
}
registerStruct(struct: string, classId: string){
this.structLookup[struct] = classId;
}
public writeTo(filename: string){
const writer = new CodeWriter()
writer.writeGenerator(this.root)
@ -70,32 +77,45 @@ export abstract class GenericQuickJsGenerator<T extends QuickJsGenerator> extend
}
jsToC(type: string, name: string, src: string){
this.inline(`${type} ${name}`)
switch (type) {
case "const char *":
this.statement(` = JS_ToCString(ctx, ${src})`)
this.statement(`${type} ${name} = JS_ToCString(ctx, ${src})`)
this.statement(`if(${name} == NULL) return JS_EXCEPTION`)
break;
case "int":
this.statement('')
this.statement(`${type} ${name}`)
this.statement(`JS_ToInt32(ctx, &${name}, ${src})`)
break;
case "unsigned char":
this.statement(`int _tmp`)
this.statement(`JS_ToInt32(ctx, &_tmp, ${src})`)
this.statement(`${type} ${name} = (${type})_tmp`)
break;
default:
throw new Error("Cannot handle parameter type: " + type)
}
}
jsToJs(type: string, name: string, src: string){
this.inline(`JSValue ${name}`)
jsToJs(type: string, name: string, src: string, classIds: StructLookup = {}){
switch (type) {
case "int":
this.statement(` = JS_NewInt32(ctx, ${src})`)
case "unsigned char":
this.declare(name,'JSValue', false, `JS_NewInt32(ctx, ${src})`)
break;
default:
throw new Error("Cannot handle parameter type: " + type)
const classId = classIds[type]
if(!classId) throw new Error("Cannot handle parameter type: " + type)
this.jsStructToOpq(type, name, src, classId)
}
}
jsStructToOpq(structType: string, jsVar: string, srcVar: string, classId: string){
this.declare("ptr", structType+"*", false, `(${structType}*)js_malloc(ctx, sizeof(${structType}))`)
this.statement("*ptr = " + srcVar)
this.declare(jsVar, "JSValue", false, `JS_NewObjectClass(ctx, ${classId})`)
this.call("JS_SetOpaque", [jsVar, "ptr"])
}
jsCleanUpParameter(type: string, name: string) {
switch (type) {
case "const char *":
@ -141,7 +161,7 @@ export abstract class GenericQuickJsGenerator<T extends QuickJsGenerator> extend
const body = this.function(`js_${structName}_finalizer`, "void", args, true)
body.statement(`${structName}* ptr = JS_GetOpaque(val, ${classId})`)
body.if("ptr", cond => {
cond.call("puts", ["\"Finalize "+structName+"\""])
cond.call("TraceLog", ["LOG_INFO",`"Finalize ${structName}"`])
if(onFinalize) onFinalize(<T>cond, "ptr")
cond.call("js_free_rt", ["rt","ptr"])
})
@ -173,6 +193,19 @@ export abstract class GenericQuickJsGenerator<T extends QuickJsGenerator> extend
fun.returnExp("ret")
return fun
}
jsStructSetter(structName: string, classId: string, field: string, type: string){
const args = [{type: "JSContext*", name: "ctx" }, {type: "JSValueConst", name: "this_val"},{type: "JSValueConst", name: "v"}]
const fun = this.function(`js_${structName}_set_${field}`,"JSValue",args,true)
fun.declare("ptr", structName+"*", false, `JS_GetOpaque2(ctx, this_val, ${classId})`)
fun.if("!ptr", cond => {
cond.returnExp("JS_EXCEPTION")
})
fun.jsToC(type, "value", "v");
fun.statement("ptr->"+field+" = value")
fun.returnExp("JS_UNDEFINED")
return fun
}
}
export class QuickJsGenerator extends GenericQuickJsGenerator<QuickJsGenerator> {

View File

@ -3,12 +3,16 @@ import { CodeGenerator } from "./generation"
import { QuickJsHeader } from "./quickjs"
export interface StructBindingOptions {
properties?: { [key:string]: { get?:boolean, set?:boolean } }
properties?: { [key:string]: { get?:boolean, set?:boolean } },
destructor?: string,
construct?: string,
}
export class RayLibHeader extends QuickJsHeader {
constructor(name: string, private api: ApiDescription){
super(name)
this.includes.include("raylib.h")
@ -33,8 +37,8 @@ export class RayLibHeader extends QuickJsHeader {
if(api.returnType === "void"){
fun.statement("return JS_UNDEFINED")
} else {
fun.jsToJs(api.returnType, "ret", "returnVal")
fun.returnExp("returnVal")
fun.jsToJs(api.returnType, "ret", "returnVal", this.structLookup)
fun.returnExp("ret")
}
// add binding to function declaration
@ -49,7 +53,7 @@ export class RayLibHeader extends QuickJsHeader {
addApiStruct(struct: ApiStruct, destructor: ApiFunction | null, options?: StructBindingOptions){
const classId = this.declarations.jsClassId(`js_${struct.name}_class_id`)
this.registerStruct(struct.name, classId)
const finalizer = this.structs.jsStructFinalizer(classId, struct.name, (gen,ptr) => destructor && gen.call(destructor.name, ["*"+ptr]))
const propDeclarations = this.structs.createGenerator()
@ -61,26 +65,27 @@ export class RayLibHeader extends QuickJsHeader {
let _get: CodeGenerator | undefined = undefined
let _set: CodeGenerator | undefined = undefined
if(el.get) _get = this.structs.jsStructGetter(struct.name, classId, field, type)
propDeclarations.jsGetSetDef(field, _get?.getTag("_name"), undefined)
if(el.set) _set = this.structs.jsStructSetter(struct.name, classId, field, type)
propDeclarations.jsGetSetDef(field, _get?.getTag("_name"), _set?.getTag("_name"))
}
}
const classFuncList = this.structs.jsFunctionList(`js_${struct.name}_proto_funcs`)
classFuncList.child(propDeclarations)
classFuncList.jsPropStringDef("[Symbol.toStringTag]", "Image")
classFuncList.jsPropStringDef("[Symbol.toStringTag]", struct.name)
const classDecl = this.structs.jsClassDeclaration(struct.name, classId, finalizer.getTag("_name"), classFuncList.getTag("_name"))
this.moduleInit.call(classDecl.getTag("_name"), ["ctx", "m"])
// OPT: 7. expose class and constructor
}
addApiStructByName(structName: string, destructorName: string | null = null, options?: StructBindingOptions){
addApiStructByName(structName: string, options?: StructBindingOptions){
const struct = this.api.getStruct(structName)
if(!struct) throw new Error("Struct not in API: "+ structName)
let destructor: ApiFunction | null = null
if(destructorName !== null){
destructor = this.api.getFunction(destructorName)
if(!destructor) throw new Error("Destructor func not in API: "+ destructorName)
if(options?.destructor){
destructor = this.api.getFunction(options.destructor)
if(!destructor) throw new Error("Destructor func not in API: "+ options.destructor)
}
this.addApiStruct(struct, destructor, options)
}

View File

@ -284,6 +284,7 @@ const generation_1 = __webpack_require__(/*! ./generation */ "./src/generation.t
class QuickJsHeader {
constructor(name) {
this.name = name;
this.structLookup = {};
const root = this.root = new QuickJsGenerator();
const body = this.body = root.header("JS_" + this.name + "_GUARD");
const includes = this.includes = body.child();
@ -314,6 +315,9 @@ class QuickJsHeader {
moduleEntry.statement(`JS_AddModuleExportList(ctx, m, ${this.moduleFunctionList.getTag("_name")}, countof(${this.moduleFunctionList.getTag("_name")}))`);
moduleEntryFunc.statement("return m");
}
registerStruct(struct, classId) {
this.structLookup[struct] = classId;
}
writeTo(filename) {
const writer = new generation_1.CodeWriter();
writer.writeGenerator(this.root);
@ -333,30 +337,43 @@ class GenericQuickJsGenerator extends generation_1.GenericCodeGenerator {
return sub;
}
jsToC(type, name, src) {
this.inline(`${type} ${name}`);
switch (type) {
case "const char *":
this.statement(` = JS_ToCString(ctx, ${src})`);
this.statement(`${type} ${name} = JS_ToCString(ctx, ${src})`);
this.statement(`if(${name} == NULL) return JS_EXCEPTION`);
break;
case "int":
this.statement('');
this.statement(`${type} ${name}`);
this.statement(`JS_ToInt32(ctx, &${name}, ${src})`);
break;
case "unsigned char":
this.statement(`int _tmp`);
this.statement(`JS_ToInt32(ctx, &_tmp, ${src})`);
this.statement(`${type} ${name} = (${type})_tmp`);
break;
default:
throw new Error("Cannot handle parameter type: " + type);
}
}
jsToJs(type, name, src) {
this.inline(`JSValue ${name}`);
jsToJs(type, name, src, classIds = {}) {
switch (type) {
case "int":
this.statement(` = JS_NewInt32(ctx, ${src})`);
case "unsigned char":
this.declare(name, 'JSValue', false, `JS_NewInt32(ctx, ${src})`);
break;
default:
throw new Error("Cannot handle parameter type: " + type);
const classId = classIds[type];
if (!classId)
throw new Error("Cannot handle parameter type: " + type);
this.jsStructToOpq(type, name, src, classId);
}
}
jsStructToOpq(structType, jsVar, srcVar, classId) {
this.declare("ptr", structType + "*", false, `(${structType}*)js_malloc(ctx, sizeof(${structType}))`);
this.statement("*ptr = " + srcVar);
this.declare(jsVar, "JSValue", false, `JS_NewObjectClass(ctx, ${classId})`);
this.call("JS_SetOpaque", [jsVar, "ptr"]);
}
jsCleanUpParameter(type, name) {
switch (type) {
case "const char *":
@ -396,7 +413,7 @@ class GenericQuickJsGenerator extends generation_1.GenericCodeGenerator {
const body = this.function(`js_${structName}_finalizer`, "void", args, true);
body.statement(`${structName}* ptr = JS_GetOpaque(val, ${classId})`);
body.if("ptr", cond => {
cond.call("puts", ["\"Finalize " + structName + "\""]);
cond.call("TraceLog", ["LOG_INFO", `"Finalize ${structName}"`]);
if (onFinalize)
onFinalize(cond, "ptr");
cond.call("js_free_rt", ["rt", "ptr"]);
@ -427,6 +444,18 @@ class GenericQuickJsGenerator extends generation_1.GenericCodeGenerator {
fun.returnExp("ret");
return fun;
}
jsStructSetter(structName, classId, field, type) {
const args = [{ type: "JSContext*", name: "ctx" }, { type: "JSValueConst", name: "this_val" }, { type: "JSValueConst", name: "v" }];
const fun = this.function(`js_${structName}_set_${field}`, "JSValue", args, true);
fun.declare("ptr", structName + "*", false, `JS_GetOpaque2(ctx, this_val, ${classId})`);
fun.if("!ptr", cond => {
cond.returnExp("JS_EXCEPTION");
});
fun.jsToC(type, "value", "v");
fun.statement("ptr->" + field + " = value");
fun.returnExp("JS_UNDEFINED");
return fun;
}
}
exports.GenericQuickJsGenerator = GenericQuickJsGenerator;
class QuickJsGenerator extends GenericQuickJsGenerator {
@ -474,8 +503,8 @@ class RayLibHeader extends quickjs_1.QuickJsHeader {
fun.statement("return JS_UNDEFINED");
}
else {
fun.jsToJs(api.returnType, "ret", "returnVal");
fun.returnExp("returnVal");
fun.jsToJs(api.returnType, "ret", "returnVal", this.structLookup);
fun.returnExp("ret");
}
// add binding to function declaration
this.moduleFunctionList.jsFuncDef(jName, api.argc, fun.getTag("_name"));
@ -488,6 +517,7 @@ class RayLibHeader extends quickjs_1.QuickJsHeader {
}
addApiStruct(struct, destructor, options) {
const classId = this.declarations.jsClassId(`js_${struct.name}_class_id`);
this.registerStruct(struct.name, classId);
const finalizer = this.structs.jsStructFinalizer(classId, struct.name, (gen, ptr) => destructor && gen.call(destructor.name, ["*" + ptr]));
const propDeclarations = this.structs.createGenerator();
if (options && options.properties) {
@ -500,25 +530,27 @@ class RayLibHeader extends quickjs_1.QuickJsHeader {
let _set = undefined;
if (el.get)
_get = this.structs.jsStructGetter(struct.name, classId, field, type);
propDeclarations.jsGetSetDef(field, _get?.getTag("_name"), undefined);
if (el.set)
_set = this.structs.jsStructSetter(struct.name, classId, field, type);
propDeclarations.jsGetSetDef(field, _get?.getTag("_name"), _set?.getTag("_name"));
}
}
const classFuncList = this.structs.jsFunctionList(`js_${struct.name}_proto_funcs`);
classFuncList.child(propDeclarations);
classFuncList.jsPropStringDef("[Symbol.toStringTag]", "Image");
classFuncList.jsPropStringDef("[Symbol.toStringTag]", struct.name);
const classDecl = this.structs.jsClassDeclaration(struct.name, classId, finalizer.getTag("_name"), classFuncList.getTag("_name"));
this.moduleInit.call(classDecl.getTag("_name"), ["ctx", "m"]);
// OPT: 7. expose class and constructor
}
addApiStructByName(structName, destructorName = null, options) {
addApiStructByName(structName, options) {
const struct = this.api.getStruct(structName);
if (!struct)
throw new Error("Struct not in API: " + structName);
let destructor = null;
if (destructorName !== null) {
destructor = this.api.getFunction(destructorName);
if (options?.destructor) {
destructor = this.api.getFunction(options.destructor);
if (!destructor)
throw new Error("Destructor func not in API: " + destructorName);
throw new Error("Destructor func not in API: " + options.destructor);
}
this.addApiStruct(struct, destructor, options);
}
@ -581,13 +613,28 @@ function main() {
const api = JSON.parse((0, fs_1.readFileSync)("thirdparty/raylib/parser/output/raylib_api.json", 'utf8'));
const apiDesc = new api_1.ApiDescription(api);
const core_gen = new raylib_header_1.RayLibHeader("raylib_core", apiDesc);
core_gen.addApiStructByName("Color", {
properties: {
r: { get: true, set: true },
g: { get: true, set: true },
b: { get: true, set: true },
a: { get: true, set: true },
}
});
core_gen.addApiFunctionByName("SetWindowTitle");
core_gen.addApiFunctionByName("SetWindowPosition");
core_gen.addApiFunctionByName("BeginDrawing");
core_gen.addApiFunctionByName("EndDrawing");
core_gen.writeTo("src/bindings/js_raylib_core.h");
const texture_gen = new raylib_header_1.RayLibHeader("raylib_texture", apiDesc);
texture_gen.addApiStructByName("Image", "UnloadImage", { properties: { width: { get: true } } });
texture_gen.addApiStructByName("Image", {
properties: {
width: { get: true },
height: { get: true }
},
destructor: "UnloadImage"
});
texture_gen.addApiFunctionByName("LoadImage");
texture_gen.writeTo("src/bindings/js_raylib_texture.h");
}
main();

14
main.js
View File

@ -1,15 +1,15 @@
import { setWindowTitle, setWindowPosition } from "raylib.core"
import { loadImage, Image } from "raylib.texture"
import { loadImage } from "raylib.texture"
import { gc } from "std"
console.log(loadImage("assets/planet00.png"))
const img = new Image("assets/planet00.png")
gc()
const img = loadImage("assets/planet00.png")
console.log(img.width)
//const img = new Image("assets/planet00.png")
gc()
setWindowTitle("My Window")
setWindowPosition(1920,50)
setWindowPosition(20,50)

View File

@ -12,6 +12,121 @@
#define countof(x) (sizeof(x) / sizeof((x)[0]))
#endif
static JSClassID js_Color_class_id;
static void js_Color_finalizer(JSRuntime * rt, JSValue val) {
Color* ptr = JS_GetOpaque(val, js_Color_class_id);
if(ptr) {
TraceLog(LOG_INFO, "Finalize Color");
js_free_rt(rt, ptr);
}
}
static JSValue js_Color_get_r(JSContext* ctx, JSValueConst this_val) {
Color* ptr = JS_GetOpaque2(ctx, this_val, js_Color_class_id);
if(!ptr) {
return JS_EXCEPTION;
}
unsigned char r = ptr->r;
JSValue ret = JS_NewInt32(ctx, r);
return ret;
}
static JSValue js_Color_set_r(JSContext* ctx, JSValueConst this_val, JSValueConst v) {
Color* ptr = JS_GetOpaque2(ctx, this_val, js_Color_class_id);
if(!ptr) {
return JS_EXCEPTION;
}
int _tmp;
JS_ToInt32(ctx, &_tmp, v);
unsigned char value = (unsigned char)_tmp;
ptr->r = value;
return JS_UNDEFINED;
}
static JSValue js_Color_get_g(JSContext* ctx, JSValueConst this_val) {
Color* ptr = JS_GetOpaque2(ctx, this_val, js_Color_class_id);
if(!ptr) {
return JS_EXCEPTION;
}
unsigned char g = ptr->g;
JSValue ret = JS_NewInt32(ctx, g);
return ret;
}
static JSValue js_Color_set_g(JSContext* ctx, JSValueConst this_val, JSValueConst v) {
Color* ptr = JS_GetOpaque2(ctx, this_val, js_Color_class_id);
if(!ptr) {
return JS_EXCEPTION;
}
int _tmp;
JS_ToInt32(ctx, &_tmp, v);
unsigned char value = (unsigned char)_tmp;
ptr->g = value;
return JS_UNDEFINED;
}
static JSValue js_Color_get_b(JSContext* ctx, JSValueConst this_val) {
Color* ptr = JS_GetOpaque2(ctx, this_val, js_Color_class_id);
if(!ptr) {
return JS_EXCEPTION;
}
unsigned char b = ptr->b;
JSValue ret = JS_NewInt32(ctx, b);
return ret;
}
static JSValue js_Color_set_b(JSContext* ctx, JSValueConst this_val, JSValueConst v) {
Color* ptr = JS_GetOpaque2(ctx, this_val, js_Color_class_id);
if(!ptr) {
return JS_EXCEPTION;
}
int _tmp;
JS_ToInt32(ctx, &_tmp, v);
unsigned char value = (unsigned char)_tmp;
ptr->b = value;
return JS_UNDEFINED;
}
static JSValue js_Color_get_a(JSContext* ctx, JSValueConst this_val) {
Color* ptr = JS_GetOpaque2(ctx, this_val, js_Color_class_id);
if(!ptr) {
return JS_EXCEPTION;
}
unsigned char a = ptr->a;
JSValue ret = JS_NewInt32(ctx, a);
return ret;
}
static JSValue js_Color_set_a(JSContext* ctx, JSValueConst this_val, JSValueConst v) {
Color* ptr = JS_GetOpaque2(ctx, this_val, js_Color_class_id);
if(!ptr) {
return JS_EXCEPTION;
}
int _tmp;
JS_ToInt32(ctx, &_tmp, v);
unsigned char value = (unsigned char)_tmp;
ptr->a = value;
return JS_UNDEFINED;
}
static const JSCFunctionListEntry js_Color_proto_funcs[] = {
JS_CGETSET_DEF("r",js_Color_get_r,js_Color_set_r),
JS_CGETSET_DEF("g",js_Color_get_g,js_Color_set_g),
JS_CGETSET_DEF("b",js_Color_get_b,js_Color_set_b),
JS_CGETSET_DEF("a",js_Color_get_a,js_Color_set_a),
JS_PROP_STRING_DEF("[Symbol.toStringTag]","Color", JS_PROP_CONFIGURABLE),
};
static int js_declare_Color(JSContext * ctx, JSModuleDef * m) {
JS_NewClassID(&js_Color_class_id);
JSClassDef js_Color_def = { .class_name = "Color", .finalizer = js_Color_finalizer };
JS_NewClass(JS_GetRuntime(ctx), js_Color_class_id, &js_Color_def);
JSValue proto = JS_NewObject(ctx);
JS_SetPropertyFunctionList(ctx, proto, js_Color_proto_funcs, countof(js_Color_proto_funcs));
JS_SetClassProto(ctx, js_Color_class_id, proto);
return 0;
}
static JSValue js_setWindowTitle(JSContext * ctx, JSValueConst this_val, int argc, JSValueConst * argv) {
const char * title = JS_ToCString(ctx, argv[0]);
@ -49,6 +164,7 @@ static const JSCFunctionListEntry js_raylib_core_funcs[] = {
static int js_raylib_core_init(JSContext * ctx, JSModuleDef * m) {
JS_SetModuleExportList(ctx, m,js_raylib_core_funcs,countof(js_raylib_core_funcs));
js_declare_Color(ctx, m);
return 0;
}

View File

@ -17,7 +17,7 @@ static JSClassID js_Image_class_id;
static void js_Image_finalizer(JSRuntime * rt, JSValue val) {
Image* ptr = JS_GetOpaque(val, js_Image_class_id);
if(ptr) {
puts("Finalize Image");
TraceLog(LOG_INFO, "Finalize Image");
UnloadImage(*ptr);
js_free_rt(rt, ptr);
}
@ -33,8 +33,19 @@ static JSValue js_Image_get_width(JSContext* ctx, JSValueConst this_val) {
return ret;
}
static JSValue js_Image_get_height(JSContext* ctx, JSValueConst this_val) {
Image* ptr = JS_GetOpaque2(ctx, this_val, js_Image_class_id);
if(!ptr) {
return JS_EXCEPTION;
}
int height = ptr->height;
JSValue ret = JS_NewInt32(ctx, height);
return ret;
}
static const JSCFunctionListEntry js_Image_proto_funcs[] = {
JS_CGETSET_DEF("width",js_Image_get_width,NULL),
JS_CGETSET_DEF("height",js_Image_get_height,NULL),
JS_PROP_STRING_DEF("[Symbol.toStringTag]","Image", JS_PROP_CONFIGURABLE),
};
@ -48,7 +59,20 @@ static int js_declare_Image(JSContext * ctx, JSModuleDef * m) {
return 0;
}
static JSValue js_loadImage(JSContext * ctx, JSValueConst this_val, int argc, JSValueConst * argv) {
const char * fileName = JS_ToCString(ctx, argv[0]);
if(fileName == NULL) return JS_EXCEPTION;
Image returnVal = LoadImage(fileName);
JS_FreeCString(ctx, fileName);
Image* ptr = (Image*)js_malloc(ctx, sizeof(Image));
*ptr = returnVal;
JSValue ret = JS_NewObjectClass(ctx, js_Image_class_id);
JS_SetOpaque(ret, ptr);
return ret;
}
static const JSCFunctionListEntry js_raylib_texture_funcs[] = {
JS_CFUNC_DEF("loadImage",1,js_loadImage),
};
static int js_raylib_texture_init(JSContext * ctx, JSModuleDef * m) {

2
thirdparty/raylib vendored

@ -1 +1 @@
Subproject commit 5573f0f1c7b29bfe46d0b70487e4adb4d01cba62
Subproject commit a48bb6e1ed7b33190e486ba65b7875f0dff73701