From 36d9b17c44a41136bef32bf51f18b9df7bc22fbf Mon Sep 17 00:00:00 2001 From: "Alexander Klingenbeck (SHS DI SY R&D DEV4)" Date: Thu, 4 May 2023 17:00:22 +0200 Subject: [PATCH] Integrate raylib --- .gitmodules | 11 +-- .vscode/settings.json | 3 +- CMakeLists.txt | 23 +----- bindings.json | 8 ++ generate_bindings.js | 94 ++++++++++++++++++++++ src/common.h | 3 - src/main.c | 71 ++++++++++++++++ src/main.cpp | 61 -------------- src/quickjs.c | 182 ++++++++++++++++++++++++++++++++++++++++++ src/quickjs.cpp | 116 --------------------------- src/utils.cpp | 33 -------- thirdparty/SDL | 1 - thirdparty/corrade | 1 - thirdparty/magnum | 1 - 14 files changed, 362 insertions(+), 246 deletions(-) create mode 100644 bindings.json create mode 100644 generate_bindings.js create mode 100644 src/main.c delete mode 100644 src/main.cpp create mode 100644 src/quickjs.c delete mode 100644 src/quickjs.cpp delete mode 100644 src/utils.cpp delete mode 160000 thirdparty/SDL delete mode 160000 thirdparty/corrade delete mode 160000 thirdparty/magnum diff --git a/.gitmodules b/.gitmodules index fde4567..b39a3e6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,16 +1,7 @@ -[submodule "thirdparty/SDL"] - path = thirdparty/SDL - url = https://github.com/libsdl-org/SDL.git - branch = tags/release-2.26.5 [submodule "thirdparty/quickjs"] path = thirdparty/quickjs url = https://github.com/bellard/quickjs.git -[submodule "thirdparty/corrade"] - path = thirdparty/corrade - url = https://github.com/mosra/corrade.git -[submodule "thirdparty/magnum"] - path = thirdparty/magnum - url = https://github.com/mosra/magnum.git [submodule "thirdparty/raylib"] path = thirdparty/raylib url = https://github.com/raysan5/raylib.git + branch = tags/4.5.0 diff --git a/.vscode/settings.json b/.vscode/settings.json index 38c2313..886f134 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,6 +2,7 @@ "files.associations": { "sdl.h": "c", "vs.sc.mtl.bin.h": "c", - "embedded_shader.h": "c" + "embedded_shader.h": "c", + "common.h": "c" } } \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index c26525a..4e8c907 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,23 +1,8 @@ cmake_minimum_required(VERSION 3.1) project(my-game) -set(CMAKE_CXX_STANDARD 14) -set(CMAKE_CXX_STANDARD_REQUIRED ON) - -message("=== Configure SDL2 ===") -add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/SDL EXCLUDE_FROM_ALL) - -message("=== Configure Corrade ===") -set(CORRADE_BUILD_STATIC ON CACHE BOOL "" FORCE) -add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/corrade EXCLUDE_FROM_ALL) - -message("=== Configure Magnum ===") -# Add Magnum as a subproject, enable Sdl2Application -set(MAGNUM_BUILD_STATIC ON CACHE BOOL "" FORCE) -set(MAGNUM_WITH_SDL2APPLICATION ON CACHE BOOL "" FORCE) -# hack to force magnum to link against static sdl -add_library(SDL2::SDL2 ALIAS SDL2-static) -add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/magnum EXCLUDE_FROM_ALL) +message("=== Configure raylib ===") +add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/raylib EXCLUDE_FROM_ALL) message("=== Configure QuickJS ===") # add quickjs @@ -46,8 +31,8 @@ target_include_directories(quickjs ) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) -file(GLOB files src/*.cpp) +file(GLOB files src/*.c) add_executable(${CMAKE_PROJECT_NAME} ${files}) target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE include) target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE src) -target_link_libraries(${CMAKE_PROJECT_NAME} Magnum::Magnum Magnum::GL Magnum::Sdl2Application Magnum::Shaders quickjs) \ No newline at end of file +target_link_libraries(${CMAKE_PROJECT_NAME} quickjs raylib) \ No newline at end of file diff --git a/bindings.json b/bindings.json new file mode 100644 index 0000000..ff10457 --- /dev/null +++ b/bindings.json @@ -0,0 +1,8 @@ +[ + { + "header": "raylib_core", + "functions": [ + { "name": "SetWindowTitle", "jsName": "setWindowTitle" } + ] + } +] \ No newline at end of file diff --git a/generate_bindings.js b/generate_bindings.js new file mode 100644 index 0000000..44e9217 --- /dev/null +++ b/generate_bindings.js @@ -0,0 +1,94 @@ +// Run with Node.js + +const fs = require('fs'); +let api, bindings + +async function main(){ + api = await readJson('thirdparty/raylib/parser/output/raylib_api.json') + bindings = await readJson('bindings.json') + + const headers = bindings.map(generateModule) + + bindings.forEach(async (header,i) => { + await writeFile(`js_${header.header}.h`, headers[i]) + }); +} + +class FunctionList { + definitions = [] + + addFunctionDef(name, args, funcname){ + this.definitions.push(``) + } +} + +const generateModule = (mod) => { + +} + +const generateFunction = (func) => { + const api = findFunction(func.name) +} + +const findFunction = (name) => findIn(api.functions,name) + +const findIn = (arr, name) => arr.find(x => x.name == name) + + +async function readJson(path){ + const c = await readFile(path) + return JSON.parse(c) +} + +function readFile(path) { + const p = new Promise((res,rej) => { + fs.readFile(path, 'utf8', (err,data) => { + if(err) rej(error) + else res(data) + }) + }) + return p +} + +function writeFile(path, data){ + return new Promise((res, rej) => { + fs.writeFile(path, data, (err) => { + if(err) rej(err) + else res() + }) + }) +} + +function templateHeader(name, content){ + const res = ` +#ifndef JS_${name} +#define JS_${name} + +#include +#include +#include + +#include + +${content} + +static int js_${name}_init(JSContext *ctx, JSModuleDef *m){ + JS_SetModuleExportList(ctx, m, js_${name}_funcs, + countof(js_${name}_funcs)); +} + +JSModuleDef *js_init_module_${name}(JSContext *ctx, const char *module_name) +{ + JSModuleDef *m; + m = JS_NewCModule(ctx, module_name, js_${name}_init); + if (!m) + return NULL; + + return m; +} + +#endif + ` +} + +main() \ No newline at end of file diff --git a/src/common.h b/src/common.h index 13eec18..cd249c9 100644 --- a/src/common.h +++ b/src/common.h @@ -13,9 +13,6 @@ int app_init_quickjs(int argc, char** argv); int app_update_quickjs(); int app_dispose_quickjs(); -// utiles -char* app_read_file(const char* filename, size_t* out_size); - #ifdef __cplusplus } #endif diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..6c989bd --- /dev/null +++ b/src/main.c @@ -0,0 +1,71 @@ +/******************************************************************************************* +* +* raylib [core] example - Basic window +* +* Welcome to raylib! +* +* To test examples, just press F6 and execute raylib_compile_execute script +* Note that compiled executable is placed in the same folder as .c file +* +* You can find all basic examples on C:\raylib\raylib\examples folder or +* raylib official webpage: www.raylib.com +* +* Enjoy using raylib. :) +* +* Example originally created with raylib 1.0, last time updated with raylib 1.0 +* +* 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) 2013-2023 Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include "raylib.h" +#include "common.h" + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(int argc, char ** argv) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [core] example - basic window"); + + SetTargetFPS(60); // Set our game to run at 60 frames-per-second + //-------------------------------------------------------------------------------------- + + app_init_quickjs(argc, argv); + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + app_update_quickjs(); + // Update + //---------------------------------------------------------------------------------- + // TODO: Update your variables here + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + DrawText("Congrats! You created your first window!", 190, 200, 20, LIGHTGRAY); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp deleted file mode 100644 index e4d9739..0000000 --- a/src/main.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include - -using namespace Magnum; -using namespace Magnum::GL; -using namespace Magnum::Shaders; -using namespace Magnum::Platform; -using namespace Math::Literals; - - -class MyApplication: public Platform::Application { - public: - explicit MyApplication(const Arguments& arguments); - - private: - void drawEvent() override; - Mesh _mesh; - VertexColorGL2D _shader; -}; - -MyApplication::MyApplication(const Arguments& arguments): - Application( - arguments, - Configuration() - .setTitle("Magnum Triangle Example") - .setSize(Vector2i{640,480}) - .setWindowFlags(Sdl2Application::Configuration::WindowFlag::Resizable)) -{ - app_init_quickjs(arguments.argc, arguments.argv); - - struct TriangleVertex { - Vector2 position; - Color3 color; - }; - const TriangleVertex vertices[]{ - {{-0.5f, -0.5f}, 0xff0000_rgbf}, /* Left vertex, red color */ - {{ 0.5f, -0.5f}, 0x00ff00_rgbf}, /* Right vertex, green color */ - {{ 0.0f, 0.5f}, 0x0000ff_rgbf} /* Top vertex, blue color */ - }; - _mesh.setCount(Containers::arraySize(vertices)) - .addVertexBuffer(Buffer(vertices), 0, - VertexColorGL2D::Position(), - VertexColorGL2D::Color3()); -} - -void MyApplication::drawEvent() { - defaultFramebuffer.clear(FramebufferClear::Color); - app_update_quickjs(); - - _shader.draw(_mesh); - - swapBuffers(); -} - -MAGNUM_APPLICATION_MAIN(MyApplication) \ No newline at end of file diff --git a/src/quickjs.c b/src/quickjs.c new file mode 100644 index 0000000..715079e --- /dev/null +++ b/src/quickjs.c @@ -0,0 +1,182 @@ +#include +#include + +#include + +#include "common.h" + +static JSContext *JS_NewCustomContext(JSRuntime *rt); +static int eval_buf(JSContext *ctx, const void *buf, int buf_len, + const char *filename, int eval_flags); + +static JSRuntime* rt; +static JSContext* ctx; + +int app_init_quickjs(int argc, char** argv){ + rt = JS_NewRuntime(); + if (!rt) + { + fprintf(stderr, "qjs: cannot allocate JS runtime\n"); + return -1; + } + js_std_set_worker_new_context_func(JS_NewCustomContext); + js_std_init_handlers(rt); + ctx = JS_NewCustomContext(rt); + if (!ctx) { + fprintf(stderr, "qjs: cannot allocate JS context\n"); + return -1; + } + + JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL); + + js_std_add_helpers(ctx, argc, argv); + + // const char *str = "import * as std from 'std';\n" + // "import * as os from 'os';\n" + // "globalThis.std = std;\n" + // "globalThis.os = os;\n"; + // eval_buf(ctx, str, strlen(str), "", JS_EVAL_TYPE_MODULE); + + const char* filename = "main.js"; + const char* buf = LoadFileText(filename); + size_t len = strlen(buf); + if (!buf) { + JS_ThrowReferenceError(ctx, "could not load module filename '%s'", + filename); + return -1; + } + int res = eval_buf(ctx, buf, len, "main", JS_EVAL_TYPE_MODULE); + if(res){ + return res; + } + return 0; +} + +int app_update_quickjs(){ + JSContext *ctx1; + int err; + + /* execute the pending jobs */ + for(;;) { + err = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1); + if (err <= 0) { + if (err < 0) { + js_std_dump_error(ctx1); + } + break; + } + } + return 0; +} + +int app_dispose_quickjs(){ + js_std_free_handlers(rt); + JS_FreeContext(ctx); + JS_FreeRuntime(rt); + return 0; +} + +/* also used to initialize the worker context */ +static JSContext *JS_NewCustomContext(JSRuntime *rt) +{ + JSContext *ctx; + ctx = JS_NewContext(rt); + if (!ctx) + return NULL; + + /* system modules */ + js_init_module_std(ctx, "std"); + js_init_module_os(ctx, "os"); + js_init_module_raylib_core(ctx, "raylib.core"); + return ctx; +} + +static const JSCFunctionListEntry js_raylib_core_funcs[] = { + JS_FUNC_DEF("beginDrawing", 0, js_raylib_core_beginDrawing); + // JS_CFUNC_DEF("exit", 1, js_std_exit ), + // JS_CFUNC_DEF("gc", 0, js_std_gc ), + // JS_CFUNC_DEF("evalScript", 1, js_evalScript ), + // JS_CFUNC_DEF("loadScript", 1, js_loadScript ), + // JS_CFUNC_DEF("getenv", 1, js_std_getenv ), + // JS_CFUNC_DEF("setenv", 1, js_std_setenv ), + // JS_CFUNC_DEF("unsetenv", 1, js_std_unsetenv ), + // JS_CFUNC_DEF("getenviron", 1, js_std_getenviron ), + // JS_CFUNC_DEF("urlGet", 1, js_std_urlGet ), + // JS_CFUNC_DEF("loadFile", 1, js_std_loadFile ), + // JS_CFUNC_DEF("strerror", 1, js_std_strerror ), + // JS_CFUNC_DEF("parseExtJSON", 1, js_std_parseExtJSON ), + + // /* FILE I/O */ + // JS_CFUNC_DEF("open", 2, js_std_open ), + // JS_CFUNC_DEF("popen", 2, js_std_popen ), + // JS_CFUNC_DEF("fdopen", 2, js_std_fdopen ), + // JS_CFUNC_DEF("tmpfile", 0, js_std_tmpfile ), + // JS_CFUNC_MAGIC_DEF("puts", 1, js_std_file_puts, 0 ), + // JS_CFUNC_DEF("printf", 1, js_std_printf ), + // JS_CFUNC_DEF("sprintf", 1, js_std_sprintf ), + // JS_PROP_INT32_DEF("SEEK_SET", SEEK_SET, JS_PROP_CONFIGURABLE ), + // JS_PROP_INT32_DEF("SEEK_CUR", SEEK_CUR, JS_PROP_CONFIGURABLE ), + // JS_PROP_INT32_DEF("SEEK_END", SEEK_END, JS_PROP_CONFIGURABLE ), + // JS_OBJECT_DEF("Error", js_std_error_props, countof(js_std_error_props), JS_PROP_CONFIGURABLE), +}; + +static int js_raylib_core_init(JSContext *ctx, JSModuleDef *m) +{ + JSValue proto; + + // /* FILE class */ + // /* the class ID is created once */ + // JS_NewClassID(&js_std_file_class_id); + // /* the class is created once per runtime */ + // JS_NewClass(JS_GetRuntime(ctx), js_std_file_class_id, &js_std_file_class); + // proto = JS_NewObject(ctx); + // JS_SetPropertyFunctionList(ctx, proto, js_std_file_proto_funcs, + // countof(js_std_file_proto_funcs)); + // JS_SetClassProto(ctx, js_std_file_class_id, proto); + + JS_SetModuleExportList(ctx, m, js_raylib_core_funcs, + countof(js_raylib_core_funcs)); + + // JS_SetModuleExport(ctx, m, "in", js_new_std_file(ctx, stdin, FALSE, FALSE)); + // JS_SetModuleExport(ctx, m, "out", js_new_std_file(ctx, stdout, FALSE, FALSE)); + // JS_SetModuleExport(ctx, m, "err", js_new_std_file(ctx, stderr, FALSE, FALSE)); + return 0; +} + +JSModuleDef *js_init_module_raylib_core(JSContext *ctx, const char *module_name) +{ + JSModuleDef *m; + m = JS_NewCModule(ctx, module_name, js_raylib_core_init); + if (!m) + return NULL; + + return m; +} + +static int eval_buf(JSContext *ctx, const void *buf, int buf_len, + const char *filename, int eval_flags) +{ + JSValue val; + int ret; + + if ((eval_flags & JS_EVAL_TYPE_MASK) == JS_EVAL_TYPE_MODULE) { + /* for the modules, we compile then run to be able to set + import.meta */ + val = JS_Eval(ctx, (const char*)buf, buf_len, filename, + eval_flags | JS_EVAL_FLAG_COMPILE_ONLY); + if (!JS_IsException(val)) { + js_module_set_import_meta(ctx, val, 1, 1); + val = JS_EvalFunction(ctx, val); + } + } else { + val = JS_Eval(ctx, (const char*)buf, buf_len, filename, eval_flags); + } + if (JS_IsException(val)) { + js_std_dump_error(ctx); + ret = -1; + } else { + ret = 0; + } + JS_FreeValue(ctx, val); + return ret; +} \ No newline at end of file diff --git a/src/quickjs.cpp b/src/quickjs.cpp deleted file mode 100644 index f21bf19..0000000 --- a/src/quickjs.cpp +++ /dev/null @@ -1,116 +0,0 @@ -#include -#include - -#include "common.h" - -static JSContext *JS_NewCustomContext(JSRuntime *rt); -static int eval_buf(JSContext *ctx, const void *buf, int buf_len, - const char *filename, int eval_flags); - -static JSRuntime* rt; -static JSContext* ctx; - -int app_init_quickjs(int argc, char** argv){ - rt = JS_NewRuntime(); - if (!rt) - { - fprintf(stderr, "qjs: cannot allocate JS runtime\n"); - return -1; - } - js_std_set_worker_new_context_func(JS_NewCustomContext); - js_std_init_handlers(rt); - ctx = JS_NewCustomContext(rt); - if (!ctx) { - fprintf(stderr, "qjs: cannot allocate JS context\n"); - return -1; - } - - JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL); - js_std_add_helpers(ctx, argc, argv); - - const char *str = "import * as std from 'std';\n" - "import * as os from 'os';\n" - "globalThis.std = std;\n" - "globalThis.os = os;\n"; - eval_buf(ctx, str, strlen(str), "", JS_EVAL_TYPE_MODULE); - - const char* filename = "main.js"; - size_t len; - const char* buf = app_read_file(filename, &len); - if (!buf) { - JS_ThrowReferenceError(ctx, "could not load module filename '%s'", - filename); - return -1; - } - int res = eval_buf(ctx, buf, len, "main", JS_EVAL_TYPE_MODULE); - if(res){ - return res; - } - return 0; -} - -int app_update_quickjs(){ - JSContext *ctx1; - int err; - - /* execute the pending jobs */ - for(;;) { - err = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1); - if (err <= 0) { - if (err < 0) { - js_std_dump_error(ctx1); - } - break; - } - } - return 0; -} - -int app_dispose_quickjs(){ - js_std_free_handlers(rt); - JS_FreeContext(ctx); - JS_FreeRuntime(rt); - return 0; -} - -/* also used to initialize the worker context */ -static JSContext *JS_NewCustomContext(JSRuntime *rt) -{ - JSContext *ctx; - ctx = JS_NewContext(rt); - if (!ctx) - return NULL; - - /* system modules */ - js_init_module_std(ctx, "std"); - js_init_module_os(ctx, "os"); - return ctx; -} - -static int eval_buf(JSContext *ctx, const void *buf, int buf_len, - const char *filename, int eval_flags) -{ - JSValue val; - int ret; - - if ((eval_flags & JS_EVAL_TYPE_MASK) == JS_EVAL_TYPE_MODULE) { - /* for the modules, we compile then run to be able to set - import.meta */ - val = JS_Eval(ctx, (const char*)buf, buf_len, filename, - eval_flags | JS_EVAL_FLAG_COMPILE_ONLY); - if (!JS_IsException(val)) { - js_module_set_import_meta(ctx, val, 1, 1); - val = JS_EvalFunction(ctx, val); - } - } else { - val = JS_Eval(ctx, (const char*)buf, buf_len, filename, eval_flags); - } - if (JS_IsException(val)) { - js_std_dump_error(ctx); - ret = -1; - } else { - ret = 0; - } - JS_FreeValue(ctx, val); - return ret; -} \ No newline at end of file diff --git a/src/utils.cpp b/src/utils.cpp deleted file mode 100644 index 6d6c0e1..0000000 --- a/src/utils.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "common.h" - -// Function to read a file into a string -char* app_read_file(const char* filename, size_t* out_size) { - FILE* file = fopen(filename, "rb"); - if (!file) { - fprintf(stderr, "Failed to open file: %s\n", filename); - return NULL; - } - - // Get the file size - fseek(file, 0, SEEK_END); - long size = ftell(file); - if(out_size) *out_size = (size_t)size; - rewind(file); - - // Allocate a buffer to hold the file contents - char* buffer = (char*) malloc(size + 1); - if (!buffer) { - fprintf(stderr, "Failed to allocate memory for file contents\n"); - fclose(file); - return NULL; - } - - // Read the file contents into the buffer - size_t bytesRead = fread(buffer, 1, size, file); - buffer[bytesRead] = '\0'; - - // Clean up - fclose(file); - - return buffer; -} \ No newline at end of file diff --git a/thirdparty/SDL b/thirdparty/SDL deleted file mode 160000 index ac13ca9..0000000 --- a/thirdparty/SDL +++ /dev/null @@ -1 +0,0 @@ -Subproject commit ac13ca9ab691e13e8eebe9684740ddcb0d716203 diff --git a/thirdparty/corrade b/thirdparty/corrade deleted file mode 160000 index 1408175..0000000 --- a/thirdparty/corrade +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 1408175dbff4c72c547aa44969f2f53769c01c40 diff --git a/thirdparty/magnum b/thirdparty/magnum deleted file mode 160000 index bc1859f..0000000 --- a/thirdparty/magnum +++ /dev/null @@ -1 +0,0 @@ -Subproject commit bc1859f653e4dde58df1a1291cd75ce0325bcf30