mirror of https://github.com/mode777/rayjs.git
				
				
				
			update binding generator
This commit is contained in:
		
							parent
							
								
									fd97c55510
								
							
						
					
					
						commit
						bdba35dda4
					
				|  | @ -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" | ||||
|     } | ||||
| } | ||||
|  | @ -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") | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -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> { | ||||
|  |  | |||
|  | @ -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) | ||||
|     } | ||||
|  |  | |||
|  | @ -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; | ||||
|             default: | ||||
|                 throw new Error("Cannot handle parameter type: " + type); | ||||
|         } | ||||
|     } | ||||
|     jsToJs(type, name, src) { | ||||
|         this.inline(`JSValue ${name}`); | ||||
|         switch (type) { | ||||
|             case "int": | ||||
|                 this.statement(` = JS_NewInt32(ctx, ${src})`); | ||||
|             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, classIds = {}) { | ||||
|         switch (type) { | ||||
|             case "int": | ||||
|             case "unsigned char": | ||||
|                 this.declare(name, 'JSValue', false, `JS_NewInt32(ctx, ${src})`); | ||||
|                 break; | ||||
|             default: | ||||
|                 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
								
								
								
								
							
							
						
						
									
										14
									
								
								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) | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -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; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -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) { | ||||
|  |  | |||
|  | @ -1 +1 @@ | |||
| Subproject commit 5573f0f1c7b29bfe46d0b70487e4adb4d01cba62 | ||||
| Subproject commit a48bb6e1ed7b33190e486ba65b7875f0dff73701 | ||||
		Loading…
	
		Reference in New Issue