2023-05-08 16:05:03 +00:00
|
|
|
import { CodeGenerator } from "./generation"
|
2023-06-02 09:52:33 +00:00
|
|
|
import { RayLibEnum, RayLibFunction, RayLibStruct } from "./interfaces"
|
2023-05-10 21:26:53 +00:00
|
|
|
import { QuickJsGenerator, QuickJsHeader } from "./quickjs"
|
2023-05-14 20:19:47 +00:00
|
|
|
import { TypeScriptDeclaration } from "./typescript"
|
2023-05-08 14:43:50 +00:00
|
|
|
|
|
|
|
|
2023-05-10 21:26:53 +00:00
|
|
|
|
2023-05-08 14:43:50 +00:00
|
|
|
|
|
|
|
export class RayLibHeader extends QuickJsHeader {
|
|
|
|
|
2023-05-14 20:19:47 +00:00
|
|
|
typings = new TypeScriptDeclaration()
|
|
|
|
|
2023-06-02 09:52:33 +00:00
|
|
|
constructor(name: string){
|
2023-05-08 14:43:50 +00:00
|
|
|
super(name)
|
|
|
|
this.includes.include("raylib.h")
|
2023-05-15 15:44:28 +00:00
|
|
|
//this.includes.line("#define RAYMATH_IMPLEMENTATION")
|
2023-05-26 06:10:27 +00:00
|
|
|
|
2023-05-08 14:43:50 +00:00
|
|
|
}
|
|
|
|
|
2023-06-02 09:52:33 +00:00
|
|
|
addApiFunction(api: RayLibFunction){
|
|
|
|
const options = api.binding || {}
|
|
|
|
if(options.ignore) return
|
|
|
|
|
|
|
|
const jName = options.jsName || api.name.charAt(0).toLowerCase() + api.name.slice(1)
|
2023-05-08 14:43:50 +00:00
|
|
|
|
|
|
|
const fun = this.functions.jsBindingFunction(jName)
|
2023-05-16 06:28:30 +00:00
|
|
|
if(options.body) {
|
|
|
|
options.body(fun)
|
2023-05-08 14:43:50 +00:00
|
|
|
} else {
|
2023-05-16 06:28:30 +00:00
|
|
|
if(options.before) options.before(fun)
|
|
|
|
// read parameters
|
2023-06-02 09:52:33 +00:00
|
|
|
api.params = api.params || []
|
2023-05-16 06:28:30 +00:00
|
|
|
for (let i = 0; i < api.params.length; i++) {
|
|
|
|
const para = api.params[i]
|
|
|
|
fun.jsToC(para.type,para.name,"argv["+i+"]", this.structLookup)
|
|
|
|
}
|
|
|
|
// call c function
|
2023-05-29 22:03:29 +00:00
|
|
|
if(options.customizeCall) fun.line(options.customizeCall)
|
|
|
|
else fun.call(api.name, api.params.map(x => x.name), api.returnType === "void" ? null : {type: api.returnType, name: "returnVal"})
|
2023-05-16 06:28:30 +00:00
|
|
|
// clean up parameters
|
|
|
|
for (const param of api.params) {
|
|
|
|
fun.jsCleanUpParameter(param.type, param.name)
|
|
|
|
}
|
|
|
|
// return result
|
|
|
|
if(api.returnType === "void"){
|
2023-05-29 22:03:29 +00:00
|
|
|
if(options.after) options.after(fun)
|
2023-05-16 06:28:30 +00:00
|
|
|
fun.statement("return JS_UNDEFINED")
|
|
|
|
} else {
|
|
|
|
fun.jsToJs(api.returnType, "ret", "returnVal", this.structLookup)
|
2023-05-29 22:03:29 +00:00
|
|
|
if(options.after) options.after(fun)
|
2023-05-16 06:28:30 +00:00
|
|
|
fun.returnExp("ret")
|
|
|
|
}
|
2023-05-08 14:43:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// add binding to function declaration
|
2023-06-02 09:52:33 +00:00
|
|
|
this.moduleFunctionList.jsFuncDef(jName, api.params?.length ?? 0, fun.getTag("_name"))
|
2023-05-14 20:19:47 +00:00
|
|
|
this.typings.addFunction(jName,api)
|
2023-05-08 14:43:50 +00:00
|
|
|
}
|
|
|
|
|
2023-06-02 09:52:33 +00:00
|
|
|
addEnum(renum: RayLibEnum){
|
|
|
|
renum.values.forEach(x => this.exportGlobalConstant(x.name, x.description))
|
2023-06-02 06:03:36 +00:00
|
|
|
}
|
|
|
|
|
2023-06-02 09:52:33 +00:00
|
|
|
addApiStruct(struct: RayLibStruct){
|
|
|
|
const options = struct.binding || {}
|
2023-05-14 20:19:47 +00:00
|
|
|
const classId = this.definitions.jsClassId(`js_${struct.name}_class_id`)
|
2023-05-08 21:37:58 +00:00
|
|
|
this.registerStruct(struct.name, classId)
|
2023-06-02 09:52:33 +00:00
|
|
|
options.aliases?.forEach(x => this.registerStruct(x, classId))
|
|
|
|
const finalizer = this.structs.jsStructFinalizer(classId, struct.name, (gen,ptr) => options.destructor && gen.call(options.destructor.name, ["*"+ptr]))
|
2023-05-08 16:05:03 +00:00
|
|
|
|
|
|
|
const propDeclarations = this.structs.createGenerator()
|
|
|
|
if(options && options.properties){
|
|
|
|
for (const field of Object.keys(options.properties)) {
|
|
|
|
const type = struct.fields.find(x => x.name === field)?.type
|
|
|
|
if(!type) throw new Error(`Struct ${struct.name} does not contain field ${field}`)
|
|
|
|
const el = options.properties[field]
|
|
|
|
let _get: CodeGenerator | undefined = undefined
|
|
|
|
let _set: CodeGenerator | undefined = undefined
|
2023-05-16 06:28:30 +00:00
|
|
|
if(el.get) _get = this.structs.jsStructGetter(struct.name, classId, field, type, /*Be carefull when allocating memory in a getter*/this.structLookup)
|
2023-05-13 12:49:05 +00:00
|
|
|
if(el.set) _set = this.structs.jsStructSetter(struct.name, classId, field, type, this.structLookup)
|
2023-05-08 21:37:58 +00:00
|
|
|
propDeclarations.jsGetSetDef(field, _get?.getTag("_name"), _set?.getTag("_name"))
|
2023-05-08 16:05:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-08 14:43:50 +00:00
|
|
|
const classFuncList = this.structs.jsFunctionList(`js_${struct.name}_proto_funcs`)
|
2023-05-08 16:05:03 +00:00
|
|
|
classFuncList.child(propDeclarations)
|
2023-05-08 21:37:58 +00:00
|
|
|
classFuncList.jsPropStringDef("[Symbol.toStringTag]", struct.name)
|
2023-05-08 14:43:50 +00:00
|
|
|
const classDecl = this.structs.jsClassDeclaration(struct.name, classId, finalizer.getTag("_name"), classFuncList.getTag("_name"))
|
|
|
|
|
|
|
|
this.moduleInit.call(classDecl.getTag("_name"), ["ctx", "m"])
|
2023-05-09 21:25:28 +00:00
|
|
|
|
2023-05-20 19:34:27 +00:00
|
|
|
if(options?.createConstructor || options?.createEmptyConstructor){
|
|
|
|
const body = this.functions.jsStructConstructor(struct.name, options?.createEmptyConstructor ? [] : struct.fields, classId, this.structLookup)
|
2023-05-09 21:25:28 +00:00
|
|
|
|
|
|
|
this.moduleInit.statement(`JSValue ${struct.name}_constr = JS_NewCFunction2(ctx, ${body.getTag("_name")},"${struct.name})", ${struct.fields.length}, JS_CFUNC_constructor_or_func, 0)`)
|
|
|
|
this.moduleInit.call("JS_SetModuleExport", ["ctx","m", `"${struct.name}"`, struct.name+"_constr"])
|
|
|
|
|
|
|
|
this.moduleEntry.call("JS_AddModuleExport", ["ctx","m",'"'+struct.name+'"'])
|
|
|
|
}
|
2023-05-14 20:19:47 +00:00
|
|
|
this.typings.addStruct(struct, options || {})
|
2023-05-08 14:43:50 +00:00
|
|
|
}
|
|
|
|
|
2023-05-14 20:19:47 +00:00
|
|
|
exportGlobalStruct(structName: string, exportName: string, values: string[], description: string){
|
2023-05-10 21:26:53 +00:00
|
|
|
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}"`])
|
2023-05-14 20:19:47 +00:00
|
|
|
this.typings.constants.tsDeclareConstant(exportName, structName, description)
|
2023-05-10 21:26:53 +00:00
|
|
|
}
|
|
|
|
|
2023-05-14 20:19:47 +00:00
|
|
|
exportGlobalConstant(name: string, description: string){
|
2023-05-11 18:54:49 +00:00
|
|
|
this.moduleInit.statement(`JS_SetModuleExport(ctx, m, "${name}", JS_NewInt32(ctx, ${name}))`)
|
|
|
|
this.moduleEntry.statement(`JS_AddModuleExport(ctx, m, "${name}")`)
|
2023-05-14 20:19:47 +00:00
|
|
|
this.typings.constants.tsDeclareConstant(name, "number", description)
|
2023-05-11 18:54:49 +00:00
|
|
|
}
|
2023-05-08 14:43:50 +00:00
|
|
|
}
|