commit 64f55c81b02e1f1922b7af97ac1cf97a8744e9d9 Author: Sebastian Date: Wed Jun 10 20:53:30 2026 +0200 Initial project scaffold for Dimma diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..eef0197 --- /dev/null +++ b/.gitignore @@ -0,0 +1,28 @@ +# Build outputs +build/ +*.exe +*.dll +*.so +*.dylib +*.app +*.o +*.a + +# Odin +odin/bin/ + +# Go +bin/ + +# IDE +.idea/ +.vscode/ +*.swp +*.swo + +# OS +.DS_Store +Thumbs.db + +# Logs +*.log diff --git a/README.md b/README.md new file mode 100644 index 0000000..48702f2 --- /dev/null +++ b/README.md @@ -0,0 +1,201 @@ +# Dimma + +A cross-platform desktop application built with Odin (raylib + raygui) and Go (auto-updater). + +## Project Structure + +``` +dimma/ +├── odin/ # Odin source code (GUI application) +│ ├── main.odin # Main application entry point +│ ├── raylib.odin # raylib C interop bindings +│ ├── raygui.odin # raygui C interop bindings +│ ├── build.odin # Odin build script +│ └── odin.json # Odin project configuration +├── go/ # Go source code (auto-updater) +│ ├── main.go # Auto-updater CLI +│ ├── go.mod # Go module definition +│ ├── build.sh # Unix build script +│ └── build.ps1 # Windows build script +├── build/ # Compiled binaries (gitignored) +├── assets/ # Static files +│ ├── icon.png # Application icon +│ └── version.txt # Current version file +├── scripts/ # Build/utility scripts +│ ├── build-all.sh # Build all platforms (Unix) +│ ├── build-all.ps1 # Build all platforms (Windows) +│ ├── run.sh # Run script (Unix) +│ └── run.ps1 # Run script (Windows) +├── .gitignore +└── README.md +``` + +## Prerequisites + +### Odin +- [Odin compiler](https://odin-lang.org/) (latest stable, e.g., `odin dev-2024-11`) +- raylib and raygui installed system-wide or via submodules +- C compiler (gcc/clang) for raylib compilation + +### Go +- Go 1.21+ + +### Dependencies +- raylib (for Odin GUI) +- raygui (for Odin GUI) + +## Build Instructions + +### Odin (GUI Application) + +Navigate to the `odin/` directory and build: + +```bash +cd odin +odin build main.odin -build-mode:exe -target:. -out:../build/dimma +``` + +**With raylib/raygui:** + +```bash +odin build main.odin \ + -build-mode:exe \ + -target:. \ + -out:../build/dimma \ + -raylib:include-path:/path/to/raylib/include \ + -raylib:lib-path:/path/to/raylib/lib \ + -raylib:static +``` + +### Go (Auto-Updater) + +Navigate to the `go/` directory and build: + +```bash +cd go +go build -o ../build/go-updater ./ +``` + +For cross-compilation: + +```bash +GOOS=linux GOARCH=amd64 go build -o ../build/go-updater-linux-amd64 ./ +GOOS=windows GOARCH=amd64 go build -o ../build/go-updater-windows-amd64.exe ./ +GOOS=darwin GOARCH=amd64 go build -o ../build/go-updater-darwin-amd64 ./ +``` + +### Cross-Platform Build + +Use the scripts in `scripts/` directory: + +**Unix (Linux/macOS):** +```bash +chmod +x scripts/*.sh +./scripts/build-all.sh +``` + +**Windows (PowerShell):** +```powershell +.\scripts\build-all.ps1 +``` + +## Testing + +### Run the Odin Application + +```bash +# Build first +cd odin +odin build main.odin -build-mode:exe -out:../build/dimma + +# Then run +./scripts/run.sh +``` + +### Test the Auto-Updater + +```bash +cd go +go run main.go --check +``` + +This will: +1. Fetch the latest version from `https://gitea.sanplex.xyz/Sansan/dimma/releases/latest` +2. Compare it to the hardcoded version `v0.1.0` +3. Print "Update available: {version}" or "Up to date" + +## Cross-Compilation Notes + +### Odin + +Set the target OS and architecture using Odin's `-target` flag: + +```bash +odin build main.odin -target:linux_amd64 -build-mode:exe +odin build main.odin -target:windows_amd64 -build-mode:exe +odin build main.odin -target:macos_amd64 -build-mode:exe +``` + +### Go + +Use environment variables: + +```bash +GOOS=linux GOARCH=amd64 go build ./ +GOOS=windows GOARCH=amd64 go build ./ +GOOS=darwin GOARCH=amd64 go build ./ +``` + +## Git Setup + +### Initialize Repository + +The repository is already initialized. For a fresh clone: + +```bash +git init +git add . +git commit -m "Initial project scaffold for Dimma" +``` + +### Add Remote + +```bash +git remote add origin gitea.sanplex.xyz:Sansan/dimma.git +``` + +Or with HTTPS: + +```bash +git remote add origin https://gitea.sanplex.xyz/Sansan/dimma.git +``` + +### First Push + +```bash +git push -u origin main +``` + +Note: You'll need to authenticate with Gitea and may need to create the repository on the Gitea web interface first. + +## Version Management + +The current version is defined in: +- `assets/version.txt` - Plain text version file +- `odin/main.odin` - `CURRENT_VERSION` constant +- `go/main.go` - `CurrentVersion` constant + +Update all three files when releasing a new version. + +## Future Auto-Updater Implementation + +The auto-updater will eventually: +1. Download the new binary from Gitea release assets +2. Replace the old binary (with appropriate permissions) +3. Restart the application + +The Odin app will spawn the updater process and exit, allowing the updater to replace the binary safely. + +## License + +[License information to be added] diff --git a/assets/icon.png b/assets/icon.png new file mode 100644 index 0000000..e69de29 diff --git a/assets/version.txt b/assets/version.txt new file mode 100644 index 0000000..b82608c --- /dev/null +++ b/assets/version.txt @@ -0,0 +1 @@ +v0.1.0 diff --git a/go/build.ps1 b/go/build.ps1 new file mode 100644 index 0000000..d469cc2 --- /dev/null +++ b/go/build.ps1 @@ -0,0 +1,30 @@ +# Build script for Go updater (PowerShell) +# Usage: .\build.ps1 [os] [arch] +# Default: builds for current OS/architecture + +$MODULE = "gitea.sanplex.xyz/Sansan/dimma-updater" +$OUTPUT_DIR = "..\build" +$BIN_NAME = "go-updater" + +$OS = if ($args.Count -gt 0) { $args[0] } else { $env:GOOS } +$ARCH = if ($args.Count -gt 1) { $args[1] } else { $env:GOARCH } + +if ($OS -eq "windows") { $EXT = ".exe" } else { $EXT = "" } + +$OUTPUT = "$OUTPUT_DIR\$BIN_NAME-$OS-$ARCH$EXT" + +New-Item -ItemType Directory -Force -Path $OUTPUT_DIR | Out-Null + +Write-Host "Building Go updater for $OS/$ARCH..." +Write-Host "Output: $OUTPUT" + +go build -o $OUTPUT .\ + +if ($OS -eq "linux" -or $OS -eq "darwin") { + # On Unix-like systems, make executable + if ($IsLinux -or $IsMacOS) { + chmod +x $OUTPUT + } +} + +Write-Host "Build complete: $OUTPUT" diff --git a/go/build.sh b/go/build.sh new file mode 100755 index 0000000..5945dbe --- /dev/null +++ b/go/build.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +# Build script for Go updater +# Usage: ./build.sh [os] [arch] +# Default: builds for current OS/architecture + +MODULE="gitea.sanplex.xyz/Sansan/dimma-updater" +OUTPUT_DIR="../build" +BIN_NAME="go-updater" + +OS=${1:-$(go env GOOS)} +ARCH=${2:-$(go env GOARCH)} + +case "$OS" in + windows) EXT=".exe" ;; + *) EXT="" ;; +esac + +OUTPUT="${OUTPUT_DIR}/${BIN_NAME}-${OS}-${ARCH}${EXT}" + +mkdir -p "$OUTPUT_DIR" + +echo "Building Go updater for ${OS}/${ARCH}..." +echo "Output: ${OUTPUT}" + +go build -o "$OUTPUT" ./ + +if [ "$OS" = "linux" ] || [ "$OS" = "darwin" ]; then + chmod +x "$OUTPUT" +fi + +echo "Build complete: ${OUTPUT}" diff --git a/go/go.mod b/go/go.mod new file mode 100644 index 0000000..a1ca723 --- /dev/null +++ b/go/go.mod @@ -0,0 +1,7 @@ +module gitea.sanplex.xyz/Sansan/dimma-updater + +go 1.21 + +require ( + github.com/inconshreveable/go-update v0.0.0-20230525132907-6d786845c5a3 +) diff --git a/go/main.go b/go/main.go new file mode 100644 index 0000000..08889c8 --- /dev/null +++ b/go/main.go @@ -0,0 +1,100 @@ +package main + +import ( + "encoding/json" + "flag" + "fmt" + "io" + "net/http" + "os" + "strings" +) + +const ( + CurrentVersion = "v0.1.0" + ReleaseURL = "https://gitea.sanplex.xyz/Sansan/dimma/releases/latest" +) + +type ReleaseInfo struct { + TagName string `json:"tag_name"` +} + +func main() { + check := flag.Bool("check", false, "Check for updates") + flag.Parse() + + if !*check { + flag.Usage() + return + } + + fmt.Printf("Current version: %s\n", CurrentVersion) + + latestVersion, err := fetchLatestVersion() + if err != nil { + fmt.Printf("Error fetching latest version: %v\n", err) + return + } + + fmt.Printf("Latest version: %s\n", latestVersion) + + if compareVersions(latestVersion, CurrentVersion) > 0 { + fmt.Printf("Update available: %s\n", latestVersion) + } else { + fmt.Println("Up to date") + } +} + +func fetchLatestVersion() (string, error) { + resp, err := http.Get(ReleaseURL) + if err != nil { + return "", err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return "", fmt.Errorf("HTTP %d", resp.StatusCode) + } + + body, err := io.ReadAll(resp.Body) + if err != nil { + return "", err + } + + // Gitea releases API returns JSON with tag_name + var release ReleaseInfo + if err := json.Unmarshal(body, &release); err != nil { + // Try to extract from HTML if not JSON + release.TagName = extractVersionFromHTML(string(body)) + if release.TagName == "" { + return "", fmt.Errorf("failed to parse release info") + } + } + + return release.TagName, nil +} + +func extractVersionFromHTML(html string) string { + // Simple extraction from HTML (fallback for non-API URLs) + // Looks for patterns like "v0.1.0" or "0.1.0" + parts := strings.Split(html, "v") + for _, part := range parts { + if len(part) > 0 && part[0] >= '0' && part[0] <= '9' { + version := "v" + strings.Split(part, "\"")[0] + version = strings.Split(version, " ")[0] + version = strings.Split(version, ">")[0] + version = strings.TrimSpace(version) + if version != "" { + return version + } + } + } + return "" +} + +func compareVersions(a, b string) int { + // Simple version comparison (v0.1.0 format) + a = strings.TrimPrefix(a, "v") + b = strings.TrimPrefix(b, "v") + return strings.Compare(a, b) +} diff --git a/odin.json b/odin.json new file mode 100644 index 0000000..731b864 --- /dev/null +++ b/odin.json @@ -0,0 +1,18 @@ +{ + "name": "dimma", + "root": ".", + "vendor": false, + "definition_files": [ + "main.odin" + ], + "flags": [ + "-raylib:include-path:/usr/local/include", + "-raylib:lib-path:/usr/local/lib", + "-raylib:static" + ], + "build_flags": [ + "-build-mode:exe", + "-target:.", + "-out:../build/dimma" + ] +} diff --git a/odin/build.odin b/odin/build.odin new file mode 100644 index 0000000..ce53440 --- /dev/null +++ b/odin/build.odin @@ -0,0 +1,37 @@ +// Odin build script for Dimma +// Usage: odin build build.odin + +package build + +import "core:os" +import "core:fmt" + +const ( + OUTPUT_DIR = "../build/" + APP_NAME = "dimma" +) + +main :: proc() { + // Determine OS and architecture + os_name := os.GetEnv("ODIN_OS") + if os_name == "" { + os_name = os.Environ()[0] // Fallback + } + + arch := os.GetEnv("ODIN_ARCH") + if arch == "" { + arch = "amd64" // Default + } + + output_path := OUTPUT_DIR + APP_NAME + "-" + os_name + "-" + arch + + // Create build directory + os.MkdirAll(OUTPUT_DIR, 0755) + + fmt.printf("Building Dimma for %s/%s...\n", os_name, arch) + fmt.printf("Output: %s\n", output_path) + + // Build command would be: + // odin build main.odin -out:%s -build-mode:exe -target:.)... + // with appropriate raylib/raygui paths +} diff --git a/odin/main.odin b/odin/main.odin new file mode 100644 index 0000000..ac4641f --- /dev/null +++ b/odin/main.odin @@ -0,0 +1,44 @@ +package main + +import "core:fmt" +import "core:os" +import raylib "./raylib.odin" +import raygui "./raygui.odin" + +const ( + SCREEN_WIDTH = 800 + SCREEN_HEIGHT = 450 + APP_TITLE = "Dimma" + CURRENT_VERSION = "v0.1.0" +) + +main :: proc() { + raylib.InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, APP_TITLE) + defer raylib.CloseWindow() + + raylib.SetTargetFPS(60) + + for !raylib.WindowShouldClose() { + raylib.BeginDrawing() + defer raylib.EndDrawing() + + raylib.ClearBackground(raylib.RAYWHITE) + + // Draw raygui + raygui.Draw() + } +} + +// GUI procedure to be called from main loop +Draw :: proc() { + // Draw version label + pos := raylib.Vector2{10, 10} + raygui.Label(pos, "Current Version: " + CURRENT_VERSION) + + // Draw update button + btn_pos := raylib.Vector2{10, 40} + btn_size := raylib.Vector2{200, 30} + if raygui.Button(btn_pos, btn_size, "Check for Updates") { + fmt.println("Check for Updates clicked") + } +} diff --git a/odin/raygui.odin b/odin/raygui.odin new file mode 100644 index 0000000..cd16c37 --- /dev/null +++ b/odin/raygui.odin @@ -0,0 +1,17 @@ +// Placeholder for raygui C interop bindings +// Assumes raygui headers are available system-wide +package raygui + +import raylib "../raylib.odin" + +// GUI control functions +Label :: proc(pos: raylib.Vector2, text: rawstring) #cdecl +Button :: proc(pos: raylib.Vector2, size: raylib.Vector2, text: rawstring) -> bool #cdecl + +// Layout functions +GuiSetStyle :: proc(control: i32, property: i32, value: i32) #cdecl +GuiLoadStyle :: proc(fileName: rawstring) -> bool #cdecl +GuiEnable :: proc() #cdecl +GuiDisable :: proc() #cdecl +GuiLock :: proc() #cdecl +GuiUnlock :: proc() #cdecl diff --git a/odin/raylib.odin b/odin/raylib.odin new file mode 100644 index 0000000..7e4d02a --- /dev/null +++ b/odin/raylib.odin @@ -0,0 +1,25 @@ +// Placeholder for raylib C interop bindings +// Assumes raylib headers are available system-wide +package raylib + +@(import_c) +const ( + RAYWHITE = 0xF5F5F5FF +) + +// Window functions +InitWindow :: proc(width: i32, height: i32, title: rawstring) #cdecl +CloseWindow :: proc() #cdecl +WindowShouldClose :: proc() -> bool #cdecl +SetTargetFPS :: proc(fps: i32) #cdecl + +// Drawing functions +BeginDrawing :: proc() #cdecl +EndDrawing :: proc() #cdecl +ClearBackground :: proc(color: u32) #cdecl + +// Vector2 type +Vector2 :: struct { + X: f32, + Y: f32, +} diff --git a/scripts/build-all.ps1 b/scripts/build-all.ps1 new file mode 100644 index 0000000..5903acc --- /dev/null +++ b/scripts/build-all.ps1 @@ -0,0 +1,53 @@ +# Cross-platform build script for Dimma (PowerShell) +# Builds Odin app + Go updater for all platforms + +$ErrorActionPreference = "Stop" + +$PROJECT_DIR = Resolve-Path (Split-Path $PSScriptRoot -Parent) +$BUILD_DIR = "$PROJECT_DIR\build" +$ODIN_DIR = "$PROJECT_DIR\odin" +$GO_DIR = "$PROJECT_DIR\go" + +New-Item -ItemType Directory -Force -Path $BUILD_DIR | Out-Null + +# Build Go updater for all platforms +$GO_PLATFORMS = @( + @("linux", "amd64"), + @("linux", "arm64"), + @("darwin", "amd64"), + @("darwin", "arm64"), + @("windows", "amd64") +) + +foreach ($platform in $GO_PLATFORMS) { + $os = $platform[0] + $arch = $platform[1] + Write-Host "Building Go updater for $os/$arch..." + Push-Location $GO_DIR + $env:GOOS = $os + $env:GOARCH = $arch + .\build.ps1 $os $arch + Pop-Location +} + +# Build Odin app for all platforms +$ODIN_PLATFORMS = @( + @("linux", "amd64"), + @("windows", "amd64"), + @("darwin", "amd64") +) + +foreach ($platform in $ODIN_PLATFORMS) { + $os = $platform[0] + $arch = $platform[1] + Write-Host "Building Odin app for $os/$arch..." + # odin build $ODIN_DIR\main.odin ` + # -out:`$BUILD_DIR\dimma-$os-$arch.exe ` + # -build-mode:exe ` + # -target:. ` + # -raylib:include-path:C:\path\to\raylib\include ` + # -raylib:lib-path:C:\path\to\raylib\lib + Write-Host " (Run: odin build $ODIN_DIR\main.odin -out:`$BUILD_DIR\dimma-$os-$arch -build-mode:exe)" +} + +Write-Host "All builds complete. Output in $BUILD_DIR" diff --git a/scripts/build-all.sh b/scripts/build-all.sh new file mode 100755 index 0000000..1f78333 --- /dev/null +++ b/scripts/build-all.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +# Cross-platform build script for Dimma +# Builds Odin app + Go updater for all platforms + +set -e + +PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +BUILD_DIR="$PROJECT_DIR/build" +ODIN_DIR="$PROJECT_DIR/odin" +GO_DIR="$PROJECT_DIR/go" + +mkdir -p "$BUILD_DIR" + +# Build Go updater for all platforms +GO_PLATFORMS=("linux/amd64" "linux/arm64" "darwin/amd64" "darwin/arm64" "windows/amd64") + +for platform in "${GO_PLATFORMS[@]}"; do + IFS='/' read -r os arch <<< "$platform" + echo "Building Go updater for $os/$arch..." + (cd "$GO_DIR" && GOOS=$os GOARCH=$arch ./build.sh $os $arch) +done + +# Build Odin app for all platforms +ODIN_PLATFORMS=("linux:amd64" "windows:amd64" "darwin:amd64") + +for platform in "${ODIN_PLATFORMS[@]}"; do + IFS=':' read -r os arch <<< "$platform" + echo "Building Odin app for $os/$arch..." + # odin build $ODIN_DIR/main.odin \ + # -out:$BUILD_DIR/dimma-$os-$arch \ + # -build-mode:exe \ + # -target:. \ + # -raylib:include-path:/path/to/raylib/include \ + # -raylib:lib-path:/path/to/raylib/lib + echo " (Run: odin build $ODIN_DIR/main.odin -out:$BUILD_DIR/dimma-$os-$arch -build-mode:exe)" +done + +echo "All builds complete. Output in $BUILD_DIR/" diff --git a/scripts/run.ps1 b/scripts/run.ps1 new file mode 100644 index 0000000..12f75a4 --- /dev/null +++ b/scripts/run.ps1 @@ -0,0 +1,26 @@ +# Run script for Dimma (PowerShell) +# Usage: .\run.ps1 [platform] [arch] +# Platform can be: linux, windows, darwin +# Default: auto-detects current platform + +$PROJECT_DIR = Resolve-Path (Split-Path $PSScriptRoot -Parent) +$BUILD_DIR = "$PROJECT_DIR\build" +$PLATFORM = if ($args.Count -gt 0) { $args[0] } else { $env:GOOS } +$ARCH = if ($args.Count -gt 1) { $args[1] } else { $env:GOARCH } + +if ($PLATFORM -eq "") { $PLATFORM = $IsWindows -as [string] ? "windows" : ($IsLinux -as [string] ? "linux" : "darwin") } +if ($ARCH -eq "") { $ARCH = $env:PROCESSOR_ARCHITEW6432 -replace "AMD64", "amd64" -replace "ARM64", "arm64" } + +$BINARY = "$BUILD_DIR\dimma-$PLATFORM-$ARCH" + +if ($PLATFORM -eq "windows") { $BINARY = "$BINARY.exe" } + +if (-not (Test-Path $BINARY)) { + Write-Host "Binary not found: $BINARY" + Write-Host "Available binaries in $BUILD_DIR:" + Get-ChildItem $BUILD_DIR + exit 1 +} + +Write-Host "Running: $BINARY" +& $BINARY diff --git a/scripts/run.sh b/scripts/run.sh new file mode 100755 index 0000000..1d6bc59 --- /dev/null +++ b/scripts/run.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +# Run script for Dimma +# Usage: ./run.sh [platform] +# Platform can be: linux, windows, darwin +# Default: auto-detects current platform + +PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +BUILD_DIR="$PROJECT_DIR/build" +PLATFORM=${1:-$(uname -s | tr '[:upper:]' '[:lower:]')} +ARCH=${2:-$(uname -m)} + +# Map uname output to platform +case "$PLATFORM" in + linux*) PLATFORM="linux" ;; + darwin*) PLATFORM="darwin" ;; + mingw*|cygwin*|msys*) PLATFORM="windows" ;; + windows) PLATFORM="windows" ;; +esac + +# Map architecture +case "$ARCH" in + x86_64) ARCH="amd64" ;; + aarch64) ARCH="arm64" ;; + i?86) ARCH="386" ;; + armv*) ARCH="arm" ;; +esac + +BINARY="$BUILD_DIR/dimma-$PLATFORM-$ARCH" + +if [ "$PLATFORM" = "windows" ]; then + BINARY="$BINARY.exe" +fi + +if [ ! -f "$BINARY" ]; then + echo "Binary not found: $BINARY" + echo "Available binaries in $BUILD_DIR/:" + ls -la "$BUILD_DIR/" + exit 1 +fi + +chmod +x "$BINARY" +echo "Running: $BINARY" +"$BINARY"