From 277a85f5273dd897bbfcf6d7fbe64253cb01d17a Mon Sep 17 00:00:00 2001 From: Alexander Klingenbeck Date: Wed, 10 May 2023 23:26:53 +0200 Subject: [PATCH] more bindings --- bindings.json | 17 -- bindings/src/generation.ts | 5 + bindings/src/index.ts | 18 +- bindings/src/interfaces.ts | 13 -- bindings/src/quickjs.ts | 33 ++- bindings/src/raylib-header.ts | 26 ++- examples/basic_window.js | 33 +++ examples/input_keys.js | 48 ++++ generate-bindings.js | 75 ++++++- generate_bindings.js | 191 ---------------- main.js | 40 +++- my-module.js | 3 - src/bindings/js_raylib_core.h | 362 ++++++++++++++++++++++++++++++- src/bindings/js_raylib_texture.h | 6 +- src/main.c | 62 +++--- src/quickjs.c | 41 ++-- 16 files changed, 658 insertions(+), 315 deletions(-) delete mode 100644 bindings.json create mode 100644 examples/basic_window.js create mode 100644 examples/input_keys.js delete mode 100644 generate_bindings.js delete mode 100644 my-module.js diff --git a/bindings.json b/bindings.json deleted file mode 100644 index 290f883..0000000 --- a/bindings.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "headers": [ - { - "name": "raylib_core", - "functions": [ - { "name": "SetWindowTitle" }, - { "name": "SetWindowPosition" }, - { "name": "BeginDrawing" }, - { "name": "EndDrawing" } - ] - }, - { - "name": "raylib_texture", - "functions": [] - } - ] -} diff --git a/bindings/src/generation.ts b/bindings/src/generation.ts index 253c9e4..8b05651 100644 --- a/bindings/src/generation.ts +++ b/bindings/src/generation.ts @@ -214,6 +214,11 @@ export abstract class GenericCodeGenerator { if(fun) fun(sub) return sub } + + public declareStruct(structName: string, varName: string, values: string[], isStatic: boolean = false){ + if(isStatic) this.inline("static ") + this.statement(`${structName} ${varName} = { ${values.join(', ')} }`) + } } export class CodeGenerator extends GenericCodeGenerator{ diff --git a/bindings/src/index.ts b/bindings/src/index.ts index 43c4329..632c6f6 100644 --- a/bindings/src/index.ts +++ b/bindings/src/index.ts @@ -1,5 +1,5 @@ import { readFileSync, writeFileSync } from "fs"; -import { Bindings, RayLibApi } from "./interfaces"; +import { RayLibApi } from "./interfaces"; import { ApiDescription } from "./api"; import { RayLibHeader } from "./raylib-header"; @@ -17,12 +17,28 @@ function main(){ }, createConstructor: true }) + core_gen.addApiStructByName("Vector2", { + properties: { + x: { get: true, set: true }, + y: { get: true, set: true }, + }, + createConstructor: true + }) core_gen.addApiFunctionByName("SetWindowTitle") core_gen.addApiFunctionByName("SetWindowPosition") core_gen.addApiFunctionByName("BeginDrawing") core_gen.addApiFunctionByName("EndDrawing") + core_gen.addApiFunctionByName("InitWindow") + core_gen.addApiFunctionByName("SetTargetFPS") + core_gen.addApiFunctionByName("WindowShouldClose", null, { before: fun => fun.call("app_update_quickjs", []) }) core_gen.addApiFunctionByName("ClearBackground") + core_gen.addApiFunctionByName("CloseWindow") core_gen.addApiFunctionByName("DrawText") + core_gen.addApiFunctionByName("DrawCircleV") + core_gen.addApiFunctionByName("IsKeyDown") + api.defines.filter(x => x.type === "COLOR").map(x => ({ name: x.name, values: (x.value.match(/\{([^}]+)\}/) || "")[1].split(',').map(x => x.trim()) })).forEach(x => { + core_gen.exportGlobalStruct("Color", x.name, x.values) + }) core_gen.writeTo("src/bindings/js_raylib_core.h") const texture_gen = new RayLibHeader("raylib_texture", apiDesc) diff --git a/bindings/src/interfaces.ts b/bindings/src/interfaces.ts index 8060a68..60b82a2 100644 --- a/bindings/src/interfaces.ts +++ b/bindings/src/interfaces.ts @@ -48,17 +48,4 @@ export interface RayLibApi { structs: RayLibStruct[], enums: RayLibEnum[], functions: RayLibFunction[] -} - -export interface BindingFunction { - name: string -} - -export interface BindingHeader { - name: string, - functions: BindingFunction[], -} - -export interface Bindings { - headers: BindingHeader } \ No newline at end of file diff --git a/bindings/src/quickjs.ts b/bindings/src/quickjs.ts index 8a37c3e..336ea72 100644 --- a/bindings/src/quickjs.ts +++ b/bindings/src/quickjs.ts @@ -76,12 +76,17 @@ export abstract class GenericQuickJsGenerator extend return sub } - jsToC(type: string, name: string, src: string){ + jsToC(type: string, name: string, src: string, classIds: StructLookup = {}){ switch (type) { case "const char *": this.statement(`${type} ${name} = JS_ToCString(ctx, ${src})`) this.statement(`if(${name} == NULL) return JS_EXCEPTION`) break; + case "float": + this.statement("double _double_"+name) + this.statement(`JS_ToFloat64(ctx, &_double_${name}, ${src})`) + this.statement(`${type} ${name} = (${type})_double_${name}`) + break; case "int": this.statement(`${type} ${name}`) this.statement(`JS_ToInt32(ctx, &${name}, ${src})`) @@ -92,7 +97,11 @@ export abstract class GenericQuickJsGenerator extend this.statement(`${type} ${name} = (${type})_int_${name}`) break; default: - throw new Error("Cannot handle parameter type: " + type) + const classId = classIds[type] + if(!classId) throw new Error("Cannot convert into parameter type: " + type) + this.jsOpqToStructPtr(type, name+"_ptr", src, classId) + this.statement(`if(${name}_ptr == NULL) return JS_EXCEPTION`) + this.declare(name, type, false, `*${name}_ptr`) } } @@ -102,18 +111,24 @@ export abstract class GenericQuickJsGenerator extend case "unsigned char": this.declare(name,'JSValue', false, `JS_NewInt32(ctx, ${src})`) break; + case "bool": + this.declare(name, 'JSValue', false, `JS_NewBool(ctx, ${src})`) + break; + case "float": + this.declare(name, 'JSValue', false, `JS_NewFloat64(ctx, ${src})`) + break; default: const classId = classIds[type] - if(!classId) throw new Error("Cannot handle parameter type: " + type) + if(!classId) throw new Error("Cannot convert parameter type to Javascript: " + 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+"_ptr", structType+"*", false, `(${structType}*)js_malloc(ctx, sizeof(${structType}))`) + this.statement("*"+jsVar+"_ptr = " + srcVar) this.declare(jsVar, "JSValue", false, `JS_NewObjectClass(ctx, ${classId})`) - this.call("JS_SetOpaque", [jsVar, "ptr"]) + this.call("JS_SetOpaque", [jsVar, jsVar+"_ptr"]) } jsCleanUpParameter(type: string, name: string) { @@ -207,13 +222,17 @@ export abstract class GenericQuickJsGenerator extend return fun } + jsOpqToStructPtr(structType: string, structVar: string, srcVar: string, classId: string){ + this.declare(structVar, structType+"*", false, `(${structType}*)JS_GetOpaque2(ctx, ${srcVar}, ${classId})`) + } + jsStructConstructor(structName: string, fields: FunctionArgument[], classId: string){ const body = this.jsBindingFunction(structName + "_constructor") for (let i = 0; i < fields.length; i++) { const para = fields[i] body.jsToC(para.type,para.name,"argv["+i+"]") } - body.statement(`${structName} _struct = { ${fields.map(x => x.name).join(', ')} }`) + body.declareStruct(structName, "_struct", fields.map(x => x.name)) body.jsStructToOpq(structName,"_return","_struct", classId) body.returnExp("_return") return body diff --git a/bindings/src/raylib-header.ts b/bindings/src/raylib-header.ts index 07feccb..b22bd9c 100644 --- a/bindings/src/raylib-header.ts +++ b/bindings/src/raylib-header.ts @@ -1,6 +1,6 @@ import { ApiDescription, ApiFunction, ApiStruct } from "./api" import { CodeGenerator } from "./generation" -import { QuickJsHeader } from "./quickjs" +import { QuickJsGenerator, QuickJsHeader } from "./quickjs" export interface StructBindingOptions { properties?: { [key:string]: { get?:boolean, set?:boolean } }, @@ -9,6 +9,11 @@ export interface StructBindingOptions { createConstructor?: boolean } +export interface FuncBindingOptions { + before?: (gen: QuickJsGenerator) => void + after?: (gen: QuickJsGenerator) => void +} + export class RayLibHeader extends QuickJsHeader { @@ -17,14 +22,15 @@ export class RayLibHeader extends QuickJsHeader { this.includes.include("raylib.h") } - addApiFunction(api: ApiFunction, jsName: string | null = null){ + addApiFunction(api: ApiFunction, jsName: string | null = null, options: FuncBindingOptions = {}){ const jName = jsName || api.name.charAt(0).toLowerCase() + api.name.slice(1) const fun = this.functions.jsBindingFunction(jName) + if(options.before) options.before(fun) // read parameters for (let i = 0; i < api.params.length; i++) { const para = api.params[i] - fun.jsToC(para.type,para.name,"argv["+i+"]") + fun.jsToC(para.type,para.name,"argv["+i+"]", this.structLookup) } // call c function fun.call(api.name, api.params.map(x => x.name), api.returnType === "void" ? null : {type: api.returnType, name: "returnVal"}) @@ -32,6 +38,7 @@ export class RayLibHeader extends QuickJsHeader { for (const param of api.params) { fun.jsCleanUpParameter(param.type, param.name) } + if(options.after) options.after(fun) // return result if(api.returnType === "void"){ fun.statement("return JS_UNDEFINED") @@ -44,10 +51,10 @@ export class RayLibHeader extends QuickJsHeader { this.moduleFunctionList.jsFuncDef(jName, api.argc, fun.getTag("_name")) } - addApiFunctionByName(name: string, jsName: string | null = null){ + addApiFunctionByName(name: string, jsName: string | null = null, options: FuncBindingOptions = {}){ const func = this.api.getFunction(name) if(func === null) throw new Error("Function not in API: " + name) - this.addApiFunction(func, jsName) + this.addApiFunction(func, jsName, options) } addApiStruct(struct: ApiStruct, destructor: ApiFunction | null, options?: StructBindingOptions){ @@ -86,6 +93,15 @@ export class RayLibHeader extends QuickJsHeader { } } + exportGlobalStruct(structName: string, exportName: string, values: string[]){ + this.moduleInit.declareStruct(structName,exportName+"_struct", values) + const classId = this.structLookup[structName] + if(!classId) throw new Error("Struct "+structName+" not found in register") + this.moduleInit.jsStructToOpq(structName, exportName+"_js", exportName+"_struct", classId) + this.moduleInit.call("JS_SetModuleExport", ["ctx","m",`"${exportName}"`, exportName+"_js"]) + this.moduleEntry.call("JS_AddModuleExport", ["ctx","m",`"${exportName}"`]) + } + addApiStructByName(structName: string, options?: StructBindingOptions){ const struct = this.api.getStruct(structName) if(!struct) throw new Error("Struct not in API: "+ structName) diff --git a/examples/basic_window.js b/examples/basic_window.js new file mode 100644 index 0000000..0155dd4 --- /dev/null +++ b/examples/basic_window.js @@ -0,0 +1,33 @@ +import * as rlc from "raylib.core" + +// Initialization +//-------------------------------------------------------------------------------------- +const screenWidth = 800; +const screenHeight = 450; + +rlc.initWindow(screenWidth, screenHeight, "raylib [core] example - basic window"); + +rlc.setTargetFPS(60); // Set our game to run at 60 frames-per-second +//-------------------------------------------------------------------------------------- + + +// Main game loop +while (!rlc.windowShouldClose()) // Detect window close button or ESC key +{ + // Update + //---------------------------------------------------------------------------------- + // TODO: Update your variables here + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + rlc.beginDrawing(); + + rlc.clearBackground(rlc.RAYWHITE); + + rlc.drawText("Congrats! You created your first window!", 190, 200, 20, rlc.LIGHTGRAY); + + rlc.endDrawing(); + //---------------------------------------------------------------------------------- +} + diff --git a/examples/input_keys.js b/examples/input_keys.js new file mode 100644 index 0000000..c1bff89 --- /dev/null +++ b/examples/input_keys.js @@ -0,0 +1,48 @@ +import * as rlc from "raylib.core" + +const KEY_RIGHT = 262 // Key: Cursor right +const KEY_LEFT = 263 // Key: Cursor left +const KEY_DOWN = 264 // Key: Cursor down +const KEY_UP = 265 // Key: Cursor up + +// Initialization +//-------------------------------------------------------------------------------------- +const screenWidth = 800; +const screenHeight = 450; + +rlc.initWindow(screenWidth, screenHeight, "raylib [core] example - keyboard input"); + +const ballPosition = new rlc.Vector2(screenWidth/2, screenHeight/2); + +rlc.setTargetFPS(60); // Set our game to run at 60 frames-per-second +//-------------------------------------------------------------------------------------- + +// Main game loop +while (!rlc.windowShouldClose()) // Detect window close button or ESC key +{ + // Update + //---------------------------------------------------------------------------------- + if (rlc.isKeyDown(KEY_RIGHT)) ballPosition.x += 2; + if (rlc.isKeyDown(KEY_LEFT)) ballPosition.x -= 2; + if (rlc.isKeyDown(KEY_UP)) ballPosition.y -= 2; + if (rlc.isKeyDown(KEY_DOWN)) ballPosition.y += 2; + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + rlc.beginDrawing(); + + rlc.clearBackground(rlc.RAYWHITE); + + rlc.drawText("move the ball with arrow keys", 10, 10, 20, rlc.DARKGRAY); + + rlc.drawCircleV(ballPosition, 50, rlc.MAROON); + + rlc.endDrawing(); + //---------------------------------------------------------------------------------- +} + +// De-Initialization +//-------------------------------------------------------------------------------------- +rlc.closeWindow(); // Close window and OpenGL context +//-------------------------------------------------------------------------------------- diff --git a/generate-bindings.js b/generate-bindings.js index 5d42dcc..765928f 100644 --- a/generate-bindings.js +++ b/generate-bindings.js @@ -258,6 +258,11 @@ class GenericCodeGenerator { fun(sub); return sub; } + declareStruct(structName, varName, values, isStatic = false) { + if (isStatic) + this.inline("static "); + this.statement(`${structName} ${varName} = { ${values.join(', ')} }`); + } } exports.GenericCodeGenerator = GenericCodeGenerator; class CodeGenerator extends GenericCodeGenerator { @@ -336,12 +341,17 @@ class GenericQuickJsGenerator extends generation_1.GenericCodeGenerator { const sub = this.function("js_" + jsName, "JSValue", args, true); return sub; } - jsToC(type, name, src) { + jsToC(type, name, src, classIds = {}) { switch (type) { case "const char *": this.statement(`${type} ${name} = JS_ToCString(ctx, ${src})`); this.statement(`if(${name} == NULL) return JS_EXCEPTION`); break; + case "float": + this.statement("double _double_" + name); + this.statement(`JS_ToFloat64(ctx, &_double_${name}, ${src})`); + this.statement(`${type} ${name} = (${type})_double_${name}`); + break; case "int": this.statement(`${type} ${name}`); this.statement(`JS_ToInt32(ctx, &${name}, ${src})`); @@ -352,7 +362,12 @@ class GenericQuickJsGenerator extends generation_1.GenericCodeGenerator { this.statement(`${type} ${name} = (${type})_int_${name}`); break; default: - throw new Error("Cannot handle parameter type: " + type); + const classId = classIds[type]; + if (!classId) + throw new Error("Cannot convert into parameter type: " + type); + this.jsOpqToStructPtr(type, name + "_ptr", src, classId); + this.statement(`if(${name}_ptr == NULL) return JS_EXCEPTION`); + this.declare(name, type, false, `*${name}_ptr`); } } jsToJs(type, name, src, classIds = {}) { @@ -361,18 +376,24 @@ class GenericQuickJsGenerator extends generation_1.GenericCodeGenerator { case "unsigned char": this.declare(name, 'JSValue', false, `JS_NewInt32(ctx, ${src})`); break; + case "bool": + this.declare(name, 'JSValue', false, `JS_NewBool(ctx, ${src})`); + break; + case "float": + this.declare(name, 'JSValue', false, `JS_NewFloat64(ctx, ${src})`); + break; default: const classId = classIds[type]; if (!classId) - throw new Error("Cannot handle parameter type: " + type); + throw new Error("Cannot convert parameter type to Javascript: " + 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 + "_ptr", structType + "*", false, `(${structType}*)js_malloc(ctx, sizeof(${structType}))`); + this.statement("*" + jsVar + "_ptr = " + srcVar); this.declare(jsVar, "JSValue", false, `JS_NewObjectClass(ctx, ${classId})`); - this.call("JS_SetOpaque", [jsVar, "ptr"]); + this.call("JS_SetOpaque", [jsVar, jsVar + "_ptr"]); } jsCleanUpParameter(type, name) { switch (type) { @@ -456,13 +477,16 @@ class GenericQuickJsGenerator extends generation_1.GenericCodeGenerator { fun.returnExp("JS_UNDEFINED"); return fun; } + jsOpqToStructPtr(structType, structVar, srcVar, classId) { + this.declare(structVar, structType + "*", false, `(${structType}*)JS_GetOpaque2(ctx, ${srcVar}, ${classId})`); + } jsStructConstructor(structName, fields, classId) { const body = this.jsBindingFunction(structName + "_constructor"); for (let i = 0; i < fields.length; i++) { const para = fields[i]; body.jsToC(para.type, para.name, "argv[" + i + "]"); } - body.statement(`${structName} _struct = { ${fields.map(x => x.name).join(', ')} }`); + body.declareStruct(structName, "_struct", fields.map(x => x.name)); body.jsStructToOpq(structName, "_return", "_struct", classId); body.returnExp("_return"); return body; @@ -495,13 +519,15 @@ class RayLibHeader extends quickjs_1.QuickJsHeader { this.api = api; this.includes.include("raylib.h"); } - addApiFunction(api, jsName = null) { + addApiFunction(api, jsName = null, options = {}) { const jName = jsName || api.name.charAt(0).toLowerCase() + api.name.slice(1); const fun = this.functions.jsBindingFunction(jName); + if (options.before) + options.before(fun); // read parameters for (let i = 0; i < api.params.length; i++) { const para = api.params[i]; - fun.jsToC(para.type, para.name, "argv[" + i + "]"); + fun.jsToC(para.type, para.name, "argv[" + i + "]", this.structLookup); } // call c function fun.call(api.name, api.params.map(x => x.name), api.returnType === "void" ? null : { type: api.returnType, name: "returnVal" }); @@ -509,6 +535,8 @@ class RayLibHeader extends quickjs_1.QuickJsHeader { for (const param of api.params) { fun.jsCleanUpParameter(param.type, param.name); } + if (options.after) + options.after(fun); // return result if (api.returnType === "void") { fun.statement("return JS_UNDEFINED"); @@ -520,11 +548,11 @@ class RayLibHeader extends quickjs_1.QuickJsHeader { // add binding to function declaration this.moduleFunctionList.jsFuncDef(jName, api.argc, fun.getTag("_name")); } - addApiFunctionByName(name, jsName = null) { + addApiFunctionByName(name, jsName = null, options = {}) { const func = this.api.getFunction(name); if (func === null) throw new Error("Function not in API: " + name); - this.addApiFunction(func, jsName); + this.addApiFunction(func, jsName, options); } addApiStruct(struct, destructor, options) { const classId = this.declarations.jsClassId(`js_${struct.name}_class_id`); @@ -558,6 +586,15 @@ class RayLibHeader extends quickjs_1.QuickJsHeader { this.moduleEntry.call("JS_AddModuleExport", ["ctx", "m", '"' + struct.name + '"']); } } + exportGlobalStruct(structName, exportName, values) { + this.moduleInit.declareStruct(structName, exportName + "_struct", values); + const classId = this.structLookup[structName]; + if (!classId) + throw new Error("Struct " + structName + " not found in register"); + this.moduleInit.jsStructToOpq(structName, exportName + "_js", exportName + "_struct", classId); + this.moduleInit.call("JS_SetModuleExport", ["ctx", "m", `"${exportName}"`, exportName + "_js"]); + this.moduleEntry.call("JS_AddModuleExport", ["ctx", "m", `"${exportName}"`]); + } addApiStructByName(structName, options) { const struct = this.api.getStruct(structName); if (!struct) @@ -638,12 +675,28 @@ function main() { }, createConstructor: true }); + core_gen.addApiStructByName("Vector2", { + properties: { + x: { get: true, set: true }, + y: { get: true, set: true }, + }, + createConstructor: true + }); core_gen.addApiFunctionByName("SetWindowTitle"); core_gen.addApiFunctionByName("SetWindowPosition"); core_gen.addApiFunctionByName("BeginDrawing"); core_gen.addApiFunctionByName("EndDrawing"); + core_gen.addApiFunctionByName("InitWindow"); + core_gen.addApiFunctionByName("SetTargetFPS"); + core_gen.addApiFunctionByName("WindowShouldClose", null, { before: fun => fun.call("app_update_quickjs", []) }); core_gen.addApiFunctionByName("ClearBackground"); + core_gen.addApiFunctionByName("CloseWindow"); core_gen.addApiFunctionByName("DrawText"); + core_gen.addApiFunctionByName("DrawCircleV"); + core_gen.addApiFunctionByName("IsKeyDown"); + api.defines.filter(x => x.type === "COLOR").map(x => ({ name: x.name, values: (x.value.match(/\{([^}]+)\}/) || "")[1].split(',').map(x => x.trim()) })).forEach(x => { + core_gen.exportGlobalStruct("Color", x.name, x.values); + }); core_gen.writeTo("src/bindings/js_raylib_core.h"); const texture_gen = new raylib_header_1.RayLibHeader("raylib_texture", apiDesc); texture_gen.addApiStructByName("Image", { diff --git a/generate_bindings.js b/generate_bindings.js deleted file mode 100644 index a1e0eb7..0000000 --- a/generate_bindings.js +++ /dev/null @@ -1,191 +0,0 @@ -// Run with Node.js - -const fs = require('fs'); -const { connect } = require('http2'); -let api, modules - -async function main(){ - api = await readJson('thirdparty/raylib/parser/output/raylib_api.json') - modules = await readJson('bindings.json') - - const headers = modules.map(generateModule) - - modules.forEach(async (header,i) => { - await writeFile(`src/bindings/js_${header.name}.h`, headers[i]) - }); -} - -class FunctionList { - definitions = [] - - addFunctionDef(name, args, cname){ - this.definitions.push(`JS_CFUNC_DEF("${name}", ${args}, ${cname})`) - } - - addIntConst(name, val){ - this.definitions.push(`JS_PROP_INT32_DEF("${name}", ${val})`) - } - - generate(name){ - return `static const JSCFunctionListEntry js_${name}_funcs[] = { -${this.definitions.map(x => " "+x).join(",\n")} -};` - } -} - -const generateModule = (mod) => { - const fl = new FunctionList() - let content = mod.functions.map(generateFunction(fl)).join("\n\n") - content += "\n\n" + fl.generate(mod.name) - return generateHeader(mod.name, content) -} - -const generateFunction = (functionList) => (func) => { - const api = findFunction(func.name) - const cfunc = new CFunction(func, api, functionList) - return cfunc.generate() -} - -const generateParameterCheck = (func) => (param, i) => { - const errMsg = `${func.name} argument ${param.name} (${i}) needs to be` - switch(param.type){ - case "const char *": - return `if(!JS_IsString(argv[${i}])) return JS_ThrowReferenceError(ctx, "${errMsg} a string");` - case "int": - return `if(!JS_IsNumber(argv[${i}])) return JS_ThrowReferenceError(ctx, "${errMsg} a number");` - default: - throw new Error("Unknown parameter type: "+param.type) - } -} - -const generateParameter = (param,i) => { - switch(param.type){ - case "const char *": - return `${param.type} ${param.name} = JS_ToCString(ctx, argv[${i}]);` - case "int": - return `${param.type} ${param.name}; JS_ToInt32(ctx, &${param.name}, argv[${i}]);` - default: - throw new Error("Unknown parameter type: "+param.type) - } -} - -const generateParameterCleanup = (param,i) => { - switch(param.type){ - case "const char *": - return `JS_FreeCString(ctx, ${param.name});` - default: - return "" - } -} - -class CFunction { - constructor(func, api, functionList){ - this.func = func - this.func.jsName = this.func.jsName || this.func.name.charAt(0).toLowerCase() + this.func.name.slice(1); - this.api = api - this.api.params = this.api.params || []; - this.functionList = functionList - this.functionName = `js_${func.jsName}` - } - - generateParameterCheck(){ - return this.api.params.map(generateParameterCheck(this.api)) - } - - generateParameters(){ - return this.api.params.map(generateParameter) - } - - generateFunctionCall(){ - return `${(this.api.returnType === 'void' ? '' : `${this.api.returnType} result = `)}${this.api.name}(${this.api.params.map(x => x.name).join(", ")});` - } - - generateReturn(){ - return this.api.returnType === 'void' ? 'return JS_UNDEFINED;' : 'return result' - } - - generateParametersCleanup(){ - return this.api.params.map(generateParameterCleanup).filter(x => x !== "") - } - - generate(){ - this.functionList.addFunctionDef(this.func.jsName, this.api.params.length, this.functionName) - return `static JSValue ${this.functionName}(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv){ - ${this.generateParameterCheck().join("\n ")} - ${this.generateParameters().join("\n ")} - ${this.generateFunctionCall()} - ${this.generateParametersCleanup().join("\n ")} - ${this.generateReturn()} -}` - } -} - -const findFunction = (name) => findIn(api.functions,name) - -const findIn = (arr, name) => arr.find(x => x.name == name) - - -async function readJson(path){ - const c = await readFile(path) - return JSON.parse(c) -} - -function readFile(path) { - const p = new Promise((res,rej) => { - fs.readFile(path, 'utf8', (err,data) => { - if(err) rej(error) - else res(data) - }) - }) - return p -} - -function writeFile(path, data){ - return new Promise((res, rej) => { - fs.writeFile(path, data, (err) => { - if(err) rej(err) - else res() - }) - }) -} - -function generateHeader(name, content){ - return ` -#ifndef JS_${name} -#define JS_${name} - -#include -#include -#include - -#include - -#ifndef countof -#define countof(x) (sizeof(x) / sizeof((x)[0])) -#endif - -${content} - -static int js_${name}_init(JSContext *ctx, JSModuleDef *m){ - JS_SetModuleExportList(ctx, m, js_${name}_funcs, - countof(js_${name}_funcs)); -} - -JSModuleDef *js_init_module_${name}(JSContext *ctx, const char *module_name) -{ - JSModuleDef *m; - m = JS_NewCModule(ctx, module_name, js_${name}_init); - if (!m) - return NULL; - - JS_AddModuleExportList(ctx, m, js_${name}_funcs, - countof(js_${name}_funcs)); - - return m; -} - -#endif - ` -} - -main() \ No newline at end of file diff --git a/main.js b/main.js index 606feb4..0edc27e 100644 --- a/main.js +++ b/main.js @@ -1,19 +1,35 @@ -import { setWindowTitle, setWindowPosition, Color } from "raylib.core" +import * as rlc from "raylib.core" import { loadImage } from "raylib.texture" import { gc } from "std" -const img = loadImage("assets/planet00.png") -console.log(img.width) +// Initialization +//-------------------------------------------------------------------------------------- +const screenWidth = 800; +const screenHeight = 450; -//const img = new Image("assets/planet00.png") +rlc.initWindow(screenWidth, screenHeight, "raylib [core] example - basic window"); -gc() - -const color = new Color(1,2,3,4) -color.r = 10 -console.log(color.r,color.g,color.b,color.a, color) - -setWindowTitle("My Window") -setWindowPosition(20,50) +rlc.setTargetFPS(60); // Set our game to run at 60 frames-per-second +//-------------------------------------------------------------------------------------- +// Main game loop +while (!rlc.windowShouldClose()) // Detect window close button or ESC key +{ + // Update + //---------------------------------------------------------------------------------- + // TODO: Update your variables here + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + rlc.beginDrawing(); + + rlc.clearBackground(rlc.RAYWHITE); + + rlc.drawText("Congrats! You created your first window!", 190, 200, 20, rlc.LIGHTGRAY); + + rlc.endDrawing(); + //---------------------------------------------------------------------------------- +} + diff --git a/my-module.js b/my-module.js deleted file mode 100644 index ce08bba..0000000 --- a/my-module.js +++ /dev/null @@ -1,3 +0,0 @@ -export function test() { - return 42 -} \ No newline at end of file diff --git a/src/bindings/js_raylib_core.h b/src/bindings/js_raylib_core.h index c0cf290..51211ab 100644 --- a/src/bindings/js_raylib_core.h +++ b/src/bindings/js_raylib_core.h @@ -13,6 +13,7 @@ #endif static JSClassID js_Color_class_id; +static JSClassID js_Vector2_class_id; static void js_Color_finalizer(JSRuntime * rt, JSValue val) { Color* ptr = JS_GetOpaque(val, js_Color_class_id); @@ -128,6 +129,74 @@ static int js_declare_Color(JSContext * ctx, JSModuleDef * m) { return 0; } +static void js_Vector2_finalizer(JSRuntime * rt, JSValue val) { + Vector2* ptr = JS_GetOpaque(val, js_Vector2_class_id); + if(ptr) { + TraceLog(LOG_INFO, "Finalize Vector2"); + js_free_rt(rt, ptr); + } +} + +static JSValue js_Vector2_get_x(JSContext* ctx, JSValueConst this_val) { + Vector2* ptr = JS_GetOpaque2(ctx, this_val, js_Vector2_class_id); + if(!ptr) { + return JS_EXCEPTION; + } + float x = ptr->x; + JSValue ret = JS_NewFloat64(ctx, x); + return ret; +} + +static JSValue js_Vector2_set_x(JSContext* ctx, JSValueConst this_val, JSValueConst v) { + Vector2* ptr = JS_GetOpaque2(ctx, this_val, js_Vector2_class_id); + if(!ptr) { + return JS_EXCEPTION; + } + double _double_value; + JS_ToFloat64(ctx, &_double_value, v); + float value = (float)_double_value; + ptr->x = value; + return JS_UNDEFINED; +} + +static JSValue js_Vector2_get_y(JSContext* ctx, JSValueConst this_val) { + Vector2* ptr = JS_GetOpaque2(ctx, this_val, js_Vector2_class_id); + if(!ptr) { + return JS_EXCEPTION; + } + float y = ptr->y; + JSValue ret = JS_NewFloat64(ctx, y); + return ret; +} + +static JSValue js_Vector2_set_y(JSContext* ctx, JSValueConst this_val, JSValueConst v) { + Vector2* ptr = JS_GetOpaque2(ctx, this_val, js_Vector2_class_id); + if(!ptr) { + return JS_EXCEPTION; + } + double _double_value; + JS_ToFloat64(ctx, &_double_value, v); + float value = (float)_double_value; + ptr->y = value; + return JS_UNDEFINED; +} + +static const JSCFunctionListEntry js_Vector2_proto_funcs[] = { + JS_CGETSET_DEF("x",js_Vector2_get_x,js_Vector2_set_x), + JS_CGETSET_DEF("y",js_Vector2_get_y,js_Vector2_set_y), + JS_PROP_STRING_DEF("[Symbol.toStringTag]","Vector2", JS_PROP_CONFIGURABLE), +}; + +static int js_declare_Vector2(JSContext * ctx, JSModuleDef * m) { + JS_NewClassID(&js_Vector2_class_id); + JSClassDef js_Vector2_def = { .class_name = "Vector2", .finalizer = js_Vector2_finalizer }; + JS_NewClass(JS_GetRuntime(ctx), js_Vector2_class_id, &js_Vector2_def); + JSValue proto = JS_NewObject(ctx); + JS_SetPropertyFunctionList(ctx, proto, js_Vector2_proto_funcs, countof(js_Vector2_proto_funcs)); + JS_SetClassProto(ctx, js_Vector2_class_id, proto); + return 0; +} + static JSValue js_Color_constructor(JSContext * ctx, JSValueConst this_val, int argc, JSValueConst * argv) { int _int_r; JS_ToInt32(ctx, &_int_r, argv[0]); @@ -142,10 +211,25 @@ static JSValue js_Color_constructor(JSContext * ctx, JSValueConst this_val, int JS_ToInt32(ctx, &_int_a, argv[3]); unsigned char a = (unsigned char)_int_a; Color _struct = { r, g, b, a }; - Color* ptr = (Color*)js_malloc(ctx, sizeof(Color)); - *ptr = _struct; + Color* _return_ptr = (Color*)js_malloc(ctx, sizeof(Color)); + *_return_ptr = _struct; JSValue _return = JS_NewObjectClass(ctx, js_Color_class_id); - JS_SetOpaque(_return, ptr); + JS_SetOpaque(_return, _return_ptr); + return _return; +} + +static JSValue js_Vector2_constructor(JSContext * ctx, JSValueConst this_val, int argc, JSValueConst * argv) { + double _double_x; + JS_ToFloat64(ctx, &_double_x, argv[0]); + float x = (float)_double_x; + double _double_y; + JS_ToFloat64(ctx, &_double_y, argv[1]); + float y = (float)_double_y; + Vector2 _struct = { x, y }; + Vector2* _return_ptr = (Vector2*)js_malloc(ctx, sizeof(Vector2)); + *_return_ptr = _struct; + JSValue _return = JS_NewObjectClass(ctx, js_Vector2_class_id); + JS_SetOpaque(_return, _return_ptr); return _return; } @@ -176,11 +260,97 @@ static JSValue js_endDrawing(JSContext * ctx, JSValueConst this_val, int argc, J return JS_UNDEFINED; } +static JSValue js_initWindow(JSContext * ctx, JSValueConst this_val, int argc, JSValueConst * argv) { + int width; + JS_ToInt32(ctx, &width, argv[0]); + int height; + JS_ToInt32(ctx, &height, argv[1]); + const char * title = JS_ToCString(ctx, argv[2]); + if(title == NULL) return JS_EXCEPTION; + InitWindow(width, height, title); + JS_FreeCString(ctx, title); + return JS_UNDEFINED; +} + +static JSValue js_setTargetFPS(JSContext * ctx, JSValueConst this_val, int argc, JSValueConst * argv) { + int fps; + JS_ToInt32(ctx, &fps, argv[0]); + SetTargetFPS(fps); + return JS_UNDEFINED; +} + +static JSValue js_windowShouldClose(JSContext * ctx, JSValueConst this_val, int argc, JSValueConst * argv) { + app_update_quickjs(); + bool returnVal = WindowShouldClose(); + JSValue ret = JS_NewBool(ctx, returnVal); + return ret; +} + +static JSValue js_clearBackground(JSContext * ctx, JSValueConst this_val, int argc, JSValueConst * argv) { + Color* color_ptr = (Color*)JS_GetOpaque2(ctx, argv[0], js_Color_class_id); + if(color_ptr == NULL) return JS_EXCEPTION; + Color color = *color_ptr; + ClearBackground(color); + return JS_UNDEFINED; +} + +static JSValue js_closeWindow(JSContext * ctx, JSValueConst this_val, int argc, JSValueConst * argv) { + CloseWindow(); + return JS_UNDEFINED; +} + +static JSValue js_drawText(JSContext * ctx, JSValueConst this_val, int argc, JSValueConst * argv) { + const char * text = JS_ToCString(ctx, argv[0]); + if(text == NULL) return JS_EXCEPTION; + int posX; + JS_ToInt32(ctx, &posX, argv[1]); + int posY; + JS_ToInt32(ctx, &posY, argv[2]); + int fontSize; + JS_ToInt32(ctx, &fontSize, argv[3]); + Color* color_ptr = (Color*)JS_GetOpaque2(ctx, argv[4], js_Color_class_id); + if(color_ptr == NULL) return JS_EXCEPTION; + Color color = *color_ptr; + DrawText(text, posX, posY, fontSize, color); + JS_FreeCString(ctx, text); + return JS_UNDEFINED; +} + +static JSValue js_drawCircleV(JSContext * ctx, JSValueConst this_val, int argc, JSValueConst * argv) { + Vector2* center_ptr = (Vector2*)JS_GetOpaque2(ctx, argv[0], js_Vector2_class_id); + if(center_ptr == NULL) return JS_EXCEPTION; + Vector2 center = *center_ptr; + double _double_radius; + JS_ToFloat64(ctx, &_double_radius, argv[1]); + float radius = (float)_double_radius; + Color* color_ptr = (Color*)JS_GetOpaque2(ctx, argv[2], js_Color_class_id); + if(color_ptr == NULL) return JS_EXCEPTION; + Color color = *color_ptr; + DrawCircleV(center, radius, color); + return JS_UNDEFINED; +} + +static JSValue js_isKeyDown(JSContext * ctx, JSValueConst this_val, int argc, JSValueConst * argv) { + int key; + JS_ToInt32(ctx, &key, argv[0]); + bool returnVal = IsKeyDown(key); + JSValue ret = JS_NewBool(ctx, returnVal); + return ret; +} + static const JSCFunctionListEntry js_raylib_core_funcs[] = { JS_CFUNC_DEF("setWindowTitle",1,js_setWindowTitle), JS_CFUNC_DEF("setWindowPosition",2,js_setWindowPosition), JS_CFUNC_DEF("beginDrawing",0,js_beginDrawing), JS_CFUNC_DEF("endDrawing",0,js_endDrawing), + JS_CFUNC_DEF("initWindow",3,js_initWindow), + JS_CFUNC_DEF("setTargetFPS",1,js_setTargetFPS), + JS_CFUNC_DEF("windowShouldClose",0,js_windowShouldClose), + JS_CFUNC_DEF("clearBackground",1,js_clearBackground), + JS_CFUNC_DEF("closeWindow",0,js_closeWindow), + JS_CFUNC_DEF("drawText",5,js_drawText), + JS_CFUNC_DEF("drawCircleV",3,js_drawCircleV), + JS_CFUNC_DEF("isKeyDown",1,js_isKeyDown), }; static int js_raylib_core_init(JSContext * ctx, JSModuleDef * m) { @@ -188,6 +358,165 @@ static int js_raylib_core_init(JSContext * ctx, JSModuleDef * m) { js_declare_Color(ctx, m); JSValue Color_constr = JS_NewCFunction2(ctx, js_Color_constructor,"Color)", 4, JS_CFUNC_constructor_or_func, 0); JS_SetModuleExport(ctx, m, "Color", Color_constr); + js_declare_Vector2(ctx, m); + JSValue Vector2_constr = JS_NewCFunction2(ctx, js_Vector2_constructor,"Vector2)", 2, JS_CFUNC_constructor_or_func, 0); + JS_SetModuleExport(ctx, m, "Vector2", Vector2_constr); + Color LIGHTGRAY_struct = { 200, 200, 200, 255 }; + Color* LIGHTGRAY_js_ptr = (Color*)js_malloc(ctx, sizeof(Color)); + *LIGHTGRAY_js_ptr = LIGHTGRAY_struct; + JSValue LIGHTGRAY_js = JS_NewObjectClass(ctx, js_Color_class_id); + JS_SetOpaque(LIGHTGRAY_js, LIGHTGRAY_js_ptr); + JS_SetModuleExport(ctx, m, "LIGHTGRAY", LIGHTGRAY_js); + Color GRAY_struct = { 130, 130, 130, 255 }; + Color* GRAY_js_ptr = (Color*)js_malloc(ctx, sizeof(Color)); + *GRAY_js_ptr = GRAY_struct; + JSValue GRAY_js = JS_NewObjectClass(ctx, js_Color_class_id); + JS_SetOpaque(GRAY_js, GRAY_js_ptr); + JS_SetModuleExport(ctx, m, "GRAY", GRAY_js); + Color DARKGRAY_struct = { 80, 80, 80, 255 }; + Color* DARKGRAY_js_ptr = (Color*)js_malloc(ctx, sizeof(Color)); + *DARKGRAY_js_ptr = DARKGRAY_struct; + JSValue DARKGRAY_js = JS_NewObjectClass(ctx, js_Color_class_id); + JS_SetOpaque(DARKGRAY_js, DARKGRAY_js_ptr); + JS_SetModuleExport(ctx, m, "DARKGRAY", DARKGRAY_js); + Color YELLOW_struct = { 253, 249, 0, 255 }; + Color* YELLOW_js_ptr = (Color*)js_malloc(ctx, sizeof(Color)); + *YELLOW_js_ptr = YELLOW_struct; + JSValue YELLOW_js = JS_NewObjectClass(ctx, js_Color_class_id); + JS_SetOpaque(YELLOW_js, YELLOW_js_ptr); + JS_SetModuleExport(ctx, m, "YELLOW", YELLOW_js); + Color GOLD_struct = { 255, 203, 0, 255 }; + Color* GOLD_js_ptr = (Color*)js_malloc(ctx, sizeof(Color)); + *GOLD_js_ptr = GOLD_struct; + JSValue GOLD_js = JS_NewObjectClass(ctx, js_Color_class_id); + JS_SetOpaque(GOLD_js, GOLD_js_ptr); + JS_SetModuleExport(ctx, m, "GOLD", GOLD_js); + Color ORANGE_struct = { 255, 161, 0, 255 }; + Color* ORANGE_js_ptr = (Color*)js_malloc(ctx, sizeof(Color)); + *ORANGE_js_ptr = ORANGE_struct; + JSValue ORANGE_js = JS_NewObjectClass(ctx, js_Color_class_id); + JS_SetOpaque(ORANGE_js, ORANGE_js_ptr); + JS_SetModuleExport(ctx, m, "ORANGE", ORANGE_js); + Color PINK_struct = { 255, 109, 194, 255 }; + Color* PINK_js_ptr = (Color*)js_malloc(ctx, sizeof(Color)); + *PINK_js_ptr = PINK_struct; + JSValue PINK_js = JS_NewObjectClass(ctx, js_Color_class_id); + JS_SetOpaque(PINK_js, PINK_js_ptr); + JS_SetModuleExport(ctx, m, "PINK", PINK_js); + Color RED_struct = { 230, 41, 55, 255 }; + Color* RED_js_ptr = (Color*)js_malloc(ctx, sizeof(Color)); + *RED_js_ptr = RED_struct; + JSValue RED_js = JS_NewObjectClass(ctx, js_Color_class_id); + JS_SetOpaque(RED_js, RED_js_ptr); + JS_SetModuleExport(ctx, m, "RED", RED_js); + Color MAROON_struct = { 190, 33, 55, 255 }; + Color* MAROON_js_ptr = (Color*)js_malloc(ctx, sizeof(Color)); + *MAROON_js_ptr = MAROON_struct; + JSValue MAROON_js = JS_NewObjectClass(ctx, js_Color_class_id); + JS_SetOpaque(MAROON_js, MAROON_js_ptr); + JS_SetModuleExport(ctx, m, "MAROON", MAROON_js); + Color GREEN_struct = { 0, 228, 48, 255 }; + Color* GREEN_js_ptr = (Color*)js_malloc(ctx, sizeof(Color)); + *GREEN_js_ptr = GREEN_struct; + JSValue GREEN_js = JS_NewObjectClass(ctx, js_Color_class_id); + JS_SetOpaque(GREEN_js, GREEN_js_ptr); + JS_SetModuleExport(ctx, m, "GREEN", GREEN_js); + Color LIME_struct = { 0, 158, 47, 255 }; + Color* LIME_js_ptr = (Color*)js_malloc(ctx, sizeof(Color)); + *LIME_js_ptr = LIME_struct; + JSValue LIME_js = JS_NewObjectClass(ctx, js_Color_class_id); + JS_SetOpaque(LIME_js, LIME_js_ptr); + JS_SetModuleExport(ctx, m, "LIME", LIME_js); + Color DARKGREEN_struct = { 0, 117, 44, 255 }; + Color* DARKGREEN_js_ptr = (Color*)js_malloc(ctx, sizeof(Color)); + *DARKGREEN_js_ptr = DARKGREEN_struct; + JSValue DARKGREEN_js = JS_NewObjectClass(ctx, js_Color_class_id); + JS_SetOpaque(DARKGREEN_js, DARKGREEN_js_ptr); + JS_SetModuleExport(ctx, m, "DARKGREEN", DARKGREEN_js); + Color SKYBLUE_struct = { 102, 191, 255, 255 }; + Color* SKYBLUE_js_ptr = (Color*)js_malloc(ctx, sizeof(Color)); + *SKYBLUE_js_ptr = SKYBLUE_struct; + JSValue SKYBLUE_js = JS_NewObjectClass(ctx, js_Color_class_id); + JS_SetOpaque(SKYBLUE_js, SKYBLUE_js_ptr); + JS_SetModuleExport(ctx, m, "SKYBLUE", SKYBLUE_js); + Color BLUE_struct = { 0, 121, 241, 255 }; + Color* BLUE_js_ptr = (Color*)js_malloc(ctx, sizeof(Color)); + *BLUE_js_ptr = BLUE_struct; + JSValue BLUE_js = JS_NewObjectClass(ctx, js_Color_class_id); + JS_SetOpaque(BLUE_js, BLUE_js_ptr); + JS_SetModuleExport(ctx, m, "BLUE", BLUE_js); + Color DARKBLUE_struct = { 0, 82, 172, 255 }; + Color* DARKBLUE_js_ptr = (Color*)js_malloc(ctx, sizeof(Color)); + *DARKBLUE_js_ptr = DARKBLUE_struct; + JSValue DARKBLUE_js = JS_NewObjectClass(ctx, js_Color_class_id); + JS_SetOpaque(DARKBLUE_js, DARKBLUE_js_ptr); + JS_SetModuleExport(ctx, m, "DARKBLUE", DARKBLUE_js); + Color PURPLE_struct = { 200, 122, 255, 255 }; + Color* PURPLE_js_ptr = (Color*)js_malloc(ctx, sizeof(Color)); + *PURPLE_js_ptr = PURPLE_struct; + JSValue PURPLE_js = JS_NewObjectClass(ctx, js_Color_class_id); + JS_SetOpaque(PURPLE_js, PURPLE_js_ptr); + JS_SetModuleExport(ctx, m, "PURPLE", PURPLE_js); + Color VIOLET_struct = { 135, 60, 190, 255 }; + Color* VIOLET_js_ptr = (Color*)js_malloc(ctx, sizeof(Color)); + *VIOLET_js_ptr = VIOLET_struct; + JSValue VIOLET_js = JS_NewObjectClass(ctx, js_Color_class_id); + JS_SetOpaque(VIOLET_js, VIOLET_js_ptr); + JS_SetModuleExport(ctx, m, "VIOLET", VIOLET_js); + Color DARKPURPLE_struct = { 112, 31, 126, 255 }; + Color* DARKPURPLE_js_ptr = (Color*)js_malloc(ctx, sizeof(Color)); + *DARKPURPLE_js_ptr = DARKPURPLE_struct; + JSValue DARKPURPLE_js = JS_NewObjectClass(ctx, js_Color_class_id); + JS_SetOpaque(DARKPURPLE_js, DARKPURPLE_js_ptr); + JS_SetModuleExport(ctx, m, "DARKPURPLE", DARKPURPLE_js); + Color BEIGE_struct = { 211, 176, 131, 255 }; + Color* BEIGE_js_ptr = (Color*)js_malloc(ctx, sizeof(Color)); + *BEIGE_js_ptr = BEIGE_struct; + JSValue BEIGE_js = JS_NewObjectClass(ctx, js_Color_class_id); + JS_SetOpaque(BEIGE_js, BEIGE_js_ptr); + JS_SetModuleExport(ctx, m, "BEIGE", BEIGE_js); + Color BROWN_struct = { 127, 106, 79, 255 }; + Color* BROWN_js_ptr = (Color*)js_malloc(ctx, sizeof(Color)); + *BROWN_js_ptr = BROWN_struct; + JSValue BROWN_js = JS_NewObjectClass(ctx, js_Color_class_id); + JS_SetOpaque(BROWN_js, BROWN_js_ptr); + JS_SetModuleExport(ctx, m, "BROWN", BROWN_js); + Color DARKBROWN_struct = { 76, 63, 47, 255 }; + Color* DARKBROWN_js_ptr = (Color*)js_malloc(ctx, sizeof(Color)); + *DARKBROWN_js_ptr = DARKBROWN_struct; + JSValue DARKBROWN_js = JS_NewObjectClass(ctx, js_Color_class_id); + JS_SetOpaque(DARKBROWN_js, DARKBROWN_js_ptr); + JS_SetModuleExport(ctx, m, "DARKBROWN", DARKBROWN_js); + Color WHITE_struct = { 255, 255, 255, 255 }; + Color* WHITE_js_ptr = (Color*)js_malloc(ctx, sizeof(Color)); + *WHITE_js_ptr = WHITE_struct; + JSValue WHITE_js = JS_NewObjectClass(ctx, js_Color_class_id); + JS_SetOpaque(WHITE_js, WHITE_js_ptr); + JS_SetModuleExport(ctx, m, "WHITE", WHITE_js); + Color BLACK_struct = { 0, 0, 0, 255 }; + Color* BLACK_js_ptr = (Color*)js_malloc(ctx, sizeof(Color)); + *BLACK_js_ptr = BLACK_struct; + JSValue BLACK_js = JS_NewObjectClass(ctx, js_Color_class_id); + JS_SetOpaque(BLACK_js, BLACK_js_ptr); + JS_SetModuleExport(ctx, m, "BLACK", BLACK_js); + Color BLANK_struct = { 0, 0, 0, 0 }; + Color* BLANK_js_ptr = (Color*)js_malloc(ctx, sizeof(Color)); + *BLANK_js_ptr = BLANK_struct; + JSValue BLANK_js = JS_NewObjectClass(ctx, js_Color_class_id); + JS_SetOpaque(BLANK_js, BLANK_js_ptr); + JS_SetModuleExport(ctx, m, "BLANK", BLANK_js); + Color MAGENTA_struct = { 255, 0, 255, 255 }; + Color* MAGENTA_js_ptr = (Color*)js_malloc(ctx, sizeof(Color)); + *MAGENTA_js_ptr = MAGENTA_struct; + JSValue MAGENTA_js = JS_NewObjectClass(ctx, js_Color_class_id); + JS_SetOpaque(MAGENTA_js, MAGENTA_js_ptr); + JS_SetModuleExport(ctx, m, "MAGENTA", MAGENTA_js); + Color RAYWHITE_struct = { 245, 245, 245, 255 }; + Color* RAYWHITE_js_ptr = (Color*)js_malloc(ctx, sizeof(Color)); + *RAYWHITE_js_ptr = RAYWHITE_struct; + JSValue RAYWHITE_js = JS_NewObjectClass(ctx, js_Color_class_id); + JS_SetOpaque(RAYWHITE_js, RAYWHITE_js_ptr); + JS_SetModuleExport(ctx, m, "RAYWHITE", RAYWHITE_js); return 0; } @@ -197,6 +526,33 @@ JSModuleDef * js_init_module_raylib_core(JSContext * ctx, const char * module_na if(!m) return NULL; JS_AddModuleExportList(ctx, m, js_raylib_core_funcs, countof(js_raylib_core_funcs)); JS_AddModuleExport(ctx, m, "Color"); + JS_AddModuleExport(ctx, m, "Vector2"); + JS_AddModuleExport(ctx, m, "LIGHTGRAY"); + JS_AddModuleExport(ctx, m, "GRAY"); + JS_AddModuleExport(ctx, m, "DARKGRAY"); + JS_AddModuleExport(ctx, m, "YELLOW"); + JS_AddModuleExport(ctx, m, "GOLD"); + JS_AddModuleExport(ctx, m, "ORANGE"); + JS_AddModuleExport(ctx, m, "PINK"); + JS_AddModuleExport(ctx, m, "RED"); + JS_AddModuleExport(ctx, m, "MAROON"); + JS_AddModuleExport(ctx, m, "GREEN"); + JS_AddModuleExport(ctx, m, "LIME"); + JS_AddModuleExport(ctx, m, "DARKGREEN"); + JS_AddModuleExport(ctx, m, "SKYBLUE"); + JS_AddModuleExport(ctx, m, "BLUE"); + JS_AddModuleExport(ctx, m, "DARKBLUE"); + JS_AddModuleExport(ctx, m, "PURPLE"); + JS_AddModuleExport(ctx, m, "VIOLET"); + JS_AddModuleExport(ctx, m, "DARKPURPLE"); + JS_AddModuleExport(ctx, m, "BEIGE"); + JS_AddModuleExport(ctx, m, "BROWN"); + JS_AddModuleExport(ctx, m, "DARKBROWN"); + JS_AddModuleExport(ctx, m, "WHITE"); + JS_AddModuleExport(ctx, m, "BLACK"); + JS_AddModuleExport(ctx, m, "BLANK"); + JS_AddModuleExport(ctx, m, "MAGENTA"); + JS_AddModuleExport(ctx, m, "RAYWHITE"); return m; } diff --git a/src/bindings/js_raylib_texture.h b/src/bindings/js_raylib_texture.h index d228a4a..887faa8 100644 --- a/src/bindings/js_raylib_texture.h +++ b/src/bindings/js_raylib_texture.h @@ -64,10 +64,10 @@ static JSValue js_loadImage(JSContext * ctx, JSValueConst this_val, int argc, JS if(fileName == NULL) return JS_EXCEPTION; Image returnVal = LoadImage(fileName); JS_FreeCString(ctx, fileName); - Image* ptr = (Image*)js_malloc(ctx, sizeof(Image)); - *ptr = returnVal; + Image* ret_ptr = (Image*)js_malloc(ctx, sizeof(Image)); + *ret_ptr = returnVal; JSValue ret = JS_NewObjectClass(ctx, js_Image_class_id); - JS_SetOpaque(ret, ptr); + JS_SetOpaque(ret, ret_ptr); return ret; } diff --git a/src/main.c b/src/main.c index 6c989bd..b6242fd 100644 --- a/src/main.c +++ b/src/main.c @@ -29,43 +29,45 @@ //------------------------------------------------------------------------------------ int main(int argc, char ** argv) { - // Initialization - //-------------------------------------------------------------------------------------- - const int screenWidth = 800; - const int screenHeight = 450; - - InitWindow(screenWidth, screenHeight, "raylib [core] example - basic window"); - - SetTargetFPS(60); // Set our game to run at 60 frames-per-second - //-------------------------------------------------------------------------------------- - app_init_quickjs(argc, argv); + // // Initialization + // //-------------------------------------------------------------------------------------- + // const int screenWidth = 800; + // const int screenHeight = 450; - // Main game loop - while (!WindowShouldClose()) // Detect window close button or ESC key - { - app_update_quickjs(); - // Update - //---------------------------------------------------------------------------------- - // TODO: Update your variables here - //---------------------------------------------------------------------------------- + // InitWindow(screenWidth, screenHeight, "raylib [core] example - basic window"); - // Draw - //---------------------------------------------------------------------------------- - BeginDrawing(); + // SetTargetFPS(60); // Set our game to run at 60 frames-per-second + // //-------------------------------------------------------------------------------------- - ClearBackground(RAYWHITE); - DrawText("Congrats! You created your first window!", 190, 200, 20, LIGHTGRAY); + // // Main game loop + // while (!WindowShouldClose()) // Detect window close button or ESC key + // { + // app_update_quickjs(); + // // Update + // //---------------------------------------------------------------------------------- + // // TODO: Update your variables here + // //---------------------------------------------------------------------------------- - EndDrawing(); - //---------------------------------------------------------------------------------- - } + // // Draw + // //---------------------------------------------------------------------------------- + // BeginDrawing(); - // De-Initialization - //-------------------------------------------------------------------------------------- - CloseWindow(); // Close window and OpenGL context - //-------------------------------------------------------------------------------------- + // ClearBackground(RAYWHITE); + // DrawText("Congrats! You created your first window!", 190, 200, 20, LIGHTGRAY); + + // EndDrawing(); + // //---------------------------------------------------------------------------------- + // } + + + // // De-Initialization + // //-------------------------------------------------------------------------------------- + // CloseWindow(); // Close window and OpenGL context + // //-------------------------------------------------------------------------------------- + + app_dispose_quickjs(); return 0; } \ No newline at end of file diff --git a/src/quickjs.c b/src/quickjs.c index f2e7885..dda8586 100644 --- a/src/quickjs.c +++ b/src/quickjs.c @@ -4,8 +4,6 @@ #include #include "common.h" -#include "bindings/js_raylib_core.h" -#include "bindings/js_raylib_texture.h" static JSContext *JS_NewCustomContext(JSRuntime *rt); static int eval_buf(JSContext *ctx, const void *buf, int buf_len, @@ -14,6 +12,26 @@ static int eval_buf(JSContext *ctx, const void *buf, int buf_len, static JSRuntime* rt; static JSContext* ctx; +int app_update_quickjs(){ + JSContext *ctx1; + int err; + + /* execute the pending jobs */ + for(;;) { + err = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1); + if (err <= 0) { + if (err < 0) { + js_std_dump_error(ctx1); + } + break; + } + } + return 0; +} + +#include "bindings/js_raylib_core.h" +#include "bindings/js_raylib_texture.h" + int app_init_quickjs(int argc, char** argv){ rt = JS_NewRuntime(); if (!rt) @@ -39,14 +57,14 @@ int app_init_quickjs(int argc, char** argv){ // "globalThis.os = os;\n"; // eval_buf(ctx, str, strlen(str), "", JS_EVAL_TYPE_MODULE); - const char* filename = "main.js"; + const char* filename = argc > 1 ? argv[1] : "main.js"; const char* buf = LoadFileText(filename); - size_t len = strlen(buf); if (!buf) { JS_ThrowReferenceError(ctx, "could not load module filename '%s'", filename); return -1; } + size_t len = strlen(buf); int res = eval_buf(ctx, buf, len, "main", JS_EVAL_TYPE_MODULE); if(res){ return res; @@ -54,22 +72,7 @@ int app_init_quickjs(int argc, char** argv){ return 0; } -int app_update_quickjs(){ - JSContext *ctx1; - int err; - /* execute the pending jobs */ - for(;;) { - err = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1); - if (err <= 0) { - if (err < 0) { - js_std_dump_error(ctx1); - } - break; - } - } - return 0; -} int app_dispose_quickjs(){ //js_std_free_handlers(rt);