Refactor binding generation

This commit is contained in:
Alexander Klingenbeck 2023-06-02 11:52:33 +02:00
parent 1947483541
commit 8049204120
6 changed files with 227 additions and 611 deletions

View File

@ -1,49 +0,0 @@
import { RayLibApi, RayLibFunction, RayLibStruct, RayLibType } from "./interfaces"
export class ApiFunction{
constructor(private api: RayLibFunction){
api.params = api.params || []
}
get name() { return this.api.name }
get argc() { return this.api.params?.length || 0 }
get params() { return this.api.params || [] }
get returnType() { return this.api.returnType }
set returnType(v) { this.api.returnType = v }
get description() { return this.api.description }
}
export class ApiStruct{
constructor(private api: RayLibStruct){
}
get name() { return this.api.name }
get fields() { return this.api.fields || [] }
}
export class ApiDescription{
constructor(private api: RayLibApi){
}
getAliases(name: string) {
return this.api.aliases.filter(x => x.type === name).map(x => x.name)
}
getFunction(name: string){
const f = this.api.functions.find(x => x.name === name)
if(!f) return null
return new ApiFunction(f)
}
getStruct(name: string){
const s = this.api.structs.find(x => x.name === name)
if(!s) return null
return new ApiStruct(s)
}
getEnums(){
return this.api.enums
}
}

View File

@ -1,20 +1,25 @@
import { readFileSync, writeFileSync } from "fs";
import { RayLibApi, RayLibFunction, RayLibType } from "./interfaces";
import { ApiDescription, ApiFunction } from "./api";
import { RayLibApi, RayLibFunction, RayLibStruct } from "./interfaces";
import { RayLibHeader } from "./raylib-header";
import { HeaderParser } from "./header-parser";
import { RayLibAlias } from "./interfaces";
function getFunction(funList: RayLibFunction[], name: string){
return funList.find(x => x.name === name)
}
function getStruct(strList: RayLibStruct[], name: string){
return strList.find(x => x.name === name)
}
function getAliases(aliasList: RayLibAlias[], name: string) {
return aliasList.filter(x => x.type === name).map(x => x.name)
}
function main(){
// Load the pre-generated raylib api
const api = <RayLibApi>JSON.parse(readFileSync("thirdparty/raylib/parser/output/raylib_api.json", 'utf8'))
api.functions.push({
name: "SetModelMaterial",
description: "Replace material in slot materialIndex",
returnType: "void",
params: [{type: "Model *",name:"model"},{type:"int",name:"materialIndex"},{type:"Material",name:"material"}]
})
const parser = new HeaderParser()
@ -40,12 +45,18 @@ function main(){
const reasingsHeader = readFileSync("include/reasings.h","utf8");
const reasingsFunctions = parser.parseFunctions(reasingsHeader);
//reasingsFunctions.forEach(x => console.log(`core.addApiFunctionByName("${x.name}")`))
reasingsFunctions.forEach(x => api.functions.push(x))
const apiDesc = new ApiDescription(api)
// Custom Rayjs functions
api.functions.push({
name: "SetModelMaterial",
description: "Replace material in slot materialIndex",
returnType: "void",
params: [{type: "Model *",name:"model"},{type:"int",name:"materialIndex"},{type:"Material",name:"material"}]
})
const core = new RayLibHeader("raylib_core", apiDesc)
// Define a new header
const core = new RayLibHeader("raylib_core")
core.includes.include("raymath.h")
core.includes.include("rcamera.h")
core.includes.line("#define RAYGUI_IMPLEMENTATION")
@ -54,7 +65,7 @@ function main(){
core.includes.include("rlights.h")
core.includes.include("reasings.h")
core.addApiStructByName("Color", {
getStruct(api.structs, "Color")!.binding = {
properties: {
r: { get: true, set: true },
g: { get: true, set: true },
@ -62,8 +73,8 @@ function main(){
a: { get: true, set: true },
},
createConstructor: true
})
core.addApiStructByName("Rectangle", {
}
getStruct(api.structs, "Rectangle")!.binding = {
properties: {
x: { get: true, set: true },
y: { get: true, set: true },
@ -71,39 +82,40 @@ function main(){
height: { get: true, set: true },
},
createConstructor: true
})
core.addApiStructByName("Vector2", {
}
getStruct(api.structs, "Vector2")!.binding = {
properties: {
x: { get: true, set: true },
y: { get: true, set: true },
},
createConstructor: true
})
core.addApiStructByName("Vector3", {
}
getStruct(api.structs, "Vector3")!.binding = {
properties: {
x: { get: true, set: true },
y: { get: true, set: true },
z: { get: true, set: true },
},
createConstructor: true
})
core.addApiStructByName("Vector4", {
}
getStruct(api.structs, "Vector4")!.binding = {
properties: {
x: { get: true, set: true },
y: { get: true, set: true },
z: { get: true, set: true },
w: { get: true, set: true },
},
createConstructor: true
})
core.addApiStructByName("Ray", {
createConstructor: true,
aliases: getAliases(api.aliases, "Vector4")
}
getStruct(api.structs, "Ray")!.binding = {
properties: {
position: { get: false, set: true },
direction: { get: false, set: true },
},
createConstructor: true
})
core.addApiStructByName("RayCollision", {
}
getStruct(api.structs, "RayCollision")!.binding = {
properties: {
hit: { get: true, set: false },
distance: { get: true, set: false },
@ -111,8 +123,8 @@ function main(){
normal: { get: true, set: false },
},
createConstructor: false
})
core.addApiStructByName("Camera2D",{
}
getStruct(api.structs, "Camera2D")!.binding = {
properties: {
offset: { get: true, set: true },
target: { get: true, set: true },
@ -120,8 +132,8 @@ function main(){
zoom: { get: true, set: true },
},
createConstructor: true
})
core.addApiStructByName("Camera3D",{
}
getStruct(api.structs, "Camera3D")!.binding = {
properties: {
position: { get: true, set: true },
target: { get: true, set: true },
@ -129,20 +141,21 @@ function main(){
fovy: { get: true, set: true },
projection: { get: true, set: true },
},
createConstructor: true
})
core.addApiStructByName("BoundingBox",{
createConstructor: true,
aliases: getAliases(api.aliases, "Camera3D")
}
getStruct(api.structs, "BoundingBox")!.binding = {
properties: {
min: { get: true, set: true },
max: { get: true, set: true },
},
createConstructor: true
})
core.addApiStructByName("Matrix",{
}
getStruct(api.structs, "Matrix")!.binding = {
properties: {},
createConstructor: false
})
core.addApiStructByName("NPatchInfo",{
}
getStruct(api.structs, "NPatchInfo")!.binding = {
properties: {
source: { get: true, set: true },
left: { get: true, set: true },
@ -152,8 +165,8 @@ function main(){
layout: { get: true, set: true },
},
createConstructor: true
})
core.addApiStructByName("Image", {
}
getStruct(api.structs, "Image")!.binding = {
properties: {
//data: { set: true },
width: { get: true },
@ -162,8 +175,8 @@ function main(){
format: { get: true }
},
//destructor: "UnloadImage"
})
core.addApiStructByName("Wave", {
}
getStruct(api.structs, "Wave")!.binding = {
properties: {
frameCount: { get: true },
sampleRate: { get: true },
@ -171,22 +184,22 @@ function main(){
channels: { get: true }
},
//destructor: "UnloadWave"
})
core.addApiStructByName("Sound", {
}
getStruct(api.structs, "Sound")!.binding = {
properties: {
frameCount: { get: true }
},
//destructor: "UnloadSound"
})
core.addApiStructByName("Music", {
}
getStruct(api.structs, "Music")!.binding = {
properties: {
frameCount: { get: true },
looping: { get: true, set: true },
ctxType: { get: true },
},
//destructor: "UnloadMusicStream"
})
core.addApiStructByName("Model", {
}
getStruct(api.structs, "Model")!.binding = {
properties: {
transform: { get: true, set: true },
meshCount: { get: true },
@ -194,8 +207,8 @@ function main(){
boneCount: { get: true },
},
//destructor: "UnloadModel"
})
core.addApiStructByName("Mesh", {
}
getStruct(api.structs, "Mesh")!.binding = {
properties: {
vertexCount: { get: true, set: true },
triangleCount: { get: true, set: true },
@ -214,139 +227,68 @@ function main(){
},
createEmptyConstructor: true
//destructor: "UnloadMesh"
})
core.addApiStructByName("Shader", {
}
getStruct(api.structs, "Shader")!.binding = {
properties: {
id: { get: true }
},
//destructor: "UnloadShader"
})
core.addApiStructByName("Texture", {
}
getStruct(api.structs, "Texture")!.binding = {
properties: {
width: { get: true },
height: { get: true },
mipmaps: { get: true },
format: { get: true },
},
aliases: getAliases(api.aliases, "Texture")
//destructor: "UnloadTexture"
})
core.addApiStructByName("Font", {
}
getStruct(api.structs, "Font")!.binding = {
properties: {
baseSize: { get: true },
glyphCount: { get: true },
glyphPadding: { get: true },
},
//destructor: "UnloadFont"
})
core.addApiStructByName("RenderTexture", {
}
getStruct(api.structs, "RenderTexture")!.binding = {
properties: {
id: { get: true }
},
aliases: getAliases(api.aliases, "RenderTexture")
//destructor: "UnloadRenderTexture"
})
core.addApiStructByName("MaterialMap", {
}
getStruct(api.structs, "MaterialMap")!.binding = {
properties: {
texture: { set: true },
color: { set: true, get: true },
value: { get: true, set: true }
},
//destructor: "UnloadMaterialMap"
})
core.addApiStructByName("Material", {
}
getStruct(api.structs, "Material")!.binding = {
properties: {
shader: { set: true }
},
//destructor: "UnloadMaterial"
})
}
// Window-related functions
core.addApiFunctionByName("InitWindow")
core.addApiFunctionByName("WindowShouldClose")
core.addApiFunctionByName("CloseWindow")
core.addApiFunctionByName("IsWindowReady")
core.addApiFunctionByName("IsWindowFullscreen")
core.addApiFunctionByName("IsWindowHidden")
core.addApiFunctionByName("IsWindowMinimized")
core.addApiFunctionByName("IsWindowMaximized")
core.addApiFunctionByName("IsWindowFocused")
core.addApiFunctionByName("IsWindowResized")
core.addApiFunctionByName("IsWindowState")
core.addApiFunctionByName("SetWindowState")
core.addApiFunctionByName("ClearWindowState")
core.addApiFunctionByName("ToggleFullscreen")
core.addApiFunctionByName("MaximizeWindow")
core.addApiFunctionByName("MinimizeWindow")
core.addApiFunctionByName("RestoreWindow")
core.addApiFunctionByName("SetWindowIcon")
// SetWindowIcons
core.addApiFunctionByName("SetWindowTitle")
core.addApiFunctionByName("SetWindowPosition")
core.addApiFunctionByName("SetWindowMonitor")
core.addApiFunctionByName("SetWindowMinSize")
core.addApiFunctionByName("SetWindowSize")
core.addApiFunctionByName("SetWindowOpacity")
// GetWindowHandle
core.addApiFunctionByName("GetScreenWidth")
core.addApiFunctionByName("GetScreenHeight")
core.addApiFunctionByName("GetRenderWidth")
core.addApiFunctionByName("GetRenderHeight")
core.addApiFunctionByName("GetMonitorCount")
core.addApiFunctionByName("GetCurrentMonitor")
core.addApiFunctionByName("GetMonitorPosition")
core.addApiFunctionByName("GetMonitorWidth")
core.addApiFunctionByName("GetMonitorHeight")
core.addApiFunctionByName("GetMonitorPhysicalWidth")
core.addApiFunctionByName("GetMonitorPhysicalHeight")
core.addApiFunctionByName("GetMonitorRefreshRate")
core.addApiFunctionByName("GetWindowPosition")
core.addApiFunctionByName("GetWindowScaleDPI")
core.addApiFunctionByName("GetMonitorName")
core.addApiFunctionByName("SetClipboardText")
core.addApiFunctionByName("GetClipboardText")
core.addApiFunctionByName("EnableEventWaiting")
core.addApiFunctionByName("DisableEventWaiting")
getFunction(api.functions, "SetWindowIcons")!.binding = { ignore: true }
getFunction(api.functions, "GetWindowHandle")!.binding = { ignore: true }
// Custom frame control functions
// NOT SUPPORTED BECAUSE NEEDS COMPILER FLAG
// Cursor-related functions
core.addApiFunctionByName("ShowCursor")
core.addApiFunctionByName("HideCursor")
core.addApiFunctionByName("IsCursorHidden")
core.addApiFunctionByName("EnableCursor")
core.addApiFunctionByName("DisableCursor")
core.addApiFunctionByName("IsCursorOnScreen")
// Drawing related functions
core.addApiFunctionByName("ClearBackground")
core.addApiFunctionByName("BeginDrawing")
core.addApiFunctionByName("EndDrawing", null, { before: fun => fun.call("app_update_quickjs", []) })
core.addApiFunctionByName("BeginMode2D")
core.addApiFunctionByName("EndMode2D")
core.addApiFunctionByName("BeginMode3D")
core.addApiFunctionByName("EndMode3D")
core.addApiFunctionByName("BeginTextureMode")
core.addApiFunctionByName("EndTextureMode")
core.addApiFunctionByName("BeginShaderMode")
core.addApiFunctionByName("EndShaderMode")
core.addApiFunctionByName("BeginBlendMode")
core.addApiFunctionByName("EndBlendMode")
core.addApiFunctionByName("BeginScissorMode")
core.addApiFunctionByName("EndScissorMode")
//core.addApiFunctionByName("BeginVrStereoMode")
//core.addApiFunctionByName("EndVrStereoMode")
getFunction(api.functions, "SwapScreenBuffer")!.binding = { ignore: true }
getFunction(api.functions, "PollInputEvents")!.binding = { ignore: true }
getFunction(api.functions, "WaitTime")!.binding = { ignore: true }
// VR Stereo config options
//core.addApiFunctionByName("LoadVrStereoConfig")
//core.addApiFunctionByName("UnloadVrStereoConfig")
// Shader Management
core.addApiFunctionByName("LoadShader")
core.addApiFunctionByName("LoadShaderFromMemory")
core.addApiFunctionByName("IsShaderReady")
core.addApiFunctionByName("GetShaderLocation")
core.addApiFunctionByName("GetShaderLocationAttrib")
core.addApiFunctionByName("SetShaderValue", null, { body: (gen) => {
getFunction(api.functions, "BeginVrStereoMode")!.binding = { ignore: true }
getFunction(api.functions, "EndVrStereoMode")!.binding = { ignore: true }
getFunction(api.functions, "LoadVrStereoConfig")!.binding = { ignore: true }
getFunction(api.functions, "UnloadVrStereoConfig")!.binding = { ignore: true }
getFunction(api.functions, "SetShaderValue")!.binding = { body: (gen) => {
gen.jsToC("Shader","shader","argv[0]", core.structLookup)
gen.jsToC("int","locIndex","argv[1]", core.structLookup)
gen.declare("value","void *", false, "NULL")
@ -373,32 +315,9 @@ function main(){
b.returnExp("JS_EXCEPTION")
gen.call("SetShaderValue", ["shader","locIndex","value","uniformType"])
gen.returnExp("JS_UNDEFINED")
}})
// core.addApiFunctionByName("SetShaderValueV")
core.addApiFunctionByName("SetShaderValueMatrix")
core.addApiFunctionByName("SetShaderValueTexture")
core.addApiFunctionByName("UnloadShader")
}}
getFunction(api.functions, "SetShaderValueV")!.binding = { ignore: true }
// ScreenSpaceRelatedFunctions
core.addApiFunctionByName("GetMouseRay")
core.addApiFunctionByName("GetCameraMatrix")
core.addApiFunctionByName("GetCameraMatrix2D")
core.addApiFunctionByName("GetWorldToScreen")
core.addApiFunctionByName("GetScreenToWorld2D")
core.addApiFunctionByName("GetWorldToScreenEx")
core.addApiFunctionByName("GetWorldToScreen2D")
// Timing related functions
core.addApiFunctionByName("SetTargetFPS")
core.addApiFunctionByName("GetFPS")
core.addApiFunctionByName("GetFrameTime")
core.addApiFunctionByName("GetTime")
// Misc functions
core.addApiFunctionByName("GetRandomValue")
core.addApiFunctionByName("SetRandomSeed")
core.addApiFunctionByName("TakeScreenshot")
core.addApiFunctionByName("SetConfigFlags")
const traceLog = apiDesc.getFunction("TraceLog")
if(!traceLog) throw new Error("TraceLog not found")

View File

@ -1,3 +1,23 @@
import { QuickJsGenerator } from "./quickjs"
export interface StructBindingOptions {
properties?: { [key:string]: { get?:boolean, set?:boolean } },
destructor?: RayLibFunction,
construct?: string,
createConstructor?: boolean
createEmptyConstructor?: boolean,
aliases?: string[]
}
export interface FuncBindingOptions {
before?: (gen: QuickJsGenerator) => void,
after?: (gen: QuickJsGenerator) => void,
customizeCall?: string,
body?: (gen: QuickJsGenerator) => void,
jsName?: string,
ignore?: boolean
}
export type RayLibType = "void" | "const char *" | "bool" | "float" | "unsigned char" | "void *" | "int" | "usigned int" | "Texture" | "Rectangle" | "Image" | "Rectangle *" | "GylphInfo *" | "Texture2D" | "Vector3" | "Vector2" | "float *" | "unsigned char *" | "unsigned short *" | "unsigned int *" | "Shader" | "MaterialMap *" | "float[4]" | "Vector3"
export interface RayLibDefine {
@ -16,7 +36,8 @@ export interface RayLibFieldDescription {
export interface RayLibStruct {
name: string,
description: string,
fields: RayLibFieldDescription[]
fields: RayLibFieldDescription[],
binding?: StructBindingOptions
}
export interface RayLibEnumValue {
@ -40,7 +61,8 @@ export interface RayLibFunction {
name: string,
description: string,
returnType: RayLibType | string,
params?: RayLibParamDescription[]
params?: RayLibParamDescription[],
binding?: FuncBindingOptions
}
export interface RayLibAlias {

View File

@ -1,37 +1,27 @@
import { ApiDescription, ApiFunction, ApiStruct } from "./api"
import { CodeGenerator } from "./generation"
import { RayLibEnum, RayLibFunction, RayLibStruct } from "./interfaces"
import { QuickJsGenerator, QuickJsHeader } from "./quickjs"
import { TypeScriptDeclaration } from "./typescript"
export interface StructBindingOptions {
properties?: { [key:string]: { get?:boolean, set?:boolean } },
destructor?: string,
construct?: string,
createConstructor?: boolean
createEmptyConstructor?: boolean
}
export interface FuncBindingOptions {
before?: (gen: QuickJsGenerator) => void,
after?: (gen: QuickJsGenerator) => void,
customizeCall?: string,
body?: (gen: QuickJsGenerator) => void
}
export class RayLibHeader extends QuickJsHeader {
typings = new TypeScriptDeclaration()
constructor(name: string, private api: ApiDescription){
constructor(name: string){
super(name)
this.includes.include("raylib.h")
//this.includes.line("#define RAYMATH_IMPLEMENTATION")
}
addApiFunction(api: ApiFunction, jsName: string | null = null, options: FuncBindingOptions = {}){
const jName = jsName || api.name.charAt(0).toLowerCase() + api.name.slice(1)
addApiFunction(api: RayLibFunction){
const options = api.binding || {}
if(options.ignore) return
const jName = options.jsName || api.name.charAt(0).toLowerCase() + api.name.slice(1)
const fun = this.functions.jsBindingFunction(jName)
if(options.body) {
@ -39,6 +29,7 @@ export class RayLibHeader extends QuickJsHeader {
} else {
if(options.before) options.before(fun)
// read parameters
api.params = api.params || []
for (let i = 0; i < api.params.length; i++) {
const para = api.params[i]
fun.jsToC(para.type,para.name,"argv["+i+"]", this.structLookup)
@ -62,25 +53,20 @@ export class RayLibHeader extends QuickJsHeader {
}
// add binding to function declaration
this.moduleFunctionList.jsFuncDef(jName, api.argc, fun.getTag("_name"))
this.moduleFunctionList.jsFuncDef(jName, api.params?.length ?? 0, fun.getTag("_name"))
this.typings.addFunction(jName,api)
}
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, options)
addEnum(renum: RayLibEnum){
renum.values.forEach(x => this.exportGlobalConstant(x.name, x.description))
}
addAllEnums(){
this.api.getEnums().forEach(x => x.values.forEach(y => this.exportGlobalConstant(y.name, y.description)))
}
addApiStruct(struct: ApiStruct, destructor: ApiFunction | null, options?: StructBindingOptions){
addApiStruct(struct: RayLibStruct){
const options = struct.binding || {}
const classId = this.definitions.jsClassId(`js_${struct.name}_class_id`)
this.registerStruct(struct.name, classId)
this.api.getAliases(struct.name).forEach(x => this.registerStruct(x, classId))
const finalizer = this.structs.jsStructFinalizer(classId, struct.name, (gen,ptr) => destructor && gen.call(destructor.name, ["*"+ptr]))
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]))
const propDeclarations = this.structs.createGenerator()
if(options && options.properties){
@ -129,15 +115,4 @@ export class RayLibHeader extends QuickJsHeader {
this.moduleEntry.statement(`JS_AddModuleExport(ctx, m, "${name}")`)
this.typings.constants.tsDeclareConstant(name, "number", description)
}
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(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)
}
}

View File

@ -1,99 +0,0 @@
/******/ (() => { // webpackBootstrap
/******/ "use strict";
/******/ var __webpack_modules__ = ({
/***/ "./src/game.ts":
/*!*********************!*\
!*** ./src/game.ts ***!
\*********************/
/***/ ((__unused_webpack_module, exports) => {
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.Game = void 0;
class Game {
constructor(width, height, title) {
this.width = width;
this.height = height;
this.title = title;
this.clearColor = RAYWHITE;
this.quit = false;
}
run() {
initWindow(this.width, this.height, this.title);
setTargetFPS(60);
this.load();
while (!(this.quit = windowShouldClose())) {
this.update();
beginDrawing();
clearBackground(this.clearColor);
this.draw();
endDrawing();
}
this.unload();
closeWindow();
}
}
exports.Game = Game;
/***/ })
/******/ });
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/************************************************************************/
var __webpack_exports__ = {};
// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
(() => {
var exports = __webpack_exports__;
/*!**********************!*\
!*** ./src/index.ts ***!
\**********************/
Object.defineProperty(exports, "__esModule", ({ value: true }));
const game_1 = __webpack_require__(/*! ./game */ "./src/game.ts");
class MyGame extends game_1.Game {
draw() {
throw new Error("Method not implemented.");
}
update() {
throw new Error("Method not implemented.");
}
load() {
throw new Error("Method not implemented.");
}
unload() {
throw new Error("Method not implemented.");
}
}
const game = new MyGame(800, 450, "Typescript Game");
game.run();
})();
/******/ })()
;

View File

@ -2,64 +2,6 @@
/******/ "use strict";
/******/ var __webpack_modules__ = ({
/***/ "./src/api.ts":
/*!********************!*\
!*** ./src/api.ts ***!
\********************/
/***/ ((__unused_webpack_module, exports) => {
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.ApiDescription = exports.ApiStruct = exports.ApiFunction = void 0;
class ApiFunction {
constructor(api) {
this.api = api;
api.params = api.params || [];
}
get name() { return this.api.name; }
get argc() { return this.api.params?.length || 0; }
get params() { return this.api.params || []; }
get returnType() { return this.api.returnType; }
set returnType(v) { this.api.returnType = v; }
get description() { return this.api.description; }
}
exports.ApiFunction = ApiFunction;
class ApiStruct {
constructor(api) {
this.api = api;
}
get name() { return this.api.name; }
get fields() { return this.api.fields || []; }
}
exports.ApiStruct = ApiStruct;
class ApiDescription {
constructor(api) {
this.api = api;
}
getAliases(name) {
return this.api.aliases.filter(x => x.type === name).map(x => x.name);
}
getFunction(name) {
const f = this.api.functions.find(x => x.name === name);
if (!f)
return null;
return new ApiFunction(f);
}
getStruct(name) {
const s = this.api.structs.find(x => x.name === name);
if (!s)
return null;
return new ApiStruct(s);
}
getEnums() {
return this.api.enums;
}
}
exports.ApiDescription = ApiDescription;
/***/ }),
/***/ "./src/generation.ts":
/*!***************************!*\
!*** ./src/generation.ts ***!
@ -698,15 +640,17 @@ exports.RayLibHeader = void 0;
const quickjs_1 = __webpack_require__(/*! ./quickjs */ "./src/quickjs.ts");
const typescript_1 = __webpack_require__(/*! ./typescript */ "./src/typescript.ts");
class RayLibHeader extends quickjs_1.QuickJsHeader {
constructor(name, api) {
constructor(name) {
super(name);
this.api = api;
this.typings = new typescript_1.TypeScriptDeclaration();
this.includes.include("raylib.h");
//this.includes.line("#define RAYMATH_IMPLEMENTATION")
}
addApiFunction(api, jsName = null, options = {}) {
const jName = jsName || api.name.charAt(0).toLowerCase() + api.name.slice(1);
addApiFunction(api) {
const options = api.binding || {};
if (options.ignore)
return;
const jName = options.jsName || api.name.charAt(0).toLowerCase() + api.name.slice(1);
const fun = this.functions.jsBindingFunction(jName);
if (options.body) {
options.body(fun);
@ -715,6 +659,7 @@ class RayLibHeader extends quickjs_1.QuickJsHeader {
if (options.before)
options.before(fun);
// read parameters
api.params = api.params || [];
for (let i = 0; i < api.params.length; i++) {
const para = api.params[i];
fun.jsToC(para.type, para.name, "argv[" + i + "]", this.structLookup);
@ -742,23 +687,18 @@ class RayLibHeader extends quickjs_1.QuickJsHeader {
}
}
// add binding to function declaration
this.moduleFunctionList.jsFuncDef(jName, api.argc, fun.getTag("_name"));
this.moduleFunctionList.jsFuncDef(jName, api.params?.length ?? 0, fun.getTag("_name"));
this.typings.addFunction(jName, api);
}
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, options);
addEnum(renum) {
renum.values.forEach(x => this.exportGlobalConstant(x.name, x.description));
}
addAllEnums() {
this.api.getEnums().forEach(x => x.values.forEach(y => this.exportGlobalConstant(y.name, y.description)));
}
addApiStruct(struct, destructor, options) {
addApiStruct(struct) {
const options = struct.binding || {};
const classId = this.definitions.jsClassId(`js_${struct.name}_class_id`);
this.registerStruct(struct.name, classId);
this.api.getAliases(struct.name).forEach(x => this.registerStruct(x, classId));
const finalizer = this.structs.jsStructFinalizer(classId, struct.name, (gen, ptr) => destructor && gen.call(destructor.name, ["*" + ptr]));
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]));
const propDeclarations = this.structs.createGenerator();
if (options && options.properties) {
for (const field of Object.keys(options.properties)) {
@ -803,18 +743,6 @@ class RayLibHeader extends quickjs_1.QuickJsHeader {
this.moduleEntry.statement(`JS_AddModuleExport(ctx, m, "${name}")`);
this.typings.constants.tsDeclareConstant(name, "number", description);
}
addApiStructByName(structName, options) {
const struct = this.api.getStruct(structName);
if (!struct)
throw new Error("Struct not in API: " + structName);
let destructor = null;
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);
}
}
exports.RayLibHeader = RayLibHeader;
@ -985,18 +913,20 @@ var exports = __webpack_exports__;
Object.defineProperty(exports, "__esModule", ({ value: true }));
const fs_1 = __webpack_require__(/*! fs */ "fs");
const api_1 = __webpack_require__(/*! ./api */ "./src/api.ts");
const raylib_header_1 = __webpack_require__(/*! ./raylib-header */ "./src/raylib-header.ts");
const header_parser_1 = __webpack_require__(/*! ./header-parser */ "./src/header-parser.ts");
function getFunction(funList, name) {
return funList.find(x => x.name === name);
}
function getStruct(strList, name) {
return strList.find(x => x.name === name);
}
function getAliases(aliasList, name) {
return aliasList.filter(x => x.type === name).map(x => x.name);
}
function main() {
// Load the pre-generated raylib api
const api = JSON.parse((0, fs_1.readFileSync)("thirdparty/raylib/parser/output/raylib_api.json", 'utf8'));
api.functions.push({
name: "SetModelMaterial",
description: "Replace material in slot materialIndex",
returnType: "void",
params: [{ type: "Model *", name: "model" }, { type: "int", name: "materialIndex" }, { type: "Material", name: "material" }]
});
const parser = new header_parser_1.HeaderParser();
const rmathHeader = (0, fs_1.readFileSync)("thirdparty/raylib/src/raymath.h", "utf8");
const mathApi = parser.parseFunctions(rmathHeader);
@ -1016,10 +946,16 @@ function main() {
api.functions.push(rlightsFunctions[1]);
const reasingsHeader = (0, fs_1.readFileSync)("include/reasings.h", "utf8");
const reasingsFunctions = parser.parseFunctions(reasingsHeader);
//reasingsFunctions.forEach(x => console.log(`core.addApiFunctionByName("${x.name}")`))
reasingsFunctions.forEach(x => api.functions.push(x));
const apiDesc = new api_1.ApiDescription(api);
const core = new raylib_header_1.RayLibHeader("raylib_core", apiDesc);
// Custom Rayjs functions
api.functions.push({
name: "SetModelMaterial",
description: "Replace material in slot materialIndex",
returnType: "void",
params: [{ type: "Model *", name: "model" }, { type: "int", name: "materialIndex" }, { type: "Material", name: "material" }]
});
// Define a new header
const core = new raylib_header_1.RayLibHeader("raylib_core");
core.includes.include("raymath.h");
core.includes.include("rcamera.h");
core.includes.line("#define RAYGUI_IMPLEMENTATION");
@ -1027,7 +963,7 @@ function main() {
core.includes.line("#define RLIGHTS_IMPLEMENTATION");
core.includes.include("rlights.h");
core.includes.include("reasings.h");
core.addApiStructByName("Color", {
getStruct(api.structs, "Color").binding = {
properties: {
r: { get: true, set: true },
g: { get: true, set: true },
@ -1035,8 +971,8 @@ function main() {
a: { get: true, set: true },
},
createConstructor: true
});
core.addApiStructByName("Rectangle", {
};
getStruct(api.structs, "Rectangle").binding = {
properties: {
x: { get: true, set: true },
y: { get: true, set: true },
@ -1044,39 +980,40 @@ function main() {
height: { get: true, set: true },
},
createConstructor: true
});
core.addApiStructByName("Vector2", {
};
getStruct(api.structs, "Vector2").binding = {
properties: {
x: { get: true, set: true },
y: { get: true, set: true },
},
createConstructor: true
});
core.addApiStructByName("Vector3", {
};
getStruct(api.structs, "Vector3").binding = {
properties: {
x: { get: true, set: true },
y: { get: true, set: true },
z: { get: true, set: true },
},
createConstructor: true
});
core.addApiStructByName("Vector4", {
};
getStruct(api.structs, "Vector4").binding = {
properties: {
x: { get: true, set: true },
y: { get: true, set: true },
z: { get: true, set: true },
w: { get: true, set: true },
},
createConstructor: true
});
core.addApiStructByName("Ray", {
createConstructor: true,
aliases: getAliases(api.aliases, "Vector4")
};
getStruct(api.structs, "Ray").binding = {
properties: {
position: { get: false, set: true },
direction: { get: false, set: true },
},
createConstructor: true
});
core.addApiStructByName("RayCollision", {
};
getStruct(api.structs, "RayCollision").binding = {
properties: {
hit: { get: true, set: false },
distance: { get: true, set: false },
@ -1084,8 +1021,8 @@ function main() {
normal: { get: true, set: false },
},
createConstructor: false
});
core.addApiStructByName("Camera2D", {
};
getStruct(api.structs, "Camera2D").binding = {
properties: {
offset: { get: true, set: true },
target: { get: true, set: true },
@ -1093,8 +1030,8 @@ function main() {
zoom: { get: true, set: true },
},
createConstructor: true
});
core.addApiStructByName("Camera3D", {
};
getStruct(api.structs, "Camera3D").binding = {
properties: {
position: { get: true, set: true },
target: { get: true, set: true },
@ -1102,20 +1039,21 @@ function main() {
fovy: { get: true, set: true },
projection: { get: true, set: true },
},
createConstructor: true
});
core.addApiStructByName("BoundingBox", {
createConstructor: true,
aliases: getAliases(api.aliases, "Camera3D")
};
getStruct(api.structs, "BoundingBox").binding = {
properties: {
min: { get: true, set: true },
max: { get: true, set: true },
},
createConstructor: true
});
core.addApiStructByName("Matrix", {
};
getStruct(api.structs, "Matrix").binding = {
properties: {},
createConstructor: false
});
core.addApiStructByName("NPatchInfo", {
};
getStruct(api.structs, "NPatchInfo").binding = {
properties: {
source: { get: true, set: true },
left: { get: true, set: true },
@ -1125,8 +1063,8 @@ function main() {
layout: { get: true, set: true },
},
createConstructor: true
});
core.addApiStructByName("Image", {
};
getStruct(api.structs, "Image").binding = {
properties: {
//data: { set: true },
width: { get: true },
@ -1135,8 +1073,8 @@ function main() {
format: { get: true }
},
//destructor: "UnloadImage"
});
core.addApiStructByName("Wave", {
};
getStruct(api.structs, "Wave").binding = {
properties: {
frameCount: { get: true },
sampleRate: { get: true },
@ -1144,22 +1082,22 @@ function main() {
channels: { get: true }
},
//destructor: "UnloadWave"
});
core.addApiStructByName("Sound", {
};
getStruct(api.structs, "Sound").binding = {
properties: {
frameCount: { get: true }
},
//destructor: "UnloadSound"
});
core.addApiStructByName("Music", {
};
getStruct(api.structs, "Music").binding = {
properties: {
frameCount: { get: true },
looping: { get: true, set: true },
ctxType: { get: true },
},
//destructor: "UnloadMusicStream"
});
core.addApiStructByName("Model", {
};
getStruct(api.structs, "Model").binding = {
properties: {
transform: { get: true, set: true },
meshCount: { get: true },
@ -1167,8 +1105,8 @@ function main() {
boneCount: { get: true },
},
//destructor: "UnloadModel"
});
core.addApiStructByName("Mesh", {
};
getStruct(api.structs, "Mesh").binding = {
properties: {
vertexCount: { get: true, set: true },
triangleCount: { get: true, set: true },
@ -1187,133 +1125,64 @@ function main() {
},
createEmptyConstructor: true
//destructor: "UnloadMesh"
});
core.addApiStructByName("Shader", {
};
getStruct(api.structs, "Shader").binding = {
properties: {
id: { get: true }
},
//destructor: "UnloadShader"
});
core.addApiStructByName("Texture", {
};
getStruct(api.structs, "Texture").binding = {
properties: {
width: { get: true },
height: { get: true },
mipmaps: { get: true },
format: { get: true },
},
aliases: getAliases(api.aliases, "Texture")
//destructor: "UnloadTexture"
});
core.addApiStructByName("Font", {
};
getStruct(api.structs, "Font").binding = {
properties: {
baseSize: { get: true },
glyphCount: { get: true },
glyphPadding: { get: true },
},
//destructor: "UnloadFont"
});
core.addApiStructByName("RenderTexture", {
};
getStruct(api.structs, "RenderTexture").binding = {
properties: {
id: { get: true }
},
aliases: getAliases(api.aliases, "RenderTexture")
//destructor: "UnloadRenderTexture"
});
core.addApiStructByName("MaterialMap", {
};
getStruct(api.structs, "MaterialMap").binding = {
properties: {
texture: { set: true },
color: { set: true, get: true },
value: { get: true, set: true }
},
//destructor: "UnloadMaterialMap"
});
core.addApiStructByName("Material", {
};
getStruct(api.structs, "Material").binding = {
properties: {
shader: { set: true }
},
//destructor: "UnloadMaterial"
});
// Window-related functions
core.addApiFunctionByName("InitWindow");
core.addApiFunctionByName("WindowShouldClose");
core.addApiFunctionByName("CloseWindow");
core.addApiFunctionByName("IsWindowReady");
core.addApiFunctionByName("IsWindowFullscreen");
core.addApiFunctionByName("IsWindowHidden");
core.addApiFunctionByName("IsWindowMinimized");
core.addApiFunctionByName("IsWindowMaximized");
core.addApiFunctionByName("IsWindowFocused");
core.addApiFunctionByName("IsWindowResized");
core.addApiFunctionByName("IsWindowState");
core.addApiFunctionByName("SetWindowState");
core.addApiFunctionByName("ClearWindowState");
core.addApiFunctionByName("ToggleFullscreen");
core.addApiFunctionByName("MaximizeWindow");
core.addApiFunctionByName("MinimizeWindow");
core.addApiFunctionByName("RestoreWindow");
core.addApiFunctionByName("SetWindowIcon");
// SetWindowIcons
core.addApiFunctionByName("SetWindowTitle");
core.addApiFunctionByName("SetWindowPosition");
core.addApiFunctionByName("SetWindowMonitor");
core.addApiFunctionByName("SetWindowMinSize");
core.addApiFunctionByName("SetWindowSize");
core.addApiFunctionByName("SetWindowOpacity");
// GetWindowHandle
core.addApiFunctionByName("GetScreenWidth");
core.addApiFunctionByName("GetScreenHeight");
core.addApiFunctionByName("GetRenderWidth");
core.addApiFunctionByName("GetRenderHeight");
core.addApiFunctionByName("GetMonitorCount");
core.addApiFunctionByName("GetCurrentMonitor");
core.addApiFunctionByName("GetMonitorPosition");
core.addApiFunctionByName("GetMonitorWidth");
core.addApiFunctionByName("GetMonitorHeight");
core.addApiFunctionByName("GetMonitorPhysicalWidth");
core.addApiFunctionByName("GetMonitorPhysicalHeight");
core.addApiFunctionByName("GetMonitorRefreshRate");
core.addApiFunctionByName("GetWindowPosition");
core.addApiFunctionByName("GetWindowScaleDPI");
core.addApiFunctionByName("GetMonitorName");
core.addApiFunctionByName("SetClipboardText");
core.addApiFunctionByName("GetClipboardText");
core.addApiFunctionByName("EnableEventWaiting");
core.addApiFunctionByName("DisableEventWaiting");
};
getFunction(api.functions, "SetWindowIcons").binding = { ignore: true };
getFunction(api.functions, "GetWindowHandle").binding = { ignore: true };
// Custom frame control functions
// NOT SUPPORTED BECAUSE NEEDS COMPILER FLAG
// Cursor-related functions
core.addApiFunctionByName("ShowCursor");
core.addApiFunctionByName("HideCursor");
core.addApiFunctionByName("IsCursorHidden");
core.addApiFunctionByName("EnableCursor");
core.addApiFunctionByName("DisableCursor");
core.addApiFunctionByName("IsCursorOnScreen");
// Drawing related functions
core.addApiFunctionByName("ClearBackground");
core.addApiFunctionByName("BeginDrawing");
core.addApiFunctionByName("EndDrawing", null, { before: fun => fun.call("app_update_quickjs", []) });
core.addApiFunctionByName("BeginMode2D");
core.addApiFunctionByName("EndMode2D");
core.addApiFunctionByName("BeginMode3D");
core.addApiFunctionByName("EndMode3D");
core.addApiFunctionByName("BeginTextureMode");
core.addApiFunctionByName("EndTextureMode");
core.addApiFunctionByName("BeginShaderMode");
core.addApiFunctionByName("EndShaderMode");
core.addApiFunctionByName("BeginBlendMode");
core.addApiFunctionByName("EndBlendMode");
core.addApiFunctionByName("BeginScissorMode");
core.addApiFunctionByName("EndScissorMode");
//core.addApiFunctionByName("BeginVrStereoMode")
//core.addApiFunctionByName("EndVrStereoMode")
// VR Stereo config options
//core.addApiFunctionByName("LoadVrStereoConfig")
//core.addApiFunctionByName("UnloadVrStereoConfig")
// Shader Management
core.addApiFunctionByName("LoadShader");
core.addApiFunctionByName("LoadShaderFromMemory");
core.addApiFunctionByName("IsShaderReady");
core.addApiFunctionByName("GetShaderLocation");
core.addApiFunctionByName("GetShaderLocationAttrib");
core.addApiFunctionByName("SetShaderValue", null, { body: (gen) => {
getFunction(api.functions, "SwapScreenBuffer").binding = { ignore: true };
getFunction(api.functions, "PollInputEvents").binding = { ignore: true };
getFunction(api.functions, "WaitTime").binding = { ignore: true };
getFunction(api.functions, "BeginVrStereoMode").binding = { ignore: true };
getFunction(api.functions, "EndVrStereoMode").binding = { ignore: true };
getFunction(api.functions, "LoadVrStereoConfig").binding = { ignore: true };
getFunction(api.functions, "UnloadVrStereoConfig").binding = { ignore: true };
getFunction(api.functions, "SetShaderValue").binding = { body: (gen) => {
gen.jsToC("Shader", "shader", "argv[0]", core.structLookup);
gen.jsToC("int", "locIndex", "argv[1]", core.structLookup);
gen.declare("value", "void *", false, "NULL");
@ -1340,29 +1209,8 @@ function main() {
b.returnExp("JS_EXCEPTION");
gen.call("SetShaderValue", ["shader", "locIndex", "value", "uniformType"]);
gen.returnExp("JS_UNDEFINED");
} });
// core.addApiFunctionByName("SetShaderValueV")
core.addApiFunctionByName("SetShaderValueMatrix");
core.addApiFunctionByName("SetShaderValueTexture");
core.addApiFunctionByName("UnloadShader");
// ScreenSpaceRelatedFunctions
core.addApiFunctionByName("GetMouseRay");
core.addApiFunctionByName("GetCameraMatrix");
core.addApiFunctionByName("GetCameraMatrix2D");
core.addApiFunctionByName("GetWorldToScreen");
core.addApiFunctionByName("GetScreenToWorld2D");
core.addApiFunctionByName("GetWorldToScreenEx");
core.addApiFunctionByName("GetWorldToScreen2D");
// Timing related functions
core.addApiFunctionByName("SetTargetFPS");
core.addApiFunctionByName("GetFPS");
core.addApiFunctionByName("GetFrameTime");
core.addApiFunctionByName("GetTime");
// Misc functions
core.addApiFunctionByName("GetRandomValue");
core.addApiFunctionByName("SetRandomSeed");
core.addApiFunctionByName("TakeScreenshot");
core.addApiFunctionByName("SetConfigFlags");
} };
getFunction(api.functions, "SetShaderValueV").binding = { ignore: true };
const traceLog = apiDesc.getFunction("TraceLog");
if (!traceLog)
throw new Error("TraceLog not found");