diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..567609b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..600b63f --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "3rd-party/raygui"] + path = 3rd-party/raygui + url = https://github.com/raysan5/raygui.git +[submodule "3rd-party/raylib"] + path = 3rd-party/raylib + url = https://github.com/raysan5/raylib.git diff --git a/3rd-party/Tupfile b/3rd-party/Tupfile new file mode 100644 index 0000000..c307e54 --- /dev/null +++ b/3rd-party/Tupfile @@ -0,0 +1,5 @@ +BDIR := ../build/raygui + +: raygui.c |> clang -c %f -o %o -I../build/raylib/include -Iraygui/src |> $(BDIR)/%B.o +: $(BDIR)/*.o |> ar crs %o %f |> $(BDIR)/libraygui.a + diff --git a/3rd-party/raygui b/3rd-party/raygui new file mode 160000 index 0000000..499e8bf --- /dev/null +++ b/3rd-party/raygui @@ -0,0 +1 @@ +Subproject commit 499e8bf7b1d9b0a92af8f685e646bc61f13c6dff diff --git a/3rd-party/raygui.c b/3rd-party/raygui.c new file mode 100644 index 0000000..2f9910a --- /dev/null +++ b/3rd-party/raygui.c @@ -0,0 +1,6 @@ +#define RAYGUI_IMPLEMENTATION +#include "raygui.h" +#undef RAYGUI_IMPLEMENTATION + +#define GUI_WINDOW_FILE_DIALOG_IMPLEMENTATION +#include "../examples/custom_file_dialog/gui_window_file_dialog.h" diff --git a/3rd-party/raylib b/3rd-party/raylib new file mode 160000 index 0000000..18bedbd --- /dev/null +++ b/3rd-party/raylib @@ -0,0 +1 @@ +Subproject commit 18bedbd0952c27b0eb8bc5df0df4acf589cef181 diff --git a/Tupfile.ini b/Tupfile.ini new file mode 100644 index 0000000..e69de29 diff --git a/build.zig b/build.zig new file mode 100644 index 0000000..efae36f --- /dev/null +++ b/build.zig @@ -0,0 +1,79 @@ +const std = @import("std"); + +// Although this function looks imperative, note that its job is to +// declaratively construct a build graph that will be executed by an external +// runner. +pub fn build(b: *std.Build) void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + + const exe = b.addExecutable(.{ + .name = "fabapp", + .root_source_file = .{ .path = "src/main.zig" }, + .target = target, + .optimize = optimize, + }); + + // + // C dependencies + // + exe.linkLibC(); + + // Raylib + exe.addIncludePath(.{ .path = "build/raylib/include" }); + exe.addLibraryPath(.{ .path = "build/raylib" }); + exe.linkSystemLibrary("raylib"); + + // Raygui + exe.addIncludePath(.{ .path = "3rd-party/raygui/src" }); + exe.addIncludePath(.{ .path = "3rd-party/raygui" }); + exe.addLibraryPath(.{ .path = "build/raygui" }); + exe.linkSystemLibrary("raygui"); + + // SQLite + exe.linkSystemLibrary("sqlite3"); + + // This declares intent for the executable to be installed into the + // standard location when the user invokes the "install" step (the default + // step when running `zig build`). + b.installArtifact(exe); + + // This *creates* a Run step in the build graph, to be executed when another + // step is evaluated that depends on it. The next line below will establish + // such a dependency. + const run_cmd = b.addRunArtifact(exe); + + // By making the run step depend on the install step, it will be run from the + // installation directory rather than directly from within the cache directory. + // This is not necessary, however, if the application depends on other installed + // files, this ensures they will be present and in the expected location. + run_cmd.step.dependOn(b.getInstallStep()); + + // This allows the user to pass arguments to the application in the build + // command itself, like this: `zig build run -- arg1 arg2 etc` + if (b.args) |args| { + run_cmd.addArgs(args); + } + + // This creates a build step. It will be visible in the `zig build --help` menu, + // and can be selected like this: `zig build run` + // This will evaluate the `run` step rather than the default, which is "install". + const run_step = b.step("run", "Run the app"); + run_step.dependOn(&run_cmd.step); + + // Creates a step for unit testing. This only builds the test executable + // but does not run it. + const unit_tests = b.addTest(.{ + .root_source_file = .{ .path = "src/main.zig" }, + .target = target, + .optimize = optimize, + }); + + const run_unit_tests = b.addRunArtifact(unit_tests); + + // Similar to creating the run step earlier, this exposes a `test` step to + // the `zig build --help` menu, providing a way for the user to request + // running the unit tests. + const test_step = b.step("test", "Run unit tests"); + test_step.dependOn(&run_unit_tests.step); +} diff --git a/envrc.sample b/envrc.sample index a5dbbcb..54c13ac 100644 --- a/envrc.sample +++ b/envrc.sample @@ -1 +1,2 @@ use flake . +export CMAKE_GENERATOR=Ninja diff --git a/flake.lock b/flake.lock index 8a5062e..ca5ad12 100644 --- a/flake.lock +++ b/flake.lock @@ -5,11 +5,11 @@ "nixpkgs-lib": "nixpkgs-lib" }, "locked": { - "lastModified": 1701473968, - "narHash": "sha256-YcVE5emp1qQ8ieHUnxt1wCZCC3ZfAS+SRRWZ2TMda7E=", + "lastModified": 1696343447, + "narHash": "sha256-B2xAZKLkkeRFG5XcHHSXXcP7To9Xzr59KXeZiRf4vdQ=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "34fed993f1674c8d06d58b37ce1e0fe5eebcb9f5", + "rev": "c9afaba3dfa4085dbd2ccb38dfade5141e33d9d4", "type": "github" }, "original": { @@ -20,11 +20,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1702759837, - "narHash": "sha256-u3XeJVRe/Q975nwFE+6ALEwypMKJEELMJKDAhSKyq3M=", + "lastModified": 1696983906, + "narHash": "sha256-L7GyeErguS7Pg4h8nK0wGlcUTbfUMDu+HMf1UcyP72k=", "owner": "nixos", "repo": "nixpkgs", - "rev": "b2566f4f897ac6224e094b167d9488d03e157f28", + "rev": "bd1cde45c77891214131cbbea5b1203e485a9d51", "type": "github" }, "original": { @@ -37,11 +37,11 @@ "nixpkgs-lib": { "locked": { "dir": "lib", - "lastModified": 1701253981, - "narHash": "sha256-ztaDIyZ7HrTAfEEUt9AtTDNoCYxUdSd6NrRHaYOIxtk=", + "lastModified": 1696019113, + "narHash": "sha256-X3+DKYWJm93DRSdC5M6K5hLqzSya9BjibtBsuARoPco=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "e92039b55bcd58469325ded85d4f58dd5a4eaf58", + "rev": "f5892ddac112a1e9b3612c39af1b72987ee5783a", "type": "github" }, "original": { @@ -54,11 +54,11 @@ }, "nixpkgs-unstable": { "locked": { - "lastModified": 1702539185, - "narHash": "sha256-KnIRG5NMdLIpEkZTnN5zovNYc0hhXjAgv6pfd5Z4c7U=", + "lastModified": 1697009197, + "narHash": "sha256-viVRhBTFT8fPJTb1N3brQIpFZnttmwo3JVKNuWRVc3s=", "owner": "nixos", "repo": "nixpkgs", - "rev": "aa9d4729cbc99dabacb50e3994dcefb3ea0f7447", + "rev": "01441e14af5e29c9d27ace398e6dd0b293e25a54", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 0f15fd7..032f3bf 100644 --- a/flake.nix +++ b/flake.nix @@ -29,12 +29,45 @@ devShells.default = with pkgs; mkShell { - LD_LIBRARY_PATH = lib.makeLibraryPath [ stdenv.cc.cc ]; # For libstdc++.so.6 - ANDROID_HOME = "foo/bar"; - - nativeBuildInputs = [ clang just android-tools godot_4 ]; - buildInputs = [ sqlite ]; + # EM_CONFIG = pkgs.writeText ".emscripten" '' + # EMSCRIPTEN_ROOT = '${pkgs.emscripten}/share/emscripten' + # LLVM_ROOT = '${pkgs.emscripten.llvmEnv}/bin' + # BINARYEN_ROOT = '${pkgs.binaryen}' + # NODE_JS = '${pkgs.nodejs-18_x}/bin/node' + # CACHE = '${toString ./.cache}' + # ''; + + nativeBuildInputs = [ clang cmake just ninja tup ]; + + buildInputs = [ + sqlite + + # Zig / webAssembly impl. + zig + zls + emscripten + + # Linux graphical deps + ## X11 + xorg.libX11 + xorg.libXcursor + xorg.libXi + xorg.libXext + xorg.libXrandr + xorg.libXinerama + xorg.libxcb + libGL + libGLU + pkg-config + + ## Wayland + wayland-protocols + wayland + libxkbcommon + ]; + }; + }; }; } diff --git a/godot/export_presets.cfg b/godot/export_presets.cfg deleted file mode 100644 index 0be7e60..0000000 --- a/godot/export_presets.cfg +++ /dev/null @@ -1,201 +0,0 @@ -[preset.0] - -name="Android" -platform="Android" -runnable=true -dedicated_server=false -custom_features="" -export_filter="all_resources" -include_filter="" -exclude_filter="" -export_path="" -encryption_include_filters="" -encryption_exclude_filters="" -encrypt_pck=false -encrypt_directory=false - -[preset.0.options] - -custom_template/debug="" -custom_template/release="" -gradle_build/use_gradle_build=false -gradle_build/export_format=0 -gradle_build/min_sdk="" -gradle_build/target_sdk="" -architectures/armeabi-v7a=false -architectures/arm64-v8a=true -architectures/x86=false -architectures/x86_64=false -version/code=1 -version/name="" -package/unique_name="com.example.$genname" -package/name="" -package/signed=true -package/app_category=2 -package/retain_data_on_uninstall=false -package/exclude_from_recents=false -package/show_in_android_tv=false -package/show_in_app_library=true -package/show_as_launcher_app=false -launcher_icons/main_192x192="" -launcher_icons/adaptive_foreground_432x432="" -launcher_icons/adaptive_background_432x432="" -graphics/opengl_debug=false -xr_features/xr_mode=0 -screen/immersive_mode=true -screen/support_small=true -screen/support_normal=true -screen/support_large=true -screen/support_xlarge=true -user_data_backup/allow=false -command_line/extra_args="" -apk_expansion/enable=false -apk_expansion/SALT="" -apk_expansion/public_key="" -permissions/custom_permissions=PackedStringArray() -permissions/access_checkin_properties=false -permissions/access_coarse_location=false -permissions/access_fine_location=false -permissions/access_location_extra_commands=false -permissions/access_mock_location=false -permissions/access_network_state=false -permissions/access_surface_flinger=false -permissions/access_wifi_state=false -permissions/account_manager=false -permissions/add_voicemail=false -permissions/authenticate_accounts=false -permissions/battery_stats=false -permissions/bind_accessibility_service=false -permissions/bind_appwidget=false -permissions/bind_device_admin=false -permissions/bind_input_method=false -permissions/bind_nfc_service=false -permissions/bind_notification_listener_service=false -permissions/bind_print_service=false -permissions/bind_remoteviews=false -permissions/bind_text_service=false -permissions/bind_vpn_service=false -permissions/bind_wallpaper=false -permissions/bluetooth=false -permissions/bluetooth_admin=false -permissions/bluetooth_privileged=false -permissions/brick=false -permissions/broadcast_package_removed=false -permissions/broadcast_sms=false -permissions/broadcast_sticky=false -permissions/broadcast_wap_push=false -permissions/call_phone=false -permissions/call_privileged=false -permissions/camera=false -permissions/capture_audio_output=false -permissions/capture_secure_video_output=false -permissions/capture_video_output=false -permissions/change_component_enabled_state=false -permissions/change_configuration=false -permissions/change_network_state=false -permissions/change_wifi_multicast_state=false -permissions/change_wifi_state=false -permissions/clear_app_cache=false -permissions/clear_app_user_data=false -permissions/control_location_updates=false -permissions/delete_cache_files=false -permissions/delete_packages=false -permissions/device_power=false -permissions/diagnostic=false -permissions/disable_keyguard=false -permissions/dump=false -permissions/expand_status_bar=false -permissions/factory_test=false -permissions/flashlight=false -permissions/force_back=false -permissions/get_accounts=false -permissions/get_package_size=false -permissions/get_tasks=false -permissions/get_top_activity_info=false -permissions/global_search=false -permissions/hardware_test=false -permissions/inject_events=false -permissions/install_location_provider=false -permissions/install_packages=false -permissions/install_shortcut=false -permissions/internal_system_window=false -permissions/internet=false -permissions/kill_background_processes=false -permissions/location_hardware=false -permissions/manage_accounts=false -permissions/manage_app_tokens=false -permissions/manage_documents=false -permissions/manage_external_storage=true -permissions/master_clear=false -permissions/media_content_control=false -permissions/modify_audio_settings=false -permissions/modify_phone_state=false -permissions/mount_format_filesystems=false -permissions/mount_unmount_filesystems=false -permissions/nfc=false -permissions/persistent_activity=false -permissions/process_outgoing_calls=false -permissions/read_calendar=false -permissions/read_call_log=false -permissions/read_contacts=false -permissions/read_external_storage=false -permissions/read_frame_buffer=false -permissions/read_history_bookmarks=false -permissions/read_input_state=false -permissions/read_logs=false -permissions/read_phone_state=false -permissions/read_profile=false -permissions/read_sms=false -permissions/read_social_stream=false -permissions/read_sync_settings=false -permissions/read_sync_stats=false -permissions/read_user_dictionary=false -permissions/reboot=false -permissions/receive_boot_completed=false -permissions/receive_mms=false -permissions/receive_sms=false -permissions/receive_wap_push=false -permissions/record_audio=false -permissions/reorder_tasks=false -permissions/restart_packages=false -permissions/send_respond_via_message=false -permissions/send_sms=false -permissions/set_activity_watcher=false -permissions/set_alarm=false -permissions/set_always_finish=false -permissions/set_animation_scale=false -permissions/set_debug_app=false -permissions/set_orientation=false -permissions/set_pointer_speed=false -permissions/set_preferred_applications=false -permissions/set_process_limit=false -permissions/set_time=false -permissions/set_time_zone=false -permissions/set_wallpaper=false -permissions/set_wallpaper_hints=false -permissions/signal_persistent_processes=false -permissions/status_bar=false -permissions/subscribed_feeds_read=false -permissions/subscribed_feeds_write=false -permissions/system_alert_window=false -permissions/transmit_ir=false -permissions/uninstall_shortcut=false -permissions/update_device_stats=false -permissions/use_credentials=false -permissions/use_sip=false -permissions/vibrate=false -permissions/wake_lock=false -permissions/write_apn_settings=false -permissions/write_calendar=false -permissions/write_call_log=false -permissions/write_contacts=false -permissions/write_external_storage=false -permissions/write_gservices=false -permissions/write_history_bookmarks=false -permissions/write_profile=false -permissions/write_secure_settings=false -permissions/write_settings=false -permissions/write_sms=false -permissions/write_social_stream=false -permissions/write_sync_settings=false -permissions/write_user_dictionary=false diff --git a/godot/main.gd b/godot/main.gd index fcd7cba..04bde40 100644 --- a/godot/main.gd +++ b/godot/main.gd @@ -6,8 +6,6 @@ func _ready(): $FileDialog.access = FileDialog.ACCESS_FILESYSTEM $FileDialog.use_native_dialog = true - $MarginContainer/Unloaded/Button.pressed.connect(_on_button_pressed) - Global.state_changed.connect(_update_state) if Global.current_state == Global.State.UNLOADED: pass @@ -16,6 +14,7 @@ func _ready(): var s = ResourceLoader.load("res://loaded.tscn") var current_scene = s.instantiate() $MarginContainer.add_child(current_scene) + pass # Called every frame. 'delta' is the elapsed time since the previous frame. func _process(delta): diff --git a/godot/project.godot b/godot/project.godot index 2c0efd8..1b49b39 100644 --- a/godot/project.godot +++ b/godot/project.godot @@ -32,4 +32,3 @@ enabled=PackedStringArray("res://addons/godot-sqlite/plugin.cfg") renderer/rendering_method="gl_compatibility" renderer/rendering_method.mobile="gl_compatibility" -textures/vram_compression/import_etc2_astc=true diff --git a/justfile b/justfile index d79686d..15f5c3d 100644 --- a/justfile +++ b/justfile @@ -1,17 +1,32 @@ +cpp_build_dir := justfile_directory() / "build" + alias b := build alias r := run alias t := test alias fmt := format -edit: - godot4 --editor godot/project.godot - pre-build: git submodule update --init --recursive +raylib: + mkdir -p {{ cpp_build_dir }} + cmake -B {{ cpp_build_dir }} -S {{ justfile_directory() }}/3rd-party/raylib \ + -DBUILD_EXAMPLES=OFF + cmake --build {{ cpp_build_dir }} + +raygui: + tup + +deps: pre-build raylib raygui + build: zig build -Doptimize=Debug +# web-build: pre-build +# # zig build-lib src/main.zig -target wasm32-freestanding -dynamic -rdynamic +# zig build -Dtarget=wasm32-emscripten --sysroot /nix/store/lszbak7w3k1jmx3cm3qb2qzillsib71v-emscripten-3.1.24/bin/emcc +# # zig build -Dtarget=wasm32-emscripten + run: nixGL zig build run -- {{ justfile_directory() }}/life.sqlite3 @@ -19,4 +34,5 @@ test: zig build test format: + fd -e zig -X zig fmt {} fd -e nix -X nix fmt {} diff --git a/src/main.zig b/src/main.zig new file mode 100644 index 0000000..695cf2e --- /dev/null +++ b/src/main.zig @@ -0,0 +1,114 @@ +const std = @import("std"); +const raylib = @import("raylib.zig"); +const c = @cImport({ + @cInclude("sqlite3.h"); +}); + +const StateTag = enum { + unloaded, + loaded, +}; + +const State = union(StateTag) { + unloaded: void, + loaded: *c.sqlite3, +}; + +fn loadSqlite(path: [:0]const u8) State { + var db_opt: ?*c.sqlite3 = undefined; + + const result = c.sqlite3_open(path.ptr, &db_opt); + if (result != c.SQLITE_OK) { + std.debug.print("[SQLite] err {}: {s}\n", .{ result, c.sqlite3_errmsg(db_opt) }); + _ = c.sqlite3_close(db_opt); + return State{ .unloaded = {} }; + } + + if (db_opt) |db| { + std.debug.print("[SQLite] Success\n", .{}); + return State{ .loaded = db }; + } + + return State{ .unloaded = {} }; +} + +pub fn main() !void { + var state = State{ .unloaded = {} }; + + const alloc = std.heap.c_allocator; + + const args = try std.process.argsAlloc(alloc); + defer std.process.argsFree(alloc, args); + + std.debug.print("Arguments: {s}\n", .{args}); + + if (args.len > 1) { + state = loadSqlite(args[1]); + } + + const screen_width = 800; + const screen_height = 450; + raylib.InitWindow(screen_width, screen_height, "Loggy"); + raylib.SetTargetFPS(60); + + var file_dialog_state = raylib.InitGuiWindowFileDialog(raylib.GetWorkingDirectory()); + // const ext = ".sqlite3"; + // @memcpy(file_dialog_state.filterExt[0..ext.len], ext); + var checked = false; + + while (!raylib.WindowShouldClose()) { + // + // Update + // + { + if (file_dialog_state.SelectFilePressed) { + // C-strings -> slices + const dir = std.mem.sliceTo(&file_dialog_state.dirPathText, 0); + const file = std.mem.sliceTo(&file_dialog_state.fileNameText, 0); + + // slices -> C-string (null-terminated) + const db_path = try std.fs.path.joinZ(alloc, &[_][]const u8{ dir, file }); + defer alloc.free(db_path); + state = loadSqlite(db_path); + } + file_dialog_state.SelectFilePressed = false; + } + + // + // Render + // + { + raylib.BeginDrawing(); + defer raylib.EndDrawing(); + raylib.ClearBackground(raylib.RAYWHITE); + + switch (state) { + .unloaded => { + if (file_dialog_state.windowActive) raylib.GuiLock(); + defer raylib.GuiUnlock(); + + const button_size = 200; + if (raylib.GuiButton(.{ .x = (screen_width - button_size) / 2, .y = (screen_height - button_size) / 2, .width = 200, .height = 200 }, "Load db file") == 1) { + file_dialog_state.windowActive = true; + } + }, + + .loaded => |*db| { + _ = db; + const label_rect: raylib.Rectangle = .{ .x = 10, .y = 10, .width = 40, .height = 40 }; + _ = raylib.GuiCheckBox(label_rect, "Eat well", &checked); + }, + } + + raylib.GuiWindowFileDialog(&file_dialog_state); + } + } + raylib.CloseWindow(); +} + +test "simple test" { + var list = std.ArrayList(i32).init(std.testing.allocator); + defer list.deinit(); // try commenting this out and see if zig detects the memory leak! + try list.append(42); + try std.testing.expectEqual(@as(i32, 42), list.pop()); +} diff --git a/src/raylib.zig b/src/raylib.zig new file mode 100644 index 0000000..937ee90 --- /dev/null +++ b/src/raylib.zig @@ -0,0 +1,5 @@ +pub usingnamespace @cImport({ + @cInclude("raylib.h"); + @cInclude("raygui.h"); + @cInclude("examples/custom_file_dialog/gui_window_file_dialog.h"); +});