From 5412dd1116f543c4294605cc7031531ef6a546f9 Mon Sep 17 00:00:00 2001 From: Alexander Klingenbeck Date: Fri, 26 May 2023 22:09:53 +0200 Subject: [PATCH] Add header parser for raygui --- bindings/src/header-parser.ts | 64 +++++++++ bindings/src/index.ts | 10 +- examples/{ => models}/js_mesh_generation.js | 0 examples/models/models_cubicmap.c | 95 ------------- examples/{ => models}/models_cubicmap.js | 4 +- examples/models/models_first_person_maze.c | 133 ------------------ .../models_first_person_maze.js} | 4 +- .../{logo.js => shapes/shapes_logo_raylib.js} | 0 generate-bindings.js | 79 +++++++++++ 9 files changed, 156 insertions(+), 233 deletions(-) create mode 100644 bindings/src/header-parser.ts rename examples/{ => models}/js_mesh_generation.js (100%) delete mode 100644 examples/models/models_cubicmap.c rename examples/{ => models}/models_cubicmap.js (94%) delete mode 100644 examples/models/models_first_person_maze.c rename examples/{1st_person_maze.js => models/models_first_person_maze.js} (97%) rename examples/{logo.js => shapes/shapes_logo_raylib.js} (100%) diff --git a/bindings/src/header-parser.ts b/bindings/src/header-parser.ts new file mode 100644 index 0000000..17d7e9b --- /dev/null +++ b/bindings/src/header-parser.ts @@ -0,0 +1,64 @@ +import { RayLibEnumValue, RayLibFieldDescription, RayLibParamDescription } from "./interfaces" +import { RayLibAlias, RayLibDefine, RayLibStruct, RayLibEnum, RayLibFunction } from "./interfaces" + +export class HeaderParser { + + parseEnums(input: string): RayLibEnum[] { + const matches = [...input.matchAll(/((?:\/\/.+\n)*)typedef enum {\n([^}]+)} ([^;]+)/gm)] + return matches.map(groups => { + return { + description: this.parseComments(groups[1]), + values: this.parseEnumValues(groups[2]), + name: groups[3], + } + }) + } + parseEnumValues(input: string): RayLibEnumValue[] { + let lastNumber = 0 + return input.split('\n') + .map(line => line.trim().match(/([^ ,]+)(?: = ([0-9]+))?,?(?: *)(?:\/\/ (.+))?/)) + .filter(x => x !== null && !x[0].startsWith("/")) + .map(groups => { + let val = lastNumber = groups![2] ? parseInt(groups![2]) : lastNumber + lastNumber++ + return { + name: groups![1], + description: groups![3] || "", + value: val + } + }) + + } + parseComments(input: string){ + return input.split('\n').map(x => x.replace("// ","")).join('\n').trim() + } + parseFunctionDefinitions(input: string): RayLibFunction[] { + const matches = [...input.matchAll(/^[A-Z]+API (.+?)(\w+)\(([^\)]+)\);(?:[^\/]+\/\/ (.+))?/gm)] + return matches.map(groups => ({ + returnType: groups![1].trim(), + name: groups![2], + params: this.parseFunctionArgs(groups![3]), + description: groups![4] || "" + })) + } + parseFunctions(input: string): RayLibFunction[] { + const matches = [...input.matchAll(/((?:\/\/ .+\n)*)[A-Z]+API\s+([\w<>]+)\s+([\w<>]+)\((.*)\)/gm)] + console.log(matches[0]) + return matches.map(groups => ({ + returnType: groups![1].trim(), + name: groups![2], + params: this.parseFunctionArgs(groups![3]), + description: groups![4] || "" + })) + } + parseFunctionArgs(input: string): RayLibParamDescription[] { + return input.split(',').filter(x => x !== 'void').map(arg => { + arg = arg.trim().replace(" *", "* ") + const frags = arg.split(' ') + const name = frags.pop() + const type = frags.join(' ').replace("*", " *") + + return { name: name || "", type: type.trim() } + }) + } +} \ No newline at end of file diff --git a/bindings/src/index.ts b/bindings/src/index.ts index f87a0fc..3e7a1a6 100644 --- a/bindings/src/index.ts +++ b/bindings/src/index.ts @@ -2,6 +2,7 @@ import { readFileSync, writeFileSync } from "fs"; import { RayLibApi, RayLibFunction, RayLibType } from "./interfaces"; import { ApiDescription, ApiFunction } from "./api"; import { RayLibHeader } from "./raylib-header"; +import { HeaderParser } from "./header-parser"; function parseHeader(path: string, prefix: string): RayLibFunction[] { const i = readFileSync(path, 'utf8') @@ -38,10 +39,17 @@ function main(){ returnType: "void", params: [{type: "Model *",name:"model"},{type:"int",name:"materialIndex"},{type:"Material",name:"material"}] }) - + + const rguiHeader = readFileSync("thirdparty/raylib/examples/shapes/raygui.h","utf8"); + const parser = new HeaderParser() + //writeFileSync("enums.json",JSON.stringify(parser.parseEnums(rayguiHeader))) + //writeFileSync("functions.json",JSON.stringify(parser.parseFunctions(rayguiHeader))) + + const rmathHeader = readFileSync("thirdparty/raylib/src/raymath.h","utf8"); const mathApi = parseHeader("thirdparty/raylib/src/raymath.h", "RMAPI"); mathApi.forEach(x => api.functions.push(x)) + const rcameraHeader = readFileSync("thirdparty/raylib/src/rcamera.h","utf8"); const cameraApi = parseHeader("thirdparty/raylib/src/rcamera.h", "RLAPI"); //cameraApi.forEach(x => console.log(`core.addApiFunctionByName("${x.name}")`)) cameraApi.forEach(x => api.functions.push(x)) diff --git a/examples/js_mesh_generation.js b/examples/models/js_mesh_generation.js similarity index 100% rename from examples/js_mesh_generation.js rename to examples/models/js_mesh_generation.js diff --git a/examples/models/models_cubicmap.c b/examples/models/models_cubicmap.c deleted file mode 100644 index e0a2b30..0000000 --- a/examples/models/models_cubicmap.c +++ /dev/null @@ -1,95 +0,0 @@ -/******************************************************************************************* -* -* raylib [models] example - Cubicmap loading and drawing -* -* Example originally created with raylib 1.8, last time updated with raylib 3.5 -* -* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, -* BSD-like license that allows static linking with closed source software -* -* Copyright (c) 2015-2023 Ramon Santamaria (@raysan5) -* -********************************************************************************************/ - -#include "raylib.h" - -//------------------------------------------------------------------------------------ -// Program main entry point -//------------------------------------------------------------------------------------ -int main(void) -{ - // Initialization - //-------------------------------------------------------------------------------------- - const int screenWidth = 800; - const int screenHeight = 450; - - InitWindow(screenWidth, screenHeight, "raylib [models] example - cubesmap loading and drawing"); - - // Define the camera to look into our 3d world - Camera camera = { 0 }; - camera.position = (Vector3){ 16.0f, 14.0f, 16.0f }; // Camera position - camera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; // Camera looking at point - camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector (rotation towards target) - camera.fovy = 45.0f; // Camera field-of-view Y - camera.projection = CAMERA_PERSPECTIVE; // Camera projection type - - Image image = LoadImage("resources/cubicmap.png"); // Load cubicmap image (RAM) - Texture2D cubicmap = LoadTextureFromImage(image); // Convert image to texture to display (VRAM) - - Mesh mesh = GenMeshCubicmap(image, (Vector3){ 1.0f, 1.0f, 1.0f }); - Model model = LoadModelFromMesh(mesh); - - // NOTE: By default each cube is mapped to one part of texture atlas - Texture2D texture = LoadTexture("resources/cubicmap_atlas.png"); // Load map texture - model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = texture; // Set map diffuse texture - - Vector3 mapPosition = { -16.0f, 0.0f, -8.0f }; // Set model position - - UnloadImage(image); // Unload cubesmap image from RAM, already uploaded to VRAM - - SetTargetFPS(60); // Set our game to run at 60 frames-per-second - //-------------------------------------------------------------------------------------- - - // Main game loop - while (!WindowShouldClose()) // Detect window close button or ESC key - { - // Update - //---------------------------------------------------------------------------------- - UpdateCamera(&camera, CAMERA_ORBITAL); - //---------------------------------------------------------------------------------- - - // Draw - //---------------------------------------------------------------------------------- - BeginDrawing(); - - ClearBackground(RAYWHITE); - - BeginMode3D(camera); - - DrawModel(model, mapPosition, 1.0f, WHITE); - - EndMode3D(); - - DrawTextureEx(cubicmap, (Vector2){ screenWidth - cubicmap.width*4.0f - 20, 20.0f }, 0.0f, 4.0f, WHITE); - DrawRectangleLines(screenWidth - cubicmap.width*4 - 20, 20, cubicmap.width*4, cubicmap.height*4, GREEN); - - DrawText("cubicmap image used to", 658, 90, 10, GRAY); - DrawText("generate map 3d model", 658, 104, 10, GRAY); - - DrawFPS(10, 10); - - EndDrawing(); - //---------------------------------------------------------------------------------- - } - - // De-Initialization - //-------------------------------------------------------------------------------------- - UnloadTexture(cubicmap); // Unload cubicmap texture - UnloadTexture(texture); // Unload map texture - UnloadModel(model); // Unload map model - - CloseWindow(); // Close window and OpenGL context - //-------------------------------------------------------------------------------------- - - return 0; -} diff --git a/examples/models_cubicmap.js b/examples/models/models_cubicmap.js similarity index 94% rename from examples/models_cubicmap.js rename to examples/models/models_cubicmap.js index 53c58d2..e4aed51 100644 --- a/examples/models_cubicmap.js +++ b/examples/models/models_cubicmap.js @@ -25,14 +25,14 @@ const fovy = 45.0; // Camera field-of-view Y const projection = CAMERA_PERSPECTIVE; // Camera projection type const camera = new Camera3D(position, target, up, fovy, projection) -let image = loadImage("../assets/cubicmap.png"); // Load cubicmap image (RAM) +let image = loadImage("resources/cubicmap.png"); // Load cubicmap image (RAM) let cubicmap = loadTextureFromImage(image); // Convert image to texture to display (VRAM) const mesh = genMeshCubicmap(image, new Vector3(1.0, 1.0, 1.0)); const model = loadModelFromMesh(mesh); // NOTE: By default each cube is mapped to one part of texture atlas -let texture = loadTexture("../assets/cubicmap_atlas.png"); // Load map texture +let texture = loadTexture("resources/cubicmap_atlas.png"); // Load map texture //model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = texture; // Set map diffuse texture const mat = loadMaterialDefault() diff --git a/examples/models/models_first_person_maze.c b/examples/models/models_first_person_maze.c deleted file mode 100644 index 6a4345a..0000000 --- a/examples/models/models_first_person_maze.c +++ /dev/null @@ -1,133 +0,0 @@ -/******************************************************************************************* -* -* raylib [models] example - first person maze -* -* Example originally created with raylib 2.5, last time updated with raylib 3.5 -* -* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, -* BSD-like license that allows static linking with closed source software -* -* Copyright (c) 2019-2023 Ramon Santamaria (@raysan5) -* -********************************************************************************************/ - -#include "raylib.h" - -#include // Required for: free() - -//------------------------------------------------------------------------------------ -// Program main entry point -//------------------------------------------------------------------------------------ -int main(void) -{ - // Initialization - //-------------------------------------------------------------------------------------- - const int screenWidth = 800; - const int screenHeight = 450; - - InitWindow(screenWidth, screenHeight, "raylib [models] example - first person maze"); - - // Define the camera to look into our 3d world - Camera camera = { 0 }; - camera.position = (Vector3){ 0.2f, 0.4f, 0.2f }; // Camera position - camera.target = (Vector3){ 0.185f, 0.4f, 0.0f }; // Camera looking at point - camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector (rotation towards target) - camera.fovy = 45.0f; // Camera field-of-view Y - camera.projection = CAMERA_PERSPECTIVE; // Camera projection type - Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position - - Image imMap = LoadImage("resources/cubicmap.png"); // Load cubicmap image (RAM) - Texture2D cubicmap = LoadTextureFromImage(imMap); // Convert image to texture to display (VRAM) - Mesh mesh = GenMeshCubicmap(imMap, (Vector3){ 1.0f, 1.0f, 1.0f }); - Model model = LoadModelFromMesh(mesh); - - // NOTE: By default each cube is mapped to one part of texture atlas - Texture2D texture = LoadTexture("resources/cubicmap_atlas.png"); // Load map texture - model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = texture; // Set map diffuse texture - - // Get map image data to be used for collision detection - Color *mapPixels = LoadImageColors(imMap); - UnloadImage(imMap); // Unload image from RAM - - Vector3 mapPosition = { -16.0f, 0.0f, -8.0f }; // Set model position - - DisableCursor(); // Limit cursor to relative movement inside the window - - SetTargetFPS(60); // Set our game to run at 60 frames-per-second - //-------------------------------------------------------------------------------------- - - // Main game loop - while (!WindowShouldClose()) // Detect window close button or ESC key - { - // Update - //---------------------------------------------------------------------------------- - Vector3 oldCamPos = camera.position; // Store old camera position - - UpdateCamera(&camera, CAMERA_FIRST_PERSON); - - // Check player collision (we simplify to 2D collision detection) - Vector2 playerPos = { camera.position.x, camera.position.z }; - float playerRadius = 0.1f; // Collision radius (player is modelled as a cilinder for collision) - - int playerCellX = (int)(playerPos.x - mapPosition.x + 0.5f); - int playerCellY = (int)(playerPos.y - mapPosition.z + 0.5f); - - // Out-of-limits security check - if (playerCellX < 0) playerCellX = 0; - else if (playerCellX >= cubicmap.width) playerCellX = cubicmap.width - 1; - - if (playerCellY < 0) playerCellY = 0; - else if (playerCellY >= cubicmap.height) playerCellY = cubicmap.height - 1; - - // Check map collisions using image data and player position - // TODO: Improvement: Just check player surrounding cells for collision - for (int y = 0; y < cubicmap.height; y++) - { - for (int x = 0; x < cubicmap.width; x++) - { - if ((mapPixels[y*cubicmap.width + x].r == 255) && // Collision: white pixel, only check R channel - (CheckCollisionCircleRec(playerPos, playerRadius, - (Rectangle){ mapPosition.x - 0.5f + x*1.0f, mapPosition.z - 0.5f + y*1.0f, 1.0f, 1.0f }))) - { - // Collision detected, reset camera position - camera.position = oldCamPos; - } - } - } - //---------------------------------------------------------------------------------- - - // Draw - //---------------------------------------------------------------------------------- - BeginDrawing(); - - ClearBackground(RAYWHITE); - - BeginMode3D(camera); - DrawModel(model, mapPosition, 1.0f, WHITE); // Draw maze map - EndMode3D(); - - DrawTextureEx(cubicmap, (Vector2){ GetScreenWidth() - cubicmap.width*4.0f - 20, 20.0f }, 0.0f, 4.0f, WHITE); - DrawRectangleLines(GetScreenWidth() - cubicmap.width*4 - 20, 20, cubicmap.width*4, cubicmap.height*4, GREEN); - - // Draw player position radar - DrawRectangle(GetScreenWidth() - cubicmap.width*4 - 20 + playerCellX*4, 20 + playerCellY*4, 4, 4, RED); - - DrawFPS(10, 10); - - EndDrawing(); - //---------------------------------------------------------------------------------- - } - - // De-Initialization - //-------------------------------------------------------------------------------------- - UnloadImageColors(mapPixels); // Unload color array - - UnloadTexture(cubicmap); // Unload cubicmap texture - UnloadTexture(texture); // Unload map texture - UnloadModel(model); // Unload map model - - CloseWindow(); // Close window and OpenGL context - //-------------------------------------------------------------------------------------- - - return 0; -} diff --git a/examples/1st_person_maze.js b/examples/models/models_first_person_maze.js similarity index 97% rename from examples/1st_person_maze.js rename to examples/models/models_first_person_maze.js index afaf237..7942d00 100644 --- a/examples/1st_person_maze.js +++ b/examples/models/models_first_person_maze.js @@ -21,13 +21,13 @@ initWindow(screenWidth, screenHeight, "raylib [models] example - first person ma const camera = new Camera3D(new Vector3(0.2, 0.4, 0.2),new Vector3(0.185, 0.4, 0.0),new Vector3(0,1,0), 45, CAMERA_PERSPECTIVE); const position = new Vector3(0,0,0); // Set model position -const imMap = loadImage("../assets/cubicmap.png"); // Load cubicmap image (RAM) +const imMap = loadImage("resources/cubicmap.png"); // Load cubicmap image (RAM) const cubicmap = loadTextureFromImage(imMap); // Convert image to texture to display (VRAM) const mesh = genMeshCubicmap(imMap, new Vector3(1.0, 1.0, 1.0)); const model = loadModelFromMesh(mesh); // NOTE: By default each cube is mapped to one part of texture atlas -const texture = loadTexture("../assets/cubicmap_atlas.png"); // Load map texture +const texture = loadTexture("resources/cubicmap_atlas.png"); // Load map texture //model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = texture; // Set map diffuse texture const mat = loadMaterialDefault() setMaterialTexture(mat, MATERIAL_MAP_DIFFUSE, texture) diff --git a/examples/logo.js b/examples/shapes/shapes_logo_raylib.js similarity index 100% rename from examples/logo.js rename to examples/shapes/shapes_logo_raylib.js diff --git a/generate-bindings.js b/generate-bindings.js index 3f04a63..5da683e 100644 --- a/generate-bindings.js +++ b/generate-bindings.js @@ -309,6 +309,78 @@ class CodeGenerator extends GenericCodeGenerator { exports.CodeGenerator = CodeGenerator; +/***/ }), + +/***/ "./src/header-parser.ts": +/*!******************************!*\ + !*** ./src/header-parser.ts ***! + \******************************/ +/***/ ((__unused_webpack_module, exports) => { + + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.HeaderParser = void 0; +class HeaderParser { + parseEnums(input) { + const matches = [...input.matchAll(/((?:\/\/.+\n)*)typedef enum {\n([^}]+)} ([^;]+)/gm)]; + return matches.map(groups => { + return { + description: this.parseComments(groups[1]), + values: this.parseEnumValues(groups[2]), + name: groups[3], + }; + }); + } + parseEnumValues(input) { + let lastNumber = 0; + return input.split('\n') + .map(line => line.trim().match(/([^ ,]+)(?: = ([0-9]+))?,?(?: *)(?:\/\/ (.+))?/)) + .filter(x => x !== null && !x[0].startsWith("/")) + .map(groups => { + let val = lastNumber = groups[2] ? parseInt(groups[2]) : lastNumber; + lastNumber++; + return { + name: groups[1], + description: groups[3] || "", + value: val + }; + }); + } + parseComments(input) { + return input.split('\n').map(x => x.replace("// ", "")).join('\n').trim(); + } + parseFunctionDefinitions(input) { + const matches = [...input.matchAll(/^[A-Z]+API (.+?)(\w+)\(([^\)]+)\);(?:[^\/]+\/\/ (.+))?/gm)]; + return matches.map(groups => ({ + returnType: groups[1].trim(), + name: groups[2], + params: this.parseFunctionArgs(groups[3]), + description: groups[4] || "" + })); + } + parseFunctions(input) { + const matches = [...input.matchAll(/((?:\/\/ .+\n)*)[A-Z]+API\s+([\w<>]+)\s+([\w<>]+)\((.*)\)/gm)]; + console.log(matches[0]); + return matches.map(groups => ({ + returnType: groups[1].trim(), + name: groups[2], + params: this.parseFunctionArgs(groups[3]), + description: groups[4] || "" + })); + } + parseFunctionArgs(input) { + return input.split(',').filter(x => x !== 'void').map(arg => { + arg = arg.trim().replace(" *", "* "); + const frags = arg.split(' '); + const name = frags.pop(); + const type = frags.join(' ').replace("*", " *"); + return { name: name || "", type: type.trim() }; + }); + } +} +exports.HeaderParser = HeaderParser; + + /***/ }), /***/ "./src/quickjs.ts": @@ -895,6 +967,7 @@ 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 parseHeader(path, prefix) { const i = (0, fs_1.readFileSync)(path, 'utf8'); const regex = new RegExp(`((?:\\/\\/ .+\\n)*)${prefix}\\s+([\\w<>]+)\\s+([\\w<>]+)\\((.*)\\)`, 'gm'); @@ -926,8 +999,14 @@ function main() { returnType: "void", params: [{ type: "Model *", name: "model" }, { type: "int", name: "materialIndex" }, { type: "Material", name: "material" }] }); + const rguiHeader = (0, fs_1.readFileSync)("thirdparty/raylib/examples/shapes/raygui.h", "utf8"); + const parser = new header_parser_1.HeaderParser(); + //writeFileSync("enums.json",JSON.stringify(parser.parseEnums(rayguiHeader))) + //writeFileSync("functions.json",JSON.stringify(parser.parseFunctions(rayguiHeader))) + const rmathHeader = (0, fs_1.readFileSync)("thirdparty/raylib/src/raymath.h", "utf8"); const mathApi = parseHeader("thirdparty/raylib/src/raymath.h", "RMAPI"); mathApi.forEach(x => api.functions.push(x)); + const rcameraHeader = (0, fs_1.readFileSync)("thirdparty/raylib/src/rcamera.h", "utf8"); const cameraApi = parseHeader("thirdparty/raylib/src/rcamera.h", "RLAPI"); //cameraApi.forEach(x => console.log(`core.addApiFunctionByName("${x.name}")`)) cameraApi.forEach(x => api.functions.push(x));