diff --git a/.vscode/settings.json b/.vscode/settings.json index 886f134..c21d077 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -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" } } \ No newline at end of file diff --git a/bindings/src/index.ts b/bindings/src/index.ts index 75ff659..134624b 100644 --- a/bindings/src/index.ts +++ b/bindings/src/index.ts @@ -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") } diff --git a/bindings/src/quickjs.ts b/bindings/src/quickjs.ts index a8bd423..eff9e43 100644 --- a/bindings/src/quickjs.ts +++ b/bindings/src/quickjs.ts @@ -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 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 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(cond, "ptr") cond.call("js_free_rt", ["rt","ptr"]) }) @@ -173,6 +193,19 @@ export abstract class GenericQuickJsGenerator 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 { diff --git a/bindings/src/raylib-header.ts b/bindings/src/raylib-header.ts index 2f96fc2..2c1af86 100644 --- a/bindings/src/raylib-header.ts +++ b/bindings/src/raylib-header.ts @@ -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) } diff --git a/generate-bindings.js b/generate-bindings.js index a25ac9f..773203d 100644 --- a/generate-bindings.js +++ b/generate-bindings.js @@ -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(); diff --git a/main.js b/main.js index a4b5f8a..f692f04 100644 --- a/main.js +++ b/main.js @@ -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) diff --git a/src/bindings/js_raylib_core.h b/src/bindings/js_raylib_core.h index 4178152..1b9933c 100644 --- a/src/bindings/js_raylib_core.h +++ b/src/bindings/js_raylib_core.h @@ -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; } diff --git a/src/bindings/js_raylib_texture.h b/src/bindings/js_raylib_texture.h index 553b511..d228a4a 100644 --- a/src/bindings/js_raylib_texture.h +++ b/src/bindings/js_raylib_texture.h @@ -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) { diff --git a/thirdparty/raylib b/thirdparty/raylib index 5573f0f..a48bb6e 160000 --- a/thirdparty/raylib +++ b/thirdparty/raylib @@ -1 +1 @@ -Subproject commit 5573f0f1c7b29bfe46d0b70487e4adb4d01cba62 +Subproject commit a48bb6e1ed7b33190e486ba65b7875f0dff73701