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-06-02 16:58:53 +00:00
console . log ( "Binding function " + api . name )
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-06-04 20:31:15 +00:00
const activeParams = api . params . filter ( x = > ! x . binding ? . ignore )
for ( let i = 0 ; i < activeParams . length ; i ++ ) {
const para = activeParams [ i ]
if ( para . binding ? . customConverter ) para . binding . customConverter ( fun , "argv[" + i + "]" )
2023-06-03 07:15:38 +00:00
else fun . jsToC ( para . type , para . name , "argv[" + i + "]" , this . structLookup , false , para . binding ? . typeAlias )
2023-05-16 06:28:30 +00:00
}
// 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
2023-06-04 20:31:15 +00:00
for ( let i = 0 ; i < activeParams . length ; i ++ ) {
const param = activeParams [ i ]
if ( param . binding ? . customCleanup ) param . binding . customCleanup ( fun , "argv[" + i + "]" )
2023-06-04 11:41:18 +00:00
else fun . jsCleanUpParameter ( param . type , param . name )
2023-05-16 06:28:30 +00:00
}
// 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 16:58:53 +00:00
this . module FunctionList.jsFuncDef ( jName , ( api . params || [ ] ) . filter ( x = > ! x . binding ? . ignore ) . length , 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 ) {
2023-06-02 16:58:53 +00:00
console . log ( "Binding enum " + renum . name )
2023-06-02 09:52:33 +00:00
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-06-02 16:58:53 +00:00
console . log ( "Binding struct " + struct . name )
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-06-12 15:38:31 +00:00
if ( el . get ) _get = this . structs . jsStructGetter ( struct . name , classId , field , type , /*Be carefull when allocating memory in a getter*/ this . structLookup , el . overrideRead )
if ( el . set ) _set = this . structs . jsStructSetter ( struct . name , classId , field , type , this . structLookup , el . overrideWrite )
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 . module Init.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 . module Init.statement ( ` JSValue ${ struct . name } _constr = JS_NewCFunction2(ctx, ${ body . getTag ( "_name" ) } ," ${ struct . name } )", ${ struct . fields . length } , JS_CFUNC_constructor_or_func, 0) ` )
this . module Init.call ( "JS_SetModuleExport" , [ "ctx" , "m" , ` " ${ struct . name } " ` , struct . name + "_constr" ] )
this . module Entry.call ( "JS_AddModuleExport" , [ "ctx" , "m" , '"' + struct . name + '"' ] )
}
2023-06-02 16:58:53 +00:00
this . typings . addStruct ( struct )
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 . module Init.declareStruct ( structName , exportName + "_struct" , values )
const classId = this . structLookup [ structName ]
if ( ! classId ) throw new Error ( "Struct " + structName + " not found in register" )
this . module Init.jsStructToOpq ( structName , exportName + "_js" , exportName + "_struct" , classId )
this . module Init.call ( "JS_SetModuleExport" , [ "ctx" , "m" , ` " ${ exportName } " ` , exportName + "_js" ] )
this . module Entry.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 . module Init.statement ( ` JS_SetModuleExport(ctx, m, " ${ name } ", JS_NewInt32(ctx, ${ name } )) ` )
this . module Entry.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
}