diff --git a/bindings/src/index.ts b/bindings/src/index.ts index 36ba873..a8de41f 100644 --- a/bindings/src/index.ts +++ b/bindings/src/index.ts @@ -17,6 +17,15 @@ function main(){ }, createConstructor: true }) + core_gen.addApiStructByName("Rectangle", { + properties: { + x: { get: true, set: true }, + y: { get: true, set: true }, + width: { get: true, set: true }, + height: { get: true, set: true }, + }, + createConstructor: true + }) core_gen.addApiStructByName("Vector2", { properties: { x: { get: true, set: true }, @@ -27,19 +36,25 @@ function main(){ core_gen.addApiFunctionByName("SetWindowTitle") core_gen.addApiFunctionByName("SetWindowPosition") core_gen.addApiFunctionByName("BeginDrawing") - core_gen.addApiFunctionByName("EndDrawing") + core_gen.addApiFunctionByName("EndDrawing", null, { before: fun => fun.call("app_update_quickjs", []) }) core_gen.addApiFunctionByName("InitWindow") core_gen.addApiFunctionByName("SetTargetFPS") - core_gen.addApiFunctionByName("WindowShouldClose", null, { before: fun => fun.call("app_update_quickjs", []) }) + core_gen.addApiFunctionByName("WindowShouldClose") core_gen.addApiFunctionByName("ClearBackground") core_gen.addApiFunctionByName("CloseWindow") core_gen.addApiFunctionByName("DrawText") core_gen.addApiFunctionByName("DrawCircleV") core_gen.addApiFunctionByName("IsKeyDown") + core_gen.addApiFunctionByName("GetMousePosition") + core_gen.addApiFunctionByName("IsMouseButtonPressed") + core_gen.addApiFunctionByName("GetMouseWheelMove") + core_gen.addApiFunctionByName("DrawRectangle") + core_gen.addApiFunctionByName("GetRandomValue") api.defines.filter(x => x.type === "COLOR").map(x => ({ name: x.name, values: (x.value.match(/\{([^}]+)\}/) || "")[1].split(',').map(x => x.trim()) })).forEach(x => { core_gen.exportGlobalStruct("Color", x.name, x.values) }) api.enums.find(x => x.name === "KeyboardKey")?.values.forEach(x => core_gen.exportGlobalConstant(x.name)) + api.enums.find(x => x.name === "MouseButton")?.values.forEach(x => core_gen.exportGlobalConstant(x.name)) core_gen.writeTo("src/bindings/js_raylib_core.h") const texture_gen = new RayLibHeader("raylib_texture", apiDesc) diff --git a/bindings/src/quickjs.ts b/bindings/src/quickjs.ts index 336ea72..980b47a 100644 --- a/bindings/src/quickjs.ts +++ b/bindings/src/quickjs.ts @@ -176,7 +176,7 @@ export abstract class GenericQuickJsGenerator extend const body = this.function(`js_${structName}_finalizer`, "void", args, true) body.statement(`${structName}* ptr = JS_GetOpaque(val, ${classId})`) body.if("ptr", cond => { - cond.call("TraceLog", ["LOG_INFO",`"Finalize ${structName}"`]) + //cond.call("TraceLog", ["LOG_INFO",`"Finalize ${structName}"`]) if(onFinalize) onFinalize(cond, "ptr") cond.call("js_free_rt", ["rt","ptr"]) }) diff --git a/examples/2d_camera.js b/examples/2d_camera.js new file mode 100644 index 0000000..95db2cc --- /dev/null +++ b/examples/2d_camera.js @@ -0,0 +1,114 @@ +import * as rlc from "raylib.core" + +// Initialization +//-------------------------------------------------------------------------------------- +const screenWidth = 800; +const screenHeight = 450; +const MAX_BUILDINGS = 100 + +rlc.initWindow(screenWidth, screenHeight, "raylib [core] example - 2d camera"); + +const player = new rlc.Rectangle(400, 280, 40, 40); +const buildings = new Array(MAX_BUILDINGS); +const buildColors = new Array(MAX_BUILDINGS); + +let spacing = 0; + +for (let i = 0; i < MAX_BUILDINGS; i++) +{ + buildings[i].width = rlc.getRandomValue(50, 200); + buildings[i].height = rlc.getRandomValue(100, 800); + buildings[i].y = screenHeight - 130.0 - buildings[i].height; + buildings[i].x = -6000.0 + spacing; + + spacing += buildings[i].width; + + buildColors[i] = new rlc.Color(rlc.getRandomValue(200, 240), rlc.getRandomValue(200, 240), rlc.getRandomValue(200, 250), 255); +} + +Camera2D camera = { 0 }; +camera.target = (Vector2){ player.x + 20.0f, player.y + 20.0f }; +camera.offset = (Vector2){ screenWidth/2.0f, screenHeight/2.0f }; +camera.rotation = 0.0f; +camera.zoom = 1.0f; + +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 + //---------------------------------------------------------------------------------- + // Player movement + if (IsKeyDown(KEY_RIGHT)) player.x += 2; + else if (IsKeyDown(KEY_LEFT)) player.x -= 2; + + // Camera target follows player + camera.target = (Vector2){ player.x + 20, player.y + 20 }; + + // Camera rotation controls + if (IsKeyDown(KEY_A)) camera.rotation--; + else if (IsKeyDown(KEY_S)) camera.rotation++; + + // Limit camera rotation to 80 degrees (-40 to 40) + if (camera.rotation > 40) camera.rotation = 40; + else if (camera.rotation < -40) camera.rotation = -40; + + // Camera zoom controls + camera.zoom += ((float)GetMouseWheelMove()*0.05f); + + if (camera.zoom > 3.0f) camera.zoom = 3.0f; + else if (camera.zoom < 0.1f) camera.zoom = 0.1f; + + // Camera reset (zoom and rotation) + if (IsKeyPressed(KEY_R)) + { + camera.zoom = 1.0f; + camera.rotation = 0.0f; + } + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + BeginMode2D(camera); + + DrawRectangle(-6000, 320, 13000, 8000, DARKGRAY); + + for (int i = 0; i < MAX_BUILDINGS; i++) DrawRectangleRec(buildings[i], buildColors[i]); + + DrawRectangleRec(player, RED); + + DrawLine((int)camera.target.x, -screenHeight*10, (int)camera.target.x, screenHeight*10, GREEN); + DrawLine(-screenWidth*10, (int)camera.target.y, screenWidth*10, (int)camera.target.y, GREEN); + + EndMode2D(); + + DrawText("SCREEN AREA", 640, 10, 20, RED); + + DrawRectangle(0, 0, screenWidth, 5, RED); + DrawRectangle(0, 5, 5, screenHeight - 10, RED); + DrawRectangle(screenWidth - 5, 5, 5, screenHeight - 10, RED); + DrawRectangle(0, screenHeight - 5, screenWidth, 5, RED); + + DrawRectangle( 10, 10, 250, 113, Fade(SKYBLUE, 0.5f)); + DrawRectangleLines( 10, 10, 250, 113, BLUE); + + DrawText("Free 2d camera controls:", 20, 20, 10, BLACK); + DrawText("- Right/Left to move Offset", 40, 40, 10, DARKGRAY); + DrawText("- Mouse Wheel to Zoom in-out", 40, 60, 10, DARKGRAY); + DrawText("- A / S to Rotate", 40, 80, 10, DARKGRAY); + DrawText("- R to reset Zoom and Rotation", 40, 100, 10, DARKGRAY); + + EndDrawing(); + //---------------------------------------------------------------------------------- +} + +// De-Initialization +//-------------------------------------------------------------------------------------- +CloseWindow(); // Close window and OpenGL context +//-------------------------------------------------------------------------------------- diff --git a/examples/input_mouse.js b/examples/input_mouse.js new file mode 100644 index 0000000..98e028b --- /dev/null +++ b/examples/input_mouse.js @@ -0,0 +1,49 @@ +import * as rlc from "raylib.core" + +// Initialization +//-------------------------------------------------------------------------------------- +const screenWidth = 800; +const screenHeight = 450; + +rlc.initWindow(screenWidth, screenHeight, "raylib [core] example - mouse input"); + +let ballPosition = new rlc.Vector2(-100.0, -100.0); +let ballColor = rlc.DARKBLUE; + +rlc.setTargetFPS(60); // Set our game to run at 60 frames-per-second +//--------------------------------------------------------------------------------------- + +// Main game loop +while (!rlc.windowShouldClose()) // Detect window close button or ESC key +{ + // Update + //---------------------------------------------------------------------------------- + ballPosition = rlc.getMousePosition(); + + if (rlc.isMouseButtonPressed(rlc.MOUSE_BUTTON_LEFT)) ballColor = rlc.MAROON; + else if (rlc.isMouseButtonPressed(rlc.MOUSE_BUTTON_MIDDLE)) ballColor = rlc.LIME; + else if (rlc.isMouseButtonPressed(rlc.MOUSE_BUTTON_RIGHT)) ballColor = rlc.DARKBLUE; + else if (rlc.isMouseButtonPressed(rlc.MOUSE_BUTTON_SIDE)) ballColor = rlc.PURPLE; + else if (rlc.isMouseButtonPressed(rlc.MOUSE_BUTTON_EXTRA)) ballColor = rlc.YELLOW; + else if (rlc.isMouseButtonPressed(rlc.MOUSE_BUTTON_FORWARD)) ballColor = rlc.ORANGE; + else if (rlc.isMouseButtonPressed(rlc.MOUSE_BUTTON_BACK)) ballColor = rlc.BEIGE; + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + rlc.beginDrawing(); + + rlc.clearBackground(rlc.RAYWHITE); + + rlc.drawCircleV(ballPosition, 40, ballColor); + + rlc.drawText("move ball with mouse and click mouse button to change color", 10, 10, 20, rlc.DARKGRAY); + + rlc.endDrawing(); + //---------------------------------------------------------------------------------- +} + +// De-Initialization +//-------------------------------------------------------------------------------------- +rlc.closeWindow(); // Close window and OpenGL context +//-------------------------------------------------------------------------------------- diff --git a/examples/input_mouse_wheel.js b/examples/input_mouse_wheel.js new file mode 100644 index 0000000..3bfcb88 --- /dev/null +++ b/examples/input_mouse_wheel.js @@ -0,0 +1,42 @@ +import * as rlc from "raylib.core" + +// Initialization +//-------------------------------------------------------------------------------------- +const screenWidth = 800; +const screenHeight = 450; + +rlc.initWindow(screenWidth, screenHeight, "raylib [core] example - input mouse wheel"); + +let boxPositionY = screenHeight/2 - 40; +let scrollSpeed = 4; // Scrolling speed in pixels + +rlc.setTargetFPS(60); // Set our game to run at 60 frames-per-second +//-------------------------------------------------------------------------------------- + +// Main game loop +while (!rlc.windowShouldClose()) // Detect window close button or ESC key +{ + // Update + //---------------------------------------------------------------------------------- + boxPositionY -= (rlc.getMouseWheelMove()*scrollSpeed); + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + rlc.beginDrawing(); + + rlc.clearBackground(rlc.RAYWHITE); + + rlc.drawRectangle(screenWidth/2 - 40, boxPositionY, 80, 80, rlc.MAROON); + + rlc.drawText("Use mouse wheel to move the cube up and down!", 10, 10, 20, rlc.GRAY); + rlc.drawText("Box position Y: " + boxPositionY, 10, 40, 20, rlc.LIGHTGRAY); + + rlc.endDrawing(); + //---------------------------------------------------------------------------------- +} + +// De-Initialization +//-------------------------------------------------------------------------------------- +rlc.closeWindow(); // Close window and OpenGL context +//-------------------------------------------------------------------------------------- diff --git a/generate-bindings.js b/generate-bindings.js index 990ea7f..68f1f0d 100644 --- a/generate-bindings.js +++ b/generate-bindings.js @@ -434,7 +434,7 @@ class GenericQuickJsGenerator extends generation_1.GenericCodeGenerator { const body = this.function(`js_${structName}_finalizer`, "void", args, true); body.statement(`${structName}* ptr = JS_GetOpaque(val, ${classId})`); body.if("ptr", cond => { - cond.call("TraceLog", ["LOG_INFO", `"Finalize ${structName}"`]); + //cond.call("TraceLog", ["LOG_INFO",`"Finalize ${structName}"`]) if (onFinalize) onFinalize(cond, "ptr"); cond.call("js_free_rt", ["rt", "ptr"]); @@ -679,6 +679,15 @@ function main() { }, createConstructor: true }); + core_gen.addApiStructByName("Rectangle", { + properties: { + x: { get: true, set: true }, + y: { get: true, set: true }, + width: { get: true, set: true }, + height: { get: true, set: true }, + }, + createConstructor: true + }); core_gen.addApiStructByName("Vector2", { properties: { x: { get: true, set: true }, @@ -689,19 +698,25 @@ function main() { core_gen.addApiFunctionByName("SetWindowTitle"); core_gen.addApiFunctionByName("SetWindowPosition"); core_gen.addApiFunctionByName("BeginDrawing"); - core_gen.addApiFunctionByName("EndDrawing"); + core_gen.addApiFunctionByName("EndDrawing", null, { before: fun => fun.call("app_update_quickjs", []) }); core_gen.addApiFunctionByName("InitWindow"); core_gen.addApiFunctionByName("SetTargetFPS"); - core_gen.addApiFunctionByName("WindowShouldClose", null, { before: fun => fun.call("app_update_quickjs", []) }); + core_gen.addApiFunctionByName("WindowShouldClose"); core_gen.addApiFunctionByName("ClearBackground"); core_gen.addApiFunctionByName("CloseWindow"); core_gen.addApiFunctionByName("DrawText"); core_gen.addApiFunctionByName("DrawCircleV"); core_gen.addApiFunctionByName("IsKeyDown"); + core_gen.addApiFunctionByName("GetMousePosition"); + core_gen.addApiFunctionByName("IsMouseButtonPressed"); + core_gen.addApiFunctionByName("GetMouseWheelMove"); + core_gen.addApiFunctionByName("DrawRectangle"); + core_gen.addApiFunctionByName("GetRandomValue"); api.defines.filter(x => x.type === "COLOR").map(x => ({ name: x.name, values: (x.value.match(/\{([^}]+)\}/) || "")[1].split(',').map(x => x.trim()) })).forEach(x => { core_gen.exportGlobalStruct("Color", x.name, x.values); }); api.enums.find(x => x.name === "KeyboardKey")?.values.forEach(x => core_gen.exportGlobalConstant(x.name)); + api.enums.find(x => x.name === "MouseButton")?.values.forEach(x => core_gen.exportGlobalConstant(x.name)); core_gen.writeTo("src/bindings/js_raylib_core.h"); const texture_gen = new raylib_header_1.RayLibHeader("raylib_texture", apiDesc); texture_gen.addApiStructByName("Image", { diff --git a/src/bindings/js_raylib_core.h b/src/bindings/js_raylib_core.h index 1dbc172..4ae6a1e 100644 --- a/src/bindings/js_raylib_core.h +++ b/src/bindings/js_raylib_core.h @@ -18,7 +18,6 @@ static JSClassID js_Vector2_class_id; static void js_Color_finalizer(JSRuntime * rt, JSValue val) { Color* ptr = JS_GetOpaque(val, js_Color_class_id); if(ptr) { - TraceLog(LOG_INFO, "Finalize Color"); js_free_rt(rt, ptr); } } @@ -132,7 +131,6 @@ static int js_declare_Color(JSContext * ctx, JSModuleDef * m) { static void js_Vector2_finalizer(JSRuntime * rt, JSValue val) { Vector2* ptr = JS_GetOpaque(val, js_Vector2_class_id); if(ptr) { - TraceLog(LOG_INFO, "Finalize Vector2"); js_free_rt(rt, ptr); } } @@ -256,6 +254,7 @@ static JSValue js_beginDrawing(JSContext * ctx, JSValueConst this_val, int argc, } static JSValue js_endDrawing(JSContext * ctx, JSValueConst this_val, int argc, JSValueConst * argv) { + app_update_quickjs(); EndDrawing(); return JS_UNDEFINED; } @@ -280,7 +279,6 @@ static JSValue js_setTargetFPS(JSContext * ctx, JSValueConst this_val, int argc, } static JSValue js_windowShouldClose(JSContext * ctx, JSValueConst this_val, int argc, JSValueConst * argv) { - app_update_quickjs(); bool returnVal = WindowShouldClose(); JSValue ret = JS_NewBool(ctx, returnVal); return ret; @@ -338,6 +336,45 @@ static JSValue js_isKeyDown(JSContext * ctx, JSValueConst this_val, int argc, JS return ret; } +static JSValue js_getMousePosition(JSContext * ctx, JSValueConst this_val, int argc, JSValueConst * argv) { + Vector2 returnVal = GetMousePosition(); + Vector2* ret_ptr = (Vector2*)js_malloc(ctx, sizeof(Vector2)); + *ret_ptr = returnVal; + JSValue ret = JS_NewObjectClass(ctx, js_Vector2_class_id); + JS_SetOpaque(ret, ret_ptr); + return ret; +} + +static JSValue js_isMouseButtonPressed(JSContext * ctx, JSValueConst this_val, int argc, JSValueConst * argv) { + int button; + JS_ToInt32(ctx, &button, argv[0]); + bool returnVal = IsMouseButtonPressed(button); + JSValue ret = JS_NewBool(ctx, returnVal); + return ret; +} + +static JSValue js_getMouseWheelMove(JSContext * ctx, JSValueConst this_val, int argc, JSValueConst * argv) { + float returnVal = GetMouseWheelMove(); + JSValue ret = JS_NewFloat64(ctx, returnVal); + return ret; +} + +static JSValue js_drawRectangle(JSContext * ctx, JSValueConst this_val, int argc, JSValueConst * argv) { + int posX; + JS_ToInt32(ctx, &posX, argv[0]); + int posY; + JS_ToInt32(ctx, &posY, argv[1]); + int width; + JS_ToInt32(ctx, &width, argv[2]); + int height; + JS_ToInt32(ctx, &height, argv[3]); + Color* color_ptr = (Color*)JS_GetOpaque2(ctx, argv[4], js_Color_class_id); + if(color_ptr == NULL) return JS_EXCEPTION; + Color color = *color_ptr; + DrawRectangle(posX, posY, width, height, color); + return JS_UNDEFINED; +} + static const JSCFunctionListEntry js_raylib_core_funcs[] = { JS_CFUNC_DEF("setWindowTitle",1,js_setWindowTitle), JS_CFUNC_DEF("setWindowPosition",2,js_setWindowPosition), @@ -351,6 +388,10 @@ static const JSCFunctionListEntry js_raylib_core_funcs[] = { JS_CFUNC_DEF("drawText",5,js_drawText), JS_CFUNC_DEF("drawCircleV",3,js_drawCircleV), JS_CFUNC_DEF("isKeyDown",1,js_isKeyDown), + JS_CFUNC_DEF("getMousePosition",0,js_getMousePosition), + JS_CFUNC_DEF("isMouseButtonPressed",1,js_isMouseButtonPressed), + JS_CFUNC_DEF("getMouseWheelMove",0,js_getMouseWheelMove), + JS_CFUNC_DEF("drawRectangle",5,js_drawRectangle), }; static int js_raylib_core_init(JSContext * ctx, JSModuleDef * m) { @@ -627,6 +668,13 @@ static int js_raylib_core_init(JSContext * ctx, JSModuleDef * m) { JS_SetModuleExport(ctx, m, "KEY_MENU", JS_NewInt32(ctx, KEY_MENU)); JS_SetModuleExport(ctx, m, "KEY_VOLUME_UP", JS_NewInt32(ctx, KEY_VOLUME_UP)); JS_SetModuleExport(ctx, m, "KEY_VOLUME_DOWN", JS_NewInt32(ctx, KEY_VOLUME_DOWN)); + JS_SetModuleExport(ctx, m, "MOUSE_BUTTON_LEFT", JS_NewInt32(ctx, MOUSE_BUTTON_LEFT)); + JS_SetModuleExport(ctx, m, "MOUSE_BUTTON_RIGHT", JS_NewInt32(ctx, MOUSE_BUTTON_RIGHT)); + JS_SetModuleExport(ctx, m, "MOUSE_BUTTON_MIDDLE", JS_NewInt32(ctx, MOUSE_BUTTON_MIDDLE)); + JS_SetModuleExport(ctx, m, "MOUSE_BUTTON_SIDE", JS_NewInt32(ctx, MOUSE_BUTTON_SIDE)); + JS_SetModuleExport(ctx, m, "MOUSE_BUTTON_EXTRA", JS_NewInt32(ctx, MOUSE_BUTTON_EXTRA)); + JS_SetModuleExport(ctx, m, "MOUSE_BUTTON_FORWARD", JS_NewInt32(ctx, MOUSE_BUTTON_FORWARD)); + JS_SetModuleExport(ctx, m, "MOUSE_BUTTON_BACK", JS_NewInt32(ctx, MOUSE_BUTTON_BACK)); return 0; } @@ -773,6 +821,13 @@ JSModuleDef * js_init_module_raylib_core(JSContext * ctx, const char * module_na JS_AddModuleExport(ctx, m, "KEY_MENU"); JS_AddModuleExport(ctx, m, "KEY_VOLUME_UP"); JS_AddModuleExport(ctx, m, "KEY_VOLUME_DOWN"); + JS_AddModuleExport(ctx, m, "MOUSE_BUTTON_LEFT"); + JS_AddModuleExport(ctx, m, "MOUSE_BUTTON_RIGHT"); + JS_AddModuleExport(ctx, m, "MOUSE_BUTTON_MIDDLE"); + JS_AddModuleExport(ctx, m, "MOUSE_BUTTON_SIDE"); + JS_AddModuleExport(ctx, m, "MOUSE_BUTTON_EXTRA"); + JS_AddModuleExport(ctx, m, "MOUSE_BUTTON_FORWARD"); + JS_AddModuleExport(ctx, m, "MOUSE_BUTTON_BACK"); return m; } diff --git a/src/bindings/js_raylib_texture.h b/src/bindings/js_raylib_texture.h index 887faa8..7ed9d39 100644 --- a/src/bindings/js_raylib_texture.h +++ b/src/bindings/js_raylib_texture.h @@ -17,7 +17,6 @@ static JSClassID js_Image_class_id; static void js_Image_finalizer(JSRuntime * rt, JSValue val) { Image* ptr = JS_GetOpaque(val, js_Image_class_id); if(ptr) { - TraceLog(LOG_INFO, "Finalize Image"); UnloadImage(*ptr); js_free_rt(rt, ptr); } diff --git a/thirdparty/raylib b/thirdparty/raylib index 5573f0f..a48bb6e 160000 --- a/thirdparty/raylib +++ b/thirdparty/raylib @@ -1 +1 @@ -Subproject commit 5573f0f1c7b29bfe46d0b70487e4adb4d01cba62 +Subproject commit a48bb6e1ed7b33190e486ba65b7875f0dff73701