mirror of https://github.com/mode777/rayjs.git
Add header parser for raygui
This commit is contained in:
parent
b070c9ace7
commit
5412dd1116
|
@ -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() }
|
||||
})
|
||||
}
|
||||
}
|
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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()
|
|
@ -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 <stdlib.h> // 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;
|
||||
}
|
|
@ -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)
|
|
@ -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));
|
||||
|
|
Loading…
Reference in New Issue