4 Commits

Author SHA1 Message Date
scawful
4371618a9b backend-infra-engineer: Release v0.3.1 snapshot 2025-09-28 03:07:45 -04:00
scawful
e32ac75b9c backend-infra-engineer: Release v0.3.0 snapshot 2025-09-27 00:25:45 -04:00
scawful
8ce29e1436 backend-infra-engineer: Release 0.2.2 snapshot 2024-12-31 21:00:27 -05:00
scawful
18b7fb9abf backend-infra-engineer: Pre-0.2.2 2024 Q4 snapshot 2024-11-28 11:50:47 -05:00
437 changed files with 96593 additions and 21739 deletions

83
.clang-format Normal file
View File

@@ -0,0 +1,83 @@
# Google C/C++ Code Style settings
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html
# Author: Kehan Xue, kehan.xue (at) gmail.com
Language: Cpp
BasedOnStyle: Google
AccessModifierOffset: -1
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: None
AlignOperands: Align
AllowAllArgumentsOnNextLine: true
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: Empty
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Inline
AllowShortIfStatementsOnASingleLine: Never # To avoid conflict, set this "Never" and each "if statement" should include brace when coding
AllowShortLambdasOnASingleLine: Inline
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterReturnType: None
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: true
BreakBeforeBraces: Custom
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterStruct: false
AfterControlStatement: Never
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: false
BreakBeforeBinaryOperators: None
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeColon
BreakInheritanceList: BeforeColon
ColumnLimit: 80
CompactNamespaces: false
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false # Make sure the * or & align on the left
EmptyLineBeforeAccessModifier: LogicalBlock
FixNamespaceComments: true
IncludeBlocks: Preserve
IndentCaseLabels: true
IndentPPDirectives: None
IndentWidth: 2
KeepEmptyLinesAtTheStartOfBlocks: true
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PointerAlignment: Left
ReflowComments: false
# SeparateDefinitionBlocks: Always # Only support since clang-format 14
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceBeforeSquareBrackets: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: false
SpacesInCStyleCastParentheses: false
SpacesInContainerLiterals: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: c++11
TabWidth: 4
UseTab: Never

53
.clang-tidy Normal file
View File

@@ -0,0 +1,53 @@
# YAZE clang-tidy configuration
# More lenient configuration for easier compliance
Checks: >
-*-,
clang-analyzer-*,
-clang-analyzer-alpha*,
performance-*,
-performance-unnecessary-value-param,
readability-*,
-readability-magic-numbers,
-readability-braces-around-statements,
-readability-named-parameter,
-readability-function-cognitive-complexity,
-readability-avoid-const-params-in-decls,
modernize-*,
-modernize-use-trailing-return-type,
-modernize-use-auto,
-modernize-avoid-c-arrays,
-modernize-use-default-member-init,
bugprone-*,
-bugprone-easily-swappable-parameters,
-bugprone-exception-escape,
-bugprone-narrowing-conversions,
-bugprone-implicit-widening-of-multiplication-result,
misc-*,
-misc-no-recursion,
-misc-non-private-member-variables-in-classes,
-misc-const-correctness
CheckOptions:
- key: readability-identifier-naming.VariableCase
value: lower_case
- key: readability-identifier-naming.FunctionCase
value: lower_case
- key: readability-identifier-naming.ClassCase
value: CamelCase
- key: readability-identifier-naming.StructCase
value: CamelCase
- key: readability-identifier-naming.NamespaceCase
value: lower_case
- key: readability-identifier-naming.MacroCase
value: UPPER_CASE
- key: readability-function-size.LineThreshold
value: 150
- key: readability-function-size.StatementThreshold
value: 100
- key: performance-unnecessary-value-param.AllowedTypes
value: 'std::function;std::unique_ptr;std::shared_ptr'
WarningsAsErrors: ''
HeaderFilterRegex: '(src|test)\/.*\.(h|hpp|hxx)$'
FormatStyle: google

35
.clangd Normal file
View File

@@ -0,0 +1,35 @@
CompileFlags:
Add:
- -std=c++23
- -Wall
- -Wextra
Remove:
- -mllvm
- -xclang
Index:
Background: Build
StandardLibrary: Yes
InlayHints:
Enabled: Yes
ParameterNames: Yes
DeducedTypes: Yes
Hover:
ShowAKA: Yes
Diagnostics:
ClangTidy:
Add:
- readability-*
- modernize-*
- performance-*
Remove:
- modernize-use-trailing-return-type
- readability-braces-around-statements
- readability-magic-numbers
- readability-implicit-bool-conversion
- readability-identifier-naming
- readability-function-cognitive-complexity
- readability-function-size

View File

@@ -0,0 +1,151 @@
name: Windows Build Fallback
on:
workflow_call:
inputs:
build_type:
description: 'Build type (Debug/Release)'
required: true
type: string
default: 'Release'
platform:
description: 'Platform (x64/x86)'
required: true
type: string
default: 'x64'
env:
BUILD_TYPE: ${{ inputs.build_type }}
PLATFORM: ${{ inputs.platform }}
jobs:
build-windows-fallback:
name: Windows ${{ inputs.platform }} ${{ inputs.build_type }} (Fallback)
runs-on: windows-2022
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive
# Try vcpkg first
- name: Set up vcpkg (Primary)
id: vcpkg_primary
uses: lukka/run-vcpkg@v11
continue-on-error: true
with:
vcpkgGitCommitId: 'c8696863d371ab7f46e213d8f5ca923c4aef2a00'
runVcpkgInstall: true
vcpkgJsonGlob: '**/vcpkg.json'
vcpkgDirectory: '${{ github.workspace }}/vcpkg'
env:
VCPKG_FORCE_SYSTEM_BINARIES: 1
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"
VCPKG_DEFAULT_TRIPLET: '${{ inputs.platform }}-windows'
VCPKG_INSTALL_OPTIONS: '--x-install-root="${{ github.workspace }}/vcpkg_installed"'
# Fallback to newer baseline if primary fails
- name: Set up vcpkg (Fallback)
if: steps.vcpkg_primary.outcome == 'failure'
uses: lukka/run-vcpkg@v11
with:
vcpkgGitCommitId: '2024.01.12'
runVcpkgInstall: true
vcpkgJsonGlob: '**/vcpkg.json.backup'
vcpkgDirectory: '${{ github.workspace }}/vcpkg'
env:
VCPKG_FORCE_SYSTEM_BINARIES: 1
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"
VCPKG_DEFAULT_TRIPLET: '${{ inputs.platform }}-windows'
VCPKG_INSTALL_OPTIONS: '--x-install-root="${{ github.workspace }}/vcpkg_installed"'
# Fallback to manual dependency installation if both vcpkg attempts fail
- name: Install dependencies manually
if: steps.vcpkg_primary.outcome == 'failure'
shell: pwsh
run: |
Write-Host "Installing dependencies manually using Chocolatey and pre-built libraries..."
# Install Chocolatey if not present
if (-not (Get-Command choco -ErrorAction SilentlyContinue)) {
Set-ExecutionPolicy Bypass -Scope Process -Force
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072
iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
}
# Install basic dependencies
choco install -y cmake ninja
# Create a minimal build configuration
Write-Host "Creating minimal build configuration for CI..."
# Set up environment variables for minimal build
echo "YAZE_MINIMAL_BUILD=ON" >> $env:GITHUB_ENV
echo "CMAKE_PREFIX_PATH=$env:GITHUB_WORKSPACE\vcpkg_installed\${{ inputs.platform }}-windows" >> $env:GITHUB_ENV
- name: Configure CMake
shell: cmd
run: |
if exist "${{ github.workspace }}\vcpkg_installed" (
echo "Using vcpkg installation..."
cmake -B build ^
-DCMAKE_BUILD_TYPE=%BUILD_TYPE% ^
-DCMAKE_POLICY_VERSION_MINIMUM=3.16 ^
-DCMAKE_TOOLCHAIN_FILE="${{ github.workspace }}/vcpkg/scripts/buildsystems/vcpkg.cmake" ^
-DYAZE_BUILD_TESTS=OFF ^
-DYAZE_BUILD_EMU=OFF ^
-DYAZE_BUILD_Z3ED=OFF ^
-DYAZE_ENABLE_ROM_TESTS=OFF ^
-DYAZE_ENABLE_EXPERIMENTAL_TESTS=OFF ^
-DYAZE_INSTALL_LIB=OFF ^
-DYAZE_MINIMAL_BUILD=ON ^
-G "Visual Studio 17 2022" ^
-A %PLATFORM%
) else (
echo "Using minimal build configuration..."
cmake -B build ^
-DCMAKE_BUILD_TYPE=%BUILD_TYPE% ^
-DCMAKE_POLICY_VERSION_MINIMUM=3.16 ^
-DYAZE_BUILD_TESTS=OFF ^
-DYAZE_BUILD_EMU=OFF ^
-DYAZE_BUILD_Z3ED=OFF ^
-DYAZE_ENABLE_ROM_TESTS=OFF ^
-DYAZE_ENABLE_EXPERIMENTAL_TESTS=OFF ^
-DYAZE_INSTALL_LIB=OFF ^
-DYAZE_MINIMAL_BUILD=ON ^
-G "Visual Studio 17 2022" ^
-A %PLATFORM%
)
- name: Build
run: cmake --build build --config %BUILD_TYPE% --parallel
- name: Test executable
shell: pwsh
run: |
$exePath = "build\bin\$env:BUILD_TYPE\yaze.exe"
if (Test-Path $exePath) {
Write-Host "✓ Executable created: $exePath" -ForegroundColor Green
# Test that it's not the test main
$testResult = & $exePath --help 2>&1
if ($testResult -match "Google Test" -or $testResult -match "gtest") {
Write-Error "Executable is running test main instead of app main!"
exit 1
}
Write-Host "✓ Executable runs correctly" -ForegroundColor Green
} else {
Write-Error "Executable not found at: $exePath"
exit 1
}
- name: Upload build artifacts
uses: actions/upload-artifact@v4
if: always()
with:
name: yaze-${{ inputs.platform }}-${{ inputs.build_type }}-fallback
path: |
build/bin/${{ inputs.build_type }}/
retention-days: 7

428
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,428 @@
name: CI/CD Pipeline
on:
push:
branches: [ "master", "develop" ]
paths:
- 'src/**'
- 'test/**'
- 'cmake/**'
- 'CMakeLists.txt'
- '.github/workflows/**'
pull_request:
branches: [ "master", "develop" ]
paths:
- 'src/**'
- 'test/**'
- 'cmake/**'
- 'CMakeLists.txt'
- '.github/workflows/**'
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
BUILD_TYPE: RelWithDebInfo
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"
jobs:
build-and-test:
strategy:
fail-fast: false
matrix:
include:
- name: "Ubuntu 22.04 (GCC-12)"
os: ubuntu-22.04
cc: gcc-12
cxx: g++-12
vcpkg_triplet: x64-linux
- name: "Ubuntu 22.04 (Clang)"
os: ubuntu-22.04
cc: clang-15
cxx: clang++-15
vcpkg_triplet: x64-linux
- name: "macOS 13 (Clang)"
os: macos-13
cc: clang
cxx: clang++
vcpkg_triplet: x64-osx
- name: "macOS 14 (Clang)"
os: macos-14
cc: clang
cxx: clang++
vcpkg_triplet: arm64-osx
- name: "Windows 2022 (MSVC x64)"
os: windows-2022
cc: cl
cxx: cl
vcpkg_triplet: x64-windows
cmake_generator: "Visual Studio 17 2022"
cmake_generator_platform: x64
- name: "Windows 2022 (MSVC x86)"
os: windows-2022
cc: cl
cxx: cl
vcpkg_triplet: x86-windows
cmake_generator: "Visual Studio 17 2022"
cmake_generator_platform: Win32
name: ${{ matrix.name }}
runs-on: ${{ matrix.os }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 0
- name: Export GitHub Actions cache environment variables
uses: actions/github-script@v7
with:
script: |
core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || '');
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');
- name: Set up vcpkg cache
if: runner.os == 'Windows'
uses: actions/cache@v4
with:
path: |
${{ github.workspace }}/vcpkg
${{ github.workspace }}/vcpkg_installed
key: vcpkg-${{ matrix.vcpkg_triplet }}-${{ hashFiles('vcpkg.json') }}
restore-keys: |
vcpkg-${{ matrix.vcpkg_triplet }}-
# Linux-specific setup
- name: Install Linux dependencies
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y \
build-essential \
ninja-build \
pkg-config \
libglew-dev \
libxext-dev \
libwavpack-dev \
libabsl-dev \
libboost-all-dev \
libboost-python-dev \
libpng-dev \
python3-dev \
libpython3-dev \
libasound2-dev \
libpulse-dev \
libaudio-dev \
libx11-dev \
libxrandr-dev \
libxcursor-dev \
libxinerama-dev \
libxi-dev \
libxss-dev \
libxxf86vm-dev \
libxkbcommon-dev \
libwayland-dev \
libdecor-0-dev \
libgtk-3-dev \
libdbus-1-dev \
gcc-12 \
g++-12 \
clang-15
- name: Set up Linux compilers
if: runner.os == 'Linux'
run: |
sudo update-alternatives --install /usr/bin/cc cc /usr/bin/${{ matrix.cc }} 100
sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/${{ matrix.cxx }} 100
# macOS-specific setup
- name: Install macOS dependencies
if: runner.os == 'macOS'
run: |
# Install Homebrew dependencies if needed
# brew install pkg-config libpng boost abseil
# Windows-specific setup (skip vcpkg for CI builds)
- name: Set up vcpkg (non-CI builds only)
if: runner.os == 'Windows' && github.event_name != 'push' && github.event_name != 'pull_request'
uses: lukka/run-vcpkg@v11
with:
vcpkgGitCommitId: 'c8696863d371ab7f46e213d8f5ca923c4aef2a00'
runVcpkgInstall: true
vcpkgJsonGlob: '**/vcpkg.json'
vcpkgDirectory: '${{ github.workspace }}/vcpkg'
- name: Configure CMake (Linux/macOS)
if: runner.os != 'Windows'
run: |
cmake -B ${{ github.workspace }}/build \
-DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \
-DCMAKE_C_COMPILER=${{ matrix.cc }} \
-DCMAKE_CXX_COMPILER=${{ matrix.cxx }} \
-DCMAKE_POLICY_VERSION_MINIMUM=3.16 \
-DYAZE_MINIMAL_BUILD=ON \
-DYAZE_ENABLE_ROM_TESTS=OFF \
-DYAZE_ENABLE_EXPERIMENTAL_TESTS=OFF \
-DYAZE_ENABLE_UI_TESTS=OFF \
-Wno-dev \
-GNinja
- name: Configure CMake (Windows)
if: runner.os == 'Windows'
shell: cmd
run: |
cmake -B ${{ github.workspace }}/build -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} -DCMAKE_POLICY_VERSION_MINIMUM=3.16 -DYAZE_MINIMAL_BUILD=ON -DYAZE_ENABLE_ROM_TESTS=OFF -DYAZE_ENABLE_EXPERIMENTAL_TESTS=OFF -DYAZE_ENABLE_UI_TESTS=OFF -Wno-dev -G "${{ matrix.cmake_generator }}" -A ${{ matrix.cmake_generator_platform }}
# Build
- name: Build
run: cmake --build ${{ github.workspace }}/build --config ${{ env.BUILD_TYPE }} --parallel
# Test (stable core functionality only for CI)
- name: Run Core Tests
working-directory: ${{ github.workspace }}/build
run: ctest --build-config ${{ env.BUILD_TYPE }} --output-on-failure -j1 -R "AsarWrapperTest|SnesTileTest|CompressionTest|SnesPaletteTest|HexTest"
# Run experimental tests separately (allowed to fail for information only)
- name: Run Additional Tests (Informational)
working-directory: ${{ github.workspace }}/build
continue-on-error: true
run: ctest --build-config ${{ env.BUILD_TYPE }} --output-on-failure --parallel -E "AsarWrapperTest|SnesTileTest|CompressionTest|SnesPaletteTest|HexTest|CpuTest|Spc700Test|ApuTest|MessageTest|.*IntegrationTest"
# Package (only on successful builds)
- name: Package artifacts
if: success()
run: |
cmake --build ${{ github.workspace }}/build --config ${{ env.BUILD_TYPE }} --target package
# Upload artifacts
- name: Upload build artifacts
if: success()
uses: actions/upload-artifact@v4
with:
name: yaze-${{ matrix.name }}-${{ github.sha }}
path: |
${{ github.workspace }}/build/bin/
${{ github.workspace }}/build/lib/
retention-days: 7
# Upload packages for release candidates
- name: Upload package artifacts
if: success() && (github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/'))
uses: actions/upload-artifact@v4
with:
name: yaze-package-${{ matrix.name }}-${{ github.sha }}
path: |
${{ github.workspace }}/build/*.tar.gz
${{ github.workspace }}/build/*.zip
${{ github.workspace }}/build/*.dmg
${{ github.workspace }}/build/*.msi
retention-days: 30
code-quality:
name: Code Quality Checks
runs-on: ubuntu-22.04
# Relaxed requirements for releases and master branch:
# - Formatting errors become warnings
# - Fewer cppcheck categories enabled
# - Reduced clang-tidy file count
# - Job failure won't block releases
continue-on-error: ${{ github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/') }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y \
clang-format-14 \
clang-tidy-14 \
cppcheck
- name: Check code formatting
run: |
# Relaxed formatting check for releases and master branch
if [[ "${{ github.ref }}" == "refs/heads/master" ]] || [[ "${{ github.ref }}" == refs/tags/* ]] || [[ "${{ github.event_name }}" == "pull_request" && "${{ github.base_ref }}" == "master" ]]; then
echo "🔄 Running relaxed formatting check for release/master branch..."
find src test -name "*.cc" -o -name "*.h" | \
xargs clang-format-14 --dry-run --Werror || {
echo "⚠️ Code formatting issues found, but allowing for release builds"
echo "📝 Consider running 'make format' to fix formatting before next release"
exit 0
}
else
echo "🔍 Running strict formatting check for development..."
find src test -name "*.cc" -o -name "*.h" | \
xargs clang-format-14 --dry-run --Werror
fi
- name: Run cppcheck
run: |
if [[ "${{ github.ref }}" == "refs/heads/master" ]] || [[ "${{ github.ref }}" == refs/tags/* ]]; then
echo "🔄 Running relaxed cppcheck for release/master branch..."
cppcheck --enable=warning \
--error-exitcode=0 \
--suppress=missingIncludeSystem \
--suppress=unusedFunction \
--suppress=unmatchedSuppression \
--suppress=variableScope \
--suppress=cstyleCast \
--suppress=unreadVariable \
--suppress=unusedStructMember \
--suppress=constParameter \
--suppress=constVariable \
--suppress=useStlAlgorithm \
--suppress=noExplicitConstructor \
--suppress=passedByValue \
--suppress=functionStatic \
src/ || echo "Cppcheck completed (non-blocking for releases)"
else
echo "🔍 Running standard cppcheck for development..."
cppcheck --enable=warning,style,performance \
--error-exitcode=0 \
--suppress=missingIncludeSystem \
--suppress=unusedFunction \
--suppress=unmatchedSuppression \
--suppress=variableScope \
--suppress=cstyleCast \
--suppress=unreadVariable \
--suppress=unusedStructMember \
--suppress=constParameter \
--suppress=constVariable \
--suppress=useStlAlgorithm \
--inconclusive \
src/ || echo "Cppcheck completed with warnings (non-blocking)"
fi
- name: Run clang-tidy (lenient)
run: |
if [[ "${{ github.ref }}" == "refs/heads/master" ]] || [[ "${{ github.ref }}" == refs/tags/* ]]; then
echo "🔄 Running minimal clang-tidy for release/master branch..."
# Only check a small subset of critical files for releases
find src -name "*.cc" -not -path "*/lib/*" -not -path "*/gui/*" | head -10 | \
xargs clang-tidy-14 --config-file=.clang-tidy \
--header-filter='src/.*\.(h|hpp)$' || echo "Clang-tidy completed (non-blocking for releases)"
else
echo "🔍 Running standard clang-tidy for development..."
# Run clang-tidy on a subset of files to avoid overwhelming output
find src -name "*.cc" -not -path "*/lib/*" | head -20 | \
xargs clang-tidy-14 --config-file=.clang-tidy \
--header-filter='src/.*\.(h|hpp)$' || echo "Clang-tidy completed with warnings (non-blocking)"
fi
memory-sanitizer:
name: Memory Sanitizer (Linux)
runs-on: ubuntu-22.04
if: github.event_name == 'pull_request'
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y \
build-essential \
ninja-build \
clang-14 \
libc++-14-dev \
libc++abi-14-dev \
libglew-dev \
libxext-dev \
libwavpack-dev \
libpng-dev \
libgtk-3-dev \
libdbus-1-dev
- name: Configure with AddressSanitizer
run: |
cmake -B ${{ github.workspace }}/build \
-DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_C_COMPILER=clang-14 \
-DCMAKE_CXX_COMPILER=clang++-14 \
-DCMAKE_CXX_FLAGS="-fsanitize=address -fno-omit-frame-pointer" \
-DCMAKE_C_FLAGS="-fsanitize=address -fno-omit-frame-pointer" \
-DCMAKE_EXE_LINKER_FLAGS="-fsanitize=address" \
-DYAZE_MINIMAL_BUILD=ON \
-DYAZE_ENABLE_ROM_TESTS=OFF \
-DYAZE_ENABLE_EXPERIMENTAL_TESTS=OFF \
-GNinja
- name: Build
run: cmake --build ${{ github.workspace }}/build --parallel
- name: Test with AddressSanitizer
working-directory: ${{ github.workspace }}/build
env:
ASAN_OPTIONS: detect_leaks=1:abort_on_error=1
run: ctest --output-on-failure
coverage:
name: Code Coverage
runs-on: ubuntu-22.04
if: github.event_name == 'pull_request'
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y \
build-essential \
ninja-build \
gcov \
lcov \
libglew-dev \
libxext-dev \
libwavpack-dev \
libpng-dev \
libgtk-3-dev \
libdbus-1-dev
- name: Configure with coverage
run: |
cmake -B ${{ github.workspace }}/build \
-DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_CXX_FLAGS="--coverage" \
-DCMAKE_C_FLAGS="--coverage" \
-DCMAKE_EXE_LINKER_FLAGS="--coverage" \
-DYAZE_MINIMAL_BUILD=ON \
-DYAZE_ENABLE_ROM_TESTS=OFF \
-DYAZE_ENABLE_EXPERIMENTAL_TESTS=OFF \
-GNinja
- name: Build
run: cmake --build ${{ github.workspace }}/build --parallel
- name: Test
working-directory: ${{ github.workspace }}/build
run: ctest --output-on-failure
- name: Generate coverage report
run: |
lcov --capture --directory ${{ github.workspace }}/build --output-file coverage.info
lcov --remove coverage.info '/usr/*' --output-file coverage.info
lcov --remove coverage.info '**/test/**' --output-file coverage.info
lcov --remove coverage.info '**/lib/**' --output-file coverage.info
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
file: ./coverage.info
flags: unittests
name: codecov-umbrella
fail_ci_if_error: false

View File

@@ -1,53 +0,0 @@
name: CMake
on:
push:
paths:
- 'src/**'
- 'test/**'
branches: [ "master" ]
pull_request:
paths:
- 'src/**'
- 'test/**'
branches: [ "master" ]
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
BUILD_TYPE: Debug
jobs:
build:
# The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac.
# You can convert this to a matrix build if you need cross-platform coverage.
# See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
submodules: recursive
- name: Install Video Libs
run: sudo apt install libglew-dev
- name: Install Audio Libs
run: sudo apt install libwavpack-dev
- name: Install Abseil-cpp
run: sudo apt install libabsl-dev
- name: Configure CMake
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
- name: Build
# Build your program with the given configuration
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
- name: Test
working-directory: ${{github.workspace}}/build
# Execute tests defined by the CMake configuration.
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
run: ${{github.workspace}}/build/bin/yaze_test

View File

@@ -1,45 +1,81 @@
name: Doxygen Action name: Doxygen Documentation
# Controls when the action will run. Triggers the workflow on push or pull request # Only run when documentation-related files are modified
# events but only for the master branch
on: on:
push: push:
branches: [ master ] branches: [ master ]
paths:
- 'src/**/*.h'
- 'src/**/*.cc'
- 'src/**/*.cpp'
- 'docs/**'
- 'Doxyfile'
- '.github/workflows/doxy.yml'
pull_request:
branches: [ master ]
paths:
- 'src/**/*.h'
- 'src/**/*.cc'
- 'src/**/*.cpp'
- 'docs/**'
- 'Doxyfile'
- '.github/workflows/doxy.yml'
# A workflow run is made up of one or more jobs that can run sequentially or in parallel # A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs: jobs:
# This workflow contains a single job called "build" generate-docs:
build: name: Generate Documentation
# The type of runner that the job will run on
runs-on: ubuntu-latest runs-on: ubuntu-latest
# Steps represent a sequence of tasks that will be executed as part of the job
steps: steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - name: Checkout repository
- uses: actions/checkout@v2 uses: actions/checkout@v4
with:
fetch-depth: 0
# Delete the html directory if it exists - name: Install dependencies
- name: Delete html directory run: |
sudo apt-get update
sudo apt-get install -y doxygen graphviz
- name: Check if documentation build is needed
id: changes
run: |
# Check if this is the first commit or if docs-related files changed
if git show --name-only HEAD | grep -E '\.(h|cc|cpp|md)$|Doxyfile'; then
echo "docs_changed=true" >> $GITHUB_OUTPUT
echo "📝 Documentation-related files have changed"
else
echo "docs_changed=false" >> $GITHUB_OUTPUT
echo " No documentation changes detected"
fi
- name: Clean previous build
if: steps.changes.outputs.docs_changed == 'true'
run: rm -rf html run: rm -rf html
# Installs graphviz for DOT graphs - name: Generate Doxygen documentation
- name: Install graphviz if: steps.changes.outputs.docs_changed == 'true'
run: sudo apt-get install graphviz uses: mattnotmitt/doxygen-action@v1.9.8
- name: Doxygen Action
uses: mattnotmitt/doxygen-action@v1.1.0
with: with:
# Path to Doxyfile doxyfile-path: "./Doxyfile"
doxyfile-path: "./Doxyfile" # default is ./Doxyfile working-directory: "."
# Working directory
working-directory: "." # default is .
- name: Deploy - name: Deploy to GitHub Pages
if: steps.changes.outputs.docs_changed == 'true'
uses: peaceiris/actions-gh-pages@v3 uses: peaceiris/actions-gh-pages@v3
with: with:
github_token: ${{ secrets.GITHUB_TOKEN }} github_token: ${{ secrets.GITHUB_TOKEN }}
# Default Doxyfile build documentation to html directory.
# Change the directory if changes in Doxyfile
publish_dir: ./html publish_dir: ./html
commit_message: 'docs: update API documentation'
- name: Summary
run: |
if [[ "${{ steps.changes.outputs.docs_changed }}" == "true" ]]; then
echo "✅ Documentation generated and deployed successfully"
echo "📖 View at: https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}"
else
echo "⏭️ Documentation build skipped - no relevant changes detected"
fi

712
.github/workflows/release-complex.yml vendored Normal file
View File

@@ -0,0 +1,712 @@
name: Release-Complex
on:
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
- 'v[0-9]+.[0-9]+.[0-9]+-*'
workflow_dispatch:
inputs:
tag:
description: 'Release tag (must start with v and follow semantic versioning)'
required: true
default: 'v0.3.0'
type: string
env:
BUILD_TYPE: Release
jobs:
validate-and-prepare:
name: Validate Release
runs-on: ubuntu-latest
outputs:
tag_name: ${{ steps.validate.outputs.tag_name }}
release_notes: ${{ steps.notes.outputs.content }}
steps:
- name: Validate tag format
id: validate
run: |
# Debug information
echo "Event name: ${{ github.event_name }}"
echo "Ref: ${{ github.ref }}"
echo "Ref name: ${{ github.ref_name }}"
echo "Ref type: ${{ github.ref_type }}"
# Determine the tag based on trigger type
if [[ "${{ github.event_name }}" == "push" ]]; then
if [[ "${{ github.ref_type }}" != "tag" ]]; then
echo "❌ Error: Release workflow triggered by push to ${{ github.ref_type }} '${{ github.ref_name }}'"
echo "This workflow should only be triggered by pushing version tags (v1.2.3)"
echo "Use: git tag v0.3.0 && git push origin v0.3.0"
exit 1
fi
TAG="${{ github.ref_name }}"
elif [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
TAG="${{ github.event.inputs.tag }}"
if [[ -z "$TAG" ]]; then
echo "❌ Error: No tag specified for manual workflow dispatch"
exit 1
fi
else
echo "❌ Error: Unsupported event type: ${{ github.event_name }}"
exit 1
fi
echo "Validating tag: $TAG"
# Check if tag follows semantic versioning pattern
if [[ ! "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-.*)?$ ]]; then
echo "❌ Error: Tag '$TAG' does not follow semantic versioning format (v1.2.3 or v1.2.3-beta)"
echo "Valid examples: v0.3.0, v1.0.0, v2.1.3-beta, v1.0.0-rc1"
echo ""
echo "To create a proper release:"
echo "1. Use the helper script: ./scripts/create_release.sh 0.3.0"
echo "2. Or manually: git tag v0.3.0 && git push origin v0.3.0"
exit 1
fi
echo "✅ Tag format is valid: $TAG"
echo "VALIDATED_TAG=$TAG" >> $GITHUB_ENV
echo "tag_name=$TAG" >> $GITHUB_OUTPUT
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Generate release notes
id: release_notes
run: |
# Extract release version from validated tag
VERSION="${VALIDATED_TAG}"
VERSION_NUM=$(echo "$VERSION" | sed 's/^v//')
# Generate release notes using the dedicated script
echo "Extracting changelog for version: $VERSION_NUM"
if python3 scripts/extract_changelog.py "$VERSION_NUM" > release_notes.md; then
echo "Changelog extracted successfully"
echo "Release notes content:"
cat release_notes.md
else
echo "Failed to extract changelog, creating default release notes"
echo "# Yaze $VERSION Release Notes\n\nPlease see the full changelog at docs/C1-changelog.md" > release_notes.md
fi
- name: Store release notes
id: notes
run: |
# Store release notes content for later use
echo "content<<EOF" >> $GITHUB_OUTPUT
cat release_notes.md >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
build-release:
name: Build Release
needs: validate-and-prepare
strategy:
matrix:
include:
- name: "Windows x64"
os: windows-2022
vcpkg_triplet: x64-windows
cmake_generator: "Visual Studio 17 2022"
cmake_generator_platform: x64
artifact_name: "yaze-windows-x64"
artifact_path: "build/bin/Release/"
package_cmd: |
mkdir -p package
cp -r build/bin/Release/* package/ 2>/dev/null || echo "No Release binaries found, trying Debug..."
cp -r build/bin/Debug/* package/ 2>/dev/null || echo "No Debug binaries found"
cp -r assets package/ 2>/dev/null || echo "assets directory not found"
cp LICENSE package/ 2>/dev/null || echo "LICENSE not found"
cp README.md package/ 2>/dev/null || echo "README.md not found"
cd package && zip -r ../yaze-windows-x64.zip *
- name: "Windows ARM64"
os: windows-2022
vcpkg_triplet: arm64-windows
cmake_generator: "Visual Studio 17 2022"
cmake_generator_platform: ARM64
artifact_name: "yaze-windows-arm64"
artifact_path: "build/bin/Release/"
package_cmd: |
mkdir -p package
cp -r build/bin/Release/* package/ 2>/dev/null || echo "No Release binaries found, trying Debug..."
cp -r build/bin/Debug/* package/ 2>/dev/null || echo "No Debug binaries found"
cp -r assets package/ 2>/dev/null || echo "assets directory not found"
cp LICENSE package/ 2>/dev/null || echo "LICENSE not found"
cp README.md package/ 2>/dev/null || echo "README.md not found"
cd package && zip -r ../yaze-windows-arm64.zip *
- name: "macOS Universal"
os: macos-14
vcpkg_triplet: arm64-osx
artifact_name: "yaze-macos"
artifact_path: "build/bin/"
package_cmd: |
# Debug: List what was actually built
echo "Contents of build/bin/:"
ls -la build/bin/ || echo "build/bin/ does not exist"
# Check if we have a bundle or standalone executable
if [ -d "build/bin/yaze.app" ]; then
echo "Found macOS bundle, using it directly"
# Use the existing bundle and just update it
cp -r build/bin/yaze.app ./Yaze.app
# Add additional resources to the bundle
cp -r assets "Yaze.app/Contents/Resources/" 2>/dev/null || echo "assets directory not found"
# Update Info.plist with correct version
if [ -f "cmake/yaze.plist.in" ]; then
VERSION_NUM=$(echo "${{ needs.validate-and-prepare.outputs.tag_name }}" | sed 's/^v//')
sed "s/@yaze_VERSION@/$VERSION_NUM/g" cmake/yaze.plist.in > "Yaze.app/Contents/Info.plist"
fi
else
echo "No bundle found, creating manual bundle"
# Create bundle structure manually
mkdir -p "Yaze.app/Contents/MacOS"
mkdir -p "Yaze.app/Contents/Resources"
cp build/bin/yaze "Yaze.app/Contents/MacOS/"
cp -r assets "Yaze.app/Contents/Resources/" 2>/dev/null || echo "assets directory not found"
# Create Info.plist with correct version
if [ -f "cmake/yaze.plist.in" ]; then
VERSION_NUM=$(echo "${{ needs.validate-and-prepare.outputs.tag_name }}" | sed 's/^v//')
sed "s/@yaze_VERSION@/$VERSION_NUM/g" cmake/yaze.plist.in > "Yaze.app/Contents/Info.plist"
else
# Create a basic Info.plist
VERSION_NUM=$(echo "${{ needs.validate-and-prepare.outputs.tag_name }}" | sed 's/^v//')
echo '<?xml version="1.0" encoding="UTF-8"?>' > "Yaze.app/Contents/Info.plist"
echo '<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">' >> "Yaze.app/Contents/Info.plist"
echo '<plist version="1.0">' >> "Yaze.app/Contents/Info.plist"
echo '<dict>' >> "Yaze.app/Contents/Info.plist"
echo '<key>CFBundleExecutable</key>' >> "Yaze.app/Contents/Info.plist"
echo '<string>yaze</string>' >> "Yaze.app/Contents/Info.plist"
echo '<key>CFBundleIdentifier</key>' >> "Yaze.app/Contents/Info.plist"
echo '<string>com.yaze.editor</string>' >> "Yaze.app/Contents/Info.plist"
echo '<key>CFBundleName</key>' >> "Yaze.app/Contents/Info.plist"
echo '<string>Yaze</string>' >> "Yaze.app/Contents/Info.plist"
echo '<key>CFBundleVersion</key>' >> "Yaze.app/Contents/Info.plist"
echo "<string>$VERSION_NUM</string>" >> "Yaze.app/Contents/Info.plist"
echo '<key>CFBundleShortVersionString</key>' >> "Yaze.app/Contents/Info.plist"
echo "<string>$VERSION_NUM</string>" >> "Yaze.app/Contents/Info.plist"
echo '<key>CFBundlePackageType</key>' >> "Yaze.app/Contents/Info.plist"
echo '<string>APPL</string>' >> "Yaze.app/Contents/Info.plist"
echo '</dict>' >> "Yaze.app/Contents/Info.plist"
echo '</plist>' >> "Yaze.app/Contents/Info.plist"
fi
fi
# Create DMG
mkdir dmg_staging
cp -r Yaze.app dmg_staging/
cp LICENSE dmg_staging/ 2>/dev/null || echo "LICENSE not found"
cp README.md dmg_staging/ 2>/dev/null || echo "README.md not found"
cp -r docs dmg_staging/ 2>/dev/null || echo "docs directory not found"
hdiutil create -srcfolder dmg_staging -format UDZO -volname "Yaze ${{ needs.validate-and-prepare.outputs.tag_name }}" yaze-macos.dmg
- name: "Linux x64"
os: ubuntu-22.04
artifact_name: "yaze-linux-x64"
artifact_path: "build/bin/"
package_cmd: |
mkdir package
cp build/bin/yaze package/
cp -r assets package/ 2>/dev/null || echo "assets directory not found"
cp -r docs package/ 2>/dev/null || echo "docs directory not found"
cp LICENSE package/ 2>/dev/null || echo "LICENSE not found"
cp README.md package/ 2>/dev/null || echo "README.md not found"
tar -czf yaze-linux-x64.tar.gz -C package .
runs-on: ${{ matrix.os }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive
# Clean up any potential vcpkg issues (Windows only)
- name: Clean vcpkg state (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
Write-Host "Cleaning up any existing vcpkg state..."
if (Test-Path "vcpkg") {
Remove-Item -Recurse -Force "vcpkg" -ErrorAction SilentlyContinue
}
if (Test-Path "vcpkg_installed") {
Remove-Item -Recurse -Force "vcpkg_installed" -ErrorAction SilentlyContinue
}
Write-Host "Cleanup completed"
# Platform-specific dependency installation
- name: Install Linux dependencies
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y \
build-essential \
ninja-build \
pkg-config \
libglew-dev \
libxext-dev \
libwavpack-dev \
libabsl-dev \
libboost-all-dev \
libpng-dev \
python3-dev \
libpython3-dev \
libasound2-dev \
libpulse-dev \
libx11-dev \
libxrandr-dev \
libxcursor-dev \
libxinerama-dev \
libxi-dev
- name: Install macOS dependencies
if: runner.os == 'macOS'
run: |
# Install Homebrew dependencies needed for UI tests and full builds
brew install pkg-config libpng boost abseil ninja gtk+3
- name: Setup build environment
run: |
echo "Using streamlined release build configuration for all platforms"
echo "Linux/macOS: UI tests enabled with full dependency support"
echo "Windows: Full build with vcpkg integration for proper releases"
echo "All platforms: Emulator and developer tools disabled for clean releases"
# Configure CMake
- name: Configure CMake (Linux/macOS)
if: runner.os != 'Windows'
run: |
cmake -B build \
-DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \
-DCMAKE_POLICY_VERSION_MINIMUM=3.16 \
-DYAZE_BUILD_TESTS=OFF \
-DYAZE_BUILD_EMU=OFF \
-DYAZE_BUILD_Z3ED=OFF \
-DYAZE_ENABLE_UI_TESTS=ON \
-DYAZE_ENABLE_ROM_TESTS=OFF \
-DYAZE_ENABLE_EXPERIMENTAL_TESTS=OFF \
-DYAZE_INSTALL_LIB=OFF \
-DYAZE_MINIMAL_BUILD=OFF \
-GNinja
# Set up vcpkg for Windows builds with fallback
- name: Set up vcpkg (Windows)
id: vcpkg_setup
if: runner.os == 'Windows'
uses: lukka/run-vcpkg@v11
continue-on-error: true
with:
vcpkgGitCommitId: 'c8696863d371ab7f46e213d8f5ca923c4aef2a00'
runVcpkgInstall: true
vcpkgJsonGlob: '**/vcpkg.json'
vcpkgDirectory: '${{ github.workspace }}/vcpkg'
env:
VCPKG_FORCE_SYSTEM_BINARIES: 1
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"
VCPKG_DISABLE_METRICS: 1
VCPKG_DEFAULT_TRIPLET: ${{ matrix.vcpkg_triplet }}
VCPKG_ROOT: ${{ github.workspace }}/vcpkg
# Debug vcpkg failure (Windows only)
- name: Debug vcpkg failure (Windows)
if: runner.os == 'Windows' && steps.vcpkg_setup.outcome == 'failure'
shell: pwsh
run: |
Write-Host "=== vcpkg Setup Failed - Debug Information ===" -ForegroundColor Red
Write-Host "vcpkg directory exists: $(Test-Path 'vcpkg')"
Write-Host "vcpkg_installed directory exists: $(Test-Path 'vcpkg_installed')"
if (Test-Path "vcpkg") {
Write-Host "vcpkg directory contents:"
Get-ChildItem "vcpkg" | Select-Object -First 10
}
Write-Host "Git status:"
git status --porcelain
Write-Host "=============================================" -ForegroundColor Red
# Fallback: Install dependencies manually if vcpkg fails
- name: Install dependencies manually (Windows fallback)
if: runner.os == 'Windows' && steps.vcpkg_setup.outcome == 'failure'
shell: pwsh
run: |
Write-Host "vcpkg setup failed, installing dependencies manually..."
# Install Chocolatey if not present
if (-not (Get-Command choco -ErrorAction SilentlyContinue)) {
Write-Host "Installing Chocolatey..."
Set-ExecutionPolicy Bypass -Scope Process -Force
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072
iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
}
# Install basic build tools and dependencies
Write-Host "Installing build tools and dependencies..."
try {
choco install -y cmake ninja git python3
Write-Host "Successfully installed build tools via Chocolatey"
} catch {
Write-Host "Chocolatey installation failed, trying individual packages..."
choco install -y cmake || Write-Host "CMake installation failed"
choco install -y ninja || Write-Host "Ninja installation failed"
choco install -y git || Write-Host "Git installation failed"
choco install -y python3 || Write-Host "Python3 installation failed"
}
# Set up basic development environment
Write-Host "Setting up basic development environment..."
$env:Path += ";C:\Program Files\Git\bin"
# Verify installations
Write-Host "Verifying installations..."
cmake --version
ninja --version
git --version
# Set environment variable to indicate minimal build
echo "YAZE_MINIMAL_BUILD=ON" >> $env:GITHUB_ENV
echo "VCPKG_AVAILABLE=false" >> $env:GITHUB_ENV
Write-Host "Manual dependency installation completed"
Write-Host "Build will proceed with minimal configuration (no vcpkg dependencies)"
# Set vcpkg availability flag when vcpkg succeeds
- name: Set vcpkg availability flag
if: runner.os == 'Windows' && steps.vcpkg_setup.outcome == 'success'
shell: pwsh
run: |
echo "VCPKG_AVAILABLE=true" >> $env:GITHUB_ENV
Write-Host "vcpkg setup successful"
- name: Configure CMake (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
Write-Host "Configuring CMake for Windows build..."
# Check if vcpkg is available
if ((Test-Path "${{ github.workspace }}/vcpkg/scripts/buildsystems/vcpkg.cmake") -and ($env:VCPKG_AVAILABLE -ne "false")) {
Write-Host "Using vcpkg toolchain..."
cmake -B build `
-DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} `
-DCMAKE_POLICY_VERSION_MINIMUM=3.16 `
-DCMAKE_TOOLCHAIN_FILE="${{ github.workspace }}/vcpkg/scripts/buildsystems/vcpkg.cmake" `
-DYAZE_BUILD_TESTS=OFF `
-DYAZE_BUILD_EMU=OFF `
-DYAZE_BUILD_Z3ED=OFF `
-DYAZE_ENABLE_ROM_TESTS=OFF `
-DYAZE_ENABLE_EXPERIMENTAL_TESTS=OFF `
-DYAZE_INSTALL_LIB=OFF `
-DYAZE_MINIMAL_BUILD=OFF `
-G "${{ matrix.cmake_generator }}" `
-A ${{ matrix.cmake_generator_platform }}
} else {
Write-Host "Using minimal build configuration (vcpkg not available)..."
cmake -B build `
-DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} `
-DCMAKE_POLICY_VERSION_MINIMUM=3.16 `
-DYAZE_BUILD_TESTS=OFF `
-DYAZE_BUILD_EMU=OFF `
-DYAZE_BUILD_Z3ED=OFF `
-DYAZE_ENABLE_ROM_TESTS=OFF `
-DYAZE_ENABLE_EXPERIMENTAL_TESTS=OFF `
-DYAZE_INSTALL_LIB=OFF `
-DYAZE_MINIMAL_BUILD=ON `
-G "${{ matrix.cmake_generator }}" `
-A ${{ matrix.cmake_generator_platform }}
}
Write-Host "CMake configuration completed successfully"
# Verify CMake configuration (Windows only)
- name: Verify CMake configuration (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
Write-Host "Verifying CMake configuration..."
if (Test-Path "build/CMakeCache.txt") {
Write-Host "✓ CMakeCache.txt found"
Write-Host "Build type: $(Select-String -Path 'build/CMakeCache.txt' -Pattern 'CMAKE_BUILD_TYPE' | ForEach-Object { $_.Line.Split('=')[1] })"
Write-Host "Minimal build: $(Select-String -Path 'build/CMakeCache.txt' -Pattern 'YAZE_MINIMAL_BUILD' | ForEach-Object { $_.Line.Split('=')[1] })"
} else {
Write-Error "CMakeCache.txt not found - CMake configuration failed!"
exit 1
}
# Build
- name: Build
run: |
echo "Building YAZE for ${{ matrix.name }}..."
cmake --build build --config ${{ env.BUILD_TYPE }} --parallel
echo "Build completed successfully!"
# Validate Visual Studio project builds (Windows only)
# Generate yaze_config.h for Visual Studio builds
- name: Generate yaze_config.h
if: runner.os == 'Windows'
shell: pwsh
run: |
$version = "${{ needs.validate-and-prepare.outputs.tag_name }}" -replace '^v', ''
$versionParts = $version -split '\.'
$major = if ($versionParts.Length -gt 0) { $versionParts[0] } else { "0" }
$minor = if ($versionParts.Length -gt 1) { $versionParts[1] } else { "0" }
$patch = if ($versionParts.Length -gt 2) { $versionParts[2] -split '-' | Select-Object -First 1 } else { "0" }
Write-Host "Generating yaze_config.h with version: $major.$minor.$patch"
Copy-Item "src\yaze_config.h.in" "yaze_config.h"
(Get-Content 'yaze_config.h') -replace '@yaze_VERSION_MAJOR@', $major -replace '@yaze_VERSION_MINOR@', $minor -replace '@yaze_VERSION_PATCH@', $patch | Set-Content 'yaze_config.h'
Write-Host "Generated yaze_config.h:"
Get-Content 'yaze_config.h'
- name: Validate Visual Studio Project Build
if: runner.os == 'Windows'
shell: pwsh
run: |
$ErrorActionPreference = "Stop"
Write-Host "========================================" -ForegroundColor Cyan
Write-Host "Validating Visual Studio Project Build" -ForegroundColor Cyan
Write-Host "Platform: ${{ matrix.cmake_generator_platform }}" -ForegroundColor Yellow
Write-Host "Configuration: ${{ env.BUILD_TYPE }}" -ForegroundColor Yellow
Write-Host "========================================" -ForegroundColor Cyan
# Check if we're in the right directory
if (-not (Test-Path "yaze.sln")) {
Write-Error "yaze.sln not found. Please run this script from the project root directory."
exit 1
}
Write-Host "✓ yaze.sln found" -ForegroundColor Green
# Build using MSBuild
Write-Host "Building with MSBuild..." -ForegroundColor Yellow
$msbuildArgs = @(
"yaze.sln"
"/p:Configuration=${{ env.BUILD_TYPE }}"
"/p:Platform=${{ matrix.cmake_generator_platform }}"
"/p:VcpkgEnabled=true"
"/p:VcpkgManifestInstall=true"
"/m" # Multi-processor build
"/verbosity:minimal"
)
Write-Host "MSBuild command: msbuild $($msbuildArgs -join ' ')" -ForegroundColor Gray
& msbuild @msbuildArgs
if ($LASTEXITCODE -ne 0) {
Write-Error "MSBuild failed with exit code $LASTEXITCODE"
exit 1
}
Write-Host "✓ Visual Studio build completed successfully" -ForegroundColor Green
# Verify executable was created
$exePath = "build\bin\${{ env.BUILD_TYPE }}\yaze.exe"
if (-not (Test-Path $exePath)) {
Write-Error "Executable not found at expected path: $exePath"
exit 1
}
Write-Host "✓ Executable created: $exePath" -ForegroundColor Green
# Test that the executable runs (basic test)
Write-Host "Testing executable startup..." -ForegroundColor Yellow
$testResult = & $exePath --help 2>&1
$exitCode = $LASTEXITCODE
# Check if it's the test main or app main
if ($testResult -match "Google Test" -or $testResult -match "gtest") {
Write-Error "Executable is running test main instead of app main!"
Write-Host "Output: $testResult" -ForegroundColor Red
exit 1
}
Write-Host "✓ Executable runs correctly (exit code: $exitCode)" -ForegroundColor Green
Write-Host "========================================" -ForegroundColor Cyan
Write-Host "✓ Visual Studio build validation PASSED" -ForegroundColor Green
Write-Host "========================================" -ForegroundColor Cyan
# Test executable functionality (Windows)
- name: Test executable functionality (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
$ErrorActionPreference = "Stop"
# Debug: List build directory contents
Write-Host "Build directory contents:" -ForegroundColor Cyan
if (Test-Path "build") {
Get-ChildItem -Recurse build -Name | Select-Object -First 20
} else {
Write-Host "build directory does not exist" -ForegroundColor Red
}
# Determine executable path for Windows
$exePath = "build\bin\${{ env.BUILD_TYPE }}\yaze.exe"
if (Test-Path $exePath) {
Write-Host "✓ Executable found: $exePath" -ForegroundColor Green
# Test that it's not the test main
$testResult = & $exePath --help 2>&1
$exitCode = $LASTEXITCODE
if ($testResult -match "Google Test" -or $testResult -match "gtest") {
Write-Error "Executable is running test main instead of app main!"
Write-Host "Output: $testResult" -ForegroundColor Red
exit 1
}
Write-Host "✓ Executable runs correctly (exit code: $exitCode)" -ForegroundColor Green
# Display file info
$exeInfo = Get-Item $exePath
Write-Host "Executable size: $([math]::Round($exeInfo.Length / 1MB, 2)) MB" -ForegroundColor Cyan
} else {
Write-Error "Executable not found at: $exePath"
exit 1
}
# Test executable functionality (macOS)
- name: Test executable functionality (macOS)
if: runner.os == 'macOS'
shell: bash
run: |
set -e
echo "Build directory contents:"
if [ -d "build" ]; then
find build -name "*.app" -o -name "yaze" | head -10
else
echo "build directory does not exist"
exit 1
fi
# Determine executable path for macOS
exePath="build/bin/yaze.app/Contents/MacOS/yaze"
if [ -f "$exePath" ]; then
echo "✓ Executable found: $exePath"
# Test that it's not the test main
testResult=$($exePath --help 2>&1 || true)
exitCode=$?
if echo "$testResult" | grep -q "Google Test\|gtest"; then
echo "ERROR: Executable is running test main instead of app main!"
echo "Output: $testResult"
exit 1
fi
echo "✓ Executable runs correctly (exit code: $exitCode)"
# Display file info
fileSize=$(stat -f%z "$exePath")
fileSizeMB=$(echo "scale=2; $fileSize / 1024 / 1024" | bc -l)
echo "Executable size: ${fileSizeMB} MB"
else
echo "ERROR: Executable not found at: $exePath"
exit 1
fi
# Test executable functionality (Linux)
- name: Test executable functionality (Linux)
if: runner.os == 'Linux'
shell: bash
run: |
set -e
echo "Build directory contents:"
if [ -d "build" ]; then
find build -type f -name "yaze" | head -10
else
echo "build directory does not exist"
exit 1
fi
# Determine executable path for Linux
exePath="build/bin/yaze"
if [ -f "$exePath" ]; then
echo "✓ Executable found: $exePath"
# Test that it's not the test main
testResult=$($exePath --help 2>&1 || true)
exitCode=$?
if echo "$testResult" | grep -q "Google Test\|gtest"; then
echo "ERROR: Executable is running test main instead of app main!"
echo "Output: $testResult"
exit 1
fi
echo "✓ Executable runs correctly (exit code: $exitCode)"
# Display file info
fileSize=$(stat -c%s "$exePath")
fileSizeMB=$(echo "scale=2; $fileSize / 1024 / 1024" | bc -l)
echo "Executable size: ${fileSizeMB} MB"
else
echo "ERROR: Executable not found at: $exePath"
exit 1
fi
# Verify build artifacts
- name: Verify build artifacts
shell: bash
run: |
echo "Verifying build artifacts for ${{ matrix.name }}..."
if [ -d "build/bin" ]; then
echo "Build directory contents:"
find build/bin -type f -name "yaze*" -o -name "*.exe" -o -name "*.app" | head -10
else
echo "ERROR: build/bin directory not found!"
exit 1
fi
# Package
- name: Package
shell: bash
run: |
set -e
echo "Packaging for ${{ matrix.name }}..."
${{ matrix.package_cmd }}
echo "Packaging completed successfully!"
# Create release with artifacts (will create release if it doesn't exist)
- name: Upload to Release
uses: softprops/action-gh-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ needs.validate-and-prepare.outputs.tag_name }}
name: Yaze ${{ needs.validate-and-prepare.outputs.tag_name }}
body: ${{ needs.validate-and-prepare.outputs.release_notes }}
draft: false
prerelease: ${{ contains(needs.validate-and-prepare.outputs.tag_name, 'beta') || contains(needs.validate-and-prepare.outputs.tag_name, 'alpha') || contains(needs.validate-and-prepare.outputs.tag_name, 'rc') }}
files: |
${{ matrix.artifact_name }}.*
fail_on_unmatched_files: false
publish-packages:
name: Publish Packages
needs: [validate-and-prepare, build-release]
runs-on: ubuntu-latest
if: success()
steps:
- name: Update release status
run: |
echo "Release has been published successfully"
echo "All build artifacts have been uploaded"
- name: Announce release
run: |
echo "🎉 Yaze ${{ needs.validate-and-prepare.outputs.tag_name }} has been released!"
echo "📦 Packages are now available for download"
echo "🔗 Release URL: https://github.com/${{ github.repository }}/releases/tag/${{ needs.validate-and-prepare.outputs.tag_name }}"

414
.github/workflows/release-simplified.yml vendored Normal file
View File

@@ -0,0 +1,414 @@
name: Release-Simplified
on:
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
- 'v[0-9]+.[0-9]+.[0-9]+-*'
workflow_dispatch:
inputs:
tag:
description: 'Release tag (must start with v and follow semantic versioning)'
required: true
default: 'v0.3.0'
type: string
env:
BUILD_TYPE: Release
jobs:
validate-and-prepare:
name: Validate Release
runs-on: ubuntu-latest
outputs:
tag_name: ${{ steps.validate.outputs.tag_name }}
release_notes: ${{ steps.notes.outputs.content }}
steps:
- name: Validate tag format
id: validate
run: |
# Determine the tag based on trigger type
if [[ "${{ github.event_name }}" == "push" ]]; then
if [[ "${{ github.ref_type }}" != "tag" ]]; then
echo "❌ Error: Release workflow triggered by push to ${{ github.ref_type }} '${{ github.ref_name }}'"
echo "This workflow should only be triggered by pushing version tags (v1.2.3)"
echo "Use: git tag v0.3.0 && git push origin v0.3.0"
exit 1
fi
TAG="${{ github.ref_name }}"
elif [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
TAG="${{ github.event.inputs.tag }}"
if [[ -z "$TAG" ]]; then
echo "❌ Error: No tag specified for manual workflow dispatch"
exit 1
fi
else
echo "❌ Error: Unsupported event type: ${{ github.event_name }}"
exit 1
fi
echo "Validating tag: $TAG"
# Check if tag follows semantic versioning pattern
if [[ ! "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-.*)?$ ]]; then
echo "❌ Error: Tag '$TAG' does not follow semantic versioning format (v1.2.3 or v1.2.3-beta)"
echo "Valid examples: v0.3.0, v1.0.0, v2.1.3-beta, v1.0.0-rc1"
echo ""
echo "To create a proper release:"
echo "1. Use the helper script: ./scripts/create_release.sh 0.3.0"
echo "2. Or manually: git tag v0.3.0 && git push origin v0.3.0"
exit 1
fi
echo "✅ Tag format is valid: $TAG"
echo "VALIDATED_TAG=$TAG" >> $GITHUB_ENV
echo "tag_name=$TAG" >> $GITHUB_OUTPUT
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Generate release notes
id: release_notes
run: |
# Extract release version from validated tag
VERSION="${VALIDATED_TAG}"
VERSION_NUM=$(echo "$VERSION" | sed 's/^v//')
# Generate release notes using the dedicated script
echo "Extracting changelog for version: $VERSION_NUM"
if python3 scripts/extract_changelog.py "$VERSION_NUM" > release_notes.md; then
echo "Changelog extracted successfully"
echo "Release notes content:"
cat release_notes.md
else
echo "Failed to extract changelog, creating default release notes"
echo "# Yaze $VERSION Release Notes\n\nPlease see the full changelog at docs/C1-changelog.md" > release_notes.md
fi
- name: Store release notes
id: notes
run: |
# Store release notes content for later use
echo "content<<EOF" >> $GITHUB_OUTPUT
cat release_notes.md >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
build-release:
name: Build Release
needs: validate-and-prepare
strategy:
matrix:
include:
- name: "Windows x64"
os: windows-2022
vcpkg_triplet: x64-windows
cmake_generator: "Visual Studio 17 2022"
cmake_generator_platform: x64
artifact_name: "yaze-windows-x64"
- name: "Windows ARM64"
os: windows-2022
vcpkg_triplet: arm64-windows
cmake_generator: "Visual Studio 17 2022"
cmake_generator_platform: ARM64
artifact_name: "yaze-windows-arm64"
- name: "macOS Universal"
os: macos-14
vcpkg_triplet: arm64-osx
artifact_name: "yaze-macos"
- name: "Linux x64"
os: ubuntu-22.04
artifact_name: "yaze-linux-x64"
runs-on: ${{ matrix.os }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive
# Platform-specific dependency installation
- name: Install Linux dependencies
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y \
build-essential \
ninja-build \
pkg-config \
libglew-dev \
libxext-dev \
libwavpack-dev \
libabsl-dev \
libboost-all-dev \
libpng-dev \
python3-dev \
libpython3-dev \
libasound2-dev \
libpulse-dev \
libx11-dev \
libxrandr-dev \
libxcursor-dev \
libxinerama-dev \
libxi-dev
- name: Install macOS dependencies
if: runner.os == 'macOS'
run: |
# Install Homebrew dependencies needed for UI tests and full builds
brew install pkg-config libpng boost abseil ninja gtk+3
# Set up vcpkg for Windows builds with fallback
- name: Set up vcpkg (Windows)
id: vcpkg_setup
if: runner.os == 'Windows'
uses: lukka/run-vcpkg@v11
continue-on-error: true
with:
vcpkgGitCommitId: 'c8696863d371ab7f46e213d8f5ca923c4aef2a00'
runVcpkgInstall: true
vcpkgJsonGlob: '**/vcpkg.json'
vcpkgDirectory: '${{ github.workspace }}/vcpkg'
env:
VCPKG_FORCE_SYSTEM_BINARIES: 1
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"
VCPKG_DISABLE_METRICS: 1
VCPKG_DEFAULT_TRIPLET: ${{ matrix.vcpkg_triplet }}
VCPKG_ROOT: ${{ github.workspace }}/vcpkg
# Set vcpkg availability flag when vcpkg succeeds
- name: Set vcpkg availability flag
if: runner.os == 'Windows' && steps.vcpkg_setup.outcome == 'success'
shell: pwsh
run: |
echo "VCPKG_AVAILABLE=true" >> $env:GITHUB_ENV
Write-Host "vcpkg setup successful"
# Fallback: Set minimal build flag when vcpkg fails
- name: Set minimal build flag (Windows fallback)
if: runner.os == 'Windows' && steps.vcpkg_setup.outcome == 'failure'
shell: pwsh
run: |
echo "VCPKG_AVAILABLE=false" >> $env:GITHUB_ENV
echo "YAZE_MINIMAL_BUILD=ON" >> $env:GITHUB_ENV
Write-Host "vcpkg setup failed, using minimal build configuration"
# Configure CMake
- name: Configure CMake (Linux/macOS)
if: runner.os != 'Windows'
run: |
cmake -B build \
-DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \
-DCMAKE_POLICY_VERSION_MINIMUM=3.16 \
-DYAZE_BUILD_TESTS=OFF \
-DYAZE_BUILD_EMU=OFF \
-DYAZE_BUILD_Z3ED=OFF \
-DYAZE_ENABLE_UI_TESTS=ON \
-DYAZE_ENABLE_ROM_TESTS=OFF \
-DYAZE_ENABLE_EXPERIMENTAL_TESTS=OFF \
-DYAZE_INSTALL_LIB=OFF \
-DYAZE_MINIMAL_BUILD=OFF \
-GNinja
- name: Configure CMake (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
Write-Host "Configuring CMake for Windows build..."
# Check if vcpkg is available
if ((Test-Path "${{ github.workspace }}/vcpkg/scripts/buildsystems/vcpkg.cmake") -and ($env:VCPKG_AVAILABLE -ne "false")) {
Write-Host "Using vcpkg toolchain..."
cmake -B build `
-DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} `
-DCMAKE_POLICY_VERSION_MINIMUM=3.16 `
-DCMAKE_TOOLCHAIN_FILE="${{ github.workspace }}/vcpkg/scripts/buildsystems/vcpkg.cmake" `
-DYAZE_BUILD_TESTS=OFF `
-DYAZE_BUILD_EMU=OFF `
-DYAZE_BUILD_Z3ED=OFF `
-DYAZE_ENABLE_ROM_TESTS=OFF `
-DYAZE_ENABLE_EXPERIMENTAL_TESTS=OFF `
-DYAZE_INSTALL_LIB=OFF `
-DYAZE_MINIMAL_BUILD=OFF `
-G "${{ matrix.cmake_generator }}" `
-A ${{ matrix.cmake_generator_platform }}
} else {
Write-Host "Using minimal build configuration (vcpkg not available)..."
cmake -B build `
-DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} `
-DCMAKE_POLICY_VERSION_MINIMUM=3.16 `
-DYAZE_BUILD_TESTS=OFF `
-DYAZE_BUILD_EMU=OFF `
-DYAZE_BUILD_Z3ED=OFF `
-DYAZE_ENABLE_ROM_TESTS=OFF `
-DYAZE_ENABLE_EXPERIMENTAL_TESTS=OFF `
-DYAZE_INSTALL_LIB=OFF `
-DYAZE_MINIMAL_BUILD=ON `
-G "${{ matrix.cmake_generator }}" `
-A ${{ matrix.cmake_generator_platform }}
}
Write-Host "CMake configuration completed successfully"
# Build
- name: Build
run: |
echo "Building YAZE for ${{ matrix.name }}..."
cmake --build build --config ${{ env.BUILD_TYPE }} --parallel
echo "Build completed successfully!"
# Test executable functionality
- name: Test executable functionality
shell: bash
run: |
set -e
echo "Testing executable for ${{ matrix.name }}..."
# Determine executable path based on platform
if [[ "${{ runner.os }}" == "Windows" ]]; then
exePath="build/bin/${{ env.BUILD_TYPE }}/yaze.exe"
elif [[ "${{ runner.os }}" == "macOS" ]]; then
exePath="build/bin/yaze.app/Contents/MacOS/yaze"
else
exePath="build/bin/yaze"
fi
if [ -f "$exePath" ]; then
echo "✓ Executable found: $exePath"
# Test that it's not the test main
testResult=$($exePath --help 2>&1 || true)
exitCode=$?
if echo "$testResult" | grep -q "Google Test\|gtest"; then
echo "ERROR: Executable is running test main instead of app main!"
echo "Output: $testResult"
exit 1
fi
echo "✓ Executable runs correctly (exit code: $exitCode)"
# Display file info
if [[ "${{ runner.os }}" == "Windows" ]]; then
fileSize=$(stat -c%s "$exePath" 2>/dev/null || echo "0")
else
fileSize=$(stat -f%z "$exePath" 2>/dev/null || stat -c%s "$exePath" 2>/dev/null || echo "0")
fi
fileSizeMB=$(echo "scale=2; $fileSize / 1024 / 1024" | bc -l 2>/dev/null || echo "0")
echo "Executable size: ${fileSizeMB} MB"
else
echo "ERROR: Executable not found at: $exePath"
exit 1
fi
# Package
- name: Package
shell: bash
run: |
set -e
echo "Packaging for ${{ matrix.name }}..."
if [[ "${{ runner.os }}" == "Windows" ]]; then
# Windows packaging
mkdir -p package
cp -r build/bin/${{ env.BUILD_TYPE }}/* package/ 2>/dev/null || echo "No Release binaries found, trying Debug..."
cp -r build/bin/Debug/* package/ 2>/dev/null || echo "No Debug binaries found"
cp -r assets package/ 2>/dev/null || echo "assets directory not found"
cp LICENSE package/ 2>/dev/null || echo "LICENSE not found"
cp README.md package/ 2>/dev/null || echo "README.md not found"
cd package && zip -r ../${{ matrix.artifact_name }}.zip *
elif [[ "${{ runner.os }}" == "macOS" ]]; then
# macOS packaging
if [ -d "build/bin/yaze.app" ]; then
echo "Found macOS bundle, using it directly"
cp -r build/bin/yaze.app ./Yaze.app
# Add additional resources to the bundle
cp -r assets "Yaze.app/Contents/Resources/" 2>/dev/null || echo "assets directory not found"
# Update Info.plist with correct version
if [ -f "cmake/yaze.plist.in" ]; then
VERSION_NUM=$(echo "${{ needs.validate-and-prepare.outputs.tag_name }}" | sed 's/^v//')
sed "s/@yaze_VERSION@/$VERSION_NUM/g" cmake/yaze.plist.in > "Yaze.app/Contents/Info.plist"
fi
else
echo "No bundle found, creating manual bundle"
mkdir -p "Yaze.app/Contents/MacOS"
mkdir -p "Yaze.app/Contents/Resources"
cp build/bin/yaze "Yaze.app/Contents/MacOS/"
cp -r assets "Yaze.app/Contents/Resources/" 2>/dev/null || echo "assets directory not found"
# Create Info.plist with correct version
VERSION_NUM=$(echo "${{ needs.validate-and-prepare.outputs.tag_name }}" | sed 's/^v//')
echo '<?xml version="1.0" encoding="UTF-8"?>' > "Yaze.app/Contents/Info.plist"
echo '<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">' >> "Yaze.app/Contents/Info.plist"
echo '<plist version="1.0">' >> "Yaze.app/Contents/Info.plist"
echo '<dict>' >> "Yaze.app/Contents/Info.plist"
echo '<key>CFBundleExecutable</key>' >> "Yaze.app/Contents/Info.plist"
echo '<string>yaze</string>' >> "Yaze.app/Contents/Info.plist"
echo '<key>CFBundleIdentifier</key>' >> "Yaze.app/Contents/Info.plist"
echo '<string>com.yaze.editor</string>' >> "Yaze.app/Contents/Info.plist"
echo '<key>CFBundleName</key>' >> "Yaze.app/Contents/Info.plist"
echo '<string>Yaze</string>' >> "Yaze.app/Contents/Info.plist"
echo '<key>CFBundleVersion</key>' >> "Yaze.app/Contents/Info.plist"
echo "<string>$VERSION_NUM</string>" >> "Yaze.app/Contents/Info.plist"
echo '<key>CFBundleShortVersionString</key>' >> "Yaze.app/Contents/Info.plist"
echo "<string>$VERSION_NUM</string>" >> "Yaze.app/Contents/Info.plist"
echo '<key>CFBundlePackageType</key>' >> "Yaze.app/Contents/Info.plist"
echo '<string>APPL</string>' >> "Yaze.app/Contents/Info.plist"
echo '</dict>' >> "Yaze.app/Contents/Info.plist"
echo '</plist>' >> "Yaze.app/Contents/Info.plist"
fi
# Create DMG
mkdir dmg_staging
cp -r Yaze.app dmg_staging/
cp LICENSE dmg_staging/ 2>/dev/null || echo "LICENSE not found"
cp README.md dmg_staging/ 2>/dev/null || echo "README.md not found"
cp -r docs dmg_staging/ 2>/dev/null || echo "docs directory not found"
hdiutil create -srcfolder dmg_staging -format UDZO -volname "Yaze ${{ needs.validate-and-prepare.outputs.tag_name }}" ${{ matrix.artifact_name }}.dmg
else
# Linux packaging
mkdir package
cp build/bin/yaze package/
cp -r assets package/ 2>/dev/null || echo "assets directory not found"
cp -r docs package/ 2>/dev/null || echo "docs directory not found"
cp LICENSE package/ 2>/dev/null || echo "LICENSE not found"
cp README.md package/ 2>/dev/null || echo "README.md not found"
tar -czf ${{ matrix.artifact_name }}.tar.gz -C package .
fi
echo "Packaging completed successfully!"
# Create release with artifacts
- name: Upload to Release
uses: softprops/action-gh-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ needs.validate-and-prepare.outputs.tag_name }}
name: Yaze ${{ needs.validate-and-prepare.outputs.tag_name }}
body: ${{ needs.validate-and-prepare.outputs.release_notes }}
draft: false
prerelease: ${{ contains(needs.validate-and-prepare.outputs.tag_name, 'beta') || contains(needs.validate-and-prepare.outputs.tag_name, 'alpha') || contains(needs.validate-and-prepare.outputs.tag_name, 'rc') }}
files: |
${{ matrix.artifact_name }}.*
publish-packages:
name: Publish Packages
needs: [validate-and-prepare, build-release]
runs-on: ubuntu-latest
if: success()
steps:
- name: Announce release
run: |
echo "🎉 Yaze ${{ needs.validate-and-prepare.outputs.tag_name }} has been released!"
echo "📦 Packages are now available for download"
echo "🔗 Release URL: https://github.com/${{ github.repository }}/releases/tag/${{ needs.validate-and-prepare.outputs.tag_name }}"

369
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,369 @@
name: Release
on:
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
- 'v[0-9]+.[0-9]+.[0-9]+-*'
workflow_dispatch:
inputs:
tag:
description: 'Release tag (must start with v and follow semantic versioning)'
required: true
default: 'v0.3.0'
type: string
env:
BUILD_TYPE: Release
jobs:
validate-and-prepare:
name: Validate Release
runs-on: ubuntu-latest
outputs:
tag_name: ${{ steps.validate.outputs.tag_name }}
release_notes: ${{ steps.notes.outputs.content }}
steps:
- name: Validate tag format
id: validate
run: |
# Determine the tag based on trigger type
if [[ "${{ github.event_name }}" == "push" ]]; then
if [[ "${{ github.ref_type }}" != "tag" ]]; then
echo "❌ Error: Release workflow triggered by push to ${{ github.ref_type }} '${{ github.ref_name }}'"
echo "This workflow should only be triggered by pushing version tags (v1.2.3)"
echo "Use: git tag v0.3.0 && git push origin v0.3.0"
exit 1
fi
TAG="${{ github.ref_name }}"
elif [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
TAG="${{ github.event.inputs.tag }}"
if [[ -z "$TAG" ]]; then
echo "❌ Error: No tag specified for manual workflow dispatch"
exit 1
fi
else
echo "❌ Error: Unsupported event type: ${{ github.event_name }}"
exit 1
fi
echo "Validating tag: $TAG"
# Check if tag follows semantic versioning pattern
if [[ ! "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-.*)?$ ]]; then
echo "❌ Error: Tag '$TAG' does not follow semantic versioning format (v1.2.3 or v1.2.3-beta)"
echo "Valid examples: v0.3.0, v1.0.0, v2.1.3-beta, v1.0.0-rc1"
echo ""
echo "To create a proper release:"
echo "1. Use the helper script: ./scripts/create_release.sh 0.3.0"
echo "2. Or manually: git tag v0.3.0 && git push origin v0.3.0"
exit 1
fi
echo "✅ Tag format is valid: $TAG"
echo "VALIDATED_TAG=$TAG" >> $GITHUB_ENV
echo "tag_name=$TAG" >> $GITHUB_OUTPUT
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Generate release notes
id: release_notes
run: |
# Extract release version from validated tag
VERSION="${VALIDATED_TAG}"
VERSION_NUM=$(echo "$VERSION" | sed 's/^v//')
# Generate release notes using the dedicated script
echo "Extracting changelog for version: $VERSION_NUM"
if python3 scripts/extract_changelog.py "$VERSION_NUM" > release_notes.md; then
echo "Changelog extracted successfully"
echo "Release notes content:"
cat release_notes.md
else
echo "Failed to extract changelog, creating default release notes"
echo "# Yaze $VERSION Release Notes\n\nPlease see the full changelog at docs/C1-changelog.md" > release_notes.md
fi
- name: Store release notes
id: notes
run: |
# Store release notes content for later use
echo "content<<EOF" >> $GITHUB_OUTPUT
cat release_notes.md >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
build-release:
name: Build Release
needs: validate-and-prepare
strategy:
matrix:
include:
- name: "Windows x64"
os: windows-2022
vcpkg_triplet: x64-windows
cmake_generator: "Visual Studio 17 2022"
cmake_generator_platform: x64
artifact_name: "yaze-windows-x64"
- name: "Windows ARM64"
os: windows-2022
vcpkg_triplet: arm64-windows
cmake_generator: "Visual Studio 17 2022"
cmake_generator_platform: ARM64
artifact_name: "yaze-windows-arm64"
- name: "macOS Universal"
os: macos-14
vcpkg_triplet: arm64-osx
artifact_name: "yaze-macos"
- name: "Linux x64"
os: ubuntu-22.04
artifact_name: "yaze-linux-x64"
runs-on: ${{ matrix.os }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive
# Platform-specific dependency installation
- name: Install Linux dependencies
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y \
build-essential \
ninja-build \
pkg-config \
libglew-dev \
libxext-dev \
libwavpack-dev \
libabsl-dev \
libboost-all-dev \
libpng-dev \
python3-dev \
libpython3-dev \
libasound2-dev \
libpulse-dev \
libx11-dev \
libxrandr-dev \
libxcursor-dev \
libxinerama-dev \
libxi-dev
- name: Install macOS dependencies
if: runner.os == 'macOS'
run: |
# Install Homebrew dependencies needed for UI tests and full builds
brew install pkg-config libpng boost abseil ninja gtk+3
# Set up vcpkg for Windows builds with fallback
- name: Set up vcpkg (Windows)
id: vcpkg_setup
if: runner.os == 'Windows'
uses: lukka/run-vcpkg@v11
continue-on-error: true
with:
vcpkgGitCommitId: 'c8696863d371ab7f46e213d8f5ca923c4aef2a00'
runVcpkgInstall: true
vcpkgJsonGlob: '**/vcpkg.json'
vcpkgDirectory: '${{ github.workspace }}/vcpkg'
env:
VCPKG_FORCE_SYSTEM_BINARIES: 1
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"
VCPKG_DISABLE_METRICS: 1
VCPKG_DEFAULT_TRIPLET: ${{ matrix.vcpkg_triplet }}
VCPKG_ROOT: ${{ github.workspace }}/vcpkg
# Set vcpkg availability flag when vcpkg succeeds
- name: Set vcpkg availability flag
if: runner.os == 'Windows' && steps.vcpkg_setup.outcome == 'success'
shell: pwsh
run: |
echo "VCPKG_AVAILABLE=true" >> $env:GITHUB_ENV
Write-Host "vcpkg setup successful"
# Fallback: Set minimal build flag when vcpkg fails
- name: Set minimal build flag (Windows fallback)
if: runner.os == 'Windows' && steps.vcpkg_setup.outcome == 'failure'
shell: pwsh
run: |
echo "VCPKG_AVAILABLE=false" >> $env:GITHUB_ENV
echo "YAZE_MINIMAL_BUILD=ON" >> $env:GITHUB_ENV
Write-Host "vcpkg setup failed, using minimal build configuration"
# Configure CMake
- name: Configure CMake (Linux/macOS)
if: runner.os != 'Windows'
run: |
cmake -B build \
-DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \
-DCMAKE_POLICY_VERSION_MINIMUM=3.16 \
-DYAZE_BUILD_TESTS=OFF \
-DYAZE_BUILD_EMU=OFF \
-DYAZE_BUILD_Z3ED=OFF \
-DYAZE_ENABLE_UI_TESTS=ON \
-DYAZE_ENABLE_ROM_TESTS=OFF \
-DYAZE_ENABLE_EXPERIMENTAL_TESTS=OFF \
-DYAZE_INSTALL_LIB=OFF \
-DYAZE_MINIMAL_BUILD=OFF \
-GNinja
- name: Configure CMake (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
Write-Host "Configuring CMake for Windows build..."
# Check if vcpkg is available
if ((Test-Path "${{ github.workspace }}/vcpkg/scripts/buildsystems/vcpkg.cmake") -and ($env:VCPKG_AVAILABLE -ne "false")) {
Write-Host "Using vcpkg toolchain..."
cmake -B build `
-DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} `
-DCMAKE_POLICY_VERSION_MINIMUM=3.16 `
-DCMAKE_TOOLCHAIN_FILE="${{ github.workspace }}/vcpkg/scripts/buildsystems/vcpkg.cmake" `
-DYAZE_BUILD_TESTS=OFF `
-DYAZE_BUILD_EMU=OFF `
-DYAZE_ENABLE_ROM_TESTS=OFF `
-DYAZE_ENABLE_EXPERIMENTAL_TESTS=OFF `
-DYAZE_INSTALL_LIB=OFF `
-DYAZE_MINIMAL_BUILD=OFF `
-G "${{ matrix.cmake_generator }}" `
-A ${{ matrix.cmake_generator_platform }}
} else {
Write-Host "Using minimal build configuration (vcpkg not available)..."
cmake -B build `
-DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} `
-DCMAKE_POLICY_VERSION_MINIMUM=3.16 `
-DYAZE_BUILD_TESTS=OFF `
-DYAZE_BUILD_EMU=OFF `
-DYAZE_ENABLE_ROM_TESTS=OFF `
-DYAZE_ENABLE_EXPERIMENTAL_TESTS=OFF `
-DYAZE_INSTALL_LIB=OFF `
-DYAZE_MINIMAL_BUILD=ON `
-G "${{ matrix.cmake_generator }}" `
-A ${{ matrix.cmake_generator_platform }}
}
Write-Host "CMake configuration completed successfully"
# Build
- name: Build
run: |
echo "Building YAZE for ${{ matrix.name }}..."
cmake --build build --config ${{ env.BUILD_TYPE }} --parallel
echo "Build completed successfully!"
# Test executable functionality
- name: Test executable functionality
shell: bash
run: |
set -e
echo "Testing executable for ${{ matrix.name }}..."
# Determine executable path based on platform
if [[ "${{ runner.os }}" == "Windows" ]]; then
exePath="build/bin/${{ env.BUILD_TYPE }}/yaze.exe"
elif [[ "${{ runner.os }}" == "macOS" ]]; then
exePath="build/bin/yaze.app/Contents/MacOS/yaze"
else
exePath="build/bin/yaze"
fi
if [ -f "$exePath" ]; then
echo "✓ Executable found: $exePath"
# Test that it's not the test main
testResult=$($exePath --help 2>&1 || true)
exitCode=$?
if echo "$testResult" | grep -q "Google Test\|gtest"; then
echo "ERROR: Executable is running test main instead of app main!"
echo "Output: $testResult"
exit 1
fi
echo "✓ Executable runs correctly (exit code: $exitCode)"
# Display file info
if [[ "${{ runner.os }}" == "Windows" ]]; then
fileSize=$(stat -c%s "$exePath" 2>/dev/null || echo "0")
else
fileSize=$(stat -f%z "$exePath" 2>/dev/null || stat -c%s "$exePath" 2>/dev/null || echo "0")
fi
fileSizeMB=$(echo "scale=2; $fileSize / 1024 / 1024" | bc -l 2>/dev/null || echo "0")
echo "Executable size: ${fileSizeMB} MB"
else
echo "ERROR: Executable not found at: $exePath"
exit 1
fi
# Package
- name: Package
shell: bash
run: |
set -e
echo "Packaging for ${{ matrix.name }}..."
if [[ "${{ runner.os }}" == "Windows" ]]; then
# Windows packaging
mkdir -p package
cp -r build/bin/${{ env.BUILD_TYPE }}/* package/ 2>/dev/null || echo "No Release binaries found, trying Debug..."
cp -r build/bin/Debug/* package/ 2>/dev/null || echo "No Debug binaries found"
cp -r assets package/ 2>/dev/null || echo "assets directory not found"
cp LICENSE package/ 2>/dev/null || echo "LICENSE not found"
cp README.md package/ 2>/dev/null || echo "README.md not found"
cd package && zip -r ../${{ matrix.artifact_name }}.zip *
elif [[ "${{ runner.os }}" == "macOS" ]]; then
# macOS packaging using dedicated script
VERSION_NUM=$(echo "${{ needs.validate-and-prepare.outputs.tag_name }}" | sed 's/^v//')
./scripts/create-macos-bundle.sh "$VERSION_NUM" "${{ matrix.artifact_name }}"
else
# Linux packaging
mkdir package
cp build/bin/yaze package/
cp -r assets package/ 2>/dev/null || echo "assets directory not found"
cp -r docs package/ 2>/dev/null || echo "docs directory not found"
cp LICENSE package/ 2>/dev/null || echo "LICENSE not found"
cp README.md package/ 2>/dev/null || echo "README.md not found"
tar -czf ${{ matrix.artifact_name }}.tar.gz -C package .
fi
echo "Packaging completed successfully!"
# Create release with artifacts
- name: Upload to Release
uses: softprops/action-gh-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ needs.validate-and-prepare.outputs.tag_name }}
name: Yaze ${{ needs.validate-and-prepare.outputs.tag_name }}
body: ${{ needs.validate-and-prepare.outputs.release_notes }}
draft: false
prerelease: ${{ contains(needs.validate-and-prepare.outputs.tag_name, 'beta') || contains(needs.validate-and-prepare.outputs.tag_name, 'alpha') || contains(needs.validate-and-prepare.outputs.tag_name, 'rc') }}
files: |
${{ matrix.artifact_name }}.*
publish-packages:
name: Publish Packages
needs: [validate-and-prepare, build-release]
runs-on: ubuntu-latest
if: success()
steps:
- name: Announce release
run: |
echo "🎉 Yaze ${{ needs.validate-and-prepare.outputs.tag_name }} has been released!"
echo "📦 Packages are now available for download"
echo "🔗 Release URL: https://github.com/${{ github.repository }}/releases/tag/${{ needs.validate-and-prepare.outputs.tag_name }}"

157
.github/workflows/validate-vs-build.yml vendored Normal file
View File

@@ -0,0 +1,157 @@
name: Validate Visual Studio Builds
on:
push:
branches: [ "master", "develop" ]
paths:
- 'vcpkg.json'
- 'src/**'
- 'scripts/generate-vs-projects.py'
- 'scripts/validate-vs-build.ps1'
- '.github/workflows/validate-vs-build.yml'
pull_request:
branches: [ "master", "develop" ]
paths:
- 'vcpkg.json'
- 'src/**'
- 'scripts/generate-vs-projects.py'
- 'scripts/validate-vs-build.ps1'
- '.github/workflows/validate-vs-build.yml'
env:
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"
jobs:
validate-vs-builds:
strategy:
fail-fast: false
matrix:
include:
- name: "Windows x64 Debug"
platform: x64
configuration: Debug
- name: "Windows x64 Release"
platform: x64
configuration: Release
name: ${{ matrix.name }}
runs-on: windows-2022
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive
- name: Set up vcpkg
uses: lukka/run-vcpkg@v11
with:
vcpkgGitCommitId: 'c8696863d371ab7f46e213d8f5ca923c4aef2a00'
runVcpkgInstall: true
vcpkgJsonGlob: '**/vcpkg.json'
vcpkgDirectory: '${{ github.workspace }}/vcpkg'
env:
VCPKG_FORCE_SYSTEM_BINARIES: 1
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"
- name: Validate Visual Studio Build
shell: pwsh
run: |
$ErrorActionPreference = "Stop"
Write-Host "========================================" -ForegroundColor Cyan
Write-Host "YAZE Visual Studio Build Validation" -ForegroundColor Cyan
Write-Host "Platform: ${{ matrix.platform }}" -ForegroundColor Yellow
Write-Host "Configuration: ${{ matrix.configuration }}" -ForegroundColor Yellow
Write-Host "========================================" -ForegroundColor Cyan
# Check if we're in the right directory
if (-not (Test-Path "yaze.sln")) {
Write-Error "yaze.sln not found. Please run this script from the project root directory."
exit 1
}
Write-Host "✓ yaze.sln found" -ForegroundColor Green
# Ensure build directory exists
if (-not (Test-Path "build")) {
New-Item -ItemType Directory -Path "build" | Out-Null
}
# Build using MSBuild
Write-Host "Building with MSBuild..." -ForegroundColor Yellow
$msbuildArgs = @(
"yaze.sln"
"/p:Configuration=${{ matrix.configuration }}"
"/p:Platform=${{ matrix.platform }}"
"/p:VcpkgEnabled=true"
"/p:VcpkgManifestInstall=true"
"/m" # Multi-processor build
"/verbosity:minimal"
)
Write-Host "MSBuild command: msbuild $($msbuildArgs -join ' ')" -ForegroundColor Gray
& msbuild @msbuildArgs
if ($LASTEXITCODE -ne 0) {
Write-Error "MSBuild failed with exit code $LASTEXITCODE"
exit 1
}
Write-Host "✓ Build completed successfully" -ForegroundColor Green
# Verify executable was created
$exePath = "build\bin\${{ matrix.configuration }}\yaze.exe"
if (-not (Test-Path $exePath)) {
Write-Error "Executable not found at expected path: $exePath"
exit 1
}
Write-Host "✓ Executable created: $exePath" -ForegroundColor Green
# Verify assets were copied
$assetsPath = "build\bin\${{ matrix.configuration }}\assets"
if (-not (Test-Path $assetsPath)) {
Write-Error "Assets directory not found at expected path: $assetsPath"
exit 1
}
Write-Host "✓ Assets copied to: $assetsPath" -ForegroundColor Green
# Test that the executable runs (basic test)
Write-Host "Testing executable startup..." -ForegroundColor Yellow
$testResult = & $exePath --help 2>&1
$exitCode = $LASTEXITCODE
# Check if it's the test main or app main
if ($testResult -match "Google Test" -or $testResult -match "gtest") {
Write-Error "Executable is running test main instead of app main!"
Write-Host "Output: $testResult" -ForegroundColor Red
exit 1
}
Write-Host "✓ Executable runs correctly (exit code: $exitCode)" -ForegroundColor Green
# Display file info
$exeInfo = Get-Item $exePath
Write-Host ""
Write-Host "Build Summary:" -ForegroundColor Cyan
Write-Host " Executable: $($exeInfo.FullName)" -ForegroundColor White
Write-Host " Size: $([math]::Round($exeInfo.Length / 1MB, 2)) MB" -ForegroundColor White
Write-Host " Created: $($exeInfo.CreationTime)" -ForegroundColor White
Write-Host ""
Write-Host "========================================" -ForegroundColor Cyan
Write-Host "✓ Visual Studio build validation PASSED" -ForegroundColor Green
Write-Host "========================================" -ForegroundColor Cyan
- name: Upload build artifacts
uses: actions/upload-artifact@v4
if: always()
with:
name: yaze-${{ matrix.platform }}-${{ matrix.configuration }}
path: |
build/bin/${{ matrix.configuration }}/
retention-days: 7

28
.gitignore vendored
View File

@@ -1,19 +1,21 @@
.favorites.json
build/ build/
.cache/ .cache/
.vscode/ .vscode/
src/lib/SDL2 disasm/
src/lib/cmake src/etc
src/lib/GL src/lib/
src/lib/abseil-cpp
src/lib/libGLEW.2.2.0.dylib
src/lib/libGLEW.2.2.dylib
src/lib/libGLEW.a
src/lib/libGLEW.dylib
src/lib/libSDL2_test.a
src/lib/libSDL2-2.0.0.dylib
src/lib/libSDL2.a
src/lib/libSDL2.dylib
src/lib/libSDL2main.a
checks.json checks.json
assets/lib/libasar.dll assets/lib/libasar.dll
cmake/yaze.plist.in cmake/yaze.plist.in
etc/
latex/
html/
docs/zarby_algos.md
docs/overworld-expansion.md
assets/asm/EditorCore.asm
src/app/emu/cpu/internal/old_cpu.cc
build-windows
src/lib/libpng
src/lib/zlib
assets/layouts/ow_toolset.zeml

12
.gitmodules vendored
View File

@@ -1,12 +1,6 @@
[submodule "src/lib/imgui"] [submodule "src/lib/imgui"]
path = src/lib/imgui path = src/lib/imgui
url = https://github.com/ocornut/imgui.git url = https://github.com/ocornut/imgui.git
[submodule "src/lib/ImGuiFileDialog"]
path = src/lib/ImGuiFileDialog
url = https://github.com/aiekick/ImGuiFileDialog.git
[submodule "src/lib/ImGuiColorTextEdit"]
path = src/lib/ImGuiColorTextEdit
url = https://github.com/BalazsJako/ImGuiColorTextEdit.git
[submodule "assets/asm/alttp-hacker-workspace"] [submodule "assets/asm/alttp-hacker-workspace"]
path = assets/asm/alttp-hacker-workspace path = assets/asm/alttp-hacker-workspace
url = https://github.com/scawful/alttp-hacker-workspace.git url = https://github.com/scawful/alttp-hacker-workspace.git
@@ -22,3 +16,9 @@
[submodule "src/lib/imgui_test_engine"] [submodule "src/lib/imgui_test_engine"]
path = src/lib/imgui_test_engine path = src/lib/imgui_test_engine
url = https://github.com/ocornut/imgui_test_engine.git url = https://github.com/ocornut/imgui_test_engine.git
[submodule "src/lib/nativefiledialog-extended"]
path = src/lib/nativefiledialog-extended
url = https://github.com/btzy/nativefiledialog-extended.git
[submodule "assets/asm/usdasm"]
path = assets/asm/usdasm
url = https://github.com/spannerisms/usdasm.git

View File

@@ -1,34 +1,222 @@
# CMake Specifications
cmake_minimum_required(VERSION 3.10)
# Yet Another Zelda3 Editor # Yet Another Zelda3 Editor
# by scawful # by scawful
project(yaze VERSION 0.10) cmake_minimum_required(VERSION 3.16)
# C++ Standard Specifications # Set policy version to handle compatibility issues
set(CMAKE_CXX_STANDARD 20) if(POLICY CMP0091)
cmake_policy(SET CMP0091 NEW)
endif()
# Set additional policies to handle submodule compatibility
if(POLICY CMP0048)
cmake_policy(SET CMP0048 NEW)
endif()
if(POLICY CMP0077)
cmake_policy(SET CMP0077 NEW)
endif()
if(POLICY CMP0091)
cmake_policy(SET CMP0091 NEW)
endif()
# Suppress deprecation warnings from submodules
set(CMAKE_WARN_DEPRECATED OFF CACHE BOOL "Suppress deprecation warnings")
# Handle pthread issues on Windows
if(WIN32)
set(THREADS_PREFER_PTHREAD_FLAG OFF)
endif()
project(yaze VERSION 0.3.1
DESCRIPTION "Yet Another Zelda3 Editor"
LANGUAGES CXX C)
# Set project metadata
set(YAZE_VERSION_MAJOR 0)
set(YAZE_VERSION_MINOR 3)
set(YAZE_VERSION_PATCH 1)
configure_file(src/yaze_config.h.in yaze_config.h @ONLY)
# Build Flags
set(YAZE_BUILD_APP ON)
set(YAZE_BUILD_LIB ON)
set(YAZE_BUILD_EMU ON)
set(YAZE_BUILD_Z3ED ON)
set(YAZE_BUILD_TESTS ON)
set(YAZE_INSTALL_LIB OFF)
# Testing and CI Configuration
option(YAZE_ENABLE_ROM_TESTS "Enable tests that require ROM files" OFF)
option(YAZE_ENABLE_EXPERIMENTAL_TESTS "Enable experimental/unstable tests" ON)
option(YAZE_ENABLE_UI_TESTS "Enable ImGui Test Engine UI testing" ON)
option(YAZE_MINIMAL_BUILD "Minimal build for CI (disable optional features)" OFF)
# Configure minimal builds for CI/CD
if(YAZE_MINIMAL_BUILD)
set(YAZE_ENABLE_UI_TESTS OFF CACHE BOOL "Disabled for minimal build" FORCE)
set(YAZE_BUILD_Z3ED OFF CACHE BOOL "Disabled for minimal build" FORCE)
# Keep EMU and LIB enabled for comprehensive testing
set(YAZE_BUILD_EMU ON CACHE BOOL "Required for test suite" FORCE)
set(YAZE_BUILD_LIB ON CACHE BOOL "Required for test suite" FORCE)
set(YAZE_INSTALL_LIB OFF CACHE BOOL "Disabled for minimal build" FORCE)
endif()
set(YAZE_TEST_ROM_PATH "${CMAKE_BINARY_DIR}/bin/zelda3.sfc" CACHE STRING "Path to test ROM file")
# libpng features in bitmap.cc - conditional for minimal builds
if(PNG_FOUND)
add_definitions("-DYAZE_LIB_PNG=1")
else()
add_definitions("-DYAZE_LIB_PNG=0")
message(STATUS "Building without PNG support for minimal build")
endif()
# Modern CMake standards
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_C_STANDARD 99)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) set(CMAKE_C_STANDARD_REQUIRED ON)
# Output directories
include(GNUInstallDirs)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR})
set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
set(BUILD_SHARED_LIBS OFF) set(BUILD_SHARED_LIBS OFF)
set(CMAKE_FIND_FRAMEWORK LAST) set(CMAKE_FIND_FRAMEWORK LAST)
# Platform detection
if(CMAKE_SYSTEM_NAME MATCHES "Darwin")
set(YAZE_PLATFORM_MACOS ON)
elseif(CMAKE_SYSTEM_NAME MATCHES "Linux")
set(YAZE_PLATFORM_LINUX ON)
elseif(CMAKE_SYSTEM_NAME MATCHES "Windows")
set(YAZE_PLATFORM_WINDOWS ON)
# Enable vcpkg integration for Windows builds
if(DEFINED ENV{VCPKG_ROOT} AND NOT DEFINED CMAKE_TOOLCHAIN_FILE)
set(CMAKE_TOOLCHAIN_FILE "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
CACHE STRING "Vcpkg toolchain file")
elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/vcpkg/scripts/buildsystems/vcpkg.cmake" AND NOT DEFINED CMAKE_TOOLCHAIN_FILE)
set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_SOURCE_DIR}/vcpkg/scripts/buildsystems/vcpkg.cmake"
CACHE STRING "Vcpkg toolchain file")
endif()
endif()
# Create a common interface target for shared settings
add_library(yaze_common INTERFACE)
target_compile_features(yaze_common INTERFACE cxx_std_23)
# Platform-specific configurations
if(YAZE_PLATFORM_LINUX)
target_compile_definitions(yaze_common INTERFACE linux stricmp=strcasecmp)
elseif(YAZE_PLATFORM_MACOS)
set(CMAKE_INSTALL_PREFIX /usr/local)
target_compile_definitions(yaze_common INTERFACE MACOS)
elseif(YAZE_PLATFORM_WINDOWS)
include(cmake/vcpkg.cmake)
target_compile_definitions(yaze_common INTERFACE WINDOWS)
# Windows-specific architecture detection and configuration
if(CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64|aarch64")
target_compile_definitions(yaze_common INTERFACE YAZE_ARCH_ARM64)
message(STATUS "Building for Windows ARM64")
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "AMD64|x86_64")
target_compile_definitions(yaze_common INTERFACE YAZE_ARCH_X64)
message(STATUS "Building for Windows x64")
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "i386|i686|x86")
target_compile_definitions(yaze_common INTERFACE YAZE_ARCH_X86)
message(STATUS "Building for Windows x86")
else()
message(WARNING "Unknown Windows architecture: ${CMAKE_SYSTEM_PROCESSOR}")
endif()
endif()
# Compiler-specific settings
if(MSVC)
target_compile_options(yaze_common INTERFACE
/W4 /permissive-
/bigobj # Support large object files
/utf-8 # Use UTF-8 encoding
)
target_compile_definitions(yaze_common INTERFACE
_CRT_SECURE_NO_WARNINGS
_CRT_NONSTDC_NO_WARNINGS
SILENCE_CXX23_DEPRECATIONS
_SILENCE_CXX23_DEPRECATION_WARNING
_SILENCE_ALL_CXX23_DEPRECATION_WARNINGS
NOMINMAX # Disable min/max macros
WIN32_LEAN_AND_MEAN # Reduce Windows header bloat
strncasecmp=_strnicmp
strcasecmp=_stricmp
)
else()
target_compile_options(yaze_common INTERFACE
-Wall -Wextra -Wpedantic
-Wno-deprecated-declarations # Silence deprecation warnings
-Wno-c++23-compat # Silence C++23 compatibility warnings
)
# Add C++23 deprecation silencing for GCC/Clang
target_compile_definitions(yaze_common INTERFACE
_SILENCE_CXX23_DEPRECATION_WARNING
_SILENCE_ALL_CXX23_DEPRECATION_WARNINGS
ABSL_HAVE_INTRINSIC_INT128=1 # Enable intrinsic int128 support
)
endif()
# Abseil Standard Specifications # Abseil Standard Specifications
include(cmake/absl.cmake) include(cmake/absl.cmake)
# Video Libraries # SDL2 and PNG
find_package(PNG REQUIRED)
include(cmake/sdl2.cmake) include(cmake/sdl2.cmake)
# Asar # Asar
add_subdirectory(src/lib/asar/src)
include(cmake/asar.cmake) include(cmake/asar.cmake)
# ImGui # Google Test (if needed for main app integration)
if (YAZE_BUILD_TESTS)
include(cmake/gtest.cmake)
endif()
# ImGui (after minimal build flags are set)
include(cmake/imgui.cmake) include(cmake/imgui.cmake)
# Project Files # Project Files
# Copy theme files to build directory (for development)
file(GLOB THEME_FILES "${CMAKE_SOURCE_DIR}/assets/themes/*.theme")
file(COPY ${THEME_FILES} DESTINATION "${CMAKE_BINARY_DIR}/assets/themes/")
# IMPORTANT: Also ensure themes are included in macOS bundles
# This is handled in src/CMakeLists.txt via YAZE_RESOURCE_FILES
add_subdirectory(src) add_subdirectory(src)
# Tests
if (YAZE_BUILD_TESTS)
add_subdirectory(test)
endif()
# Code quality targets
find_program(CLANG_FORMAT NAMES clang-format clang-format-14 clang-format-15 clang-format-16 clang-format-17 clang-format-18)
if(CLANG_FORMAT)
file(GLOB_RECURSE ALL_SOURCE_FILES
"${CMAKE_SOURCE_DIR}/src/*.cc"
"${CMAKE_SOURCE_DIR}/src/*.h"
"${CMAKE_SOURCE_DIR}/test/*.cc"
"${CMAKE_SOURCE_DIR}/test/*.h")
add_custom_target(format
COMMAND ${CLANG_FORMAT} -i --style=Google ${ALL_SOURCE_FILES}
COMMENT "Running clang-format on source files"
)
add_custom_target(format-check
COMMAND ${CLANG_FORMAT} --dry-run --Werror --style=Google ${ALL_SOURCE_FILES}
COMMENT "Checking code format"
)
endif()
# Packaging configuration
include(cmake/packaging.cmake)

470
CMakePresets.json Normal file
View File

@@ -0,0 +1,470 @@
{
"version": 6,
"cmakeMinimumRequired": {
"major": 3,
"minor": 16,
"patch": 0
},
"configurePresets": [
{
"name": "default",
"displayName": "Default Config",
"description": "Default build configuration",
"generator": "Unix Makefiles",
"binaryDir": "${sourceDir}/build",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "RelWithDebInfo",
"YAZE_BUILD_TESTS": "ON",
"YAZE_BUILD_APP": "ON",
"YAZE_BUILD_LIB": "ON",
"YAZE_BUILD_EMU": "ON",
"YAZE_BUILD_Z3ED": "ON"
}
},
{
"name": "debug",
"displayName": "Debug",
"description": "Debug build with full debugging symbols",
"inherits": "default",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_CXX_FLAGS_DEBUG": "-g -O0 -DDEBUG",
"CMAKE_C_FLAGS_DEBUG": "-g -O0 -DDEBUG",
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
}
},
{
"name": "release",
"displayName": "Release",
"description": "Optimized release build",
"inherits": "default",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"YAZE_BUILD_TESTS": "OFF"
}
},
{
"name": "dev",
"displayName": "Development",
"description": "Development build with ROM testing enabled",
"inherits": "debug",
"cacheVariables": {
"YAZE_ENABLE_ROM_TESTS": "ON",
"YAZE_TEST_ROM_PATH": "${sourceDir}/build/bin/zelda3.sfc"
}
},
{
"name": "macos-dev",
"displayName": "macOS Development (ARM64)",
"description": "macOS ARM64 development build with ROM testing",
"inherits": "macos-debug",
"cacheVariables": {
"YAZE_ENABLE_ROM_TESTS": "ON",
"YAZE_TEST_ROM_PATH": "${sourceDir}/build/bin/zelda3.sfc"
}
},
{
"name": "ci",
"displayName": "Continuous Integration",
"description": "CI build without ROM-dependent tests",
"inherits": "default",
"cacheVariables": {
"YAZE_ENABLE_ROM_TESTS": "OFF",
"YAZE_BUILD_TESTS": "ON"
}
},
{
"name": "macos-debug",
"displayName": "macOS Debug (ARM64)",
"description": "macOS ARM64-specific debug configuration",
"inherits": "debug",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Darwin"
},
"cacheVariables": {
"CMAKE_OSX_DEPLOYMENT_TARGET": "11.0",
"CMAKE_OSX_ARCHITECTURES": "arm64"
}
},
{
"name": "macos-release",
"displayName": "macOS Release (ARM64)",
"description": "macOS ARM64-specific release configuration",
"inherits": "release",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Darwin"
},
"cacheVariables": {
"CMAKE_OSX_DEPLOYMENT_TARGET": "11.0",
"CMAKE_OSX_ARCHITECTURES": "arm64"
}
},
{
"name": "macos-debug-universal",
"displayName": "macOS Debug (Universal)",
"description": "macOS universal binary debug configuration",
"inherits": "debug",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Darwin"
},
"cacheVariables": {
"CMAKE_OSX_DEPLOYMENT_TARGET": "10.15",
"CMAKE_OSX_ARCHITECTURES": "x86_64;arm64"
}
},
{
"name": "macos-release-universal",
"displayName": "macOS Release (Universal)",
"description": "macOS universal binary release configuration",
"inherits": "release",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Darwin"
},
"cacheVariables": {
"CMAKE_OSX_DEPLOYMENT_TARGET": "10.15",
"CMAKE_OSX_ARCHITECTURES": "x86_64;arm64"
}
},
{
"name": "linux-debug",
"displayName": "Linux Debug",
"description": "Linux-specific debug configuration",
"inherits": "debug",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Linux"
},
"cacheVariables": {
"CMAKE_CXX_COMPILER": "g++",
"CMAKE_C_COMPILER": "gcc"
}
},
{
"name": "linux-clang",
"displayName": "Linux Clang",
"description": "Linux build with Clang",
"inherits": "debug",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Linux"
},
"cacheVariables": {
"CMAKE_CXX_COMPILER": "clang++",
"CMAKE_C_COMPILER": "clang"
}
},
{
"name": "windows-debug",
"displayName": "Windows Debug",
"description": "Windows-specific debug configuration with vcpkg",
"inherits": "debug",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
},
"generator": "Visual Studio 17 2022",
"architecture": "x64",
"cacheVariables": {
"CMAKE_TOOLCHAIN_FILE": "${sourceDir}/vcpkg/scripts/buildsystems/vcpkg.cmake",
"VCPKG_TARGET_TRIPLET": "x64-windows",
"VCPKG_MANIFEST_MODE": "ON"
}
},
{
"name": "windows-release",
"displayName": "Windows Release",
"description": "Windows-specific release configuration with vcpkg",
"inherits": "release",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
},
"generator": "Visual Studio 17 2022",
"architecture": "x64",
"cacheVariables": {
"CMAKE_TOOLCHAIN_FILE": "${sourceDir}/vcpkg/scripts/buildsystems/vcpkg.cmake",
"VCPKG_TARGET_TRIPLET": "x64-windows",
"VCPKG_MANIFEST_MODE": "ON"
}
},
{
"name": "windows-dev",
"displayName": "Windows Development",
"description": "Windows development build with vcpkg and testing enabled",
"inherits": "debug",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
},
"generator": "Visual Studio 17 2022",
"architecture": "x64",
"cacheVariables": {
"CMAKE_TOOLCHAIN_FILE": "${sourceDir}/vcpkg/scripts/buildsystems/vcpkg.cmake",
"VCPKG_TARGET_TRIPLET": "x64-windows",
"VCPKG_MANIFEST_MODE": "ON",
"YAZE_BUILD_TESTS": "ON",
"YAZE_ENABLE_ROM_TESTS": "ON"
}
},
{
"name": "asan",
"displayName": "AddressSanitizer",
"description": "Debug build with AddressSanitizer",
"inherits": "debug",
"cacheVariables": {
"CMAKE_CXX_FLAGS": "-fsanitize=address -fno-omit-frame-pointer -g",
"CMAKE_C_FLAGS": "-fsanitize=address -fno-omit-frame-pointer -g",
"CMAKE_EXE_LINKER_FLAGS": "-fsanitize=address",
"CMAKE_SHARED_LINKER_FLAGS": "-fsanitize=address"
}
},
{
"name": "coverage",
"displayName": "Code Coverage",
"description": "Debug build with code coverage",
"inherits": "debug",
"cacheVariables": {
"CMAKE_CXX_FLAGS": "--coverage -g -O0",
"CMAKE_C_FLAGS": "--coverage -g -O0",
"CMAKE_EXE_LINKER_FLAGS": "--coverage"
}
}
],
"buildPresets": [
{
"name": "default",
"configurePreset": "default",
"displayName": "Default Build"
},
{
"name": "debug",
"configurePreset": "debug",
"displayName": "Debug Build"
},
{
"name": "release",
"configurePreset": "release",
"displayName": "Release Build"
},
{
"name": "dev",
"configurePreset": "dev",
"displayName": "Development Build"
},
{
"name": "macos-dev",
"configurePreset": "macos-dev",
"displayName": "macOS Development Build (ARM64)"
},
{
"name": "ci",
"configurePreset": "ci",
"displayName": "CI Build"
},
{
"name": "macos-debug",
"configurePreset": "macos-debug",
"displayName": "macOS Debug Build"
},
{
"name": "macos-release",
"configurePreset": "macos-release",
"displayName": "macOS Release Build (ARM64)"
},
{
"name": "macos-debug-universal",
"configurePreset": "macos-debug-universal",
"displayName": "macOS Debug Build (Universal)"
},
{
"name": "macos-release-universal",
"configurePreset": "macos-release-universal",
"displayName": "macOS Release Build (Universal)"
},
{
"name": "fast",
"configurePreset": "debug",
"displayName": "Fast Debug Build",
"jobs": 0
},
{
"name": "windows-debug",
"configurePreset": "windows-debug",
"displayName": "Windows Debug Build"
},
{
"name": "windows-release",
"configurePreset": "windows-release",
"displayName": "Windows Release Build"
},
{
"name": "windows-dev",
"configurePreset": "windows-dev",
"displayName": "Windows Development Build"
}
],
"testPresets": [
{
"name": "stable",
"configurePreset": "default",
"displayName": "Stable Tests (Release Ready)",
"execution": {
"noTestsAction": "error",
"stopOnFailure": true
},
"filter": {
"include": {
"label": "STABLE"
}
}
},
{
"name": "dev",
"configurePreset": "dev",
"displayName": "Development Tests (with ROM)",
"execution": {
"noTestsAction": "error",
"stopOnFailure": false
},
"filter": {
"exclude": {
"label": "EXPERIMENTAL"
}
}
},
{
"name": "ci",
"configurePreset": "ci",
"displayName": "CI Tests (stable only)",
"execution": {
"noTestsAction": "error",
"stopOnFailure": true
},
"filter": {
"include": {
"label": "STABLE"
}
}
},
{
"name": "experimental",
"configurePreset": "debug",
"displayName": "Experimental Tests",
"execution": {
"noTestsAction": "ignore",
"stopOnFailure": false
},
"filter": {
"include": {
"label": "EXPERIMENTAL"
}
}
},
{
"name": "asar-only",
"configurePreset": "default",
"displayName": "Asar Tests Only",
"filter": {
"include": {
"name": "*Asar*"
}
}
},
{
"name": "unit-only",
"configurePreset": "default",
"displayName": "Unit Tests Only",
"filter": {
"include": {
"label": "UNIT_TEST"
}
}
}
],
"packagePresets": [
{
"name": "default",
"configurePreset": "release",
"displayName": "Default Package"
},
{
"name": "macos",
"configurePreset": "macos-release",
"displayName": "macOS Package (ARM64)"
},
{
"name": "macos-universal",
"configurePreset": "macos-release-universal",
"displayName": "macOS Package (Universal)"
}
],
"workflowPresets": [
{
"name": "dev-workflow",
"displayName": "Development Workflow",
"steps": [
{
"type": "configure",
"name": "dev"
},
{
"type": "build",
"name": "dev"
},
{
"type": "test",
"name": "dev"
}
]
},
{
"name": "ci-workflow",
"displayName": "CI Workflow",
"steps": [
{
"type": "configure",
"name": "ci"
},
{
"type": "build",
"name": "ci"
},
{
"type": "test",
"name": "ci"
}
]
},
{
"name": "release-workflow",
"displayName": "Release Workflow",
"steps": [
{
"type": "configure",
"name": "macos-release"
},
{
"type": "build",
"name": "macos-release"
},
{
"type": "package",
"name": "macos"
}
]
}
]
}

View File

@@ -48,7 +48,7 @@ PROJECT_NAME = "yaze"
# could be handy for archiving the generated documentation or if some version # could be handy for archiving the generated documentation or if some version
# control system is used. # control system is used.
PROJECT_NUMBER = PROJECT_NUMBER = "0.3.1"
# Using the PROJECT_BRIEF tag one can provide an optional one line description # Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a # for a project that appears at the top of each page and should give viewer a
@@ -61,13 +61,13 @@ PROJECT_BRIEF = Link to the Past ROM Editor
# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy # pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
# the logo to the output directory. # the logo to the output directory.
PROJECT_LOGO = PROJECT_LOGO = "src/win32/yaze.ico"
# With the PROJECT_ICON tag one can specify an icon that is included in the tabs # With the PROJECT_ICON tag one can specify an icon that is included in the tabs
# when the HTML document is shown. Doxygen will copy the logo to the output # when the HTML document is shown. Doxygen will copy the logo to the output
# directory. # directory.
PROJECT_ICON = PROJECT_ICON = "src/win32/yaze.ico"
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
# into which the generated documentation will be written. If a relative path is # into which the generated documentation will be written. If a relative path is
@@ -1168,7 +1168,7 @@ FILTER_SOURCE_PATTERNS =
# (index.html). This can be useful if you have a project on for instance GitHub # (index.html). This can be useful if you have a project on for instance GitHub
# and want to reuse the introduction page also for the doxygen output. # and want to reuse the introduction page also for the doxygen output.
USE_MDFILE_AS_MAINPAGE = USE_MDFILE_AS_MAINPAGE = getting-started.md
# The Fortran standard specifies that for fixed formatted Fortran code all # The Fortran standard specifies that for fixed formatted Fortran code all
# characters from position 72 are to be considered as comment. A common # characters from position 72 are to be considered as comment. A common
@@ -1190,7 +1190,7 @@ FORTRAN_COMMENT_AFTER = 72
# also VERBATIM_HEADERS is set to NO. # also VERBATIM_HEADERS is set to NO.
# The default value is: NO. # The default value is: NO.
SOURCE_BROWSER = NO SOURCE_BROWSER = YES
# Setting the INLINE_SOURCES tag to YES will include the body of functions, # Setting the INLINE_SOURCES tag to YES will include the body of functions,
# multi-line macros, enums or list initialized variables directly into the # multi-line macros, enums or list initialized variables directly into the
@@ -1284,7 +1284,7 @@ ALPHABETICAL_INDEX = YES
# after removing the prefix. # after removing the prefix.
# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
IGNORE_PREFIX = IGNORE_PREFIX = googletest
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# Configuration options related to the HTML output # Configuration options related to the HTML output
@@ -1402,7 +1402,7 @@ HTML_COLORSTYLE = AUTO_LIGHT
# Minimum value: 0, maximum value: 359, default value: 220. # Minimum value: 0, maximum value: 359, default value: 220.
# This tag requires that the tag GENERATE_HTML is set to YES. # This tag requires that the tag GENERATE_HTML is set to YES.
HTML_COLORSTYLE_HUE = 220 HTML_COLORSTYLE_HUE = 280
# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
# in the HTML output. For a value of 0 the output will use gray-scales only. A # in the HTML output. For a value of 0 the output will use gray-scales only. A
@@ -2798,7 +2798,7 @@ PLANTUML_INCLUDE_PATH =
# Minimum value: 0, maximum value: 10000, default value: 50. # Minimum value: 0, maximum value: 10000, default value: 50.
# This tag requires that the tag HAVE_DOT is set to YES. # This tag requires that the tag HAVE_DOT is set to YES.
DOT_GRAPH_MAX_NODES = 50 DOT_GRAPH_MAX_NODES = 5
# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
# generated by dot. A depth value of 3 means that only nodes reachable from the # generated by dot. A depth value of 3 means that only nodes reachable from the
@@ -2810,7 +2810,7 @@ DOT_GRAPH_MAX_NODES = 50
# Minimum value: 0, maximum value: 1000, default value: 0. # Minimum value: 0, maximum value: 1000, default value: 0.
# This tag requires that the tag HAVE_DOT is set to YES. # This tag requires that the tag HAVE_DOT is set to YES.
MAX_DOT_GRAPH_DEPTH = 0 MAX_DOT_GRAPH_DEPTH = 2
# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output # Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
# files in one run (i.e. multiple -o and -T options on the command line). This # files in one run (i.e. multiple -o and -T options on the command line). This

View File

@@ -1,4 +1,4 @@
Copyright (C) 2022 Justin Scofield Copyright (C) 2024 Justin Scofield
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -13,3 +13,7 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
Dependencies:
- SDL2 <https://www.libsdl.org/license.php>
- ImGui <https://github.com/ocornut/imgui/blob/master/LICENSE.txt>
- Abseil <https://github.com/abseil/abseil-cpp/blob/master/LICENSE>

139
README.md
View File

@@ -1,53 +1,134 @@
# Yet Another Zelda3 Editor # YAZE - Yet Another Zelda3 Editor
- Platform: Windows, macOS, GNU/Linux A modern, cross-platform editor for The Legend of Zelda: A Link to the Past ROM hacking, built with C++23 and featuring complete Asar 65816 assembler integration.
- Dependencies: SDL2, ImGui
## Description [![Build Status](https://github.com/scawful/yaze/workflows/CI/badge.svg)](https://github.com/scawful/yaze/actions)
[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
General purpose editor for The Legend of Zelda: A Link to the Past for the Super Nintendo. ## Version 0.3.1 - Release
Takes heavy inspiration from ALTTP community efforts such as [Hyrule Magic](https://www.romhacking.net/utilities/200/) and [ZScream](https://github.com/Zarby89/ZScreamDungeon) #### Asar 65816 Assembler Integration
- **Cross-platform ROM patching** with assembly code support
- **Symbol extraction** with addresses and opcodes from assembly files
- **Assembly validation** with comprehensive error reporting
- **Modern C++ API** with safe memory management
Building and installation #### ZSCustomOverworld v3
------------------------- - **Enhanced overworld editing** capabilities
[CMake](http://www.cmake.org "CMake") is required to build yaze - **Advanced map properties** and metadata support
- **Custom graphics support** and tile management
- **Improved compatibility** with existing projects
1. Clone the repository #### Advanced Features
- **Theme Management**: Complete theme system with 5+ built-in themes and custom theme editor
- **Multi-Session Support**: Work with multiple ROMs simultaneously in docked workspace
- **Enhanced Welcome Screen**: Themed interface with quick access to all editors
- **Message Editing**: Enhanced text editing interface with real-time preview
- **GUI Docking**: Flexible workspace management with customizable layouts
- **Modern CLI**: Enhanced z3ed tool with interactive TUI and subcommands
- **Cross-Platform**: Full support for Windows, macOS, and Linux
``` ### 🛠️ Technical Improvements
git clone --recurse-submodules https://github.com/scawful/yaze.git - **Modern CMake 3.16+**: Target-based configuration and build system
- **CMakePresets**: Development workflow presets for better productivity
- **Cross-platform CI/CD**: Automated builds and testing for all platforms
- **Professional packaging**: NSIS, DMG, and DEB/RPM installers
- **Enhanced testing**: ROM-dependent test separation for CI compatibility
## Quick Start
### Build
```bash
# Clone with submodules
git clone --recursive https://github.com/scawful/yaze.git
cd yaze
# Build with CMake
cmake --preset debug # macOS
cmake -B build && cmake --build build # Linux/Windows
``` ```
2. Create the build directory and configuration ### Applications
- **yaze**: Complete GUI editor for Zelda 3 ROM hacking
- **z3ed**: Command-line tool with interactive interface
- **yaze_test**: Comprehensive test suite for development
``` ## Usage
cmake -S . -B build
### GUI Editor
Launch the main application to edit Zelda 3 ROMs:
- Load ROM files using native file dialogs
- Edit overworld maps, dungeons, sprites, and graphics
- Apply assembly patches with integrated Asar support
- Export modifications as patches or modified ROMs
### Command Line Tool
```bash
# Apply assembly patch
z3ed asar patch.asm --rom=zelda3.sfc
# Extract symbols from assembly
z3ed extract patch.asm
# Interactive mode
z3ed --tui
``` ```
3. Build and run. ### C++ API
```cpp
#include "yaze.h"
``` // Load ROM and apply patch
cmake --build build yaze_project_t* project = yaze_load_project("zelda3.sfc");
yaze_apply_asar_patch(project, "patch.asm");
yaze_save_project(project, "modified.sfc");
``` ```
## Documentation ## Documentation
- For users, please refer to [getting_started.md](docs/getting-started.md) for instructions on how to use yaze. - [Getting Started](docs/01-getting-started.md) - Setup and basic usage
- For developers, please refer to the [documentation](https://scawful.github.io/yaze/index.html) for information on the project's infrastructure. - [Build Instructions](docs/02-build-instructions.md) - Building from source
- [API Reference](docs/04-api-reference.md) - Programming interface
- [Contributing](docs/B1-contributing.md) - Development guidelines
License **[Complete Documentation](docs/index.md)**
--------
YAZE is distributed under the [GNU GPLv3](https://www.gnu.org/licenses/gpl-3.0.txt) license.
SDL2, ImGui and Abseil are subject to respective licenses. ## Supported Platforms
Screenshots - **Windows** (MSVC 2019+, MinGW)
-------- - **macOS** (Intel and Apple Silicon)
![image](https://github.com/scawful/yaze/assets/47263509/8b62b142-1de4-4ca4-8c49-d50c08ba4c8e) - **Linux** (GCC 13+, Clang 16+)
## ROM Compatibility
![image](https://github.com/scawful/yaze/assets/47263509/d8f0039d-d2e4-47d7-b420-554b20ac626f) - Original Zelda 3 ROMs (US/Japan versions)
- ZSCustomOverworld v2/v3 enhanced overworld features
- Community ROM hacks and modifications
![image](https://github.com/scawful/yaze/assets/47263509/34b36666-cbea-420b-af90-626099470ae4) ## Contributing
See [Contributing Guide](docs/B1-contributing.md) for development guidelines.
**Community**: [Oracle of Secrets Discord](https://discord.gg/MBFkMTPEmk)
## License
GNU GPL v3 - See [LICENSE](LICENSE) for details.
## 🙏 Acknowledgments
Takes inspiration from:
- [Hyrule Magic](https://www.romhacking.net/utilities/200/) - Original Zelda 3 editor
- [ZScream](https://github.com/Zarby89/ZScreamDungeon) - Dungeon editing capabilities
- [Asar](https://github.com/RPGHacker/asar) - 65816 assembler integration
## 📸 Screenshots
![YAZE GUI Editor](https://github.com/scawful/yaze/assets/47263509/8b62b142-1de4-4ca4-8c49-d50c08ba4c8e)
![Dungeon Editor](https://github.com/scawful/yaze/assets/47263509/d8f0039d-d2e4-47d7-b420-554b20ac626f)
![Overworld Editor](https://github.com/scawful/yaze/assets/47263509/34b36666-cbea-420b-af90-626099470ae4)
---
**Ready to hack Zelda 3? [Get started now!](docs/01-getting-started.md)**

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1
assets/asm/usdasm Submodule

Submodule assets/asm/usdasm added at d53311a54a

22
assets/asm/yaze.asm Normal file
View File

@@ -0,0 +1,22 @@
; =========================================================
; yaze custom assembly code
; =========================================================
namespace yaze
{
!YAZE_CUSTOM_MOSAIC = 1
if !YAZE_CUSTOM_MOSAIC != 0
incsrc "mosaic_change.asm"
endif
!ZS_CUSTOM_OVERWORLD = 1
if !ZS_CUSTOM_OVERWORLD != 0
incsrc "ZSCustomOverworld_v3.asm"
endif
}
namespace off

View File

@@ -1,25 +0,0 @@
BeginTabBar title="##OwEditorTabBar" {
BeginTabItem title="Map Editor" {
Function id="owToolset",
Table id="##owEditTable" count="2" flags="Resizable|Reorderable|Hideable|BordersOuter|BordersV" {
TableSetupColumn title="Canvas" flags="WidthStretch",
TableSetupColumn title="Tile Selector" flags="WidthFixed" width="256",
TableHeadersRow
TableNextRow,
TableNextColumn,
Function id="OverworldCanvas",
TableNextColumn,
Function id="OverworldTileSelector",
}
}
BeginTabItem title="Tile16 Editor" {
Function id="OwTile16Editor"
}
BeginTabItem title "Graphics Group Editor" {
Function id="OwGfxGroupEditor"
}
BeginTabItem title="Usage Statistics" {
Function id="OwUsageStats"
}
}

View File

@@ -0,0 +1,62 @@
# Cyberpunk Theme
# Neon-inspired futuristic theme
name=Cyberpunk
description=Neon-inspired futuristic theme
author=YAZE Team
version=1.0
[colors]
# Primary colors (neon cyberpunk)
primary=255,20,147,255
secondary=0,255,255,255
accent=255,0,128,255
background=10,10,20,255
surface=20,20,40,255
# Status colors
error=255,50,100,255
warning=255,255,0,255
success=0,255,100,255
info=100,200,255,255
# Text colors
text_primary=255,255,255,255
text_secondary=200,200,255,255
text_disabled=100,100,150,255
# Window colors
window_bg=15,15,30,240
child_bg=10,10,25,200
popup_bg=20,20,40,250
# Interactive elements
button=40,20,60,255
button_hovered=120,20,120,255
button_active=160,40,160,255
frame_bg=30,30,50,255
frame_bg_hovered=40,40,70,255
frame_bg_active=60,20,80,255
# Navigation
header=30,10,50,255
header_hovered=80,20,100,255
header_active=120,40,140,255
tab=25,15,45,255
tab_hovered=60,30,80,255
tab_active=100,20,120,255
menu_bar_bg=20,10,40,255
title_bg=25,15,45,255
title_bg_active=30,10,50,255
title_bg_collapsed=25,15,45,255
[style]
window_rounding=10.0
frame_rounding=8.0
scrollbar_rounding=10.0
grab_rounding=6.0
tab_rounding=6.0
window_border_size=1.0
frame_border_size=1.0
enable_animations=true
enable_glow_effects=true
animation_speed=1.5

View File

@@ -0,0 +1,73 @@
# Forest Theme
# Enhanced forest theme with better readability
name=Forest
description=Deep forest theme with enhanced readability
author=YAZE Team
version=1.0
[colors]
# Primary colors (enhanced forest with better contrast)
primary=100,180,120,255 # Brighter forest green
secondary=70,130,85,255 # Mid forest green
accent=130,220,150,255 # Light accent green
background=15,25,15,255 # Darker background for contrast
surface=25,35,25,255
# Status colors
error=255,120,120,255
warning=255,220,120,255
success=100,180,120,255
info=120,200,180,255
# Text colors (enhanced for readability)
text_primary=250,255,250,255 # Very light for contrast
text_secondary=220,240,220,255 # Light green tint
text_disabled=150,170,150,255 # Brighter disabled text
# Window colors (better contrast)
window_bg=20,30,20,240
child_bg=15,25,15,200
popup_bg=25,35,25,250
# Interactive elements (better visibility)
button=70,110,80,255
button_hovered=100,150,115,255
button_active=130,180,145,255
frame_bg=40,60,45,200
frame_bg_hovered=55,80,60,220
frame_bg_active=70,110,80,240
# Navigation (better contrast)
header=55,85,60,255
header_hovered=100,150,115,255
header_active=130,180,145,255
tab=45,75,50,255
tab_hovered=70,110,80,255
tab_active=100,150,115,255
menu_bar_bg=40,70,45,255
title_bg=50,80,55,255
title_bg_active=55,85,60,255
title_bg_collapsed=45,75,50,255
# Separators (better visibility)
separator=120,160,130,180
separator_hovered=150,200,160,220
separator_active=180,240,190,255
# Scrollbars (better visibility)
scrollbar_bg=40,60,45,180
scrollbar_grab=80,120,90,200
scrollbar_grab_hovered=100,150,115,230
scrollbar_grab_active=130,180,145,255
[style]
window_rounding=6.0
frame_rounding=4.0
scrollbar_rounding=6.0
grab_rounding=3.0
tab_rounding=3.0
window_border_size=0.0
frame_border_size=0.0
enable_animations=true
enable_glow_effects=false
animation_speed=1.0

View File

@@ -0,0 +1,73 @@
# Midnight Theme
# Enhanced midnight theme with better readability
name=Midnight
description=Deep blue midnight theme with enhanced readability
author=YAZE Team
version=1.0
[colors]
# Primary colors (enhanced midnight with better contrast)
primary=100,160,230,255 # Brighter blue
secondary=70,120,180,255 # Mid blue
accent=140,200,255,255 # Light blue accent
background=10,15,25,255 # Darker background for contrast
surface=20,25,35,255
# Status colors
error=255,120,120,255
warning=255,220,120,255
success=120,255,180,255
info=140,200,255,255
# Text colors (enhanced for readability)
text_primary=245,250,255,255 # Very light blue-white
text_secondary=200,220,240,255 # Light blue tint
text_disabled=140,160,180,255 # Brighter disabled text
# Window colors (better contrast)
window_bg=15,20,30,240
child_bg=10,15,25,200
popup_bg=20,25,35,250
# Interactive elements (better visibility)
button=50,80,120,255
button_hovered=80,120,160,255
button_active=110,150,190,255
frame_bg=30,45,65,200
frame_bg_hovered=40,60,85,220
frame_bg_active=60,90,130,240
# Navigation (better contrast)
header=40,65,100,255
header_hovered=70,110,150,255
header_active=100,140,180,255
tab=30,55,90,255
tab_hovered=50,80,120,255
tab_active=70,110,150,255
menu_bar_bg=25,50,85,255
title_bg=35,60,95,255
title_bg_active=40,65,100,255
title_bg_collapsed=30,55,90,255
# Separators (better visibility)
separator=100,140,180,180
separator_hovered=130,170,210,220
separator_active=160,200,240,255
# Scrollbars (better visibility)
scrollbar_bg=30,45,65,180
scrollbar_grab=70,110,150,200
scrollbar_grab_hovered=100,140,180,230
scrollbar_grab_active=130,170,210,255
[style]
window_rounding=8.0
frame_rounding=6.0
scrollbar_rounding=8.0
grab_rounding=4.0
tab_rounding=6.0
window_border_size=0.0
frame_border_size=0.0
enable_animations=true
enable_glow_effects=true
animation_speed=1.2

View File

@@ -0,0 +1,62 @@
# Sunset Theme
# Warm orange and purple sunset theme
name=Sunset
description=Warm orange and purple sunset theme
author=YAZE Team
version=1.0
[colors]
# Primary colors (sunset)
primary=255,140,60,255
secondary=200,100,150,255
accent=255,180,100,255
background=30,20,35,255
surface=40,30,45,255
# Status colors
error=255,100,120,255
warning=255,200,100,255
success=150,255,150,255
info=150,200,255,255
# Text colors
text_primary=255,245,235,255
text_secondary=220,200,180,255
text_disabled=150,130,120,255
# Window colors
window_bg=35,25,40,240
child_bg=30,20,35,200
popup_bg=40,30,45,250
# Interactive elements
button=60,40,70,255
button_hovered=120,80,100,255
button_active=150,100,120,255
frame_bg=45,35,50,255
frame_bg_hovered=55,45,60,255
frame_bg_active=80,60,90,255
# Navigation
header=50,35,60,255
header_hovered=100,70,90,255
header_active=130,90,110,255
tab=40,30,50,255
tab_hovered=70,50,70,255
tab_active=100,70,90,255
menu_bar_bg=35,25,45,255
title_bg=40,30,50,255
title_bg_active=50,35,60,255
title_bg_collapsed=40,30,50,255
[style]
window_rounding=12.0
frame_rounding=8.0
scrollbar_rounding=12.0
grab_rounding=6.0
tab_rounding=8.0
window_border_size=0.0
frame_border_size=0.0
enable_animations=true
enable_glow_effects=false
animation_speed=1.0

View File

@@ -0,0 +1,115 @@
# YAZE Tre Theme - Enhanced Edition
# Premium theme resource edition with improved colors and contrast
name=YAZE Tre
description=Enhanced YAZE theme with improved readability and modern colors
author=YAZE Team
version=2.0
[colors]
# Primary colors (enhanced ALTTP colors with better contrast)
primary=105,135,105,255 # Brighter green for better visibility
secondary=85,110,85,255 # Mid-tone green with more saturation
accent=110,145,110,255 # Vibrant accent green for highlights
background=12,12,15,255 # Slightly blue-tinted dark background
surface=18,18,22,255 # Warmer surface color
# Status colors (enhanced for better visibility)
error=235,75,75,255 # Brighter red for better visibility
warning=255,200,50,255 # Warmer yellow-orange
success=105,135,105,255 # Match primary green
info=70,170,255,255 # Brighter blue
# Text colors (enhanced contrast)
text_primary=245,245,245,255 # Brighter white for better readability
text_secondary=200,200,200,255 # Higher contrast secondary text
text_disabled=140,140,140,255 # Slightly brighter disabled text
# Window colors (enhanced backgrounds)
window_bg=12,12,15,230 # Slightly blue-tinted with transparency
child_bg=0,0,0,0 # Transparent child backgrounds
popup_bg=20,20,25,240 # Warmer popup background
# Interactive elements (enhanced for better UX)
button=85,110,85,255 # Enhanced mid-green for better visibility
button_hovered=135,160,135,255 # Brighter hover state
button_active=105,135,105,255 # Active state matches primary
frame_bg=25,25,30,150 # Darker frames with transparency
frame_bg_hovered=85,110,85,120 # Green tint on hover
frame_bg_active=105,135,105,180 # Primary green when active
# Navigation (enhanced contrast)
header=55,75,55,255 # Slightly brighter header
header_hovered=105,135,105,255 # Primary green on hover
header_active=85,110,85,255 # Secondary green when active
tab=45,60,45,255 # Darker tab background
tab_hovered=85,110,85,255 # Secondary green on hover
tab_active=110,145,110,255 # Accent green for active tab
menu_bar_bg=55,75,55,255 # Match header background
title_bg=85,110,85,255 # Secondary green
title_bg_active=55,75,55,255 # Darker when active
title_bg_collapsed=85,110,85,255 # Secondary green when collapsed
# Borders and separators (exact from original)
border=92,115,92,255 # allttpLightGreen
border_shadow=0,0,0,0 # No shadow in original
separator=127,127,127,153 # 0.50f, 0.50f, 0.50f, 0.60f
separator_hovered=153,153,178,255 # 0.60f, 0.60f, 0.70f
separator_active=178,178,230,255 # 0.70f, 0.70f, 0.90f
# Scrollbars (exact from original)
scrollbar_bg=92,115,92,153 # 0.36f, 0.45f, 0.36f, 0.60f
scrollbar_grab=92,115,92,76 # 0.36f, 0.45f, 0.36f, 0.30f (exact)
scrollbar_grab_hovered=92,115,92,102 # 0.36f, 0.45f, 0.36f, 0.40f
scrollbar_grab_active=92,115,92,153 # 0.36f, 0.45f, 0.36f, 0.60f
# Resize grips (exact from original - these are light blue, not white!)
resize_grip=255,255,255,26 # 1.00f, 1.00f, 1.00f, 0.10f
resize_grip_hovered=199,209,255,153 # 0.78f, 0.82f, 1.00f, 0.60f (light blue!)
resize_grip_active=199,209,255,230 # 0.78f, 0.82f, 1.00f, 0.90f (light blue!)
# Additional controls (enhanced)
check_mark=245,245,245,200 # Brighter check marks for visibility
slider_grab=180,180,180,120 # More visible slider grab
slider_grab_active=110,145,110,200 # Accent color when active
# Table colors (enhanced)
table_header_bg=55,75,55,255 # Slightly brighter header
table_border_strong=85,110,85,255 # Secondary green borders
table_border_light=70,70,75,255 # Better contrast light borders
table_row_bg=0,0,0,0 # Transparent
table_row_bg_alt=255,255,255,25 # Slightly more visible alternating rows
# Link colors (high contrast for better visibility)
text_link=120,200,255,255 # Bright blue for links - high contrast against dark backgrounds
# Navigation and special elements
input_text_cursor=245,245,245,255
nav_cursor=110,145,110,255
nav_windowing_highlight=110,145,110,255
nav_windowing_dim_bg=0,0,0,128
modal_window_dim_bg=0,0,0,89
text_selected_bg=89,119,89,89
drag_drop_target=110,145,110,255
docking_preview=92,115,92,180
docking_empty_bg=46,66,46,255
# Tree lines
tree_lines=127,127,127,153
# Tab variations for unfocused windows
tab_dimmed=37,52,37,255
tab_dimmed_selected=62,83,62,255
tab_dimmed_selected_overline=110,145,110,255
tab_selected_overline=110,145,110,255
[style]
window_rounding=0.0
frame_rounding=5.0
scrollbar_rounding=5.0
grab_rounding=3.0
tab_rounding=0.0
window_border_size=0.0
frame_border_size=0.0
enable_animations=true
enable_glow_effects=false
animation_speed=1.0

BIN
assets/yaze.icns Normal file

Binary file not shown.

BIN
assets/yaze.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

View File

@@ -1,12 +1,41 @@
find_package(absl) if (MINGW OR WIN32)
add_subdirectory(src/lib/abseil-cpp)
elseif(YAZE_MINIMAL_BUILD)
# For CI builds, always use submodule to avoid dependency issues
add_subdirectory(src/lib/abseil-cpp)
else()
# Try system package first, fallback to submodule
find_package(absl QUIET)
if(NOT absl_FOUND)
message(STATUS "System Abseil not found, using submodule")
add_subdirectory(src/lib/abseil-cpp)
endif()
endif()
set(ABSL_PROPAGATE_CXX_STD ON) set(ABSL_PROPAGATE_CXX_STD ON)
set(ABSL_CXX_STANDARD 17) set(ABSL_CXX_STANDARD 23)
set(ABSL_USE_GOOGLETEST_HEAD ON) set(ABSL_USE_GOOGLETEST_HEAD ON)
set(ABSL_ENABLE_INSTALL ON) set(ABSL_ENABLE_INSTALL ON)
# Silence C++23 deprecation warnings for Abseil int128
if(MSVC)
add_definitions(-DSILENCE_CXX23_DEPRECATIONS)
else()
add_definitions(-D_SILENCE_CXX23_DEPRECATION_WARNING)
endif()
# Define base Abseil targets
set( set(
ABSL_TARGETS ABSL_TARGETS
absl::strings absl::strings
absl::str_format
absl::flags absl::flags
absl::flags_parse
absl::flags_usage
absl::flags_commandlineflag
absl::flags_marshalling
absl::flags_private_handle_accessor
absl::flags_program_name
absl::flags_config
absl::flags_reflection
absl::status absl::status
absl::statusor absl::statusor
absl::examine_stack absl::examine_stack
@@ -14,7 +43,22 @@ set(
absl::base absl::base
absl::config absl::config
absl::core_headers absl::core_headers
absl::raw_logging_internal
absl::failure_signal_handler absl::failure_signal_handler
absl::flat_hash_map absl::flat_hash_map
absl::cord
absl::hash
absl::synchronization
absl::time
absl::symbolize
absl::container_memory
absl::memory
absl::utility
) )
# Add int128 only on non-Windows platforms to avoid C++23 deprecation issues
if(NOT WIN32)
list(APPEND ABSL_TARGETS absl::int128)
message(STATUS "Including absl::int128 (non-Windows platform)")
else()
message(STATUS "Excluding absl::int128 on Windows to avoid C++23 deprecation issues")
endif()

View File

@@ -1,33 +1,94 @@
get_target_property(ASAR_INCLUDE_DIR asar-static INCLUDE_DIRECTORIES) # Modern Asar 65816 Assembler Integration
target_include_directories(asar-static PRIVATE ${ASAR_INCLUDE_DIR}) # Improved cross-platform support for macOS, Linux, and Windows
set(ASAR_GEN_EXE OFF)
set(ASAR_GEN_DLL ON)
set(ASAR_GEN_LIB ON)
set(ASAR_GEN_EXE_TEST OFF)
set(ASAR_GEN_DLL_TEST OFF)
set(ASAR_STATIC_SRC # Configure Asar build options
"../src/lib/asar/src/asar/interface-lib.cpp" set(ASAR_GEN_EXE OFF CACHE BOOL "Build Asar standalone executable")
"../src/lib/asar/src/asar/addr2line.cpp" set(ASAR_GEN_DLL ON CACHE BOOL "Build Asar shared library")
"../src/lib/asar/src/asar/arch-65816.cpp" set(ASAR_GEN_LIB ON CACHE BOOL "Build Asar static library")
"../src/lib/asar/src/asar/arch-spc700.cpp" set(ASAR_GEN_EXE_TEST OFF CACHE BOOL "Build Asar executable tests")
"../src/lib/asar/src/asar/arch-superfx.cpp" set(ASAR_GEN_DLL_TEST OFF CACHE BOOL "Build Asar DLL tests")
"../src/lib/asar/src/asar/assembleblock.cpp"
"../src/lib/asar/src/asar/crc32.cpp"
"../src/lib/asar/src/asar/libcon.cpp"
"../src/lib/asar/src/asar/libsmw.cpp"
"../src/lib/asar/src/asar/libstr.cpp"
"../src/lib/asar/src/asar/macro.cpp"
"../src/lib/asar/src/asar/main.cpp"
"../src/lib/asar/src/asar/asar_math.cpp"
"../src/lib/asar/src/asar/virtualfile.cpp"
"../src/lib/asar/src/asar/warnings.cpp"
"../src/lib/asar/src/asar/errors.cpp"
"../src/lib/asar/src/asar/platform/file-helpers.cpp"
)
if(WIN32 OR MINGW) # Set Asar source directory
list(APPEND ASAR_STATIC_SRC "../src/lib/asar/src/asar/platform/windows/file-helpers-win32.cpp") set(ASAR_SRC_DIR "${CMAKE_SOURCE_DIR}/src/lib/asar/src")
# Add Asar as subdirectory
add_subdirectory(${ASAR_SRC_DIR} EXCLUDE_FROM_ALL)
# Create modern CMake target for Asar integration
if(TARGET asar-static)
# Ensure asar-static is available and properly configured
set_target_properties(asar-static PROPERTIES
CXX_STANDARD 17
CXX_STANDARD_REQUIRED ON
POSITION_INDEPENDENT_CODE ON
)
# Set platform-specific definitions for Asar
if(WIN32)
target_compile_definitions(asar-static PRIVATE
windows
strncasecmp=_strnicmp
strcasecmp=_stricmp
_CRT_SECURE_NO_WARNINGS
_CRT_NONSTDC_NO_WARNINGS
)
elseif(UNIX AND NOT APPLE)
target_compile_definitions(asar-static PRIVATE
linux
stricmp=strcasecmp
)
elseif(APPLE)
target_compile_definitions(asar-static PRIVATE
MACOS
stricmp=strcasecmp
)
endif()
# Add include directories
target_include_directories(asar-static PUBLIC
$<BUILD_INTERFACE:${ASAR_SRC_DIR}>
$<BUILD_INTERFACE:${ASAR_SRC_DIR}/asar>
$<BUILD_INTERFACE:${ASAR_SRC_DIR}/asar-dll-bindings/c>
)
# Create alias for easier linking
add_library(yaze::asar ALIAS asar-static)
# Export Asar variables for use in other parts of the build
set(ASAR_FOUND TRUE CACHE BOOL "Asar library found")
set(ASAR_LIBRARIES asar-static CACHE STRING "Asar library target")
set(ASAR_INCLUDE_DIRS
"${ASAR_SRC_DIR}"
"${ASAR_SRC_DIR}/asar"
"${ASAR_SRC_DIR}/asar-dll-bindings/c"
CACHE STRING "Asar include directories"
)
message(STATUS "Asar 65816 assembler integration configured successfully")
else() else()
list(APPEND ASAR_STATIC_SRC "../src/lib/asar/src/asar/platform/linux/file-helpers-linux.cpp") message(WARNING "Failed to configure Asar static library target")
set(ASAR_FOUND FALSE CACHE BOOL "Asar library found")
endif() endif()
# Function to add Asar patching capabilities to a target
function(yaze_add_asar_support target_name)
if(ASAR_FOUND)
target_link_libraries(${target_name} PRIVATE yaze::asar)
target_include_directories(${target_name} PRIVATE ${ASAR_INCLUDE_DIRS})
target_compile_definitions(${target_name} PRIVATE YAZE_ENABLE_ASAR=1)
else()
message(WARNING "Asar not available for target ${target_name}")
endif()
endfunction()
# Create function for ROM patching utilities
function(yaze_create_asar_patch_tool tool_name patch_file rom_file)
if(ASAR_FOUND)
add_custom_target(${tool_name}
COMMAND ${CMAKE_COMMAND} -E echo "Patching ROM with Asar..."
COMMAND $<TARGET_FILE:asar-standalone> ${patch_file} ${rom_file}
DEPENDS asar-standalone
COMMENT "Applying Asar patch ${patch_file} to ${rom_file}"
)
endif()
endfunction()

11
cmake/gtest.cmake Normal file
View File

@@ -0,0 +1,11 @@
# GoogleTest ------------------------------------------------------------------
include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip
)
# For Windows: Prevent overriding the parent project's compiler/linker settings
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)
enable_testing()

View File

@@ -1,33 +1,43 @@
# gui libraries --------------------------------------------------------------- # gui libraries ---------------------------------------------------------------
set(IMGUI_PATH ${CMAKE_SOURCE_DIR}/src/lib/imgui) set(IMGUI_PATH ${CMAKE_SOURCE_DIR}/src/lib/imgui)
file(GLOB IMGUI_SOURCES ${IMGUI_PATH}/*.cpp) file(GLOB IMGUI_SOURCES ${IMGUI_PATH}/*.cpp)
add_library("ImGui" STATIC ${IMGUI_SOURCES}) set(IMGUI_BACKEND_SOURCES
target_include_directories("ImGui" PUBLIC ${IMGUI_PATH}) ${IMGUI_PATH}/backends/imgui_impl_sdl2.cpp
${IMGUI_PATH}/backends/imgui_impl_sdlrenderer2.cpp
${IMGUI_PATH}/misc/cpp/imgui_stdlib.cpp
)
add_library("ImGui" STATIC ${IMGUI_SOURCES} ${IMGUI_BACKEND_SOURCES})
target_include_directories("ImGui" PUBLIC ${IMGUI_PATH} ${IMGUI_PATH}/backends)
target_include_directories(ImGui PUBLIC ${SDL2_INCLUDE_DIR}) target_include_directories(ImGui PUBLIC ${SDL2_INCLUDE_DIR})
target_compile_definitions(ImGui PUBLIC target_compile_definitions(ImGui PUBLIC
IMGUI_IMPL_OPENGL_LOADER_CUSTOM=<SDL2/SDL_opengl.h> GL_GLEXT_PROTOTYPES=1) IMGUI_IMPL_OPENGL_LOADER_CUSTOM=<SDL2/SDL_opengl.h> GL_GLEXT_PROTOTYPES=1)
set(IMGUI_FILE_DLG_PATH ${CMAKE_SOURCE_DIR}/src/lib/ImGuiFileDialog) # Set up ImGui Test Engine sources and target conditionally
file(GLOB IMGUI_FILE_DLG_SOURCES ${IMGUI_FILE_DLG_PATH}/*.cpp) if(YAZE_ENABLE_UI_TESTS)
add_library("ImGuiFileDialog" STATIC ${IMGUI_FILE_DLG_SOURCES}) set(IMGUI_TEST_ENGINE_PATH ${CMAKE_SOURCE_DIR}/src/lib/imgui_test_engine/imgui_test_engine)
target_include_directories(ImGuiFileDialog PUBLIC ${IMGUI_PATH}) file(GLOB IMGUI_TEST_ENGINE_SOURCES ${IMGUI_TEST_ENGINE_PATH}/*.cpp)
target_compile_definitions(ImGuiFileDialog PUBLIC add_library("ImGuiTestEngine" STATIC ${IMGUI_TEST_ENGINE_SOURCES})
IMGUI_IMPL_OPENGL_LOADER_CUSTOM=<SDL2/SDL_opengl.h> GL_GLEXT_PROTOTYPES=1) target_include_directories(ImGuiTestEngine PUBLIC ${IMGUI_PATH} ${CMAKE_SOURCE_DIR}/src/lib)
target_link_libraries(ImGuiTestEngine PUBLIC ImGui)
set(IMGUI_COLOR_TEXT_EDIT_PATH ${CMAKE_SOURCE_DIR}/src/lib/ImGuiColorTextEdit) # Enable test engine definitions only when UI tests are enabled
file(GLOB IMGUI_COLOR_TEXT_EDIT_SOURCES ${IMGUI_COLOR_TEXT_EDIT_PATH}/*.cpp) target_compile_definitions(ImGuiTestEngine PUBLIC
add_library("ImGuiColorTextEdit" STATIC ${IMGUI_COLOR_TEXT_EDIT_SOURCES}) IMGUI_ENABLE_TEST_ENGINE=1
target_include_directories(ImGuiColorTextEdit PUBLIC ${IMGUI_PATH}) IMGUI_TEST_ENGINE_ENABLE_COROUTINE_STDTHREAD_IMPL=1)
target_compile_definitions(ImGuiColorTextEdit PUBLIC
IMGUI_IMPL_OPENGL_LOADER_CUSTOM=<SDL2/SDL_opengl.h> GL_GLEXT_PROTOTYPES=1)
set(IMGUI_TEST_ENGINE_PATH ${CMAKE_SOURCE_DIR}/src/lib/imgui_test_engine/imgui_test_engine) # Also define for targets that link to ImGuiTestEngine
file(GLOB IMGUI_TEST_ENGINE_SOURCES ${IMGUI_TEST_ENGINE_PATH}/*.cpp) set(IMGUI_TEST_ENGINE_DEFINITIONS
add_library("ImGuiTestEngine" STATIC ${IMGUI_TEST_ENGINE_SOURCES}) IMGUI_ENABLE_TEST_ENGINE=1
target_include_directories(ImGuiTestEngine PUBLIC ${IMGUI_PATH}) IMGUI_TEST_ENGINE_ENABLE_COROUTINE_STDTHREAD_IMPL=1)
target_link_libraries(ImGuiTestEngine PUBLIC ImGui)
target_compile_definitions(ImGuiTestEngine PUBLIC # Make ImGuiTestEngine target available
IMGUI_IMPL_OPENGL_LOADER_CUSTOM=<SDL2/SDL_opengl.h> GL_GLEXT_PROTOTYPES=1) set(IMGUI_TEST_ENGINE_TARGET ImGuiTestEngine)
else()
# Create empty variables when UI tests are disabled
set(IMGUI_TEST_ENGINE_SOURCES "")
set(IMGUI_TEST_ENGINE_TARGET "")
set(IMGUI_TEST_ENGINE_DEFINITIONS "")
endif()
set( set(
IMGUI_SRC IMGUI_SRC
@@ -38,6 +48,5 @@ set(
${IMGUI_PATH}/backends/imgui_impl_sdl2.cpp ${IMGUI_PATH}/backends/imgui_impl_sdl2.cpp
${IMGUI_PATH}/backends/imgui_impl_sdlrenderer2.cpp ${IMGUI_PATH}/backends/imgui_impl_sdlrenderer2.cpp
${IMGUI_PATH}/misc/cpp/imgui_stdlib.cpp ${IMGUI_PATH}/misc/cpp/imgui_stdlib.cpp
${IMGUI_FILE_DLG_PATH}/ImGuiFileDialog.cpp
${IMGUI_COLOR_TEXT_EDIT_PATH}/TextEditor.cpp
) )

21
cmake/mingw64.cmake Normal file
View File

@@ -0,0 +1,21 @@
# cmake -DCMAKE_TOOLCHAIN_FILE=./cmake/mingw64.cmake -B build/build-windows && cmake --build ./build/build-windows
set(CMAKE_SYSTEM_NAME Windows)
set(CMAKE_SYSTEM_VERSION 1)
set(CMAKE_SYSTEM_PROCESSOR x86_64)
set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc)
set(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++)
set(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres)
set(CMAKE_FIND_ROOT_PATH /usr/local/opt/mingw-w64)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2 -pipe -g -feliminate-unused-debug-types")
# Static link the C++ standard library
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static -static-libgcc -static-libstdc++")

221
cmake/packaging.cmake Normal file
View File

@@ -0,0 +1,221 @@
# Modern packaging configuration for Yaze
# Supports Windows (NSIS), macOS (DMG), and Linux (DEB/RPM)
include(InstallRequiredSystemLibraries)
# Basic package information
set(CPACK_PACKAGE_NAME "yaze")
set(CPACK_PACKAGE_VENDOR "scawful")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Yet Another Zelda3 Editor")
set(CPACK_PACKAGE_DESCRIPTION "A comprehensive editor for The Legend of Zelda: A Link to the Past ROM hacking")
set(CPACK_PACKAGE_VERSION_MAJOR ${YAZE_VERSION_MAJOR})
set(CPACK_PACKAGE_VERSION_MINOR ${YAZE_VERSION_MINOR})
set(CPACK_PACKAGE_VERSION_PATCH ${YAZE_VERSION_PATCH})
set(CPACK_PACKAGE_VERSION "${YAZE_VERSION_MAJOR}.${YAZE_VERSION_MINOR}.${YAZE_VERSION_PATCH}")
set(CPACK_PACKAGE_INSTALL_DIRECTORY "Yaze")
set(CPACK_PACKAGE_CONTACT "scawful@github.com")
set(CPACK_PACKAGE_HOMEPAGE_URL "https://github.com/scawful/yaze")
# Resource files
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE")
set(CPACK_RESOURCE_FILE_README "${CMAKE_SOURCE_DIR}/README.md")
# Package icon
if(EXISTS "${CMAKE_SOURCE_DIR}/assets/yaze.png")
set(CPACK_PACKAGE_ICON "${CMAKE_SOURCE_DIR}/assets/yaze.png")
endif()
# Platform-specific configuration
if(WIN32)
# Windows packaging configuration (conditional based on environment)
if(DEFINED ENV{GITHUB_ACTIONS})
# CI/CD build - use only ZIP (NSIS not available)
set(CPACK_GENERATOR "ZIP")
else()
# Local build - use both NSIS installer and ZIP
set(CPACK_GENERATOR "NSIS;ZIP")
endif()
# NSIS-specific configuration (only for local builds with NSIS available)
if(NOT DEFINED ENV{GITHUB_ACTIONS})
set(CPACK_NSIS_DISPLAY_NAME "Yaze - Zelda3 Editor")
set(CPACK_NSIS_PACKAGE_NAME "Yaze")
set(CPACK_NSIS_CONTACT "scawful@github.com")
set(CPACK_NSIS_URL_INFO_ABOUT "https://github.com/scawful/yaze")
set(CPACK_NSIS_HELP_LINK "https://github.com/scawful/yaze/issues")
set(CPACK_NSIS_MENU_LINKS
"bin/yaze.exe" "Yaze Editor"
"https://github.com/scawful/yaze" "Yaze Homepage"
)
set(CPACK_NSIS_CREATE_ICONS_EXTRA
"CreateShortCut '$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Yaze.lnk' '$INSTDIR\\\\bin\\\\yaze.exe'"
"CreateShortCut '$DESKTOP\\\\Yaze.lnk' '$INSTDIR\\\\bin\\\\yaze.exe'"
)
set(CPACK_NSIS_DELETE_ICONS_EXTRA
"Delete '$SMPROGRAMS\\\\$START_MENU\\\\Yaze.lnk'"
"Delete '$DESKTOP\\\\Yaze.lnk'"
)
endif()
# Windows architecture detection
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
if(DEFINED ENV{GITHUB_ACTIONS})
set(CPACK_PACKAGE_FILE_NAME "yaze-${CPACK_PACKAGE_VERSION}-windows-x64")
else()
set(CPACK_PACKAGE_FILE_NAME "yaze-${CPACK_PACKAGE_VERSION}-win64")
endif()
set(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES64")
else()
if(DEFINED ENV{GITHUB_ACTIONS})
set(CPACK_PACKAGE_FILE_NAME "yaze-${CPACK_PACKAGE_VERSION}-windows-x86")
else()
set(CPACK_PACKAGE_FILE_NAME "yaze-${CPACK_PACKAGE_VERSION}-win32")
endif()
set(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES")
endif()
elseif(APPLE)
# macOS DMG configuration
set(CPACK_GENERATOR "DragNDrop")
set(CPACK_DMG_VOLUME_NAME "Yaze ${CPACK_PACKAGE_VERSION}")
set(CPACK_DMG_FORMAT "UDZO")
set(CPACK_PACKAGE_FILE_NAME "yaze-${CPACK_PACKAGE_VERSION}-macos")
# macOS app bundle configuration
if(EXISTS "${CMAKE_SOURCE_DIR}/assets/dmg_background.png")
set(CPACK_DMG_BACKGROUND_IMAGE "${CMAKE_SOURCE_DIR}/assets/dmg_background.png")
endif()
if(EXISTS "${CMAKE_SOURCE_DIR}/cmake/dmg_setup.scpt")
set(CPACK_DMG_DS_STORE_SETUP_SCRIPT "${CMAKE_SOURCE_DIR}/cmake/dmg_setup.scpt")
endif()
elseif(UNIX)
# Linux DEB/RPM configuration
set(CPACK_GENERATOR "DEB;RPM;TGZ")
# DEB package configuration
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "scawful <scawful@github.com>")
set(CPACK_DEBIAN_PACKAGE_SECTION "games")
set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional")
set(CPACK_DEBIAN_PACKAGE_DEPENDS
"libsdl2-2.0-0, libpng16-16, libgl1-mesa-glx, libabsl20210324")
set(CPACK_DEBIAN_PACKAGE_RECOMMENDS "git")
set(CPACK_DEBIAN_PACKAGE_SUGGESTS "asar")
set(CPACK_DEBIAN_FILE_NAME DEB-DEFAULT)
# RPM package configuration
set(CPACK_RPM_PACKAGE_SUMMARY "Zelda3 ROM Editor")
set(CPACK_RPM_PACKAGE_LICENSE "MIT")
set(CPACK_RPM_PACKAGE_GROUP "Amusements/Games")
set(CPACK_RPM_PACKAGE_REQUIRES
"SDL2 >= 2.0.0, libpng >= 1.6.0, mesa-libGL, abseil-cpp")
set(CPACK_RPM_PACKAGE_SUGGESTS "asar")
set(CPACK_RPM_FILE_NAME RPM-DEFAULT)
# Architecture detection
execute_process(
COMMAND uname -m
OUTPUT_VARIABLE CPACK_SYSTEM_ARCH
OUTPUT_STRIP_TRAILING_WHITESPACE
)
set(CPACK_PACKAGE_FILE_NAME "yaze-${CPACK_PACKAGE_VERSION}-linux-${CPACK_SYSTEM_ARCH}")
endif()
# Component configuration for advanced packaging
set(CPACK_COMPONENTS_ALL applications libraries headers documentation)
set(CPACK_COMPONENT_APPLICATIONS_DISPLAY_NAME "Yaze Application")
set(CPACK_COMPONENT_APPLICATIONS_DESCRIPTION "Main Yaze editor application")
set(CPACK_COMPONENT_APPLICATIONS_REQUIRED TRUE)
set(CPACK_COMPONENT_LIBRARIES_DISPLAY_NAME "Development Libraries")
set(CPACK_COMPONENT_LIBRARIES_DESCRIPTION "Yaze development libraries")
set(CPACK_COMPONENT_LIBRARIES_REQUIRED FALSE)
set(CPACK_COMPONENT_HEADERS_DISPLAY_NAME "Development Headers")
set(CPACK_COMPONENT_HEADERS_DESCRIPTION "Header files for Yaze development")
set(CPACK_COMPONENT_HEADERS_REQUIRED FALSE)
set(CPACK_COMPONENT_HEADERS_DEPENDS libraries)
set(CPACK_COMPONENT_DOCUMENTATION_DISPLAY_NAME "Documentation")
set(CPACK_COMPONENT_DOCUMENTATION_DESCRIPTION "User and developer documentation")
set(CPACK_COMPONENT_DOCUMENTATION_REQUIRED FALSE)
# Installation components
if(APPLE)
install(TARGETS yaze
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR}
COMPONENT applications
)
else()
install(TARGETS yaze
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
COMPONENT applications
)
endif()
# Install assets
install(DIRECTORY ${CMAKE_SOURCE_DIR}/assets/
DESTINATION ${CMAKE_INSTALL_DATADIR}/yaze/assets
COMPONENT applications
PATTERN "*.png"
PATTERN "*.ttf"
PATTERN "*.asm"
)
# Install documentation
install(FILES
${CMAKE_SOURCE_DIR}/README.md
${CMAKE_SOURCE_DIR}/LICENSE
DESTINATION ${CMAKE_INSTALL_DOCDIR}
COMPONENT documentation
)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/docs/
DESTINATION ${CMAKE_INSTALL_DOCDIR}
COMPONENT documentation
PATTERN "*.md"
PATTERN "*.html"
)
# Install headers and libraries if building library components
if(YAZE_INSTALL_LIB)
install(TARGETS yaze_c
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
COMPONENT libraries
)
install(FILES ${CMAKE_SOURCE_DIR}/incl/yaze.h ${CMAKE_SOURCE_DIR}/incl/zelda.h
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/yaze
COMPONENT headers
)
endif()
# Desktop integration for Linux
if(UNIX AND NOT APPLE)
# Desktop file
configure_file(
${CMAKE_SOURCE_DIR}/cmake/yaze.desktop.in
${CMAKE_BINARY_DIR}/yaze.desktop
@ONLY
)
install(FILES ${CMAKE_BINARY_DIR}/yaze.desktop
DESTINATION ${CMAKE_INSTALL_DATADIR}/applications
COMPONENT applications
)
# Icon
if(EXISTS "${CMAKE_SOURCE_DIR}/assets/yaze.png")
install(FILES ${CMAKE_SOURCE_DIR}/assets/yaze.png
DESTINATION ${CMAKE_INSTALL_DATADIR}/pixmaps
RENAME yaze.png
COMPONENT applications
)
endif()
endif()
# Include CPack
include(CPack)

View File

@@ -1,6 +1,54 @@
# SDL2 # SDL2
if (UNIX) if (UNIX OR MINGW OR WIN32)
add_subdirectory(src/lib/SDL) add_subdirectory(src/lib/SDL)
# When using bundled SDL, use the static target and set include directories
set(SDL_TARGETS SDL2-static)
set(SDL2_INCLUDE_DIR
${CMAKE_SOURCE_DIR}/src/lib/SDL/include
${CMAKE_BINARY_DIR}/src/lib/SDL/include
${CMAKE_BINARY_DIR}/src/lib/SDL/include-config-${CMAKE_BUILD_TYPE}
)
# Also set for consistency with bundled SDL
set(SDL2_INCLUDE_DIRS ${SDL2_INCLUDE_DIR})
else() else()
find_package(SDL2) find_package(SDL2)
# When using system SDL, use the imported targets
set(SDL_TARGETS SDL2::SDL2)
if(WIN32)
list(PREPEND SDL_TARGETS SDL2::SDL2main ws2_32)
add_definitions("-DSDL_MAIN_HANDLED")
endif()
endif()
# libpng and ZLIB dependencies
if(WIN32)
# Windows builds with vcpkg (OpenGL/GLEW removed to avoid MSYS2 issues)
if(NOT YAZE_MINIMAL_BUILD)
find_package(ZLIB REQUIRED)
find_package(PNG REQUIRED)
else()
# For CI/minimal builds, try to find but don't require
find_package(ZLIB QUIET)
find_package(PNG QUIET)
if(NOT ZLIB_FOUND OR NOT PNG_FOUND)
message(STATUS "PNG/ZLIB not found in minimal build, some features may be disabled")
set(PNG_FOUND FALSE)
set(PNG_LIBRARIES "")
set(PNG_INCLUDE_DIRS "")
endif()
endif()
elseif(YAZE_MINIMAL_BUILD)
# For CI builds on other platforms, try to find but don't require
find_package(ZLIB QUIET)
find_package(PNG QUIET)
if(NOT ZLIB_FOUND OR NOT PNG_FOUND)
message(STATUS "PNG/ZLIB not found in minimal build, some features may be disabled")
set(PNG_FOUND FALSE)
set(PNG_LIBRARIES "")
set(PNG_INCLUDE_DIRS "")
endif()
else()
# Regular builds require these dependencies
find_package(ZLIB REQUIRED)
find_package(PNG REQUIRED)
endif() endif()

40
cmake/vcpkg.cmake Normal file
View File

@@ -0,0 +1,40 @@
# vcpkg configuration for Windows builds
add_definitions("-DMICROSOFT_WINDOWS_WINBASE_H_DEFINE_INTERLOCKED_CPLUSPLUS_OVERLOADS=0")
# vcpkg settings
set(VCPKG_CRT_LINKAGE dynamic)
set(VCPKG_LIBRARY_LINKAGE dynamic)
# Enable vcpkg manifest mode for automatic dependency management
set(VCPKG_MANIFEST_MODE ON)
# Auto-detect target architecture and set vcpkg triplet
if(NOT DEFINED VCPKG_TARGET_TRIPLET)
if(CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64|aarch64")
set(VCPKG_TARGET_TRIPLET "arm64-windows" CACHE STRING "vcpkg target triplet")
set(VCPKG_TARGET_ARCHITECTURE arm64)
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "AMD64|x86_64")
set(VCPKG_TARGET_TRIPLET "x64-windows" CACHE STRING "vcpkg target triplet")
set(VCPKG_TARGET_ARCHITECTURE x64)
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "i386|i686|x86")
set(VCPKG_TARGET_TRIPLET "x86-windows" CACHE STRING "vcpkg target triplet")
set(VCPKG_TARGET_ARCHITECTURE x86)
else()
# Fallback to x64 if architecture detection fails
set(VCPKG_TARGET_TRIPLET "x64-windows" CACHE STRING "vcpkg target triplet")
set(VCPKG_TARGET_ARCHITECTURE x64)
message(WARNING "Could not detect target architecture, defaulting to x64")
endif()
endif()
# Set vcpkg installation directory if not already set
if(NOT DEFINED VCPKG_INSTALLED_DIR)
set(VCPKG_INSTALLED_DIR "${CMAKE_BINARY_DIR}/vcpkg_installed" CACHE PATH "vcpkg installed directory")
endif()
message(STATUS "vcpkg configuration:")
message(STATUS " Target architecture: ${VCPKG_TARGET_ARCHITECTURE}")
message(STATUS " Target triplet: ${VCPKG_TARGET_TRIPLET}")
message(STATUS " Installed directory: ${VCPKG_INSTALLED_DIR}")
message(STATUS " Manifest mode: ${VCPKG_MANIFEST_MODE}")

13
cmake/yaze.desktop.in Normal file
View File

@@ -0,0 +1,13 @@
[Desktop Entry]
Version=1.0
Type=Application
Name=Yaze
Comment=Yet Another Zelda3 Editor
Comment[en]=ROM editor for The Legend of Zelda: A Link to the Past
Exec=@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_BINDIR@/yaze
Icon=yaze
Terminal=false
Categories=Game;Development;
Keywords=zelda;snes;rom;editor;hacking;
StartupNotify=true
MimeType=application/x-snes-rom;application/x-sfc;application/x-smc;

View File

@@ -0,0 +1,56 @@
# Getting Started
This software allows you to modify "The Legend of Zelda: A Link to the Past" (US or JP) ROMs. Built for compatibility with ZScream projects and designed to be cross-platform.
## Quick Start
1. **Download** the latest release for your platform
2. **Load ROM** via File > Open ROM
3. **Select Editor** from the toolbar (Overworld, Dungeon, Graphics, etc.)
4. **Make Changes** and save your project
## General Tips
- **Experiment Flags**: Enable/disable features in File > Options > Experiment Flags
- **Backup Files**: Enabled by default - each save creates a timestamped backup
- **Extensions**: Load custom tools via the Extensions menu (C library and Python module support)
## Supported Features
| Feature | Status | Details |
|---------|--------|---------|
| Overworld Maps | ✅ Complete | Edit and save tile32 data |
| OW Map Properties | ✅ Complete | Edit and save map properties |
| OW Entrances | ✅ Complete | Edit and save entrance data |
| OW Exits | ✅ Complete | Edit and save exit data |
| OW Sprites | 🔄 In Progress | Edit sprite positions, add/remove sprites |
| Dungeon Editor | 🔄 In Progress | View room metadata and edit room data |
| Palette Editor | 🔄 In Progress | Edit and save palettes, palette groups |
| Graphics Sheets | 🔄 In Progress | Edit and save graphics sheets |
| Graphics Groups | ✅ Complete | Edit and save graphics groups |
| Hex Editor | ✅ Complete | View and edit ROM data in hex |
| Asar Patching | ✅ Complete | Apply Asar 65816 assembly patches to ROM |
## Command Line Interface
The `z3ed` CLI tool provides ROM operations:
```bash
# Apply Asar assembly patch
z3ed asar patch.asm --rom=zelda3.sfc
# Extract symbols from assembly
z3ed extract patch.asm
# Validate assembly syntax
z3ed validate patch.asm
# Launch interactive TUI
z3ed --tui
```
## Extending Functionality
YAZE provides a pure C library interface and Python module for building extensions and custom sprites without assembly. Load these under the Extensions menu.
This feature is still in development and not fully documented yet.

View File

@@ -0,0 +1,459 @@
# Build Instructions
YAZE uses CMake 3.16+ with modern target-based configuration. The project includes comprehensive Windows support with Visual Studio integration, vcpkg package management, and automated setup scripts.
## Quick Start
### macOS (Apple Silicon)
```bash
cmake --preset debug
cmake --build build
```
### Linux
```bash
cmake -B build -DCMAKE_BUILD_TYPE=Debug
cmake --build build
```
### Windows (Recommended)
```powershell
# Automated setup (first time only)
.\scripts\setup-windows-dev.ps1
# Generate Visual Studio projects (with proper vcpkg integration)
python scripts/generate-vs-projects.py
# Or use CMake directly
cmake --preset windows-debug
cmake --build build --preset windows-debug
```
### Minimal Build (CI/Fast)
```bash
cmake -B build -DYAZE_MINIMAL_BUILD=ON
cmake --build build
```
## Dependencies
### Required
- CMake 3.16+
- C++23 compiler (GCC 13+, Clang 16+, MSVC 2019+)
- Git with submodule support
### Bundled Libraries
- SDL2, ImGui, Abseil, Asar, GoogleTest
- Native File Dialog Extended (NFD)
- All dependencies included in repository
## Platform Setup
### macOS
```bash
# Install Xcode Command Line Tools
xcode-select --install
# Optional: Install Homebrew dependencies (auto-detected)
brew install cmake pkg-config
```
### Linux (Ubuntu/Debian)
```bash
sudo apt-get update
sudo apt-get install -y build-essential cmake ninja-build pkg-config \
libgtk-3-dev libdbus-1-dev
```
### Windows
#### Automated Setup (Recommended)
The project includes comprehensive setup scripts for Windows development:
```powershell
# Complete development environment setup
.\scripts\setup-windows-dev.ps1
# Generate Visual Studio project files (with proper vcpkg integration)
python scripts/generate-vs-projects.py
# Test CMake configuration
.\scripts\test-cmake-config.ps1
```
**What the setup script installs:**
- Chocolatey package manager
- CMake 3.16+
- Git, Ninja, Python 3
- Visual Studio 2022 detection and verification
#### Manual Setup Options
**Option 1 - Minimal (CI/Fast Builds):**
- Visual Studio 2019+ with C++ CMake tools
- No additional dependencies needed (all bundled)
**Option 2 - Full Development with vcpkg:**
- Visual Studio 2019+ with C++ CMake tools
- vcpkg package manager for dependency management
#### vcpkg Integration
**Automatic Setup:**
```powershell
# PowerShell
.\scripts\setup-windows-dev.ps1
# Command Prompt
scripts\setup-windows-dev.bat
```
**Manual vcpkg Setup:**
```cmd
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
.\bootstrap-vcpkg.bat
.\vcpkg.exe integrate install
set VCPKG_ROOT=%CD%
```
**Dependencies (vcpkg.json):**
- zlib (compression)
- libpng (PNG support)
- sdl2 (graphics/input with Vulkan support)
**Note**: Abseil and gtest are built from source via CMake rather than through vcpkg to avoid compatibility issues.
#### Windows Build Commands
**Using CMake Presets:**
```cmd
# Debug build (minimal, no tests)
cmake --preset windows-debug
cmake --build build --preset windows-debug
# Development build (includes Google Test)
cmake --preset windows-dev
cmake --build build --preset windows-dev
# Release build (optimized, no tests)
cmake --preset windows-release
cmake --build build --preset windows-release
```
**Using Visual Studio Projects:**
```powershell
# Generate project files (with proper vcpkg integration)
python scripts/generate-vs-projects.py
# Open YAZE.sln in Visual Studio
# Select configuration (Debug/Release) and platform (x64/x86/ARM64)
# Press F5 to build and run
```
**Build Types:**
- **windows-debug**: Minimal debug build, no Google Test
- **windows-dev**: Development build with Google Test and ROM testing
- **windows-release**: Optimized release build, no Google Test
## Build Targets
### Applications
- **yaze**: Main GUI editor application
- **z3ed**: Command-line interface tool
### Libraries
- **yaze_c**: C API library for extensions
- **asar-static**: 65816 assembler library
### Development (Debug Builds Only)
- **yaze_emu**: Standalone SNES emulator
- **yaze_test**: Comprehensive test suite
## Build Configurations
### Debug (Full Features)
```bash
cmake --preset debug # macOS
# OR
cmake -B build -DCMAKE_BUILD_TYPE=Debug # All platforms
```
**Includes**: NFD, ImGuiTestEngine, PNG support, emulator, all tools
### Minimal (CI/Fast Builds)
```bash
cmake -B build -DYAZE_MINIMAL_BUILD=ON
```
**Excludes**: Emulator, CLI tools, UI tests, optional dependencies
### Release
```bash
cmake --preset release # macOS
# OR
cmake -B build -DCMAKE_BUILD_TYPE=Release # All platforms
```
## IDE Integration
### Visual Studio (Windows)
**Recommended approach:**
```powershell
# Setup development environment
.\scripts\setup-windows-dev.ps1
# Generate Visual Studio project files (with proper vcpkg integration)
python scripts/generate-vs-projects.py
# Open YAZE.sln in Visual Studio 2022
# Select configuration (Debug/Release) and platform (x64/x86/ARM64)
# Press F5 to build and run
```
**Features:**
- Full IntelliSense support
- Integrated debugging
- Automatic vcpkg dependency management (zlib, libpng, SDL2)
- Multi-platform support (x64, ARM64)
- Automatic asset copying
- Generated project files stay in sync with CMake configuration
### VS Code
1. Install CMake Tools extension
2. Open project, select "Debug" preset
3. Language server uses `compile_commands.json` automatically
### CLion
- Opens CMake projects directly
- Select Debug configuration
### Xcode (macOS)
```bash
cmake --preset debug -G Xcode
open build/yaze.xcodeproj
```
## Windows Development Scripts
The project includes several PowerShell and Batch scripts to streamline Windows development:
### Setup Scripts
- **`setup-windows-dev.ps1`**: Complete development environment setup
- **`setup-windows-dev.bat`**: Batch version of setup script
**What they install:**
- Chocolatey package manager
- CMake 3.16+
- Git, Ninja, Python 3
- Visual Studio 2022 detection
### Project Generation Scripts
- **`generate-vs-projects.py`**: Generate Visual Studio project files with proper vcpkg integration
- **`generate-vs-projects.bat`**: Batch version of project generation
**Features:**
- Automatic CMake detection and installation
- Visual Studio 2022 detection
- Multi-architecture support (x64, ARM64)
- vcpkg integration
- CMake compatibility fixes
### Testing Scripts
- **`test-cmake-config.ps1`**: Test CMake configuration without full build
**Usage:**
```powershell
# Test configuration
.\scripts\test-cmake-config.ps1
# Test with specific architecture
.\scripts\test-cmake-config.ps1 -Architecture x86
# Clean test build
.\scripts\test-cmake-config.ps1 -Clean
```
## Features by Build Type
| Feature | Debug | Release | Minimal (CI) |
|---------|-------|---------|--------------|
| GUI Editor | ✅ | ✅ | ✅ |
| Native File Dialogs | ✅ | ✅ | ❌ |
| PNG Support | ✅ | ✅ | ❌ |
| Emulator | ✅ | ✅ | ❌ |
| CLI Tools | ✅ | ✅ | ❌ |
| Test Suite | ✅ | ❌ | ✅ (limited) |
| UI Testing | ✅ | ❌ | ❌ |
## CMake Compatibility
### Submodule Compatibility Issues
YAZE includes several submodules (abseil-cpp, SDL) that may have CMake compatibility issues. The project automatically handles these with:
**Automatic Policy Management:**
- `CMAKE_POLICY_VERSION_MINIMUM=3.5` (handles SDL requirements)
- `CMAKE_POLICY_VERSION_MAXIMUM=3.28` (prevents future issues)
- `CMAKE_WARN_DEPRECATED=OFF` (suppresses submodule warnings)
- `ABSL_PROPAGATE_CXX_STD=ON` (handles Abseil C++ standard propagation)
- `THREADS_PREFER_PTHREAD_FLAG=OFF` (fixes Windows pthread issues)
**Manual Configuration (if needed):**
```bash
cmake -B build \
-DCMAKE_POLICY_VERSION_MINIMUM=3.5 \
-DCMAKE_POLICY_VERSION_MAXIMUM=3.28 \
-DCMAKE_WARN_DEPRECATED=OFF \
-DABSL_PROPAGATE_CXX_STD=ON \
-DTHREADS_PREFER_PTHREAD_FLAG=OFF \
-DCMAKE_BUILD_TYPE=Debug
```
## CI/CD and Release Builds
### GitHub Actions Workflows
The project includes three release workflows with different levels of complexity:
- **`release-simplified.yml`**: Fast, basic release builds
- **`release.yml`**: Standard release builds with fallback mechanisms
- **`release-complex.yml`**: Comprehensive release builds with multiple fallback strategies
### vcpkg Fallback Mechanisms
All Windows CI/CD builds include automatic fallback mechanisms:
**When vcpkg succeeds:**
- Full build with all dependencies (zlib, libpng, SDL2)
- Complete feature set available
**When vcpkg fails (network issues):**
- Automatic fallback to minimal build configuration
- Uses source-built dependencies (Abseil, etc.)
- Still produces functional executables
### Supported Architectures
**Windows:**
- x64 (64-bit) - Primary target for modern systems
- ARM64 - For ARM-based Windows devices (Surface Pro X, etc.)
**macOS:**
- Universal binary (Apple Silicon + Intel)
**Linux:**
- x64 (64-bit)
## Troubleshooting
### Windows CMake Issues
**CMake Not Found:**
```powershell
# Run the setup script
.\scripts\setup-windows-dev.ps1
# Or install manually via Chocolatey
choco install cmake
```
**Submodule Compatibility Errors:**
```powershell
# Test CMake configuration
.\scripts\test-cmake-config.ps1
# Clean build with compatibility flags
Remove-Item -Recurse -Force build
cmake -B build -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -DCMAKE_WARN_DEPRECATED=OFF
```
**Visual Studio Project Issues:**
```powershell
# Regenerate project files
.\scripts\generate-vs-projects.ps1
# Clean and rebuild
Remove-Item -Recurse -Force build
cmake --preset windows-debug
```
### vcpkg Issues
**Dependencies Not Installing:**
```cmd
# Check vcpkg installation
vcpkg version
# Reinstall dependencies
vcpkg install --triplet x64-windows zlib libpng sdl2
# Check installed packages
vcpkg list
```
**Network/Download Failures:**
- The CI/CD workflows automatically fall back to minimal builds
- For local development, ensure stable internet connection
- If vcpkg consistently fails, use minimal build mode:
```bash
cmake -B build -DYAZE_MINIMAL_BUILD=ON
```
**Visual Studio Integration:**
```cmd
# Re-integrate vcpkg
cd C:\vcpkg
.\vcpkg.exe integrate install
```
**ZLIB or Other Dependencies Not Found:**
```bash
# Regenerate project files with proper vcpkg integration
python scripts/generate-vs-projects.py
# Ensure vcpkg is properly set up
.\scripts\setup-windows-dev.ps1
```
### Architecture Errors (macOS)
```bash
# Clean and use ARM64-only preset
rm -rf build
cmake --preset debug # Uses arm64 only
```
### Missing Headers (Language Server)
```bash
# Regenerate compile commands
cmake --preset debug
cp build/compile_commands.json .
# Restart VS Code
```
### CI Build Failures
Use minimal build configuration that matches CI:
```bash
cmake -B build -DYAZE_MINIMAL_BUILD=ON -DYAZE_ENABLE_UI_TESTS=OFF
cmake --build build
```
### Common Error Solutions
**"CMake Deprecation Warning" from submodules:**
- This is automatically handled by the project's CMake configuration
- If you see these warnings, they can be safely ignored
**"pthread_create not found" on Windows:**
- The project automatically sets `THREADS_PREFER_PTHREAD_FLAG=OFF`
- This is normal for Windows builds
**"Abseil C++ std propagation" warnings:**
- Automatically handled with `ABSL_PROPAGATE_CXX_STD=ON`
- Ensures proper C++ standard handling
**Visual Studio "file not found" errors:**
- Run `python scripts/generate-vs-projects.py` to regenerate project files
- Ensure CMake configuration completed successfully first
**CI/CD Build Failures:**
- Check if vcpkg download failed (network issues)
- The workflows automatically fall back to minimal builds
- For persistent issues, check the workflow logs for specific error messages

141
docs/03-asar-integration.md Normal file
View File

@@ -0,0 +1,141 @@
# Asar 65816 Assembler Integration
Complete cross-platform ROM patching with assembly code support, symbol extraction, and validation.
## Quick Examples
### Command Line
```bash
# Apply assembly patch to ROM
z3ed asar my_patch.asm --rom=zelda3.sfc
# Extract symbols without patching
z3ed extract my_patch.asm
# Validate assembly syntax
z3ed validate my_patch.asm
```
### C++ API
```cpp
#include "app/core/asar_wrapper.h"
yaze::app::core::AsarWrapper wrapper;
wrapper.Initialize();
// Apply patch to ROM
auto result = wrapper.ApplyPatch("patch.asm", rom_data);
if (result.ok() && result->success) {
for (const auto& symbol : result->symbols) {
std::cout << symbol.name << " @ $" << std::hex << symbol.address << std::endl;
}
}
```
## Assembly Patch Examples
### Basic Hook
```assembly
org $008000
custom_hook:
sei ; Disable interrupts
rep #$30 ; 16-bit A and X/Y
; Your custom code
lda #$1234
sta $7E0000
rts
custom_data:
db "YAZE", $00
dw $1234, $5678
```
### Advanced Features
```assembly
!player_health = $7EF36C
!custom_ram = $7E2000
macro save_context()
pha : phx : phy
endmacro
org $008000
advanced_hook:
%save_context()
sep #$20
lda #$A0 ; Full health
sta !player_health
%save_context()
rtl
```
## API Reference
### AsarWrapper Class
```cpp
class AsarWrapper {
public:
absl::Status Initialize();
absl::StatusOr<AsarPatchResult> ApplyPatch(
const std::string& patch_path,
std::vector<uint8_t>& rom_data);
absl::StatusOr<std::vector<AsarSymbol>> ExtractSymbols(
const std::string& asm_path);
absl::Status ValidateAssembly(const std::string& asm_path);
};
```
### Data Structures
```cpp
struct AsarSymbol {
std::string name; // Symbol name
uint32_t address; // Memory address
std::string opcode; // Associated opcode
std::string file; // Source file
int line; // Line number
};
struct AsarPatchResult {
bool success; // Whether patch succeeded
std::vector<std::string> errors; // Error messages
std::vector<AsarSymbol> symbols; // Extracted symbols
uint32_t rom_size; // Final ROM size
};
```
## Testing
### ROM-Dependent Tests
```cpp
YAZE_ROM_TEST(AsarIntegration, RealRomPatching) {
auto rom_data = TestRomManager::LoadTestRom();
AsarWrapper wrapper;
wrapper.Initialize();
auto result = wrapper.ApplyPatch("test.asm", rom_data);
EXPECT_TRUE(result.ok());
}
```
ROM tests are automatically skipped in CI with `--label-exclude ROM_DEPENDENT`.
## Error Handling
| Error | Cause | Solution |
|-------|-------|----------|
| `Unknown command` | Invalid opcode | Check 65816 instruction reference |
| `Label not found` | Undefined label | Define the label or check spelling |
| `Invalid hex value` | Bad hex format | Use `$1234` format |
| `Buffer too small` | ROM needs expansion | Check if ROM needs to be larger |
## Development Workflow
1. **Write assembly patch**
2. **Validate syntax**: `z3ed validate patch.asm`
3. **Extract symbols**: `z3ed extract patch.asm`
4. **Apply to test ROM**: `z3ed asar patch.asm --rom=test.sfc`
5. **Test in emulator**

208
docs/04-api-reference.md Normal file
View File

@@ -0,0 +1,208 @@
# API Reference
Comprehensive reference for the YAZE C API and C++ interfaces.
## C API (`incl/yaze.h`, `incl/zelda.h`)
### Core Library Functions
```c
// Initialization
yaze_status yaze_library_init(void);
void yaze_library_shutdown(void);
// Version management
const char* yaze_get_version_string(void);
int yaze_get_version_number(void);
bool yaze_check_version_compatibility(const char* expected_version);
// Status utilities
const char* yaze_status_to_string(yaze_status status);
```
### ROM Operations
```c
// ROM loading and management
zelda3_rom* yaze_load_rom(const char* filename);
void yaze_unload_rom(zelda3_rom* rom);
yaze_status yaze_save_rom(zelda3_rom* rom, const char* filename);
bool yaze_is_rom_modified(const zelda3_rom* rom);
```
### Graphics Operations
```c
// SNES color management
snes_color yaze_rgb_to_snes_color(uint8_t r, uint8_t g, uint8_t b);
void yaze_snes_color_to_rgb(snes_color color, uint8_t* r, uint8_t* g, uint8_t* b);
// Bitmap operations
yaze_bitmap* yaze_create_bitmap(int width, int height, uint8_t bpp);
void yaze_free_bitmap(yaze_bitmap* bitmap);
```
### Palette System
```c
// Palette creation and management
snes_palette* yaze_create_palette(uint8_t id, uint8_t size);
void yaze_free_palette(snes_palette* palette);
snes_palette* yaze_load_palette_from_rom(const zelda3_rom* rom, uint8_t palette_id);
```
### Message System
```c
// Message handling
zelda3_message* yaze_load_message(const zelda3_rom* rom, uint16_t message_id);
void yaze_free_message(zelda3_message* message);
yaze_status yaze_save_message(zelda3_rom* rom, const zelda3_message* message);
```
## C++ API
### AsarWrapper (`src/app/core/asar_wrapper.h`)
```cpp
namespace yaze::app::core {
class AsarWrapper {
public:
// Initialization
absl::Status Initialize();
void Shutdown();
bool IsInitialized() const;
// Core functionality
absl::StatusOr<AsarPatchResult> ApplyPatch(
const std::string& patch_path,
std::vector<uint8_t>& rom_data,
const std::vector<std::string>& include_paths = {});
absl::StatusOr<std::vector<AsarSymbol>> ExtractSymbols(
const std::string& asm_path,
const std::vector<std::string>& include_paths = {});
// Symbol management
std::optional<AsarSymbol> FindSymbol(const std::string& name);
std::vector<AsarSymbol> GetSymbolsAtAddress(uint32_t address);
std::map<std::string, AsarSymbol> GetSymbolTable();
// Utility functions
absl::Status ValidateAssembly(const std::string& asm_path);
std::string GetVersion();
void Reset();
};
}
```
### Data Structures
#### ROM Version Support
```c
typedef enum zelda3_version {
ZELDA3_VERSION_US = 1,
ZELDA3_VERSION_JP = 2,
ZELDA3_VERSION_SD = 3,
ZELDA3_VERSION_RANDO = 4,
// Legacy aliases maintained for compatibility
US = ZELDA3_VERSION_US,
JP = ZELDA3_VERSION_JP,
SD = ZELDA3_VERSION_SD,
RANDO = ZELDA3_VERSION_RANDO,
} zelda3_version;
```
#### SNES Graphics
```c
typedef struct snes_color {
uint16_t raw; // Raw 15-bit SNES color
uint8_t red; // Red component (0-31)
uint8_t green; // Green component (0-31)
uint8_t blue; // Blue component (0-31)
} snes_color;
typedef struct snes_palette {
uint8_t id; // Palette ID
uint8_t size; // Number of colors
snes_color* colors; // Color array
} snes_palette;
```
#### Message System
```c
typedef struct zelda3_message {
uint16_t id; // Message ID (0-65535)
uint32_t rom_address; // Address in ROM
uint16_t length; // Length in bytes
uint8_t* raw_data; // Raw ROM data
char* parsed_text; // Decoded UTF-8 text
bool is_compressed; // Compression flag
uint8_t encoding_type; // Encoding type
} zelda3_message;
```
## Error Handling
### Status Codes
```c
typedef enum yaze_status {
YAZE_OK = 0, // Success
YAZE_ERROR_UNKNOWN = -1, // Unknown error
YAZE_ERROR_INVALID_ARG = 1, // Invalid argument
YAZE_ERROR_FILE_NOT_FOUND = 2, // File not found
YAZE_ERROR_MEMORY = 3, // Memory allocation failed
YAZE_ERROR_IO = 4, // I/O operation failed
YAZE_ERROR_CORRUPTION = 5, // Data corruption detected
YAZE_ERROR_NOT_INITIALIZED = 6, // Component not initialized
} yaze_status;
```
### Error Handling Pattern
```c
yaze_status status = yaze_library_init();
if (status != YAZE_OK) {
printf("Failed to initialize YAZE: %s\n", yaze_status_to_string(status));
return 1;
}
zelda3_rom* rom = yaze_load_rom("zelda3.sfc");
if (rom == nullptr) {
printf("Failed to load ROM file\n");
return 1;
}
// Use ROM...
yaze_unload_rom(rom);
yaze_library_shutdown();
```
## Extension System
### Plugin Architecture
```c
typedef struct yaze_extension {
const char* name; // Extension name
const char* version; // Version string
const char* description; // Description
const char* author; // Author
int api_version; // Required API version
yaze_status (*initialize)(yaze_editor_context* context);
void (*cleanup)(void);
uint32_t (*get_capabilities)(void);
} yaze_extension;
```
### Capability Flags
```c
#define YAZE_EXT_CAP_ROM_EDITING 0x0001 // ROM modification
#define YAZE_EXT_CAP_GRAPHICS 0x0002 // Graphics operations
#define YAZE_EXT_CAP_AUDIO 0x0004 // Audio processing
#define YAZE_EXT_CAP_SCRIPTING 0x0008 // Scripting support
#define YAZE_EXT_CAP_IMPORT_EXPORT 0x0010 // Data import/export
```
## Backward Compatibility
All existing code continues to work without modification due to:
- Legacy enum aliases (`US`, `JP`, `SD`, `RANDO`)
- Original struct field names maintained
- Duplicate field definitions for old/new naming conventions
- Typedef aliases for renamed types

173
docs/A1-testing-guide.md Normal file
View File

@@ -0,0 +1,173 @@
# Testing Guide
Comprehensive testing framework with efficient CI/CD integration and ROM-dependent test separation.
## Test Categories
### Stable Tests (STABLE)
**Always run in CI/CD - Required for releases**
- **AsarWrapperTest**: Core Asar functionality tests
- **SnesTileTest**: SNES tile format handling
- **CompressionTest**: Data compression/decompression
- **SnesPaletteTest**: SNES palette operations
- **HexTest**: Hexadecimal utilities
- **AsarIntegrationTest**: Asar integration without ROM dependencies
**Characteristics:**
- Fast execution (< 30 seconds total)
- No external dependencies (ROMs, complex setup)
- High reliability and deterministic results
### ROM-Dependent Tests (ROM_DEPENDENT)
**Only run in development with available ROM files**
- **AsarRomIntegrationTest**: Real ROM patching and symbol extraction
- **ROM-based integration tests**: Tests requiring actual game ROM files
**Characteristics:**
- Require specific ROM files to be present
- Test real-world functionality
- Automatically skipped in CI if ROM files unavailable
### Experimental Tests (EXPERIMENTAL)
**Run separately, allowed to fail**
- **CpuTest**: 65816 CPU emulation tests
- **Spc700Test**: SPC700 audio processor tests
- **ApuTest**: Audio Processing Unit tests
- **PpuTest**: Picture Processing Unit tests
**Characteristics:**
- May be unstable due to emulation complexity
- Test advanced/experimental features
- Allowed to fail without blocking releases
## Command Line Usage
```bash
# Run only stable tests (release-ready)
ctest --test-dir build --label-regex "STABLE"
# Run experimental tests (allowed to fail)
ctest --test-dir build --label-regex "EXPERIMENTAL"
# Run Asar-specific tests
ctest --test-dir build -R "*Asar*"
# Run tests excluding ROM-dependent ones
ctest --test-dir build --label-exclude "ROM_DEPENDENT"
# Run with specific preset
ctest --preset stable
ctest --preset experimental
```
## CMake Presets
```bash
# Development workflow
cmake --preset dev
cmake --build --preset dev
ctest --preset dev
# CI workflow
cmake --preset ci
cmake --build --preset ci
ctest --preset ci
# Release workflow
cmake --preset release
cmake --build --preset release
ctest --preset stable
```
## Writing Tests
### Stable Tests
```cpp
TEST(SnesTileTest, UnpackBppTile) {
std::vector<uint8_t> tile_data = {0xAA, 0x55, 0xAA, 0x55};
std::vector<uint8_t> result = UnpackBppTile(tile_data, 2);
EXPECT_EQ(result.size(), 64);
// Test specific pixel values...
}
```
### ROM-Dependent Tests
```cpp
YAZE_ROM_TEST(AsarIntegration, RealRomPatching) {
auto rom_data = TestRomManager::LoadTestRom();
if (!rom_data.has_value()) {
GTEST_SKIP() << "ROM file not available";
}
AsarWrapper wrapper;
wrapper.Initialize();
auto result = wrapper.ApplyPatch("test.asm", *rom_data);
EXPECT_TRUE(result.ok());
}
```
### Experimental Tests
```cpp
TEST(CpuTest, InstructionExecution) {
// Complex emulation tests
// May be timing-sensitive or platform-dependent
}
```
## CI/CD Integration
### GitHub Actions
```yaml
# Main CI pipeline
- name: Run Stable Tests
run: ctest --label-regex "STABLE"
# Experimental tests (allowed to fail)
- name: Run Experimental Tests
run: ctest --label-regex "EXPERIMENTAL"
continue-on-error: true
```
### Test Execution Strategy
1. **Stable tests run first** - Quick feedback for developers
2. **Experimental tests run in parallel** - Don't block on unstable tests
3. **ROM tests skipped** - No dependency on external files
4. **Selective test execution** - Only run relevant tests for changes
## Test Development Guidelines
### Writing Stable Tests
- **Fast execution**: Aim for < 1 second per test
- **No external dependencies**: Self-contained test data
- **Deterministic**: Same results every run
- **Core functionality**: Test essential features only
### Writing ROM-Dependent Tests
- **Use TestRomManager**: Proper ROM file handling
- **Graceful skipping**: Skip if ROM not available
- **Real-world scenarios**: Test with actual game data
- **Label appropriately**: Always include ROM_DEPENDENT label
### Writing Experimental Tests
- **Complex scenarios**: Multi-component integration
- **Advanced features**: Emulation, complex algorithms
- **Performance tests**: May vary by system
- **GUI components**: May require display context
## Performance and Maintenance
### Regular Review
- **Monthly review** of experimental test failures
- **Promote stable experimental tests** to stable category
- **Deprecate obsolete tests** that no longer provide value
- **Update test categorization** as features mature
### Performance Monitoring
- **Track test execution times** for CI efficiency
- **Identify slow tests** for optimization or recategorization
- **Monitor CI resource usage** and adjust parallelism
- **Benchmark critical path tests** for performance regression

239
docs/B1-contributing.md Normal file
View File

@@ -0,0 +1,239 @@
# Contributing
Guidelines for contributing to the YAZE project.
## Development Setup
### Prerequisites
- **CMake 3.16+**: Modern build system
- **C++23 Compiler**: GCC 13+, Clang 16+, MSVC 2022 17.8+
- **Git**: Version control with submodules
### Quick Start
```bash
# Clone with submodules
git clone --recursive https://github.com/scawful/yaze.git
cd yaze
# Build with presets
cmake --preset dev
cmake --build --preset dev
# Run tests
ctest --preset stable
```
## Code Style
### C++ Standards
- **C++23**: Use modern language features
- **Google C++ Style**: Follow Google C++ style guide
- **Naming**: Use descriptive names, avoid abbreviations
### File Organization
```cpp
// Header guards
#pragma once
// Includes (system, third-party, local)
#include <vector>
#include "absl/status/status.h"
#include "app/core/asar_wrapper.h"
// Namespace usage
namespace yaze::app::editor {
class ExampleClass {
public:
// Public interface
absl::Status Initialize();
private:
// Private implementation
std::vector<uint8_t> data_;
};
}
```
### Error Handling
```cpp
// Use absl::Status for error handling
absl::Status LoadRom(const std::string& filename) {
if (filename.empty()) {
return absl::InvalidArgumentError("Filename cannot be empty");
}
// ... implementation
return absl::OkStatus();
}
// Use absl::StatusOr for operations that return values
absl::StatusOr<std::vector<uint8_t>> ReadFile(const std::string& filename);
```
## Testing Requirements
### Test Categories
- **Stable Tests**: Fast, reliable, no external dependencies
- **ROM-Dependent Tests**: Require ROM files, skip in CI
- **Experimental Tests**: Complex, may be unstable
### Writing Tests
```cpp
// Stable test example
TEST(SnesTileTest, UnpackBppTile) {
std::vector<uint8_t> tile_data = {0xAA, 0x55};
auto result = UnpackBppTile(tile_data, 2);
EXPECT_TRUE(result.ok());
EXPECT_EQ(result->size(), 64);
}
// ROM-dependent test example
YAZE_ROM_TEST(AsarIntegration, RealRomPatching) {
auto rom_data = TestRomManager::LoadTestRom();
if (!rom_data.has_value()) {
GTEST_SKIP() << "ROM file not available";
}
// ... test implementation
}
```
### Test Execution
```bash
# Run stable tests (required)
ctest --label-regex "STABLE"
# Run experimental tests (optional)
ctest --label-regex "EXPERIMENTAL"
# Run specific test
ctest -R "AsarWrapperTest"
```
## Pull Request Process
### Before Submitting
1. **Run tests**: Ensure all stable tests pass
2. **Check formatting**: Use clang-format
3. **Update documentation**: Update relevant docs if needed
4. **Test on multiple platforms**: Verify cross-platform compatibility
### Pull Request Template
```markdown
## Description
Brief description of changes
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Testing
- [ ] Stable tests pass
- [ ] Manual testing completed
- [ ] Cross-platform testing (if applicable)
## Checklist
- [ ] Code follows project style guidelines
- [ ] Self-review completed
- [ ] Documentation updated
- [ ] Tests added/updated
```
## Development Workflow
### Branch Strategy
- **main**: Stable, release-ready code
- **feature/**: New features and enhancements
- **fix/**: Bug fixes
- **docs/**: Documentation updates
### Commit Messages
```
type(scope): brief description
Detailed explanation of changes, including:
- What was changed
- Why it was changed
- Any breaking changes
Fixes #issue_number
```
### Types
- **feat**: New features
- **fix**: Bug fixes
- **docs**: Documentation changes
- **style**: Code style changes
- **refactor**: Code refactoring
- **test**: Test additions/changes
- **chore**: Build/tooling changes
## Architecture Guidelines
### Component Design
- **Single Responsibility**: Each class should have one clear purpose
- **Dependency Injection**: Use dependency injection for testability
- **Interface Segregation**: Keep interfaces focused and minimal
### Memory Management
- **RAII**: Use RAII for resource management
- **Smart Pointers**: Prefer unique_ptr and shared_ptr
- **Avoid Raw Pointers**: Use smart pointers or references
### Performance
- **Profile Before Optimizing**: Measure before optimizing
- **Use Modern C++**: Leverage C++23 features for performance
- **Avoid Premature Optimization**: Focus on correctness first
## Documentation
### Code Documentation
- **Doxygen Comments**: Use Doxygen format for public APIs
- **Inline Comments**: Explain complex logic
- **README Updates**: Update relevant README files
### API Documentation
```cpp
/**
* @brief Applies an assembly patch to ROM data
* @param patch_path Path to the assembly patch file
* @param rom_data ROM data to patch (modified in place)
* @param include_paths Optional include paths for assembly
* @return Result containing success status and extracted symbols
* @throws std::invalid_argument if patch_path is empty
*/
absl::StatusOr<AsarPatchResult> ApplyPatch(
const std::string& patch_path,
std::vector<uint8_t>& rom_data,
const std::vector<std::string>& include_paths = {});
```
## Community Guidelines
### Communication
- **Be Respectful**: Treat all contributors with respect
- **Be Constructive**: Provide helpful feedback
- **Be Patient**: Remember that everyone is learning
### Getting Help
- **GitHub Issues**: Report bugs and request features
- **Discussions**: Ask questions and discuss ideas
- **Discord**: [Oracle of Secrets Discord](https://discord.gg/MBFkMTPEmk)
## Release Process
### Version Numbering
- **Semantic Versioning**: MAJOR.MINOR.PATCH
- **v0.3.1**: Current stable release
- **Pre-release**: v0.4.0-alpha, v0.4.0-beta
### Release Checklist
- [ ] All stable tests pass
- [ ] Documentation updated
- [ ] Changelog updated
- [ ] Cross-platform builds verified
- [ ] Release notes prepared

View File

@@ -0,0 +1,55 @@
# Platform Compatibility Improvements
Recent improvements to ensure YAZE works reliably across all supported platforms.
## Native File Dialog Support
YAZE now features native file dialogs on all platforms:
- **macOS**: Cocoa-based file selection with proper sandboxing support
- **Windows**: Windows Explorer integration with COM APIs
- **Linux**: GTK3 dialogs that match system appearance
- **Fallback**: Bespoke implementation when native dialogs unavailable
## Cross-Platform Build Reliability
Enhanced build system ensures consistent compilation:
- **Windows**: Resolved MSVC compatibility issues and dependency conflicts
- **Linux**: Fixed standard library compatibility for older distributions
- **macOS**: Proper support for both Intel and Apple Silicon architectures
- **All Platforms**: Bundled dependencies eliminate external package requirements
## Build Configuration Options
YAZE supports different build configurations for various use cases:
### Full Build (Development)
Includes all features: emulator, CLI tools, UI testing framework, and optional libraries.
### Minimal Build
Streamlined build excluding complex components, optimized for automated testing and CI environments.
## Implementation Details
The build system automatically detects platform capabilities and adjusts feature sets accordingly:
- **File Dialogs**: Uses native platform dialogs when available, with cross-platform fallbacks
- **Dependencies**: Bundles all required libraries to eliminate external package requirements
- **Testing**: Separates ROM-dependent tests from unit tests for CI compatibility
- **Architecture**: Supports both Intel and Apple Silicon on macOS without conflicts
## Platform-Specific Adaptations
### Windows
- Complete COM-based file dialog implementation
- MSVC compatibility improvements for modern C++ features
- Resource file handling for proper application integration
### macOS
- Cocoa-based native file dialogs with sandboxing support
- Universal binary support for Intel and Apple Silicon
- Proper bundle configuration for macOS applications
### Linux
- GTK3 integration for native file dialogs
- Package manager integration for system dependencies
- Support for multiple compiler toolchains (GCC, Clang)

109
docs/B3-build-presets.md Normal file
View File

@@ -0,0 +1,109 @@
# Build Presets Guide
CMake presets for development workflow and architecture-specific builds.
## 🍎 macOS ARM64 Presets (Recommended for Apple Silicon)
### For Development Work:
```bash
# ARM64-only development build with ROM testing
cmake --preset macos-dev
cmake --build --preset macos-dev
# ARM64-only debug build
cmake --preset macos-debug
cmake --build --preset macos-debug
# ARM64-only release build
cmake --preset macos-release
cmake --build --preset macos-release
```
### For Distribution:
```bash
# Universal binary (ARM64 + x86_64) - use only when needed for distribution
cmake --preset macos-debug-universal
cmake --build --preset macos-debug-universal
cmake --preset macos-release-universal
cmake --build --preset macos-release-universal
```
## 🔧 Why This Fixes Architecture Errors
**Problem**: The original presets used `CMAKE_OSX_ARCHITECTURES: "x86_64;arm64"` which forced CMake to build universal binaries. This caused issues because:
- Dependencies like Abseil tried to use x86 SSE instructions (`-msse4.1`)
- These instructions don't exist on ARM64 processors
- Build failed with "unsupported option '-msse4.1' for target 'arm64-apple-darwin'"
**Solution**: The new ARM64-only presets use `CMAKE_OSX_ARCHITECTURES: "arm64"` which:
- ✅ Only targets ARM64 architecture
- ✅ Prevents x86-specific instruction usage
- ✅ Uses ARM64 optimizations instead
- ✅ Builds much faster (no cross-compilation)
## 📋 Available Presets
| Preset Name | Architecture | Purpose | ROM Tests |
|-------------|-------------|---------|-----------|
| `macos-dev` | ARM64 only | Development | ✅ Enabled |
| `macos-debug` | ARM64 only | Debug builds | ❌ Disabled |
| `macos-release` | ARM64 only | Release builds | ❌ Disabled |
| `macos-debug-universal` | Universal | Distribution debug | ❌ Disabled |
| `macos-release-universal` | Universal | Distribution release | ❌ Disabled |
## 🚀 Quick Start
For most development work on Apple Silicon:
```bash
# Clean build
rm -rf build
# Configure for ARM64 development
cmake --preset macos-dev
# Build
cmake --build --preset macos-dev
# Run tests
cmake --build --preset macos-dev --target test
```
## 🛠️ IDE Integration
### VS Code with CMake Tools:
1. Open Command Palette (`Cmd+Shift+P`)
2. Run "CMake: Select Configure Preset"
3. Choose `macos-dev` or `macos-debug`
### CLion:
1. Go to Settings → Build, Execution, Deployment → CMake
2. Add new profile with preset `macos-dev`
### Xcode:
```bash
# Generate Xcode project
cmake --preset macos-debug -G Xcode
open build/yaze.xcodeproj
```
## 🔍 Troubleshooting
If you still get architecture errors:
1. **Clean completely**: `rm -rf build`
2. **Check preset**: Ensure you're using an ARM64 preset (not universal)
3. **Verify configuration**: Check that `CMAKE_OSX_ARCHITECTURES` shows only `arm64`
```bash
# Verify architecture setting
cmake --preset macos-debug
grep -A 5 -B 5 "CMAKE_OSX_ARCHITECTURES" build/CMakeCache.txt
```
## 📝 Notes
- **ARM64 presets**: Fast builds, no architecture conflicts
- **Universal presets**: Slower builds, for distribution only
- **Deployment target**: ARM64 presets use macOS 11.0+ (when Apple Silicon was introduced)
- **Universal presets**: Still support macOS 10.15+ for backward compatibility

View File

@@ -0,0 +1,308 @@
# Release Workflows Documentation
YAZE uses three different GitHub Actions workflows for creating releases, each designed for specific use cases and reliability levels. This document explains the differences, use cases, and when to use each workflow.
## Overview
| Workflow | Complexity | Reliability | Use Case |
|----------|------------|-------------|----------|
| **release-simplified.yml** | Low | Basic | Quick releases, testing |
| **release.yml** | Medium | High | Standard releases |
| **release-complex.yml** | High | Maximum | Production releases, fallbacks |
---
## 1. Release-Simplified (`release-simplified.yml`)
### Purpose
A streamlined workflow for quick releases and testing scenarios.
### Key Features
- **Minimal Configuration**: Basic build setup with standard dependencies
- **No Fallback Mechanisms**: Direct dependency installation without error handling
- **Standard vcpkg**: Uses fixed vcpkg commit without fallback options
- **Basic Testing**: Simple executable verification
### Use Cases
- **Development Testing**: Testing release process during development
- **Beta Releases**: Quick beta or alpha releases
- **Hotfixes**: Emergency releases that need to be deployed quickly
- **CI/CD Validation**: Ensuring the basic release process works
### Configuration
```yaml
# Standard vcpkg setup
vcpkgGitCommitId: 'c8696863d371ab7f46e213d8f5ca923c4aef2a00'
# No fallback mechanisms
# Basic dependency installation
```
### Platforms Supported
- Windows (x64, x86, ARM64)
- macOS Universal
- Linux x64
---
## 2. Release (`release.yml`)
### Purpose
The standard production release workflow with enhanced reliability.
### Key Features
- **Enhanced vcpkg**: Updated baseline and improved dependency management
- **Better Error Handling**: More robust error reporting and debugging
- **Comprehensive Testing**: Extended executable validation and artifact verification
- **Production Ready**: Designed for stable releases
### Use Cases
- **Stable Releases**: Official stable version releases
- **Feature Releases**: Major feature releases with full testing
- **Release Candidates**: Pre-release candidates for testing
### Configuration
```yaml
# Updated vcpkg baseline
builtin-baseline: "2024.12.12"
# Enhanced error handling
# Comprehensive testing
```
### Advantages over Simplified
- More reliable dependency resolution
- Better error reporting
- Enhanced artifact validation
- Production-grade stability
---
## 3. Release-Complex (`release-complex.yml`)
### Purpose
Maximum reliability release workflow with comprehensive fallback mechanisms.
### Key Features
- **Advanced Fallback System**: Multiple dependency installation strategies
- **vcpkg Failure Handling**: Automatic fallback to manual dependency installation
- **Chocolatey Integration**: Windows package manager fallback
- **Comprehensive Debugging**: Extensive logging and error analysis
- **Multiple Build Strategies**: CMake configuration fallbacks
- **Enhanced Validation**: Multi-stage build verification
### Use Cases
- **Production Releases**: Critical production releases requiring maximum reliability
- **Enterprise Deployments**: Releases for enterprise customers
- **Major Version Releases**: Significant version releases (v1.0, v2.0, etc.)
- **Problem Resolution**: When other workflows fail due to dependency issues
### Fallback Mechanisms
#### vcpkg Fallback
```yaml
# Primary: vcpkg installation
- name: Set up vcpkg (Windows)
continue-on-error: true
# Fallback: Manual dependency installation
- name: Install dependencies manually (Windows fallback)
if: steps.vcpkg_setup.outcome == 'failure'
```
#### Chocolatey Integration
```yaml
# Install Chocolatey if not present
if (-not (Get-Command choco -ErrorAction SilentlyContinue)) {
# Install Chocolatey
}
# Install dependencies via Chocolatey
choco install -y cmake ninja git python3
```
#### Build Configuration Fallback
```yaml
# Primary: Full build with vcpkg
cmake -DCMAKE_TOOLCHAIN_FILE="vcpkg.cmake" -DYAZE_MINIMAL_BUILD=OFF
# Fallback: Minimal build without vcpkg
cmake -DYAZE_MINIMAL_BUILD=ON
```
### Advanced Features
- **Multi-stage Validation**: Visual Studio project validation
- **Artifact Verification**: Comprehensive build artifact checking
- **Debug Information**: Extensive logging for troubleshooting
- **Environment Detection**: Automatic environment configuration
---
## Workflow Comparison Matrix
| Feature | Simplified | Release | Complex |
|---------|------------|---------|---------|
| **vcpkg Integration** | Basic | Enhanced | Advanced + Fallback |
| **Error Handling** | Minimal | Standard | Comprehensive |
| **Fallback Mechanisms** | None | Limited | Multiple |
| **Debugging** | Basic | Standard | Extensive |
| **Dependency Management** | Fixed | Updated | Adaptive |
| **Build Validation** | Simple | Enhanced | Multi-stage |
| **Failure Recovery** | None | Limited | Automatic |
| **Production Ready** | No | Yes | Yes |
| **Build Time** | Fast | Medium | Slow |
| **Reliability** | Low | High | Maximum |
---
## When to Use Each Workflow
### Use Simplified When:
- ✅ Testing release process during development
- ✅ Creating beta or alpha releases
- ✅ Quick hotfix releases
- ✅ Validating basic CI/CD functionality
- ✅ Development team testing
### Use Release When:
- ✅ Creating stable production releases
- ✅ Feature releases with full testing
- ✅ Release candidates
- ✅ Standard version releases
- ✅ Most production scenarios
### Use Complex When:
- ✅ Critical production releases
- ✅ Major version releases (v1.0, v2.0)
- ✅ Enterprise customer releases
- ✅ When other workflows fail
- ✅ Maximum reliability requirements
- ✅ Complex dependency scenarios
---
## Workflow Selection Guide
### For Development Team
```
Development → Simplified
Testing → Release
Production → Complex
```
### For Release Manager
```
Hotfix → Simplified
Feature Release → Release
Major Release → Complex
```
### For CI/CD Pipeline
```
PR Validation → Simplified
Nightly Builds → Release
Release Pipeline → Complex
```
---
## Configuration Examples
### Triggering a Release
#### Manual Release (All Workflows)
```bash
# Using workflow_dispatch
gh workflow run release.yml -f tag=v0.3.0
gh workflow run release-simplified.yml -f tag=v0.3.0-beta
gh workflow run release-complex.yml -f tag=v1.0.0
```
#### Automatic Release (Tag Push)
```bash
# Creates release automatically
git tag v0.3.0
git push origin v0.3.0
```
### Customizing Release Notes
All workflows support automatic changelog extraction:
```bash
# Extract changelog for version
python3 scripts/extract_changelog.py "0.3.0" > release_notes.md
```
---
## Troubleshooting
### Common Issues
#### vcpkg Failures (Windows)
- **Simplified**: Fails completely
- **Release**: Basic error reporting
- **Complex**: Automatic fallback to manual installation
#### Dependency Conflicts
- **Simplified**: Manual intervention required
- **Release**: Enhanced error reporting
- **Complex**: Multiple resolution strategies
#### Build Failures
- **Simplified**: Basic error output
- **Release**: Enhanced debugging
- **Complex**: Comprehensive failure analysis
### Debug Information
#### Simplified Workflow
- Basic build output
- Simple error messages
- Minimal logging
#### Release Workflow
- Enhanced error reporting
- Artifact verification
- Build validation
#### Complex Workflow
- Extensive debug output
- Multi-stage validation
- Comprehensive error analysis
- Automatic fallback execution
---
## Best Practices
### Workflow Selection
1. **Start with Simplified** for development and testing
2. **Use Release** for standard production releases
3. **Use Complex** only when maximum reliability is required
### Release Process
1. **Test with Simplified** first
2. **Validate with Release** for production readiness
3. **Use Complex** for critical releases
### Maintenance
1. **Keep all workflows updated** with latest dependency versions
2. **Monitor workflow performance** and adjust as needed
3. **Document any custom modifications** for team knowledge
---
## Future Improvements
### Planned Enhancements
- **Automated Workflow Selection**: Based on release type and criticality
- **Enhanced Fallback Strategies**: Additional dependency resolution methods
- **Performance Optimization**: Reduced build times while maintaining reliability
- **Cross-Platform Consistency**: Unified behavior across all platforms
### Integration Opportunities
- **Release Automation**: Integration with semantic versioning
- **Quality Gates**: Automated quality checks before release
- **Distribution**: Integration with package managers and app stores
---
*This documentation is maintained alongside the YAZE project. For updates or corrections, please refer to the project repository.*

157
docs/C1-changelog.md Normal file
View File

@@ -0,0 +1,157 @@
# Changelog
## 0.3.1
### Major Features
- **Complete Tile16 Editor Overhaul**: Professional-grade tile editing with modern UI and advanced capabilities
- **Advanced Palette Management**: Full access to all SNES palette groups with configurable normalization
- **Comprehensive Undo/Redo System**: 50-state history with intelligent time-based throttling
- **ZSCustomOverworld v3 Full Support**: Complete implementation of ZScream Save.cs functionality with complex transition calculations
- **ZEML System Removal**: Converted overworld editor from markup to pure ImGui for better performance and maintainability
- **OverworldEditorManager**: New management system to handle complex v3 overworld features
### Tile16 Editor Enhancements
- **Modern UI Layout**: Fully resizable 3-column interface (Tile8 Source, Editor, Preview & Controls)
- **Multi-Palette Group Support**: Access to Overworld Main/Aux1/Aux2, Dungeon Main, Global Sprites, Armors, and Swords palettes
- **Advanced Transform Operations**: Flip horizontal/vertical, rotate 90°, fill with tile8, clear operations
- **Professional Workflow**: Copy/paste, 4-slot scratch space, live preview with auto-commit
- **Pixel Normalization Settings**: Configurable pixel value masks (0x01-0xFF) for handling corrupted graphics sheets
### ZSCustomOverworld v3 Implementation
- **SaveLargeMapsExpanded()**: Complex neighbor-aware transition calculations for all area sizes (Small, Large, Wide, Tall)
- **Interactive Overlay System**: Full `SaveMapOverlays()` with ASM code generation for revealing holes and changing map elements
- **SaveCustomOverworldASM()**: Complete custom overworld ASM application with feature toggles and data tables
- **Expanded Memory Support**: Automatic detection and use of v3 expanded memory locations (0x140xxx)
- **Area-Specific Features**: Background colors, main palettes, mosaic transitions, GFX groups, subscreen overlays, animated tiles
- **Transition Logic**: Sophisticated camera transition calculations based on neighboring area types and quadrants
- **Version Compatibility**: Maintains vanilla/v2 compatibility while adding full v3+ feature support
### Technical Improvements
- **SNES Data Accuracy**: Proper 4-bit palette index handling with configurable normalization
- **Bitmap Pipeline Fixes**: Corrected tile16 extraction using `GetTilemapData()` with manual fallback
- **Real-time Updates**: Immediate visual feedback for all editing operations
- **Memory Safety**: Enhanced bounds checking and error handling throughout
- **ASM Version Detection**: Automatic detection of custom overworld ASM version for feature availability
- **Conditional Save Logic**: Different save paths for vanilla, v2, and v3+ ROMs
### User Interface
- **Keyboard Shortcuts**: Comprehensive shortcuts for all operations (H/V/R for transforms, Q/E for palette cycling, 1-8 for direct palette selection)
- **Visual Feedback**: Hover preview restoration, current palette highlighting, texture status indicators
- **Compact Controls**: Streamlined property panel with essential tools easily accessible
- **Settings Dialog**: Advanced palette normalization controls with real-time application
- **Pure ImGui Layout**: Removed ZEML markup system in favor of native ImGui tabs and tables for better performance
- **v3 Settings Panel**: Dedicated UI for ZSCustomOverworld v3 features with ASM version detection and feature toggles
### Bug Fixes
- **Tile16 Bitmap Display**: Fixed blank/white tile issue caused by unnormalized pixel values
- **Hover Preview**: Restored tile8 preview when hovering over tile16 canvas
- **Canvas Scaling**: Corrected coordinate scaling for 8x magnification factor
- **Palette Corruption**: Fixed high-bit contamination in graphics sheets
- **UI Layout**: Proper column sizing and resizing behavior
- **Linux CI/CD Build**: Fixed undefined reference errors for `ShowSaveFileDialog` method
- **ZSCustomOverworld v3**: Fixed complex area transition calculations and neighbor-aware tilemap adjustments
- **ZEML Performance**: Eliminated markup parsing overhead by converting to native ImGui components
### ZScream Compatibility Improvements
- **Complete Save.cs Implementation**: All major methods from ZScream's Save.cs now implemented in YAZE
- **Area Size Support**: Full support for Small, Large, Wide, and Tall area types with proper transitions
- **Interactive Overlays**: Complete overlay save system matching ZScream's functionality
- **Custom ASM Integration**: Proper handling of ZSCustomOverworld ASM versions 1-3+
- **Memory Layout**: Correct usage of expanded vs vanilla memory locations based on ROM type
## 0.3.0 (September 2025)
### Major Features
- **Complete Theme Management System**: 5+ built-in themes with custom theme creation and editing
- **Multi-Session Workspace**: Work with multiple ROMs simultaneously in enhanced docked interface
- **Enhanced Welcome Screen**: Themed interface with quick access to all editors and features
- **Asar 65816 Assembler Integration**: Complete cross-platform ROM patching with assembly code
- **ZSCustomOverworld v3**: Full integration with enhanced overworld editing capabilities
- **Advanced Message Editing**: Enhanced text editing interface with improved parsing and real-time preview
- **GUI Docking System**: Improved docking and workspace management for better user workflow
- **Symbol Extraction**: Extract symbol names and opcodes from assembly files
- **Modernized Build System**: Upgraded to CMake 3.16+ with target-based configuration
### User Interface & Theming
- **Built-in Themes**: Classic YAZE, YAZE Tre, Cyberpunk, Sunset, Forest, and Midnight themes
- **Theme Editor**: Complete custom theme creation with save-to-file functionality
- **Animated Background Grid**: Optional moving grid with color breathing effects
- **Theme Import/Export**: Share custom themes with the community
- **Responsive UI**: All UI elements properly adapt to selected themes
### Enhancements
- **Enhanced CLI Tools**: Improved z3ed with modern command line interface and TUI
- **CMakePresets**: Added development workflow presets for better productivity
- **Cross-Platform CI/CD**: Multi-platform automated builds and testing with lenient code quality checks
- **Professional Packaging**: NSIS, DMG, and DEB/RPM installers
- **ROM-Dependent Testing**: Separated testing infrastructure for CI compatibility with 46+ core tests
- **Comprehensive Documentation**: Updated guides, help menus, and API documentation
### Technical Improvements
- **Modern C++23**: Latest language features for performance and safety
- **Memory Safety**: Enhanced memory management with RAII and smart pointers
- **Error Handling**: Improved error handling using absl::Status throughout
- **Cross-Platform**: Consistent experience across Windows, macOS, and Linux
- **Performance**: Optimized rendering and data processing
### Bug Fixes
- **Graphics Arena Crash**: Fixed double-free error during Arena singleton destruction
- **SNES Tile Format**: Corrected tile unpacking algorithm based on SnesLab documentation
- **Palette System**: Fixed color conversion functions (ImVec4 float to uint8_t conversion)
- **CI/CD**: Fixed missing cstring include for Ubuntu compilation
- **ROM Loading**: Fixed file path issues in tests
## 0.2.2 (December 2024)
- DungeonMap editing improvements
- ZSCustomOverworld support
- Cross platform file handling
## 0.2.1 (August 2024)
- Improved MessageEditor parsing
- Added integration test window
- Bitmap bug fixes
## 0.2.0 (July 2024)
- iOS app support
- Graphics Sheet Browser
- Project Files
## 0.1.0 (May 2024)
- Bitmap bug fixes
- Error handling improvements
## 0.0.9 (April 2024)
- Documentation updates
- Entrance tile types
- Emulator subsystem overhaul
## 0.0.8 (February 2024)
- Hyrule Magic Compression
- Dungeon Room Entrances
- PNG Export
## 0.0.7 (January 2024)
- OverworldEntities
- Entrances
- Exits
- Items
- Sprites
## 0.0.6 (November 2023)
- ScreenEditor DungeonMap
- Tile16 Editor
- Canvas updates
## 0.0.5 (November 2023)
- DungeonEditor
- DungeonObjectRenderer
## 0.0.4 (November 2023)
- Tile16Editor
- GfxGroupEditor
- Add GfxGroups functions to Rom
- Add Tile16Editor and GfxGroupEditor to OverworldEditor
## 0.0.3 (October 2023)
- Emulator subsystem
- SNES PPU and PPURegisters

62
docs/D1-roadmap.md Normal file
View File

@@ -0,0 +1,62 @@
# Roadmap
## 0.4.X (Next Major Release)
### Core Features
- **Overworld Sprites**: Complete sprite editing with add/remove functionality
- **Enhanced Dungeon Editing**: Advanced room object editing and manipulation
- **Tile16 Editing**: Enhanced editor for creating and modifying tile16 data
- **Plugin Architecture**: Framework for community extensions and custom tools
- **Graphics Sheets**: Complete editing, saving, and re-importing of sheets
- **Project Refactoring**: Clean up resource loading and memory usage
### Technical Improvements
- **Sprite Property Editor**: Add support for changing sprite behavior and attributes
- **Custom Sprites**: Support creating and editing custom sprites
- **Asar Patching**: Stabilize existing patching system for advanced modifications
## 0.5.X
### Advanced Features
- **SCAD Format**: Polish and finalize the scad file integration
- **Hex Editing Improvements**: Enhance user interface for direct ROM manipulation
- **Music Editing**: Add an interface to edit and manage music data
## 0.6.X
### Platform & Integration
- **Cross-Platform Stability**: Test and refine builds across Windows, macOS, iOS, and Linux
- **Plugin/Integration Framework**: Provide hooks or scripting for community add-ons
## 0.7.X
### Performance & Polish
- **Performance Optimizations**: Remove bottlenecks in rendering and data processing
- **Documentation Overhaul**: Update manuals, guides, and in-app tooltips
## 0.8.X
### Beta Preparation
- **Beta Release**: Code freeze on major features, focus on bug fixes and polish
- **User Interface Refinements**: Improve UI consistency, iconography, and layout
- **Internal Cleanup**: Remove deprecated code, finalize API calls
## 1.0.0
### Stable Release
- **Stable Release**: Final, production-ready version
- **Changelog**: Comprehensive summary of all changes since 0.0.0
## Current Focus Areas
### Immediate Priorities (v0.4.X)
1. **Dungeon Editor Refactoring**: Complete component-based architecture
2. **Sprite System**: Implement comprehensive sprite editing
3. **Graphics Pipeline**: Enhance graphics editing capabilities
4. **Plugin System**: Enable community extensions
### Long-term Vision
- **Community-Driven**: Robust plugin system for community contributions
- **Cross-Platform Excellence**: Seamless experience across all platforms
- **Performance**: Optimized for large ROMs and complex modifications
- **Accessibility**: User-friendly interface for both beginners and experts

223
docs/E1-asm-style-guide.md Normal file
View File

@@ -0,0 +1,223 @@
# Asm Style Guide
65816 Assembly is the assembly language used by the Super Nintendo Entertainment System (SNES) and its Ricoh 5A22 processor. This style guide provides conventions and best practices for writing 65816 assembly code in the context of the yaze project. Following these guidelines will help maintain consistency and readability across the codebase.
This guide is based primarily on the [Oracle of Secrets](https://github.com/scawful/Oracle-of-Secrets) codebase and is meant for the [Asar](https://github.com/RPGHacker/asar) assembler and derives influence from the [Asar 1.9 Manual](https://rpghacker.github.io/asar/asar_19/manual/).
Custom assembly code applied to the game should be included through the `yaze.asm` file found in `assets/asm`. This file can be applied to the ROM by the editor using the Asar library or included into a projects codebase for use with the Asar assembler.
## Table of Contents
- [File Structure](#file-structure)
- [Labels and Symbols](#labels-and-symbols)
- [Comments](#comments)
- [Directives](#directives)
- [Instructions](#instructions)
- [Macros](#macros)
- [Loops and Branching](#loops-and-branching)
- [Data Structures](#data-structures)
- [Code Organization](#code-organization)
- [Custom Code](#custom-code)
## File Structure
- **File Extension**: Use `.asm` as the file extension for 65816 assembly files.
- **Header Comments**: Include a header comment at the beginning of each file describing its purpose and the author.
Example:
```asm
; =========================================================
; Purpose: [Brief description of the files functionality]
; Author: [Your Name]
; =========================================================
```
- **Section Headers**: Use clear and consistent section headers to divide code into logical blocks. Each major section (e.g., sprite properties, main logic, subroutines) should start with a delineated header.
Example:
```asm
; =========================================================
; Minecart Sprite Properties
; =========================================================
```
- **Macro Definitions and Includes**: Place macros and include directives at the beginning of the file to keep them organized and easily accessible.
## Labels and Symbols
- **Naming Conventions**:
- **Global Labels**: Use descriptive names in `PascalCase` for global labels (e.g., `Sprite_Minecart_Main`).
- **Local Labels**: Prefix local labels with a dot (`.`) to indicate their limited scope (e.g., `.check_direction`).
- **Constants and Flags**: Use `ALL_CAPS_WITH_UNDERSCORES` for constants and flags (e.g., `!MINECART_SPEED`, `!HARVESTING_FLAG`).
- **Variables**: Use `CamelCase` for variable names to maintain readability (e.g., `LinkInCart`, `SpriteDirection`).
- **Alignment**: Align labels to the left margin for better readability. Indent instructions and comments to separate them from labels.
Example:
```asm
Sprite_Minecart_Main:
{
JSR HandleTileDirections
JSR HandleDynamicSwitchTileDirections
RTS
}
```
## Comments
- **Purpose**: Comments should explain why the code exists and what it is intended to do, especially for complex logic.
- **Placement**:
- Comments can be placed above the code block they describe for longer explanations.
- Inline comments can be used for single lines of code where the purpose might not be immediately clear.
- **Clarity**: Avoid stating the obvious. Focus on explaining the logic rather than restating the code.
Example:
```asm
LDA $22 : SEC : SBC $3F : STA $31 ; Adjust X position for camera movement
```
## Instructions
- **Single Line Instructions**: Combine multiple instructions on a single line using colons (`:`) where appropriate for related operations.
- **Separation**: Use line breaks to separate distinct sections of code logically, improving readability.
- **Optimization**: Always consider the most efficient instruction for the task at hand, especially in performance-critical sections.
Example:
```asm
LDA #$01 : STA !LinkInCart ; Set Link in cart flag
```
## Macros
- **Naming**: Use `PascalCase` for macro names, with the first letter of each word capitalized (e.g., `InitMovement`, `MoveCart`).
- **Parameters**: Clearly define and document parameters within macros to ensure they are used correctly.
- **Reuse**: Encourage the reuse of macros to avoid code duplication and simplify maintenance.
Example:
```asm
%macro HandlePlayerCamera
LDA $22 : SEC : SBC $3F : STA $31
LDA $20 : SEC : SBC $3E : STA $30
JSL Link_HandleMovingAnimation_FullLongEntry
JSL HandleIndoorCameraAndDoors
RTS
endmacro
```
## Loops and Branching
- **Branch Labels**: Use meaningful names for branch labels, prefixed with a dot (`.`) for local branches.
- **Optimization**: Minimize the number of instructions within loops and branches to improve performance.
Example:
```asm
.loop_start
LDA $00 : CMP #$10 : BEQ .end_loop
INC $00
BRA .loop_start
.end_loop
RTS
```
## Data Structures
- **Alignment**: Align data tables and structures clearly, and use comments to describe the purpose and layout of each.
- **Access**: Ensure that data structures are accessed consistently, with clear boundaries between read and write operations.
Example:
```asm
.DirectionTileLookup
{
db $02, $00, $04, $00 ; North
db $00, $00, $03, $01 ; East
db $00, $02, $00, $04 ; South
db $03, $01, $00, $00 ; West
}
```
- **Structs**: Use structs to group related data together, improving readability and maintainability.
Example:
```asm
struct AncillaAdd_HookshotData $099AF8
.speed_y: skip 4
.speed_x: skip 4
.offset_y: skip 8
.offset_x: skip 8
endstruct
AncillaAdd_Hookshot:
; $099AF0
.speed_y
db -64 ; up
db 64 ; down
db 0 ; left
db 0 ; right
; $099AFC
.speed_x
db 0 ; up
db 0 ; down
db -64 ; left
db 64 ; right
; $099B00
.offset_y
dw 4 ; up
dw 20 ; down
dw 8 ; left
dw 8 ; right
; $099B08
.offset_x
dw 0 ; up
dw 0 ; down
dw -4 ; left
dw 11 ; right
```
## Code Organization
- **Logical Grouping**: Organize code into logical sections, with related routines and macros grouped together.
- **Separation of Concerns**: Ensure that each section of code is responsible for a specific task or set of related tasks, avoiding tightly coupled code.
- **Modularity**: Write code in a modular way, making it easier to reuse and maintain.
Example:
```asm
; =========================================================
; Minecart Sprite Logic
; =========================================================
Sprite_Minecart_Main:
{
PHX
JSR HandleMinecartMovement
PLX
REP #$20
LDA !SpriteDirection : STA $00
SEP #$20
RTS
}
```
## Custom Code
- **Integration**: Include custom assembly code in the `yaze.asm` file to ensure it is applied correctly to the ROM. The module should include a define and conditional statement to allow users to disable the module if needed.
Example:
```asm
!YAZE_CUSTOM_MOSAIC = 1
if !YAZE_CUSTOM_MOSAIC != 0
incsrc "mosaic_change.asm"
endif
```

View File

@@ -0,0 +1,360 @@
# Dungeon Editor Guide
## Overview
The Yaze Dungeon Editor is a comprehensive tool for editing Zelda 3: A Link to the Past dungeon rooms, objects, sprites, items, entrances, doors, and chests. It provides an integrated editing experience with real-time rendering, coordinate system management, and advanced features for dungeon modification.
## Architecture
### Core Components
#### 1. DungeonEditorSystem
- **Purpose**: Central coordinator for all dungeon editing operations
- **Location**: `src/app/zelda3/dungeon/dungeon_editor_system.h/cc`
- **Features**:
- Room management (loading, saving, creating, deleting)
- Sprite management (enemies, NPCs, interactive objects)
- Item management (keys, hearts, rupees, etc.)
- Entrance/exit management (room connections)
- Door management (locked doors, key requirements)
- Chest management (treasure placement)
- Undo/redo system
- Event callbacks for real-time updates
#### 2. DungeonObjectEditor
- **Purpose**: Specialized editor for room objects (walls, floors, decorations)
- **Location**: `src/app/zelda3/dungeon/dungeon_object_editor.h/cc`
- **Features**:
- Object placement and editing
- Layer management (BG1, BG2, BG3)
- Object size editing with scroll wheel
- Collision detection and validation
- Selection and multi-selection
- Grid snapping
- Real-time preview
#### 3. ObjectRenderer
- **Purpose**: High-performance rendering system for dungeon objects
- **Location**: `src/app/zelda3/dungeon/object_renderer.h/cc`
- **Features**:
- Graphics cache for performance optimization
- Memory pool management
- Performance monitoring and statistics
- Object parsing from ROM data
- Palette support and color management
- Batch rendering for efficiency
#### 4. DungeonEditor (UI Layer)
- **Purpose**: User interface and interaction handling
- **Location**: `src/app/editor/dungeon/dungeon_editor.h/cc`
- **Features**:
- Integrated tabbed interface
- Canvas-based room editing
- Coordinate system management
- Object preview system
- Real-time rendering
- Compact editing panels
## Coordinate System
### Room Coordinates vs Canvas Coordinates
The dungeon editor uses a two-tier coordinate system:
1. **Room Coordinates**: 16x16 tile units (as used in the ROM)
2. **Canvas Coordinates**: Pixel coordinates for rendering
#### Conversion Functions
```cpp
// Convert room coordinates to canvas coordinates
std::pair<int, int> RoomToCanvasCoordinates(int room_x, int room_y) const {
return {room_x * 16, room_y * 16};
}
// Convert canvas coordinates to room coordinates
std::pair<int, int> CanvasToRoomCoordinates(int canvas_x, int canvas_y) const {
return {canvas_x / 16, canvas_y / 16};
}
// Check if coordinates are within canvas bounds
bool IsWithinCanvasBounds(int canvas_x, int canvas_y, int margin = 32) const;
```
### Coordinate System Features
- **Automatic Bounds Checking**: Objects outside visible canvas area are culled
- **Scrolling Support**: Canvas handles scrolling internally with proper coordinate transformation
- **Grid Alignment**: 16x16 pixel grid for precise object placement
- **Margin Support**: Configurable margins for partial object visibility
## Object Rendering System
### Object Types
The system supports three main object subtypes based on ROM structure:
1. **Subtype 1** (0x00-0xFF): Standard room objects (walls, floors, decorations)
2. **Subtype 2** (0x100-0x1FF): Interactive objects (doors, switches, chests)
3. **Subtype 3** (0x200+): Special objects (stairs, warps, bosses)
### Rendering Pipeline
1. **Object Loading**: Objects are loaded from ROM data using `LoadObjects()`
2. **Tile Parsing**: Object tiles are parsed using `ObjectParser`
3. **Graphics Caching**: Frequently used graphics are cached for performance
4. **Palette Application**: SNES palettes are applied to object graphics
5. **Canvas Rendering**: Objects are rendered to canvas with proper coordinate transformation
### Performance Optimizations
- **Graphics Cache**: Reduces redundant graphics sheet loading
- **Memory Pool**: Efficient memory allocation for rendering
- **Batch Rendering**: Multiple objects rendered in single pass
- **Bounds Culling**: Objects outside visible area are skipped
- **Cache Invalidation**: Smart cache management based on palette changes
## User Interface
### Integrated Editing Panels
The dungeon editor features a consolidated interface with:
#### Main Canvas
- **Room Visualization**: Real-time room rendering with background layers
- **Object Display**: Objects rendered with proper positioning and sizing
- **Interactive Editing**: Click-to-select, drag-to-move, scroll-to-resize
- **Grid Overlay**: Optional grid display for precise positioning
- **Coordinate Display**: Real-time coordinate information
#### Compact Editing Panels
1. **Object Editor**
- Mode selection (Select, Insert, Edit, Delete)
- Layer management (BG1, BG2, BG3)
- Object type selection
- Size editing with scroll wheel
- Configuration options (snap to grid, show grid)
2. **Sprite Editor**
- Sprite placement and management
- Enemy and NPC configuration
- Layer assignment
- Quick sprite addition
3. **Item Editor**
- Item placement (keys, hearts, rupees)
- Hidden item configuration
- Item type selection
- Room assignment
4. **Entrance Editor**
- Room connection management
- Bidirectional connection support
- Position configuration
- Connection validation
5. **Door Editor**
- Door placement and configuration
- Lock status management
- Key requirement setup
- Direction and target room assignment
6. **Chest Editor**
- Treasure chest placement
- Item and quantity configuration
- Big chest support
- Opened status tracking
7. **Properties Editor**
- Room metadata management
- Dungeon settings
- Music and ambient sound configuration
- Boss room and save room flags
### Object Preview System
- **Real-time Preview**: Objects are previewed in the canvas as they're selected
- **Centered Display**: Preview objects are centered in the canvas for optimal viewing
- **Palette Support**: Previews use current palette settings
- **Information Display**: Object properties are shown in preview window
## Integration with ZScream
The dungeon editor is designed to be compatible with ZScream C# patterns:
### Room Loading
- Uses same room loading patterns as ZScream
- Compatible with ZScream room data structures
- Supports ZScream room naming conventions
### Object Parsing
- Follows ZScream object parsing logic
- Compatible with ZScream object type definitions
- Supports ZScream size encoding
### Coordinate System
- Matches ZScream coordinate conventions
- Uses same tile size calculations
- Compatible with ZScream positioning logic
## Testing and Validation
### Integration Tests
The system includes comprehensive integration tests:
1. **Basic Object Rendering**: Tests fundamental object rendering functionality
2. **Multi-Palette Rendering**: Tests rendering with different palettes
3. **Real Room Object Rendering**: Tests with actual ROM room data
4. **Disassembly Room Validation**: Tests specific rooms from disassembly
5. **Performance Testing**: Measures rendering performance and memory usage
6. **Cache Effectiveness**: Tests graphics cache performance
7. **Error Handling**: Tests error conditions and edge cases
### Test Data
Tests use real ROM data from `build/bin/zelda3.sfc`:
- **Room 0x0000**: Ganon's room (from disassembly)
- **Room 0x0002, 0x0012**: Sewer rooms (from disassembly)
- **Room 0x0020**: Agahnim's tower (from disassembly)
- **Additional rooms**: 0x0001, 0x0010, 0x0033, 0x005A
### Performance Benchmarks
- **Rendering Time**: < 500ms for 100 objects
- **Memory Usage**: < 100MB for large object sets
- **Cache Hit Rate**: Optimized for frequent object access
- **Coordinate Conversion**: O(1) coordinate transformation
## Usage Examples
### Basic Object Editing
```cpp
// Load a room
auto room_result = dungeon_editor_system_->GetRoom(0x0000);
// Add an object
auto status = object_editor_->InsertObject(5, 5, 0x10, 0x12, 0);
// Parameters: x, y, object_type, size, layer
// Render objects
auto result = object_renderer_->RenderObjects(objects, palette);
```
### Coordinate Conversion
```cpp
// Convert room coordinates to canvas coordinates
auto [canvas_x, canvas_y] = RoomToCanvasCoordinates(room_x, room_y);
// Check if coordinates are within bounds
if (IsWithinCanvasBounds(canvas_x, canvas_y)) {
// Render object at this position
}
```
### Object Preview
```cpp
// Create preview object
auto preview_object = zelda3::RoomObject(id, 8, 8, 0x12, 0);
preview_object.set_rom(rom_);
preview_object.EnsureTilesLoaded();
// Render preview
auto result = object_renderer_->RenderObject(preview_object, palette);
```
## Configuration Options
### Editor Configuration
```cpp
struct EditorConfig {
bool snap_to_grid = true;
int grid_size = 16;
bool show_grid = true;
bool show_preview = true;
bool auto_save = false;
int auto_save_interval = 300;
bool validate_objects = true;
bool show_collision_bounds = false;
};
```
### Performance Configuration
```cpp
// Object renderer settings
object_renderer_->SetCacheSize(100);
object_renderer_->EnablePerformanceMonitoring(true);
// Canvas settings
canvas_.SetCanvasSize(ImVec2(512, 512));
canvas_.set_draggable(true);
```
## Troubleshooting
### Common Issues
1. **Objects Not Displaying**
- Check if ROM is loaded
- Verify object tiles are loaded with `EnsureTilesLoaded()`
- Check coordinate bounds with `IsWithinCanvasBounds()`
2. **Coordinate Misalignment**
- Use coordinate conversion functions
- Check canvas scrolling settings
- Verify grid alignment
3. **Performance Issues**
- Enable graphics caching
- Check memory usage with `GetMemoryUsage()`
- Monitor performance stats with `GetPerformanceStats()`
4. **Preview Not Showing**
- Verify object is within canvas bounds
- Check palette is properly set
- Ensure object has valid tiles
### Debug Information
The system provides comprehensive debug information:
- Object count and statistics
- Cache hit/miss rates
- Memory usage tracking
- Performance metrics
- Coordinate system validation
## Future Enhancements
### Planned Features
1. **Advanced Object Editing**
- Multi-object selection and manipulation
- Object grouping and layers
- Advanced collision detection
2. **Enhanced Rendering**
- Real-time lighting effects
- Animation support
- Advanced shader effects
3. **Improved UX**
- Keyboard shortcuts
- Context menus
- Undo/redo visualization
4. **Integration Features**
- ZScream project import/export
- Collaborative editing
- Version control integration
## Conclusion
The Yaze Dungeon Editor provides a comprehensive, high-performance solution for editing Zelda 3 dungeon rooms. With its integrated interface, robust coordinate system, and advanced rendering capabilities, it offers both novice and expert users the tools needed to create and modify dungeon content effectively.
The system's compatibility with ZScream patterns and comprehensive testing ensure reliability and consistency with existing tools, while its modern architecture provides a foundation for future enhancements and features.

View File

@@ -0,0 +1,364 @@
# Dungeon Editor Design Plan
## Overview
This document provides a comprehensive guide for future developers working on the Zelda 3 Dungeon Editor system. The dungeon editor has been refactored into a modular, component-based architecture that separates concerns and improves maintainability.
## Architecture Overview
### Core Components
The dungeon editor system consists of several key components:
1. **DungeonEditor** - Main orchestrator class that manages the overall editor state
2. **DungeonRoomSelector** - Handles room and entrance selection UI
3. **DungeonCanvasViewer** - Manages the main canvas rendering and room display
4. **DungeonObjectSelector** - Provides object selection, editing panels, and tile graphics
5. **ObjectRenderer** - Core rendering engine for dungeon objects
6. **DungeonEditorSystem** - High-level system for managing dungeon editing operations
### File Structure
```
src/app/editor/dungeon/
├── dungeon_editor.h/cc # Main editor orchestrator
├── dungeon_room_selector.h/cc # Room/entrance selection component
├── dungeon_canvas_viewer.h/cc # Canvas rendering component
├── dungeon_object_selector.h/cc # Object editing component
└── dungeon_editor_system.h/cc # Core editing system
src/app/zelda3/dungeon/
├── object_renderer.h/cc # Object rendering engine
├── dungeon_object_editor.h/cc # Object editing logic
├── room.h/cc # Room data structures
├── room_object.h/cc # Object data structures
└── room_entrance.h/cc # Entrance data structures
```
## Component Responsibilities
### DungeonEditor (Main Orchestrator)
**Responsibilities:**
- Manages overall editor state and ROM data
- Coordinates between UI components
- Handles data initialization and propagation
- Implements the 3-column layout (Room Selector | Canvas | Object Selector)
**Key Methods:**
- `UpdateDungeonRoomView()` - Main UI update loop
- `Load()` - Initialize editor with ROM data
- `set_rom()` - Update ROM reference across components
### DungeonRoomSelector
**Responsibilities:**
- Room selection and navigation
- Entrance selection and editing
- Active room management
- Room list display with names
**Key Methods:**
- `Draw()` - Main rendering method
- `DrawRoomSelector()` - Room list and selection
- `DrawEntranceSelector()` - Entrance editing interface
- `set_rom()`, `set_rooms()`, `set_entrances()` - Data access methods
### DungeonCanvasViewer
**Responsibilities:**
- Main canvas rendering and display
- Room graphics loading and management
- Object rendering with proper coordinates
- Background layer management
- Coordinate conversion (room ↔ canvas)
**Key Methods:**
- `Draw(int room_id)` - Main canvas rendering
- `LoadAndRenderRoomGraphics()` - Graphics loading
- `RenderObjectInCanvas()` - Object rendering
- `RoomToCanvasCoordinates()` - Coordinate conversion
- `RenderRoomBackgroundLayers()` - Background rendering
### DungeonObjectSelector
**Responsibilities:**
- Object selection and preview
- Tile graphics display
- Compact editing panels for all editor modes
- Object renderer integration
**Key Methods:**
- `Draw()` - Main rendering with tabbed interface
- `DrawRoomGraphics()` - Tile graphics display
- `DrawIntegratedEditingPanels()` - Editing interface
- `DrawCompactObjectEditor()` - Object editing controls
- `DrawCompactSpriteEditor()` - Sprite editing controls
- Similar methods for Items, Entrances, Doors, Chests, Properties
## Data Flow
### Initialization Flow
1. **ROM Loading**: `DungeonEditor::Load()` is called with ROM data
2. **Component Setup**: ROM and data pointers are propagated to all components
3. **Graphics Initialization**: Room graphics are loaded and cached
4. **UI State Setup**: Active rooms, palettes, and editor modes are initialized
### Runtime Data Flow
1. **User Interaction**: User selects rooms, objects, or editing modes
2. **State Updates**: Components update their internal state
3. **Data Propagation**: Changes are communicated between components
4. **Rendering**: All components re-render with updated data
### Key Data Structures
```cpp
// Main editor state
std::array<zelda3::Room, 0x128> rooms_;
std::array<zelda3::RoomEntrance, 0x8C> entrances_;
ImVector<int> active_rooms_;
gfx::PaletteGroup current_palette_group_;
// Component instances
DungeonRoomSelector room_selector_;
DungeonCanvasViewer canvas_viewer_;
DungeonObjectSelector object_selector_;
```
## Integration Patterns
### Component Communication
Components communicate through:
1. **Direct method calls** - Parent calls child methods
2. **Data sharing** - Shared pointers to common data structures
3. **Event propagation** - State changes trigger updates
### ROM Data Management
```cpp
// ROM propagation pattern
void DungeonEditor::set_rom(Rom* rom) {
rom_ = rom;
room_selector_.set_rom(rom);
canvas_viewer_.SetRom(rom);
object_selector_.SetRom(rom);
}
```
### State Synchronization
Components maintain their own state but receive updates from the main editor:
- Room selection state is managed by `DungeonRoomSelector`
- Canvas rendering state is managed by `DungeonCanvasViewer`
- Object editing state is managed by `DungeonObjectSelector`
## UI Layout Architecture
### 3-Column Layout
The main editor uses a 3-column ImGui table layout:
```cpp
if (BeginTable("#DungeonEditTable", 3, kDungeonTableFlags, ImVec2(0, 0))) {
TableSetupColumn("Room/Entrance Selector", ImGuiTableColumnFlags_WidthFixed, 250);
TableSetupColumn("Canvas", ImGuiTableColumnFlags_WidthStretch);
TableSetupColumn("Object Selector/Editor", ImGuiTableColumnFlags_WidthFixed, 300);
// Column 1: Room Selector
TableNextColumn();
room_selector_.Draw();
// Column 2: Canvas
TableNextColumn();
canvas_viewer_.Draw(current_room);
// Column 3: Object Selector
TableNextColumn();
object_selector_.Draw();
}
```
### Component Internal Layout
Each component manages its own internal layout:
- **DungeonRoomSelector**: Tabbed interface (Rooms | Entrances)
- **DungeonCanvasViewer**: Canvas with controls and debug popup
- **DungeonObjectSelector**: Tabbed interface (Graphics | Editor)
## Coordinate System
### Room Coordinates vs Canvas Coordinates
- **Room Coordinates**: 16x16 tile units (0-15 for a standard room)
- **Canvas Coordinates**: Pixel coordinates for rendering
- **Conversion**: `RoomToCanvasCoordinates(x, y) = (x * 16, y * 16)`
### Bounds Checking
All rendering operations include bounds checking:
```cpp
bool IsWithinCanvasBounds(int canvas_x, int canvas_y, int margin = 32) const;
```
## Error Handling & Validation
### ROM Validation
All components validate ROM state before operations:
```cpp
if (!rom_ || !rom_->is_loaded()) {
ImGui::Text("ROM not loaded");
return;
}
```
### Bounds Validation
Graphics operations include bounds checking:
```cpp
if (room_id < 0 || room_id >= rooms_->size()) {
return; // Skip invalid operations
}
```
## Performance Considerations
### Caching Strategy
- **Object Render Cache**: Cached rendered bitmaps to avoid re-rendering
- **Graphics Cache**: Cached graphics sheets for frequently accessed data
- **Memory Pool**: Efficient memory allocation for temporary objects
### Rendering Optimization
- **Viewport Culling**: Objects outside visible area are not rendered
- **Lazy Loading**: Graphics are loaded only when needed
- **Selective Updates**: Only changed components re-render
## Testing Strategy
### Integration Tests
The system includes comprehensive integration tests:
- `dungeon_object_renderer_integration_test.cc` - Core rendering tests
- `dungeon_editor_system_integration_test.cc` - System integration tests
- `dungeon_object_renderer_mock_test.cc` - Mock ROM testing
### Test Categories
1. **Real ROM Tests**: Tests with actual Zelda 3 ROM data
2. **Mock ROM Tests**: Tests with simulated ROM data
3. **Performance Tests**: Rendering performance benchmarks
4. **Error Handling Tests**: Validation and error recovery
## Future Development Guidelines
### Adding New Features
1. **Identify Component**: Determine which component should handle the feature
2. **Extend Interface**: Add necessary methods to component header
3. **Implement Logic**: Add implementation in component source file
4. **Update Integration**: Modify main editor to use new functionality
5. **Add Tests**: Create tests for new functionality
### Component Extension Patterns
```cpp
// Adding new data access method
void Component::SetNewData(const NewDataType& data) {
new_data_ = data;
}
// Adding new rendering method
void Component::DrawNewFeature() {
// Implementation
}
// Adding to main Draw method
void Component::Draw() {
// Existing code
DrawNewFeature();
}
```
### Data Flow Extension
When adding new data types:
1. Add to main editor state
2. Create setter methods in relevant components
3. Update initialization in `Load()` method
4. Add to `set_rom()` propagation if ROM-dependent
### UI Layout Extension
For new UI elements:
1. Determine placement (new tab, new panel, etc.)
2. Follow existing ImGui patterns
3. Maintain consistent spacing and styling
4. Add to appropriate component's Draw method
## Common Pitfalls & Solutions
### Memory Management
- **Issue**: Dangling pointers to ROM data
- **Solution**: Always validate ROM state before use
### Coordinate System
- **Issue**: Objects rendering at wrong positions
- **Solution**: Use coordinate conversion helper methods
### State Synchronization
- **Issue**: Components showing stale data
- **Solution**: Ensure data propagation in setter methods
### Performance Issues
- **Issue**: Slow rendering with many objects
- **Solution**: Implement viewport culling and caching
## Debugging Tools
### Debug Popup
The canvas viewer includes a comprehensive debug popup with:
- Object statistics and metadata
- Cache information
- Performance metrics
- Object type breakdowns
### Logging
Key operations include logging for debugging:
```cpp
std::cout << "Loading room graphics for room " << room_id << std::endl;
```
## Build Integration
### CMake Configuration
New components are automatically included via:
```cmake
# In CMakeLists.txt
file(GLOB YAZE_SRC_FILES "src/app/editor/dungeon/*.cc")
```
### Dependencies
Key dependencies:
- ImGui for UI rendering
- gfx library for graphics operations
- zelda3 library for ROM data structures
- absl for status handling
## Conclusion
This modular architecture provides a solid foundation for future dungeon editor development. The separation of concerns makes the codebase maintainable, testable, and extensible. Future developers should follow the established patterns and extend components rather than modifying the main orchestrator class.
For questions or clarifications, refer to the existing integration tests and component implementations as examples of proper usage patterns.

View File

@@ -0,0 +1,248 @@
# DungeonEditor Refactoring Plan
## Overview
This document outlines the comprehensive refactoring of the 1444-line `dungeon_editor.cc` file into focused, single-responsibility components.
## Component Structure
### ✅ Created Components
#### 1. DungeonToolset (`dungeon_toolset.h/cc`)
**Responsibility**: Toolbar UI management
- Background layer selection (All/BG1/BG2/BG3)
- Placement mode selection (Object/Sprite/Item/etc.)
- Undo/Redo buttons with callbacks
- **Replaces**: `DrawToolset()` method (~70 lines)
#### 2. DungeonObjectInteraction (`dungeon_object_interaction.h/cc`)
**Responsibility**: Object selection and placement
- Mouse interaction handling
- Object selection rectangle (like OverworldEditor)
- Drag and drop operations
- Coordinate conversion utilities
- **Replaces**: All mouse/selection methods (~400 lines)
#### 3. DungeonRenderer (`dungeon_renderer.h/cc`)
**Responsibility**: All rendering operations
- Object rendering with caching
- Background layer composition
- Layout object visualization
- Render cache management
- **Replaces**: All rendering methods (~200 lines)
#### 4. DungeonRoomLoader (`dungeon_room_loader.h/cc`)
**Responsibility**: ROM data loading
- Room loading from ROM
- Room size calculation
- Entrance loading
- Graphics loading coordination
- **Replaces**: Room loading methods (~150 lines)
#### 5. DungeonUsageTracker (`dungeon_usage_tracker.h/cc`)
**Responsibility**: Resource usage analysis
- Blockset/spriteset/palette usage tracking
- Usage statistics display
- Resource optimization insights
- **Replaces**: Usage statistics methods (~100 lines)
## Refactored DungeonEditor Structure
### Before Refactoring: 1444 lines
```cpp
class DungeonEditor {
// 30+ methods handling everything
// Mixed responsibilities
// Large data structures
// Complex dependencies
};
```
### After Refactoring: ~400 lines
```cpp
class DungeonEditor {
// Core editor interface (unchanged)
void Initialize() override;
absl::Status Load() override;
absl::Status Update() override;
absl::Status Save() override;
// High-level UI orchestration
absl::Status UpdateDungeonRoomView();
void DrawCanvasAndPropertiesPanel();
void DrawRoomPropertiesDebugPopup();
// Component coordination
void OnRoomSelected(int room_id);
private:
// Focused components
DungeonToolset toolset_;
DungeonObjectInteraction object_interaction_;
DungeonRenderer renderer_;
DungeonRoomLoader room_loader_;
DungeonUsageTracker usage_tracker_;
// Existing UI components
DungeonRoomSelector room_selector_;
DungeonCanvasViewer canvas_viewer_;
DungeonObjectSelector object_selector_;
// Core data and state
std::array<zelda3::Room, 0x128> rooms_;
bool is_loaded_ = false;
// etc.
};
```
## Method Migration Map
### Core Editor Methods (Keep in main file)
-`Initialize()` - Component initialization
-`Load()` - Delegates to room_loader_
-`Update()` - High-level update coordination
-`Save()`, `Undo()`, `Redo()` - Editor interface
-`UpdateDungeonRoomView()` - UI orchestration
### UI Methods (Keep for coordination)
-`DrawCanvasAndPropertiesPanel()` - Tab management
-`DrawRoomPropertiesDebugPopup()` - Debug popup
-`DrawDungeonTabView()` - Room tab management
-`DrawDungeonCanvas()` - Canvas coordination
-`OnRoomSelected()` - Room selection handling
### Methods Moved to Components
#### → DungeonToolset
-`DrawToolset()` - Toolbar rendering
#### → DungeonObjectInteraction
-`HandleCanvasMouseInput()` - Mouse handling
-`CheckForObjectSelection()` - Selection rectangle
-`DrawObjectSelectRect()` - Selection drawing
-`SelectObjectsInRect()` - Selection logic
-`PlaceObjectAtPosition()` - Object placement
-`DrawSelectBox()` - Selection visualization
-`DrawDragPreview()` - Drag preview
-`UpdateSelectedObjects()` - Selection updates
-`IsObjectInSelectBox()` - Selection testing
- ❌ Coordinate conversion helpers
#### → DungeonRenderer
-`RenderObjectInCanvas()` - Object rendering
-`DisplayObjectInfo()` - Object info overlay
-`RenderLayoutObjects()` - Layout rendering
-`RenderRoomBackgroundLayers()` - Background rendering
-`RefreshGraphics()` - Graphics refresh
- ❌ Object cache management
#### → DungeonRoomLoader
-`LoadDungeonRoomSize()` - Room size calculation
-`LoadAndRenderRoomGraphics()` - Graphics loading
-`ReloadAllRoomGraphics()` - Bulk reload
- ❌ Room size and address management
#### → DungeonUsageTracker
-`CalculateUsageStats()` - Usage calculation
-`DrawUsageStats()` - Usage display
-`DrawUsageGrid()` - Usage visualization
-`RenderSetUsage()` - Set usage rendering
## Component Communication
### Callback System
```cpp
// Object placement callback
object_interaction_.SetObjectPlacedCallback([this](const auto& object) {
renderer_.ClearObjectCache();
});
// Toolset callbacks
toolset_.SetUndoCallback([this]() { Undo(); });
toolset_.SetPaletteToggleCallback([this]() { palette_showing_ = !palette_showing_; });
// Object selection callback
object_selector_.SetObjectSelectedCallback([this](const auto& object) {
object_interaction_.SetPreviewObject(object, true);
toolset_.set_placement_type(DungeonToolset::kObject);
});
```
### Data Sharing
```cpp
// Update components with current room
void OnRoomSelected(int room_id) {
current_room_id_ = room_id;
object_interaction_.SetCurrentRoom(&rooms_, room_id);
// etc.
}
```
## Benefits of Refactoring
### 1. **Reduced Complexity**
- Main file: 1444 → ~400 lines (72% reduction)
- Single responsibility per component
- Clear separation of concerns
### 2. **Improved Testability**
- Individual components can be unit tested
- Mocking becomes easier
- Isolated functionality testing
### 3. **Better Maintainability**
- Changes isolated to relevant components
- Easier to locate and fix bugs
- Cleaner code reviews
### 4. **Enhanced Extensibility**
- New features added to appropriate components
- Component interfaces allow easy replacement
- Plugin-style architecture possible
### 5. **Cleaner Dependencies**
- UI separate from data manipulation
- Rendering separate from business logic
- Clear component boundaries
## Implementation Status
### ✅ Completed
- Created all component header files
- Created component implementation stubs
- Updated DungeonEditor header with components
- Basic component integration
### 🔄 In Progress
- Method migration from main file to components
- Component callback setup
- Legacy method removal
### ⏳ Pending
- Full method implementation in components
- Complete integration testing
- Documentation updates
- Build system updates
## Migration Strategy
### Phase 1: Create Components ✅
- Define component interfaces
- Create header and implementation files
- Set up basic structure
### Phase 2: Integrate Components 🔄
- Add components to DungeonEditor
- Set up callback systems
- Begin method delegation
### Phase 3: Move Methods
- Systematically move methods to components
- Update method calls to use components
- Remove old implementations
### Phase 4: Cleanup
- Remove unused member variables
- Clean up includes
- Update documentation
This refactoring transforms the monolithic DungeonEditor into a well-organized, component-based architecture that's easier to maintain, test, and extend.

View File

@@ -0,0 +1,271 @@
# Dungeon Object System
## Overview
The Dungeon Object System provides a comprehensive framework for editing and managing dungeon rooms, objects, and layouts in The Legend of Zelda: A Link to the Past. This system combines real-time visual editing with precise data manipulation to create a powerful dungeon creation and modification toolkit.
## Architecture
### Core Components
The dungeon system is built around several key components that work together to provide a seamless editing experience:
#### 1. DungeonEditor (`src/app/editor/dungeon/dungeon_editor.h`)
The main interface that orchestrates all dungeon editing functionality. It provides:
- **Windowed Canvas System**: Fixed-size canvas that prevents UI layout disruption
- **Tabbed Room Interface**: Multiple rooms can be open simultaneously for easy comparison and editing
- **Integrated Object Placement**: Direct object placement from selector to canvas
- **Real-time Preview**: Live object preview follows mouse cursor during placement
#### 2. DungeonObjectSelector (`src/app/editor/dungeon/dungeon_object_selector.h`)
Combines object browsing and editing in a unified interface:
- **Object Browser**: Visual grid of all available objects with real-time previews
- **Object Editor**: Integrated editing panels for sprites, items, entrances, doors, and chests
- **Callback System**: Notifies main editor when objects are selected for placement
#### 3. DungeonCanvasViewer (`src/app/editor/dungeon/dungeon_canvas_viewer.h`)
Specialized canvas for rendering dungeon rooms:
- **Background Layer Rendering**: Proper BG1/BG2 layer composition
- **Object Rendering**: Cached object rendering with palette support
- **Coordinate System**: Seamless translation between room and canvas coordinates
#### 4. Room Management System (`src/app/zelda3/dungeon/room.h`)
Core data structures for room representation:
- **Room Objects**: Tile-based objects (walls, floors, decorations)
- **Room Layout**: Structural elements and collision data
- **Sprites**: Enemy and NPC placement
- **Entrances/Exits**: Room connections and transitions
## Object Types and Hierarchies
### Room Objects
Room objects are the fundamental building blocks of dungeon rooms. They follow a hierarchical structure:
#### Type 1 Objects (0x00-0xFF)
Basic structural elements:
- **0x10-0x1F**: Wall objects (various types and orientations)
- **0x20-0x2F**: Floor tiles (stone, wood, carpet, etc.)
- **0x30-0x3F**: Decorative elements (torches, statues, pillars)
- **0x40-0x4F**: Interactive elements (switches, blocks)
#### Type 2 Objects (0x100-0x1FF)
Complex multi-tile objects:
- **0x100-0x10F**: Large wall sections
- **0x110-0x11F**: Complex floor patterns
- **0x120-0x12F**: Multi-tile decorations
#### Type 3 Objects (0x200+)
Special dungeon-specific objects:
- **0x200-0x20F**: Boss room elements
- **0x210-0x21F**: Puzzle-specific objects
- **0xF9-0xFA**: Chests (small and large)
### Object Properties
Each object has several key properties:
```cpp
class RoomObject {
int id_; // Object type identifier
int x_, y_; // Position in room (16x16 tile units)
int size_; // Size modifier (affects rendering)
LayerType layer_; // Rendering layer (0=BG, 1=MID, 2=FG)
// ... additional properties
};
```
## How Object Placement Works
### Selection Process
1. **Object Browser**: User selects an object from the visual grid
2. **Preview Generation**: Object is rendered with current room palette
3. **Callback Trigger**: Selection notifies main editor via callback
4. **Preview Update**: Main editor receives object and enables placement mode
### Placement Process
1. **Mouse Tracking**: Preview object follows mouse cursor on canvas
2. **Coordinate Translation**: Mouse position converted to room coordinates
3. **Visual Feedback**: Semi-transparent preview shows placement position
4. **Click Placement**: Left-click places object at current position
5. **Room Update**: Object added to room data and cache cleared for redraw
### Code Flow
```cpp
// Object selection in DungeonObjectSelector
if (ImGui::Selectable("", is_selected)) {
preview_object_ = selected_object;
object_loaded_ = true;
// Notify main editor
if (object_selected_callback_) {
object_selected_callback_(preview_object_);
}
}
// Object placement in DungeonEditor
void PlaceObjectAtPosition(int room_x, int room_y) {
auto new_object = preview_object_;
new_object.x_ = room_x;
new_object.y_ = room_y;
new_object.set_rom(rom_);
new_object.EnsureTilesLoaded();
room.AddTileObject(new_object);
object_render_cache_.clear(); // Force redraw
}
```
## Rendering Pipeline
### Object Rendering
The system uses a sophisticated rendering pipeline:
1. **Tile Loading**: Object tiles loaded from ROM based on object ID
2. **Palette Application**: Room-specific palette applied to object
3. **Bitmap Generation**: Object rendered to bitmap with proper composition
4. **Caching**: Rendered objects cached for performance
5. **Canvas Drawing**: Bitmap drawn to canvas at correct position
### Performance Optimizations
- **Render Caching**: Objects cached based on ID, position, size, and palette hash
- **Bounds Checking**: Only objects within canvas bounds are rendered
- **Lazy Loading**: Graphics and objects loaded on-demand
- **Palette Hashing**: Efficient cache invalidation when palettes change
## User Interface Components
### Three-Column Layout
The dungeon editor uses a carefully designed three-column layout:
#### Column 1: Room Control Panel (280px fixed)
- **Room Selector**: Browse and select rooms
- **Debug Controls**: Room properties in table format
- **Object Statistics**: Live object counts and cache status
#### Column 2: Windowed Canvas (800px fixed)
- **Tabbed Interface**: Multiple rooms open simultaneously
- **Fixed Dimensions**: Prevents UI layout disruption
- **Real-time Preview**: Object placement preview follows cursor
- **Layer Visualization**: Proper background/foreground rendering
#### Column 3: Object Selector/Editor (stretch)
- **Object Browser Tab**: Visual grid of available objects
- **Object Editor Tab**: Integrated editing for sprites, items, etc.
- **Placement Tools**: Object property editing and placement controls
### Debug and Control Features
#### Room Properties Table
Real-time editing of room attributes:
```
Property | Value
------------|--------
Room ID | 0x001 (1)
Layout | [Hex Input]
Blockset | [Hex Input]
Spriteset | [Hex Input]
Palette | [Hex Input]
Floor 1 | [Hex Input]
Floor 2 | [Hex Input]
Message ID | [Hex Input]
```
#### Object Statistics
Live feedback on room contents:
- Total objects count
- Layout objects count
- Sprites count
- Chests count
- Cache status and controls
## Integration with ROM Data
### Data Sources
The system integrates with multiple ROM data sources:
#### Room Headers (`0x1F8000`)
- Room layout index
- Blockset and spriteset references
- Palette assignments
- Floor type definitions
#### Object Data
- Object definitions and tile mappings
- Size and layer information
- Interaction properties
#### Graphics Data
- Tile graphics (4bpp SNES format)
- Palette data (15-color palettes)
- Blockset compositions
### Assembly Integration
The system references the US disassembly (`assets/asm/usdasm/`) for:
- Room data structure validation
- Object type definitions
- Memory layout verification
- Data pointer validation
## Comparison with ZScream
### Architectural Differences
YAZE's approach differs from ZScream in several key ways:
#### Component-Based Architecture
- **YAZE**: Modular components with clear separation of concerns
- **ZScream**: More monolithic approach with integrated functionality
#### Real-time Rendering
- **YAZE**: Live object preview with mouse tracking
- **ZScream**: Static preview with separate placement step
#### UI Organization
- **YAZE**: Fixed-width columns prevent layout disruption
- **ZScream**: Resizable panels that can affect overall layout
#### Caching Strategy
- **YAZE**: Sophisticated object render caching with hash-based invalidation
- **ZScream**: Simpler caching approach
### Shared Concepts
Both systems share fundamental concepts:
- Object-based room construction
- Layer-based rendering
- ROM data integration
- Visual object browsing
## Best Practices
### Performance
1. **Use Render Caching**: Don't clear cache unnecessarily
2. **Bounds Checking**: Only render visible objects
3. **Lazy Loading**: Load graphics and objects on-demand
4. **Efficient Callbacks**: Minimize callback frequency
### Code Organization
1. **Separation of Concerns**: Keep UI, data, and rendering separate
2. **Clear Interfaces**: Use callbacks for component communication
3. **Error Handling**: Validate ROM data and handle errors gracefully
4. **Memory Management**: Clean up resources properly
### User Experience
1. **Visual Feedback**: Provide clear object placement preview
2. **Consistent Layout**: Use fixed dimensions for stable UI
3. **Contextual Information**: Show relevant object properties
4. **Efficient Workflow**: Minimize clicks for common operations
## Future Enhancements
### Planned Features
1. **Drag and Drop**: Direct object dragging from selector to canvas
2. **Multi-Selection**: Select and manipulate multiple objects
3. **Copy/Paste**: Copy object configurations between rooms
4. **Undo/Redo**: Full edit history management
5. **Template System**: Save and load room templates
### Technical Improvements
1. **GPU Acceleration**: Move rendering to GPU for better performance
2. **Advanced Caching**: Predictive loading and intelligent cache management
3. **Background Processing**: Asynchronous ROM data loading
4. **Memory Optimization**: Reduce memory footprint for large dungeons
This documentation provides a comprehensive understanding of how the YAZE dungeon object system works, from high-level architecture to low-level implementation details. The system is designed to be both powerful for advanced users and accessible for newcomers to dungeon editing.

View File

@@ -0,0 +1,492 @@
# Overworld Loading Guide
This document provides a comprehensive guide to understanding how overworld loading works in both ZScream (C#) and yaze (C++), including the differences between vanilla ROMs and ZSCustomOverworld v2/v3 ROMs.
## Table of Contents
1. [Overview](#overview)
2. [ROM Types and Versions](#rom-types-and-versions)
3. [Overworld Map Structure](#overworld-map-structure)
4. [Loading Process](#loading-process)
5. [ZScream Implementation](#zscream-implementation)
6. [Yaze Implementation](#yaze-implementation)
7. [Key Differences](#key-differences)
8. [Common Issues and Solutions](#common-issues-and-solutions)
## Overview
Both ZScream and yaze are Zelda 3 ROM editors that support editing overworld maps. They handle three main types of ROMs:
- **Vanilla ROMs**: Original Zelda 3 ROMs without modifications
- **ZSCustomOverworld v2**: ROMs with expanded overworld features
- **ZSCustomOverworld v3**: ROMs with additional features like overlays and custom background colors
## ROM Types and Versions
### Version Detection
Both editors detect the ROM version using the same constant:
```cpp
// Address: 0x140145
constexpr int OverworldCustomASMHasBeenApplied = 0x140145;
// Version values:
// 0xFF = Vanilla ROM
// 0x02 = ZSCustomOverworld v2
// 0x03 = ZSCustomOverworld v3
```
### Feature Support by Version
| Feature | Vanilla | v2 | v3 |
|---------|---------|----|----|
| Basic Overworld Maps | ✅ | ✅ | ✅ |
| Area Size Enum | ❌ | ❌ | ✅ |
| Main Palette | ❌ | ✅ | ✅ |
| Custom Background Colors | ❌ | ✅ | ✅ |
| Subscreen Overlays | ✅ | ✅ | ✅ |
| Animated GFX | ❌ | ❌ | ✅ |
| Custom Tile Graphics | ❌ | ❌ | ✅ |
| Vanilla Overlays | ✅ | ✅ | ✅ |
**Note:** Subscreen overlays are visual effects (fog, rain, backgrounds, etc.) that are shared between vanilla ROMs and ZSCustomOverworld. ZSCustomOverworld v2+ expands on this by adding support for custom overlay configurations and additional overlay types.
## Overworld Map Structure
### Core Properties
Each overworld map contains the following core properties:
```cpp
class OverworldMap {
// Basic properties
uint8_t index_; // Map index (0-159)
uint8_t parent_; // Parent map ID
uint8_t world_; // World type (0=LW, 1=DW, 2=SW)
uint8_t game_state_; // Game state (0=Beginning, 1=Zelda, 2=Agahnim)
// Graphics and palettes
uint8_t area_graphics_; // Area graphics ID
uint8_t area_palette_; // Area palette ID
uint8_t main_palette_; // Main palette ID (v2+)
std::array<uint8_t, 3> sprite_graphics_; // Sprite graphics IDs
std::array<uint8_t, 3> sprite_palette_; // Sprite palette IDs
// Map properties
uint16_t message_id_; // Message ID
bool mosaic_; // Mosaic effect enabled
bool large_map_; // Is large map (vanilla)
AreaSizeEnum area_size_; // Area size (v3)
// Custom features (v2/v3)
uint16_t area_specific_bg_color_; // Custom background color
uint16_t subscreen_overlay_; // Subscreen overlay ID (references special area maps)
uint8_t animated_gfx_; // Animated graphics ID
std::array<uint8_t, 8> custom_gfx_ids_; // Custom tile graphics
// Overlay support (vanilla and custom)
uint16_t vanilla_overlay_id_; // Vanilla overlay ID
bool has_vanilla_overlay_; // Has vanilla overlay data
std::vector<uint8_t> vanilla_overlay_data_; // Raw overlay data
};
```
## Overlays and Special Area Maps
### Understanding Overlays
Overlays in Zelda 3 are **visual effects** that are displayed over or behind the main overworld map. They include effects like fog, rain, canopy, backgrounds, and other atmospheric elements. Overlays are collections of tile positions and tile IDs that specify where to place specific graphics on the map.
### Special Area Maps (0x80-0x9F)
The special area maps (0x80-0x9F) contain the actual tile data for overlays. These maps store the graphics that overlays reference and use to create visual effects:
- **0x80-0x8F**: Various special area maps containing overlay graphics
- **0x90-0x9F**: Additional special area maps including more overlay graphics
### Overlay ID Mappings
Overlay IDs directly correspond to special area map indices. Common overlay mappings:
| Overlay ID | Special Area Map | Description |
|------------|------------------|-------------|
| 0x0093 | 0x93 | Triforce Room Curtain |
| 0x0094 | 0x94 | Under the Bridge |
| 0x0095 | 0x95 | Sky Background (LW Death Mountain) |
| 0x0096 | 0x96 | Pyramid Background |
| 0x0097 | 0x97 | First Fog Overlay (Master Sword Area) |
| 0x009C | 0x9C | Lava Background (DW Death Mountain) |
| 0x009D | 0x9D | Second Fog Overlay (Lost Woods/Skull Woods) |
| 0x009E | 0x9E | Tree Canopy (Forest) |
| 0x009F | 0x9F | Rain Effect (Misery Mire) |
### Drawing Order
Overlays are drawn in a specific order based on their type:
- **Background Overlays** (0x95, 0x96, 0x9C): Drawn behind the main map tiles
- **Foreground Overlays** (0x9D, 0x97, 0x93, 0x94, 0x9E, 0x9F): Drawn on top of the main map tiles with transparency
### Vanilla Overlay Loading
In vanilla ROMs, overlays are loaded by parsing SNES assembly-like commands that specify tile positions and IDs:
```cpp
absl::Status LoadVanillaOverlay() {
uint8_t asm_version = (*rom_)[OverworldCustomASMHasBeenApplied];
// Only load vanilla overlays for vanilla ROMs
if (asm_version != 0xFF) {
has_vanilla_overlay_ = false;
return absl::OkStatus();
}
// Load overlay pointer for this map
int address = (kOverlayPointersBank << 16) +
((*rom_)[kOverlayPointers + (index_ * 2) + 1] << 8) +
(*rom_)[kOverlayPointers + (index_ * 2)];
// Parse overlay commands:
// LDA #$xxxx - Load tile ID into accumulator
// LDX #$xxxx - Load position into X register
// STA $xxxx - Store tile at position
// STA $xxxx,x - Store tile at position + X
// INC A - Increment accumulator (for sequential tiles)
// JMP $xxxx - Jump to another overlay routine
// END (0x60) - End of overlay data
return absl::OkStatus();
}
```
### Special Area Graphics Loading
Special area maps require special handling for graphics loading:
```cpp
void LoadAreaInfo() {
if (parent_ >= kSpecialWorldMapIdStart) {
// Special World (SW) areas
if (asm_version >= 3 && asm_version != 0xFF) {
// Use expanded sprite tables for v3
sprite_graphics_[0] = (*rom_)[kOverworldSpecialSpriteGfxGroupExpandedTemp +
parent_ - kSpecialWorldMapIdStart];
} else {
// Use original sprite tables for v2/vanilla
sprite_graphics_[0] = (*rom_)[kOverworldSpecialGfxGroup +
parent_ - kSpecialWorldMapIdStart];
}
// Handle special cases for specific maps
if (index_ == 0x88 || index_ == 0x93) {
area_graphics_ = 0x51;
area_palette_ = 0x00;
} else if (index_ == 0x95) {
// Make this the same GFX as LW death mountain areas
area_graphics_ = (*rom_)[kAreaGfxIdPtr + 0x03];
area_palette_ = (*rom_)[kOverworldMapPaletteIds + 0x03];
} else if (index_ == 0x96) {
// Make this the same GFX as pyramid areas
area_graphics_ = (*rom_)[kAreaGfxIdPtr + 0x5B];
area_palette_ = (*rom_)[kOverworldMapPaletteIds + 0x5B];
} else if (index_ == 0x9C) {
// Make this the same GFX as DW death mountain areas
area_graphics_ = (*rom_)[kAreaGfxIdPtr + 0x43];
area_palette_ = (*rom_)[kOverworldMapPaletteIds + 0x43];
}
}
}
```
## Loading Process
### 1. Version Detection
Both editors first detect the ROM version:
```cpp
uint8_t asm_version = rom[OverworldCustomASMHasBeenApplied];
```
### 2. Map Initialization
For each of the 160 overworld maps (0x00-0x9F):
```cpp
// ZScream
var map = new OverworldMap(index, overworld);
// Yaze
OverworldMap map(index, rom);
```
### 3. Property Loading
The loading process varies by ROM version:
#### Vanilla ROMs (asm_version == 0xFF)
```cpp
void LoadAreaInfo() {
// Load from vanilla tables
message_id_ = rom[kOverworldMessageIds + index_ * 2];
area_graphics_ = rom[kOverworldMapGfx + index_];
area_palette_ = rom[kOverworldMapPaletteIds + index_];
// Determine large map status
large_map_ = (rom[kOverworldMapSize + index_] != 0);
// Load vanilla overlay
LoadVanillaOverlay();
}
```
#### ZSCustomOverworld v2/v3
```cpp
void LoadAreaInfo() {
// Use expanded tables for v3
if (asm_version >= 3) {
message_id_ = rom[kOverworldMessagesExpanded + index_ * 2];
area_size_ = static_cast<AreaSizeEnum>(rom[kOverworldScreenSize + index_]);
} else {
message_id_ = rom[kOverworldMessageIds + index_ * 2];
area_size_ = large_map_ ? LargeArea : SmallArea;
}
// Load custom overworld data
LoadCustomOverworldData();
}
```
### 4. Custom Data Loading
For ZSCustomOverworld ROMs:
```cpp
void LoadCustomOverworldData() {
// Load main palette
main_palette_ = rom[OverworldCustomMainPaletteArray + index_];
// Load custom background color
if (rom[OverworldCustomAreaSpecificBGEnabled] != 0) {
area_specific_bg_color_ = rom[OverworldCustomAreaSpecificBGPalette + index_ * 2];
}
// Load v3 features
if (asm_version >= 3) {
subscreen_overlay_ = rom[OverworldCustomSubscreenOverlayArray + index_ * 2];
animated_gfx_ = rom[OverworldCustomAnimatedGFXArray + index_];
// Load custom tile graphics (8 sheets)
for (int i = 0; i < 8; i++) {
custom_gfx_ids_[i] = rom[OverworldCustomTileGFXGroupArray + index_ * 8 + i];
}
}
}
```
## ZScream Implementation
### OverworldMap Constructor
```csharp
public OverworldMap(byte index, Overworld overworld) {
Index = index;
this.overworld = overworld;
// Load area info
LoadAreaInfo();
// Load custom data if available
if (ROM.DATA[Constants.OverworldCustomASMHasBeenApplied] != 0xFF) {
LoadCustomOverworldData();
}
// Build graphics and palette
BuildMap();
}
```
### Key Methods
- `LoadAreaInfo()`: Loads basic map properties from ROM
- `LoadCustomOverworldData()`: Loads ZSCustomOverworld features
- `LoadPalette()`: Loads and processes palette data
- `BuildMap()`: Constructs the final map bitmap
**Note**: ZScream is the original C# implementation that yaze is designed to be compatible with.
## Yaze Implementation
### OverworldMap Constructor
```cpp
OverworldMap::OverworldMap(int index, Rom* rom) : index_(index), rom_(rom) {
LoadAreaInfo();
LoadCustomOverworldData();
SetupCustomTileset(asm_version);
}
```
### Key Methods
- `LoadAreaInfo()`: Loads basic map properties
- `LoadCustomOverworldData()`: Loads ZSCustomOverworld features
- `LoadVanillaOverlay()`: Loads vanilla overlay data
- `LoadPalette()`: Loads and processes palette data
- `BuildTileset()`: Constructs graphics tileset
- `BuildBitmap()`: Creates the final map bitmap
### Current Status
**ZSCustomOverworld v2/v3 Support**: Fully implemented and tested
**Vanilla ROM Support**: Complete compatibility maintained
**Overlay System**: Both vanilla and custom overlays supported
**Map Properties System**: Integrated with UI components
**Graphics Loading**: Optimized with caching and performance monitoring
## Key Differences
### 1. Language and Architecture
| Aspect | ZScream | Yaze |
|--------|---------|------|
| Language | C# | C++ |
| Memory Management | Garbage Collected | Manual (RAII) |
| Graphics | System.Drawing | Custom OpenGL |
| UI Framework | WinForms | ImGui |
### 2. Data Structures
**ZScream:**
```csharp
public class OverworldMap {
public byte Index { get; set; }
public AreaSizeEnum AreaSize { get; set; }
public Bitmap GFXBitmap { get; set; }
// ... other properties
}
```
**Yaze:**
```cpp
class OverworldMap {
uint8_t index_;
AreaSizeEnum area_size_;
std::vector<uint8_t> bitmap_data_;
// ... other member variables
};
```
### 3. Error Handling
**ZScream:** Uses exceptions and try-catch blocks
**Yaze:** Uses `absl::Status` return values and `RETURN_IF_ERROR` macros
### 4. Graphics Processing
**ZScream:** Uses .NET's `Bitmap` class and GDI+
**Yaze:** Uses custom `gfx::Bitmap` class with OpenGL textures
## Common Issues and Solutions
### 1. Version Detection Issues
**Problem:** ROM not recognized as ZSCustomOverworld
**Solution:** Check that `OverworldCustomASMHasBeenApplied` is set correctly
### 2. Palette Loading Errors
**Problem:** Maps appear with wrong colors
**Solution:** Verify palette group addresses and 0xFF fallback handling
### 3. Graphics Not Loading
**Problem:** Blank textures or missing graphics
**Solution:** Check graphics buffer bounds and ProcessGraphicsBuffer implementation
### 4. Overlay Issues
**Problem:** Vanilla overlays not displaying
**Solution:**
- Verify overlay pointer addresses and SNES-to-PC conversion
- Ensure special area maps (0x80-0x9F) are properly loaded with correct graphics
- Check that overlay ID mappings are correct (e.g., 0x009D → map 0x9D)
- Verify that overlay preview shows the actual bitmap of the referenced special area map
**Problem:** Overlay preview showing incorrect information
**Solution:** Ensure overlay preview correctly maps overlay IDs to special area map indices and displays the appropriate bitmap from the special area maps (0x80-0x9F)
### 5. Large Map Problems
**Problem:** Large maps not rendering correctly
**Solution:** Check parent-child relationships and large map detection logic
### 6. Special Area Graphics Issues
**Problem:** Special area maps (0x80-0x9F) showing blank or incorrect graphics
**Solution:**
- Verify special area graphics loading in `LoadAreaInfo()`
- Check that special cases for maps like 0x88, 0x93, 0x95, 0x96, 0x9C are handled correctly
- Ensure proper sprite graphics table selection for v2 vs v3 ROMs
- Verify that special area maps use the correct graphics from referenced LW/DW maps
## Best Practices
### 1. Version-Specific Code
Always check the ASM version before accessing version-specific features:
```cpp
uint8_t asm_version = (*rom_)[OverworldCustomASMHasBeenApplied];
if (asm_version >= 3) {
// v3 features
} else if (asm_version == 0xFF) {
// Vanilla features
}
```
### 2. Error Handling
Use proper error handling for ROM operations:
```cpp
absl::Status LoadPalette() {
RETURN_IF_ERROR(LoadPaletteData());
RETURN_IF_ERROR(ProcessPalette());
return absl::OkStatus();
}
```
### 3. Memory Management
Be careful with memory management in C++:
```cpp
// Good: RAII and smart pointers
std::vector<uint8_t> data;
std::unique_ptr<OverworldMap> map;
// Bad: Raw pointers without cleanup
uint8_t* raw_data = new uint8_t[size];
OverworldMap* map = new OverworldMap();
```
### 4. Thread Safety
Both editors use threading for performance:
```cpp
// Yaze: Use std::async for parallel processing
auto future = std::async(std::launch::async, [this](int map_index) {
RefreshChildMap(map_index);
}, map_index);
```
## Conclusion
Understanding the differences between ZScream and yaze implementations is crucial for maintaining compatibility and adding new features. Both editors follow similar patterns but use different approaches due to their respective languages and architectures.
The key is to maintain the same ROM data structure understanding while adapting to each editor's specific implementation patterns.

View File

@@ -1,27 +0,0 @@
# Build Instructions
## Windows
For VSCode users, use the following CMake extensions with MinGW-w64
https://marketplace.visualstudio.com/items?itemName=twxs.cmake
https://marketplace.visualstudio.com/items?itemName=ms-vscode.cmake-tools
https://www.msys2.org/
Add to environment variables `C:\msys64\mingw64\bin`
Install the following packages using `pacman -S <package-name>`
`mingw-w64-x86_64-gcc`
`mingw-w64-x86_64-gcc-libs`
`mingw-w64-x86_64-cmake`
`mingw-w64-x86_64-glew`
`mingw-w64-x86_64-lib-png`
# macOS
- Clang 15.0.1 x86_64-apple-darrwin22.5.0
- SDL2 Source v2.26.5
- Removed snes_spc
- Removed asar_static

View File

@@ -1,66 +0,0 @@
# LC_LZ2 Compression
The compression algorithm has multiple implementations with varying levels of quality, based primarily on the implementations made in skarsnik/sneshacking, Zarby89/ZScreamDungeon and ZCompress with optimizations made for C++.
Currently, the Compress and Uncompress methods from Hyrule Magic are used and all other compression methods are considered deprecated.
## Key Definitions
### Constants and Macros:
- `BUILD_HEADER(command, length)`: Macro to build a header from a command and a length.
- Command Constants: Constants to represent different commands like `kCommandDirectCopy`, `kCommandByteFill`, etc.
- Length and Mode Constants: Such as `kMaxLengthNormalHeader`, `kNintendoMode1`, etc.
### Data Structures:
#### 1. CompressionCommand:
- **arguments**: 2D array representing the command arguments for each possible command.
- **cmd_size**: Array storing the size of each possible command.
- **data_size**: Array storing the size of the data processed by each possible command.
#### 2. CompressionPiece:
- **command**: Represents the compression command.
- **length**: Length of the compressed data piece.
- **argument_length**: Length of the argument.
- **argument**: Argument as a string.
- **next**: Pointer to the next compression piece.
#### 3. CompressionContext (for Compression V3):
- Contains vectors to store raw and compressed data, compression pieces, and compression string.
- Various counters and flags for compression control.
- Current compression command details.
## Compression Functions
### Version 1:
- **Byte Repeat**: `CheckByteRepeat`
- **Word Repeat**: `CheckWordRepeat`
- **Increasing Byte**: `CheckIncByte`
- **Intra Copy**: `CheckIntraCopy`
- **Validation and Alternatives**: `ValidateForByteGain` & `CompressionCommandAlternative`
### Version 2:
- **Byte Repeat**: `CheckByteRepeatV2`
- **Word Repeat**: `CheckWordRepeatV2`
- **Increasing Byte**: `CheckIncByteV2`
- **Intra Copy**: `CheckIntraCopyV2`
- **Validation and Alternatives**: `ValidateForByteGainV2` & `CompressionCommandAlternativeV2`
### Version 3:
Using `CompressionContext` to handle compression.
- **Initialization**: `InitializeCompression`
- **Command Checks**: Such as `CheckByteRepeatV3`
- **Determining Best Compression**: `DetermineBestCompression`
- **Handling Direct Copy**: `HandleDirectCopy`
- **Adding Compression to Chain**: `AddCompressionToChain`
## Decompression Functions:
- `SetBuffer`: Prepares a buffer from data.
- `memfill`: Fills memory.
- **Decompression**: Such as `DecompressV2`, `DecompressGraphics`, and `DecompressOverworld`.
## Utility Functions:
- **Printing**: Such as `PrintCompressionPiece` and `PrintCompressionChain`.
- **Compression String Creation**: `CreateCompressionString`
- **Compression Result Validation**: Such as `ValidateCompressionResult` and its V3 variant.
- **Compression Piece Manipulation**: Like `SplitCompressionPiece` and its V3 variant.

View File

@@ -1,23 +0,0 @@
# Getting Started with YAZE
This software allows you to modify the classic SNES game "The Legend of Zelda: A Link to the Past" by editing its ROM file. With this editor, you can change various aspects of the game, such as the maps, sprites, items, and more.
Please note that this project is currently a work in progress, and some features may not be fully implemented or may be subject to change.
## Prerequisites
Before you start using YAZE, make sure you have the following:
- A copy of "The Legend of Zelda: A Link to the Past" ROM file (US or JP)
- Basic knowledge of hexadecimal and binary data
## Usage
To use the Link to the Past ROM Editor, follow these steps:
Open the ROM file using the "File" menu.
...
Save your changes using the "File" menu.
Backup files are enabled by default. Each save will produce a timestamped copy of your ROM before you last saved.
That's it! With these instructions, you should be able to get started with using YAZE. Happy editing!

46
docs/index.md Normal file
View File

@@ -0,0 +1,46 @@
# YAZE Documentation
Yet Another Zelda3 Editor - A comprehensive ROM editor for The Legend of Zelda: A Link to the Past.
## Quick Start
- [Getting Started](01-getting-started.md) - Basic setup and usage
- [Build Instructions](02-build-instructions.md) - Cross-platform build guide
- [Asar Integration](03-asar-integration.md) - 65816 assembler usage
- [API Reference](04-api-reference.md) - C/C++ API documentation
## Development
- [Testing Guide](A1-testing-guide.md) - Testing framework and best practices
- [Contributing](B1-contributing.md) - Development guidelines and standards
- [Platform Compatibility](B2-platform-compatibility.md) - Cross-platform support details
- [Build Presets](B3-build-presets.md) - CMake preset usage guide
- [Release Workflows](B4-release-workflows.md) - GitHub Actions release pipeline documentation
## Technical Documentation
### Assembly & Code
- [Assembly Style Guide](E1-asm-style-guide.md) - 65816 assembly coding standards
### Editor Systems
- [Dungeon Editor Guide](E2-dungeon-editor-guide.md) - Complete dungeon editing guide
- [Dungeon Editor Design](E3-dungeon-editor-design.md) - Architecture and development guide
- [Dungeon Editor Refactoring](E4-dungeon-editor-refactoring.md) - Component-based architecture plan
- [Dungeon Object System](E5-dungeon-object-system.md) - Object management framework
### Overworld System
- [Overworld Loading](F1-overworld-loading.md) - ZSCustomOverworld v3 implementation
## Key Features
- Complete GUI editor for all aspects of Zelda 3 ROM hacking
- Integrated Asar 65816 assembler for custom code patches
- ZSCustomOverworld v3 support for enhanced overworld editing
- Cross-platform support (Windows, macOS, Linux)
- Modern C++23 codebase with comprehensive testing
- **Windows Development**: Automated setup scripts, Visual Studio integration, vcpkg package management
- **CMake Compatibility**: Automatic handling of submodule compatibility issues (abseil-cpp, SDL)
---
*Last updated: September 2025 - Version 0.3.0*

View File

@@ -1,140 +0,0 @@
# YAZE Infrastructure Overview
For developers to reference.
## Directory Structure
- **.github/workflows**: Contains `yaze_test` workflow config.
- **assets**: Hosts assets like fonts.
- **cmake**: Contains CMake configurations.
- **docs**: Contains documentation for users and developers.
- [Getting Started](./getting-started.md)
- [LC_LZ2 Compression](./compression.md)
- **src**: Contains source files.
- **app**: Contains the GUI editor `yaze`
- **cli**: Contains the command line interface `z3ed`
- **lib**: Contains git submodule dependencies.
- Abseil-cpp
- Asar
- ImGui
- ImGuiFileDialog
- ImGuiColorTextEdit
- imgui_memory_editor
- SDL2
- **test**: Contains testing interface `yaze_test`
### Flow of Control
- [app/yaze.cc](../src/app/yaze.cc)
- Initializes `absl::FailureSignalHandler` for stack tracing.
- Runs the `core::Controller` loop.
- [app/core/controller.cc](../src/app/core/controller.cc)
- Initializes SDLRenderer and SDLWindow
- Initializes ImGui, fonts, themes, and clipboard.
- Handles user input from keyboard and mouse.
- Updates `editor::MasterEditor`
- Renders the output to the screen.
- Handles the teardown of SDL and ImGui resources.
- [app/editor/master_editor.cc](../src/app/editor/master_editor.cc)
- Handles the main menu bar.
- File
- Open - [app::ROM::LoadFromFile](../src/app/rom.cc#l=90)
- Save - [app::ROM::SaveToFile](../src/app/rom.cc#l=301)
- Edit
- View
- Emulator
- HEX Editor
- ASM Editor
- Palette Editor
- Memory Viewer
- ImGui Demo
- GUI Tools
- Runtime Metrics
- Style Editor
- Help
- Handles `absl::Status` errors as popups delivered to the user.
- Update all the editors in a tab view.
- [app/editor/assembly_editor.cc](../src/app/editor/assembly_editor.cc)
- [app/editor/dungeon_editor.cc](../src/app/editor/dungeon_editor.cc)
- [app/editor/graphics_editor.cc](../src/app/editor/graphics_editor.cc)
- [app/editor/music_editor.cc](../src/app/editor/music_editor.cc)
- [app/editor/overworld_editor.cc](../src/app/editor/overworld_editor.cc)
- [app/editor/screen_editor.cc](../src/app/editor/screen_editor.cc)
- [app/editor/sprite_editor.cc](../src/app/editor/sprite_editor.cc)
## ROM
- [app/rom.cc](../src/app/rom.cc)
- [app/rom.h](../src/app/rom.h)
---
This `ROM` class provides methods to manipulate and access data from a ROM.
- **Key Methods**:
- `Load2BppGraphics()`: Loads 2BPP graphics data from specified sheets.
- `LoadAllGraphicsData()`: Loads all graphics data, both compressed and uncompressed, converting where necessary.
- `LoadFromFile(const absl::string_view& filename, bool z3_load)`: Loads ROM data from a file. It also handles headers and Zelda 3 specific data if requested.
- `LoadFromPointer(uchar* data, size_t length)`: Loads ROM data from a provided pointer.
- `LoadFromBytes(const Bytes& data)`: Loads ROM data from bytes.
- `LoadAllPalettes()`: Loads all color palettes used in the ROM. This includes palettes for various elements like sprites, shields, swords, etc.
- `UpdatePaletteColor(...)`: Updates a specific color within a named palette group.
- **Internal Data Structures**:
- `rom_data_`: A container that holds the ROM data.
- `graphics_bin_`: Holds the graphics data.
- `palette_groups_`: A map containing various palette groups, each having its own set of color palettes.
- **Special Notes**:
- The class interacts with various external functionalities, such as decompression algorithms (`gfx::DecompressV2`) and color conversion (`gfx::SnesTo8bppSheet`).
- Headers in the ROM data, if present, are identified and removed.
- Specific Zelda 3 data can be loaded if specified.
- Palettes are categorized into multiple groups (e.g., `ow_main`, `ow_aux`, `hud`, etc.) and loaded accordingly.
## Bitmap
- [app/gfx/bitmap.cc](../src/app/gfx/bitmap.cc)
- [app/gfx/bitmap.h](../src/app/gfx/bitmap.cc)
---
This class is responsible for creating, managing, and manipulating bitmap data, which can be displayed on the screen using the ImGui library.
### Key Attributes:
1. **Width, Height, Depth, and Data Size**: These represent the dimensions and data size of the bitmap.
2. **Pixel Data**: Points to the raw data of the bitmap.
3. **Texture and Surface**: Use SDL to manage the graphical representation of the bitmap data. Both these attributes have custom deleters, ensuring proper resource management.
### Main Functions:
1. **Constructors**: Multiple constructors allow for different ways to create a Bitmap instance, like specifying width, height, depth, and data.
2. **Create**: This set of overloaded functions provides ways to create a bitmap from different data sources.
3. **CreateFromSurface**: Allows for the creation of a bitmap from an SDL_Surface.
4. **Apply**: Changes the bitmap's data to a new set of Bytes.
5. **Texture Operations**:
- **CreateTexture**: Creates an SDL_Texture from the bitmap's data for rendering.
- **UpdateTexture**: Updates the SDL_Texture with the latest bitmap data.
6. **SaveSurfaceToFile**: Saves the SDL_Surface to a file.
7. **SetSurface**: Assigns a new SDL_Surface to the bitmap.
8. **Palette Functions**:
- **ApplyPalette (Overloaded)**: This allows for the application of a SNESPalette or a standard SDL_Color palette to the bitmap.
9. **WriteToPixel**: Directly writes a value to a specified position in the pixel data.
## Z3ED cli
| Command | Arg | Params | Status |
|---------|-----|--------|--------|
| Apply BPS Patch | -a | rom_file bps_file | In progress |
| Create BPS Patch | -c | bps_file src_file modified_file | Not started |
| Open ROM | -o | rom_file | Complete |
| Backup ROM | -b | rom_file [new_file] | In progress |
| Expand ROM | -x | rom_file file_size | Not started |
| Transfer Tile16 | -t | src_rom dest_rom tile32_id_list(csv) | Complete |
| Export Graphics | -e | rom_file bin_file | In progress |
| Import Graphics | -i | bin_file rom_file | Not started |
| SNES to PC Address | -s | address | Complete |
| PC to SNES Address | -p | address | Complete |
## Further Development Ideas
- Extend `zelda3` namespace with additional functionalities.
- Optimize program performance.
- Introduce new features in the GUI editor.

165
docs/vcpkg-integration.md Normal file
View File

@@ -0,0 +1,165 @@
# vcpkg Integration for Windows Builds
> **Note**: This document provides detailed vcpkg information. For the most up-to-date build instructions, see [Build Instructions](02-build-instructions.md).
This document describes how to use vcpkg for Windows builds in Visual Studio with YAZE.
## Overview
vcpkg is Microsoft's C++ package manager that simplifies dependency management for Windows builds. YAZE now includes full vcpkg integration with manifest mode support for automatic dependency resolution.
## Features
- **Manifest Mode**: Dependencies are automatically managed via `vcpkg.json`
- **Visual Studio Integration**: Seamless integration with Visual Studio 2022
- **Generated Project Files**: Visual Studio project files with proper vcpkg integration
- **CMake Presets**: Pre-configured build presets for Windows
- **Automatic Setup**: Setup scripts for easy vcpkg installation
## Quick Start
### 1. Setup vcpkg
Run the automated setup script:
```powershell
# PowerShell (recommended)
.\scripts\setup-windows-dev.ps1
```
This will:
- Set up vcpkg
- Install dependencies (zlib, libpng, SDL2)
- Generate Visual Studio project files with proper vcpkg integration
### 2. Build with Visual Studio
```powershell
# Generate project files (if not already done)
python scripts/generate-vs-projects.py
# Open YAZE.sln in Visual Studio 2022
# Select configuration and platform, then build
```
### 3. Alternative: Build with CMake
Use the Windows presets in CMakePresets.json:
```cmd
# Debug build
cmake --preset windows-debug
cmake --build build --preset windows-debug
# Release build
cmake --preset windows-release
cmake --build build --preset windows-release
```
## Configuration Details
### vcpkg.json Manifest
The `vcpkg.json` file defines all dependencies:
```json
{
"name": "yaze",
"version": "0.3.1",
"description": "Yet Another Zelda3 Editor",
"dependencies": [
{
"name": "zlib",
"platform": "!uwp"
},
{
"name": "libpng",
"platform": "!uwp"
},
{
"name": "sdl2",
"platform": "!uwp",
"features": ["vulkan"]
}
],
"builtin-baseline": "2024.12.12"
}
```
### CMake Configuration
vcpkg integration is handled in several files:
- **CMakeLists.txt**: Automatic toolchain detection
- **cmake/vcpkg.cmake**: vcpkg-specific settings
- **CMakePresets.json**: Windows build presets
### Build Presets
Available Windows presets:
- `windows-debug`: Debug build with vcpkg
- `windows-release`: Release build with vcpkg
## Dependencies
vcpkg automatically installs these dependencies:
- **zlib**: Compression library
- **libpng**: PNG image support
- **sdl2**: Graphics and input handling (with Vulkan support)
**Note**: Abseil and gtest are now built from source via CMake rather than through vcpkg to avoid compatibility issues.
## Environment Variables
Set `VCPKG_ROOT` to point to your vcpkg installation:
```cmd
set VCPKG_ROOT=C:\path\to\vcpkg
```
## Troubleshooting
### Common Issues
1. **vcpkg not found**: Ensure `VCPKG_ROOT` is set or vcpkg is in the project directory
2. **Dependencies not installing**: Check internet connection and vcpkg bootstrap
3. **Visual Studio integration**: Run `vcpkg integrate install` from vcpkg directory
### Manual Setup
If automated setup fails:
```cmd
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
.\bootstrap-vcpkg.bat
.\vcpkg.exe integrate install
```
## Benefits
- **Consistent Dependencies**: Same versions across development environments
- **Easy Updates**: Update dependencies via vcpkg.json
- **CI/CD Friendly**: Reproducible builds
- **Visual Studio Integration**: Native IntelliSense support
- **No Manual Downloads**: Automatic dependency resolution
## Advanced Usage
### Custom Triplets
Override the default x64-windows triplet:
```cmd
cmake --preset windows-debug -DVCPKG_TARGET_TRIPLET=x86-windows
```
### Static Linking
For static builds, modify `cmake/vcpkg.cmake`:
```cmake
set(VCPKG_LIBRARY_LINKAGE static)
set(VCPKG_CRT_LINKAGE static)
```

117
docs/vcpkg-triplet-setup.md Normal file
View File

@@ -0,0 +1,117 @@
# Installing vcpkg Triplets for Windows
This guide explains how to install the `x64-windows` triplet that's required for building YAZE on Windows.
## What is a vcpkg Triplet?
A triplet defines the target platform, architecture, and linking configuration for vcpkg packages. The `x64-windows` triplet is the most common one for 64-bit Windows development.
## Method 1: Install via Package (Recommended)
The easiest way to ensure the triplet is available is to install any package with that triplet:
```cmd
# Navigate to your vcpkg directory
cd C:\path\to\your\vcpkg
# Install a package with the x64-windows triplet
vcpkg install sdl2:x64-windows
```
This will automatically create the triplet configuration if it doesn't exist.
## Method 2: Create Triplet File Manually
If you need to create the triplet configuration manually:
1. **Navigate to vcpkg triplets directory:**
```cmd
cd C:\path\to\your\vcpkg\triplets
```
2. **Create or verify `x64-windows.cmake` exists:**
```cmd
dir x64-windows.cmake
```
3. **If it doesn't exist, create it with this content:**
```cmake
set(VCPKG_TARGET_ARCHITECTURE x64)
set(VCPKG_CRT_LINKAGE dynamic)
set(VCPKG_LIBRARY_LINKAGE dynamic)
set(VCPKG_CMAKE_SYSTEM_NAME Windows)
```
## Method 3: Check Available Triplets
To see what triplets are currently available on your system:
```cmd
vcpkg help triplet
```
Or list all available triplet files:
```cmd
vcpkg help triplet | findstr "Available"
```
## Method 4: Install YAZE Dependencies
Since YAZE uses several vcpkg packages, installing them will ensure the triplet is properly set up:
```cmd
# From the YAZE project root
vcpkg install --triplet x64-windows sdl2 zlib libpng abseil
```
## Common Issues and Solutions
### Issue: "Invalid triplet"
**Solution:** Make sure vcpkg is properly installed and in your PATH:
```cmd
vcpkg version
```
### Issue: "Triplet not found"
**Solution:** Install a package with that triplet first:
```cmd
vcpkg install zlib:x64-windows
```
### Issue: "Permission denied"
**Solution:** Run Command Prompt as Administrator, or install vcpkg in a user-writable location.
## Alternative Triplets
If `x64-windows` doesn't work, you can try these alternatives:
- `x64-windows-static` - Static linking
- `x86-windows` - 32-bit Windows
- `x64-windows-static-md` - Static runtime, dynamic CRT
## Verification
To verify the triplet is working:
```cmd
vcpkg list --triplet x64-windows
```
This should show installed packages for that triplet.
## For YAZE Build
Once the triplet is installed, you can build YAZE using CMake presets:
```cmd
cmake --preset=windows-release
cmake --build build --config Release
```
Or with the Visual Studio solution:
```cmd
# Open yaze.sln in Visual Studio
# Build normally (F5 or Ctrl+Shift+B)
```

284
docs/visual-studio-setup.md Normal file
View File

@@ -0,0 +1,284 @@
# Visual Studio Setup Guide
> **Note**: This document provides detailed Visual Studio setup information. For the most up-to-date build instructions, see [Build Instructions](02-build-instructions.md).
This guide will help Visual Studio users set up and build the yaze project on Windows.
## Prerequisites
### Required Software
1. **Visual Studio 2022** (Community, Professional, or Enterprise)
- Install with "Desktop development with C++" workload
- Ensure CMake tools are included
- Install Git for Windows (or use built-in Git support)
2. **vcpkg** (Package Manager)
- Download from: https://github.com/Microsoft/vcpkg
- Follow installation instructions to integrate with Visual Studio
3. **CMake** (3.16 or later)
- Usually included with Visual Studio 2022
- Verify with: `cmake --version`
### Environment Setup
1. **Set up vcpkg environment variable:**
```cmd
set VCPKG_ROOT=C:\vcpkg
```
2. **Integrate vcpkg with Visual Studio:**
```cmd
cd C:\vcpkg
.\vcpkg integrate install
```
## Project Setup
### 1. Clone the Repository
```cmd
git clone --recursive https://github.com/your-username/yaze.git
cd yaze
```
### 2. Install Dependencies via vcpkg
The project uses `vcpkg.json` for automatic dependency management. Dependencies will be installed automatically during CMake configuration.
Manual installation (if needed):
```cmd
vcpkg install zlib:x64-windows
vcpkg install libpng:x64-windows
vcpkg install sdl2[vulkan]:x64-windows
vcpkg install abseil:x64-windows
vcpkg install gtest:x64-windows
```
### 3. Configure Build System
#### Option A: Using Visual Studio Project File (Easiest)
1. Open Visual Studio 2022
2. Select "Open a project or solution"
3. Navigate to the yaze project folder and open `yaze.sln`
4. The project is pre-configured with vcpkg integration and proper dependencies
5. Select your desired build configuration (Debug/Release) and platform (x64/x86)
6. Press F5 to build and run, or Ctrl+Shift+B to build only
#### Option B: Using CMake with Visual Studio (Recommended for developers)
1. Open Visual Studio 2022
2. Select "Open a local folder" and navigate to the yaze project folder
3. Visual Studio will automatically detect the CMake project
4. Wait for CMake configuration to complete (check Output window)
#### Option C: Using Command Line
```cmd
mkdir build
cd build
cmake .. -G "Visual Studio 17 2022" -A x64 -DCMAKE_TOOLCHAIN_FILE=%VCPKG_ROOT%/scripts/buildsystems/vcpkg.cmake
```
### 4. Build Configuration
#### Using Visual Studio Project File (.vcxproj)
- **Debug Build:** Select "Debug" configuration and press F5 or Ctrl+Shift+B
- **Release Build:** Select "Release" configuration and press F5 or Ctrl+Shift+B
- **Platform:** Choose x64 (recommended) or x86 from the platform dropdown
#### Using CMake (Command Line)
```cmd
# For Development (Debug Build)
cmake --build . --config Debug --target yaze
# For Release Build
cmake --build . --config Release --target yaze
# For Testing (Optional)
cmake --build . --config Debug --target yaze_test
```
## Common Issues and Solutions
### Issue 1: zlib Import Errors
**Problem:** `fatal error C1083: Cannot open include file: 'zlib.h'`
**Solution:**
1. Ensure vcpkg is properly integrated with Visual Studio
2. Verify the vcpkg toolchain file is set:
```cmd
cmake .. -DCMAKE_TOOLCHAIN_FILE=%VCPKG_ROOT%/scripts/buildsystems/vcpkg.cmake
```
3. Check that zlib is installed:
```cmd
vcpkg list zlib
```
### Issue 2: Executable Runs Tests Instead of Main App
**Problem:** Running `yaze.exe` starts the test framework instead of the application
**Solution:** This has been fixed in the latest version. The issue was caused by linking `gtest_main` to the main executable. The fix removes `gtest_main` from the main application while keeping `gtest` for testing capabilities.
### Issue 3: SDL2 Configuration Issues
**Problem:** SDL2 not found or linking errors
**Solution:**
1. Install SDL2 with vcpkg:
```cmd
vcpkg install sdl2[vulkan]:x64-windows
```
2. Ensure the project uses the vcpkg toolchain file
### Issue 4: Build Errors with Abseil
**Problem:** Missing Abseil symbols or linking issues
**Solution:**
1. Install Abseil via vcpkg:
```cmd
vcpkg install abseil:x64-windows
```
2. The project is configured to use Abseil 20240116.2 (see vcpkg.json overrides)
## Visual Studio Configuration
### CMake Settings
Create or modify `.vscode/settings.json` or use Visual Studio's CMake settings:
```json
{
"cmake.configureArgs": [
"-DCMAKE_TOOLCHAIN_FILE=${env:VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake",
"-Dyaze_BUILD_TESTS=ON",
"-Dyaze_BUILD_APP=ON",
"-Dyaze_BUILD_LIB=ON"
],
"cmake.buildDirectory": "${workspaceFolder}/build"
}
```
### Build Presets
The project includes CMake presets in `CMakePresets.json`. Use these in Visual Studio:
1. **Debug Build:** `debug` preset
2. **Release Build:** `release` preset
3. **Development Build:** `dev` preset (includes ROM testing)
## Running the Application
### Using Visual Studio Project File
1. Open `yaze.sln` in Visual Studio
2. Set `yaze` as the startup project (should be default)
3. Configure command line arguments in Project Properties > Debugging > Command Arguments
- Example: `--rom_file=C:\path\to\your\zelda3.sfc`
4. Press F5 to build and run, or Ctrl+F5 to run without debugging
### Command Line
```cmd
cd build/bin/Debug # or Release
yaze.exe --rom_file=path/to/your/zelda3.sfc
```
### Visual Studio (CMake)
1. Set `yaze` as the startup project
2. Configure command line arguments in Project Properties > Debugging
3. Press F5 to run
## Testing
### Run Unit Tests
```cmd
cd build
ctest --build-config Debug
```
### Run Specific Test Suite
```cmd
cd build/bin/Debug
yaze_test.exe
```
## Troubleshooting
### Clean Build
If you encounter persistent issues:
```cmd
rmdir /s build
mkdir build
cd build
cmake .. -G "Visual Studio 17 2022" -A x64 -DCMAKE_TOOLCHAIN_FILE=%VCPKG_ROOT%/scripts/buildsystems/vcpkg.cmake
cmake --build . --config Debug
```
### Check Dependencies
Verify all dependencies are properly installed:
```cmd
vcpkg list
```
### CMake Cache Issues
Clear CMake cache:
```cmd
del CMakeCache.txt
cmake .. -DCMAKE_TOOLCHAIN_FILE=%VCPKG_ROOT%/scripts/buildsystems/vcpkg.cmake
```
## Visual Studio Project File Features
The included `yaze.vcxproj` and `yaze.sln` files provide:
### **Automatic Dependency Management**
- **vcpkg Integration:** Automatically installs and links dependencies from `vcpkg.json`
- **Platform Support:** Pre-configured for both x64 and x86 builds
- **Library Linking:** Automatically links SDL2, zlib, libpng, and system libraries
### **Build Configuration**
- **Debug Configuration:** Includes debugging symbols and runtime checks
- **Release Configuration:** Optimized for performance with full optimizations
- **C++23 Standard:** Uses modern C++ features and standard library
### **Asset Management**
- **Automatic Asset Copying:** Post-build events copy themes and assets to output directory
- **ROM File Handling:** Automatically copies `zelda3.sfc` if present in project root
- **Resource Organization:** Properly structures output directory for distribution
### **Development Features**
- **IntelliSense Support:** Full code completion and error detection
- **Debugging Integration:** Native Visual Studio debugging support
- **Project Properties:** Easy access to compiler and linker settings
## CI/CD Integration
The Visual Studio project files are fully integrated into the CI/CD pipeline:
### **Automated Validation**
- **Pre-commit checks:** Visual Studio builds are validated on every pull request
- **Release validation:** Both CMake and Visual Studio builds are tested before release
- **Multi-platform testing:** x64 and x86 builds are validated on Windows
- **Dependency verification:** vcpkg integration is tested automatically
### **Build Matrix**
The CI/CD pipeline tests:
- **Windows x64 Debug/Release** using Visual Studio 2022
- **Windows x86 Debug/Release** using Visual Studio 2022
- **CMake builds** alongside Visual Studio builds for compatibility
- **Asset copying** and executable functionality
### **Quality Assurance**
- **Test main detection:** Prevents the test framework from hijacking the main application
- **Asset validation:** Ensures themes and resources are properly copied
- **Executable testing:** Verifies the application starts correctly
- **Dependency checking:** Validates all required libraries are properly linked
## Additional Notes
- The project supports both x64 and x86 builds (use appropriate vcpkg triplets)
- For ARM64 Windows builds, use `arm64-windows` triplet
- The CI/CD pipeline validates both CMake and Visual Studio builds
- Development builds include additional debugging features and ROM testing capabilities
- The `.vcxproj` file provides the easiest setup for Visual Studio users who prefer traditional project files over CMake
- All builds are automatically validated to ensure they produce working executables
## Support
If you encounter issues not covered in this guide:
1. Check the project's GitHub issues
2. Verify your Visual Studio and vcpkg installations
3. Ensure all dependencies are properly installed via vcpkg
4. Try a clean build following the troubleshooting steps above

View File

@@ -0,0 +1,346 @@
# Windows Development Guide for YAZE
This guide will help you set up a Windows development environment for YAZE and build the project successfully.
## Prerequisites
### Required Software
1. **Visual Studio 2022** (Community, Professional, or Enterprise)
- Download from: https://visualstudio.microsoft.com/downloads/
- Required workloads:
- Desktop development with C++
- Game development with C++ (optional, for additional tools)
2. **Git for Windows**
- Download from: https://git-scm.com/download/win
- Use default installation options
3. **Python 3.8 or later**
- Download from: https://www.python.org/downloads/
- Make sure to check "Add Python to PATH" during installation
### Optional Software
- **PowerShell 7** (recommended for better script support)
- **Windows Terminal** (for better terminal experience)
## Quick Setup
### Automated Setup
The easiest way to get started is to use our automated setup script:
```powershell
# Run from the YAZE project root directory
.\scripts\setup-windows-dev.ps1
```
This script will:
- Check for required software (Visual Studio 2022, Git, Python)
- Set up vcpkg and install dependencies (zlib, libpng, SDL2)
- Generate Visual Studio project files with proper vcpkg integration
- Perform a test build to verify everything works
### Manual Setup
If you prefer to set up manually or the automated script fails:
#### 1. Clone the Repository
```bash
git clone https://github.com/your-username/yaze.git
cd yaze
```
#### 2. Set up vcpkg
```bash
# Clone vcpkg
git clone https://github.com/Microsoft/vcpkg.git vcpkg
# Bootstrap vcpkg
cd vcpkg
.\bootstrap-vcpkg.bat
cd ..
# Install dependencies
.\vcpkg\vcpkg.exe install --triplet x64-windows
```
#### 3. Generate Visual Studio Project Files
The generation script creates project files with proper vcpkg integration:
```bash
python scripts/generate-vs-projects.py
```
This creates:
- `YAZE.sln` - Visual Studio solution file
- `YAZE.vcxproj` - Visual Studio project file with vcpkg integration
- Proper vcpkg triplet settings for all platforms (x86, x64, ARM64)
#### 4. Build the Project
```bash
# Using PowerShell script (recommended)
.\scripts\build-windows.ps1 -Configuration Release -Platform x64
# Or using batch script
.\scripts\build-windows.bat Release x64
# Or using Visual Studio
# Open YAZE.sln in Visual Studio 2022 and build
```
## Building the Project
### Using Visual Studio
1. Open `YAZE.sln` in Visual Studio 2022
2. Select your desired configuration:
- **Debug**: For development and debugging
- **Release**: For optimized builds
- **RelWithDebInfo**: Release with debug information
- **MinSizeRel**: Minimal size release
3. Select your platform:
- **x64**: 64-bit (recommended)
- **x86**: 32-bit
- **ARM64**: ARM64 (if supported)
4. Build the solution (Ctrl+Shift+B)
### Using Command Line
#### PowerShell Script (Recommended)
```powershell
# Build Release x64 (default)
.\scripts\build-windows.ps1
# Build Debug x64
.\scripts\build-windows.ps1 -Configuration Debug -Platform x64
# Build Release x86
.\scripts\build-windows.ps1 -Configuration Release -Platform x86
# Clean build
.\scripts\build-windows.ps1 -Clean
# Verbose output
.\scripts\build-windows.ps1 -Verbose
```
#### Batch Script
```batch
REM Build Release x64 (default)
.\scripts\build-windows.bat
REM Build Debug x64
.\scripts\build-windows.bat Debug x64
REM Build Release x86
.\scripts\build-windows.bat Release x86
```
#### Direct MSBuild
```bash
# Build Release x64
msbuild YAZE.sln /p:Configuration=Release /p:Platform=x64 /p:VcpkgEnabled=true /p:VcpkgManifestInstall=true /m
# Build Debug x64
msbuild YAZE.sln /p:Configuration=Debug /p:Platform=x64 /p:VcpkgEnabled=true /p:VcpkgManifestInstall=true /m
```
## Project Structure
```
yaze/
├── YAZE.sln # Visual Studio solution file (generated)
├── YAZE.vcxproj # Visual Studio project file (generated)
├── vcpkg.json # vcpkg dependencies
├── scripts/ # Build and setup scripts
│ ├── build-windows.ps1 # PowerShell build script
│ ├── build-windows.bat # Batch build script
│ ├── setup-windows-dev.ps1 # Automated setup script
│ └── generate-vs-projects.py # Project file generator
├── src/ # Source code
├── incl/ # Public headers
├── assets/ # Game assets
└── docs/ # Documentation
```
**Note**: The Visual Studio project files (`YAZE.sln`, `YAZE.vcxproj`) are generated automatically and should not be edited manually. If you need to modify project settings, update the generation script instead.
## Troubleshooting
### Common Issues
#### 1. MSBuild Not Found
**Error**: `'msbuild' is not recognized as an internal or external command`
**Solution**:
- Install Visual Studio 2022 with C++ workload
- Or add MSBuild to your PATH:
```bash
# Add to PATH (adjust path as needed)
C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin
```
#### 2. vcpkg Integration Issues
**Error**: `vcpkg.json not found` or dependency resolution fails
**Solution**:
- Ensure vcpkg is properly set up:
```bash
.\scripts\setup-windows-dev.ps1
```
- Or manually set up vcpkg as described in the manual setup section
#### 3. ZLIB or Other Dependencies Not Found
**Error**: `Could NOT find ZLIB (missing: ZLIB_LIBRARY ZLIB_INCLUDE_DIR)`
**Solution**:
- This usually means vcpkg integration isn't working properly
- Regenerate project files with proper vcpkg integration:
```bash
python scripts/generate-vs-projects.py
```
- Ensure vcpkg is installed and dependencies are available:
```bash
.\vcpkg\vcpkg.exe install --triplet x64-windows
```
#### 4. Python Script Execution Policy
**Error**: `execution of scripts is disabled on this system`
**Solution**:
```powershell
# Run as Administrator
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
```
#### 5. Missing Dependencies
**Error**: Linker errors about missing libraries
**Solution**:
- Ensure all dependencies are installed via vcpkg:
```bash
.\vcpkg\vcpkg.exe install --triplet x64-windows
```
- Regenerate project files:
```bash
python scripts/generate-vs-projects.py
```
#### 6. Build Failures
**Error**: Compilation or linking errors
**Solution**:
- Clean and rebuild:
```powershell
.\scripts\build-windows.ps1 -Clean
```
- Check that all source files are included in the project
- Verify that include paths are correct
### Getting Help
If you encounter issues not covered here:
1. Check the [main build instructions](02-build-instructions.md)
2. Review the [troubleshooting section](02-build-instructions.md#troubleshooting)
3. Check the [GitHub Issues](https://github.com/your-username/yaze/issues)
4. Create a new issue with:
- Your Windows version
- Visual Studio version
- Complete error message
- Steps to reproduce
## Development Workflow
### Making Changes
1. Make your changes to the source code
2. If you added new source files, regenerate project files:
```bash
python scripts/generate-vs-projects.py
```
3. Build the project:
```powershell
.\scripts\build-windows.ps1 -Configuration Debug -Platform x64
```
4. Test your changes
### Debugging
1. Set breakpoints in Visual Studio
2. Build in Debug configuration
3. Run with debugger (F5)
4. Use Visual Studio's debugging tools
### Testing
1. Build the project
2. Run the executable:
```bash
.\build\bin\Debug\yaze.exe
```
3. Test with a ROM file:
```bash
.\build\bin\Debug\yaze.exe --rom_file=path\to\your\rom.sfc
```
## Performance Tips
### Build Performance
- Use the `/m` flag for parallel builds
- Use SSD storage for better I/O performance
- Exclude build directories from antivirus scanning
- Use Release configuration for final builds
### Development Performance
- Use Debug configuration for development
- Use incremental builds (default in Visual Studio)
- Use RelWithDebInfo for performance testing with debug info
## Advanced Configuration
### Custom Build Configurations
You can create custom build configurations by modifying the Visual Studio project file or using CMake directly.
### Cross-Platform Development
While this guide focuses on Windows, YAZE also supports:
- Linux (Ubuntu/Debian)
- macOS
See the main build instructions for other platforms.
## Contributing
When contributing to YAZE on Windows:
1. Follow the [coding standards](B1-contributing.md)
2. Test your changes on Windows
3. Ensure the build scripts still work
4. Update documentation if needed
5. Submit a pull request
## Additional Resources
- [Visual Studio Documentation](https://docs.microsoft.com/en-us/visualstudio/)
- [vcpkg Documentation](https://vcpkg.readthedocs.io/)
- [CMake Documentation](https://cmake.org/documentation/)
- [YAZE API Reference](04-api-reference.md)

63
docs/yaze.org Normal file
View File

@@ -0,0 +1,63 @@
#+TITLE: yaze todo
#+SUBTITLE: yet another zelda3 editor todo list
#+AUTHOR: @scawful
#+TODO: TODO ACTIVE FEEDBACK VERIFY | DONE
* Daily Log
<2024-11-14 Thu>
Been making lots of adjustments and cleaning up old code. Primarily improving the dungeon map editor and supporting bin graphics for my Oracle of Secrets dungeon maps. Additionally, working to support saving for resources like graphics sheets and expanded the project file system.
<2024-09-07 Sat>
Various header cleanup using the LSP in emacs to detect unused includes.
Making adjustments to font loading so the editor can be opened from terminal/emacs.
Currently the font files and the zeml files require the binary to be relative to `assets/layouts` and `assets/fonts`
I've set it up so that the macOS app bundles the resources into the `yaze.app` so that the binary can be run from anywhere. This will need to be adjusted for other platforms.
<2024-09-02 Mon>
Extracted the DisplayPalette function out of the PaletteEditor and into its own standalone function.
<2024-09-01 Sun>
Started learning spacemacs and org-mode.
* Editors
** Overworld
*** TODO ZSCustomOverworld implementation.
**** DONE Custom Overworld Map Settings Inputs
**** DONE Load ZSCOW data from ROM in OverworldMap
**** TODO Add Main Palette support
**** TODO Add Custom Area BG Color support
*** TODO Fix sprite icon draw positions
*** TODO Fix exit icon draw positions
** Dungeon
*** TODO Draw dungeon objects
** Graphics
*** TODO Tile16 Editor
- [ ] Draw tile8 to tile16 quadrant.
*** TODO Fix graphics sheet pencil drawing
** Message
*** TODO Fix Message Parsing
** Palette
*** TODO Persist color changes for saving to ROM.
** Screens
*** ACTIVE Dungeon Maps
*** ACTIVE Inventory Menu
*** TODO Overworld Map
*** TODO Title Screen
*** TODO Naming Screen
* Infrastructure
** File Handling
*** TODO Update recent files manager to bundle the recent files list with the application
*** DONE Create a util for handling file operations from the bundled resources.
** Font Loading
*** TODO Make font sizes variables so they can be reloaded by the user.
** ZEML
*** DONE Package layout files with the executable to avoid relative file lookup

588
incl/yaze.h Normal file
View File

@@ -0,0 +1,588 @@
#ifndef YAZE_H
#define YAZE_H
/**
* @file yaze.h
* @brief Yet Another Zelda3 Editor (YAZE) - Public C API
*
* This header provides the main C API for YAZE, a modern ROM editor for
* The Legend of Zelda: A Link to the Past. This API allows external
* applications to interact with YAZE's functionality.
*
* @version 0.3.1
* @author YAZE Team
*/
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "zelda.h"
/**
* @defgroup version Version Information
* @{
*/
/** Major version number */
#define YAZE_VERSION_MAJOR 0
/** Minor version number */
#define YAZE_VERSION_MINOR 3
/** Patch version number */
#define YAZE_VERSION_PATCH 1
/** Combined version as a string */
#define YAZE_VERSION_STRING "0.3.1"
/** Combined version as a number (major * 10000 + minor * 100 + patch) */
#define YAZE_VERSION_NUMBER 301
/** @} */
typedef struct yaze_editor_context {
zelda3_rom* rom;
const char* error_message;
} yaze_editor_context;
/**
* @defgroup core Core API
* @{
*/
/**
* @brief Status codes returned by YAZE functions
*
* All YAZE functions that can fail return a status code to indicate
* success or the type of error that occurred.
*/
typedef enum yaze_status {
YAZE_OK = 0, /**< Operation completed successfully */
YAZE_ERROR_UNKNOWN = -1, /**< Unknown error occurred */
YAZE_ERROR_INVALID_ARG = 1, /**< Invalid argument provided */
YAZE_ERROR_FILE_NOT_FOUND = 2, /**< File not found */
YAZE_ERROR_MEMORY = 3, /**< Memory allocation failed */
YAZE_ERROR_IO = 4, /**< I/O operation failed */
YAZE_ERROR_CORRUPTION = 5, /**< Data corruption detected */
YAZE_ERROR_NOT_INITIALIZED = 6, /**< Component not initialized */
} yaze_status;
/**
* @brief Convert a status code to a human-readable string
*
* @param status The status code to convert
* @return A null-terminated string describing the status
*/
const char* yaze_status_to_string(yaze_status status);
/**
* @brief Initialize the YAZE library
*
* This function must be called before using any other YAZE functions.
* It initializes internal subsystems and prepares the library for use.
*
* @return YAZE_OK on success, error code on failure
*/
yaze_status yaze_library_init(void);
/**
* @brief Shutdown the YAZE library
*
* This function cleans up resources allocated by yaze_library_init().
* After calling this function, no other YAZE functions should be called
* until yaze_library_init() is called again.
*/
void yaze_library_shutdown(void);
/**
* @brief Main entry point for the YAZE application
*
* @param argc Number of command line arguments
* @param argv Array of command line argument strings
* @return Exit code (0 for success, non-zero for error)
*/
int yaze_app_main(int argc, char** argv);
/**
* @brief Check if the current YAZE version is compatible with the expected version
*
* @param expected_version Expected version string (e.g., "0.3.1")
* @return true if compatible, false otherwise
*/
bool yaze_check_version_compatibility(const char* expected_version);
/**
* @brief Get the current YAZE version string
*
* @return A null-terminated string containing the version
*/
const char* yaze_get_version_string(void);
/**
* @brief Get the current YAZE version number
*
* @return Version number (major * 10000 + minor * 100 + patch)
*/
int yaze_get_version_number(void);
/**
* @brief Initialize a YAZE editor context
*
* Creates and initializes an editor context for working with ROM files.
* The context manages the ROM data and provides access to editing functions.
*
* @param context Pointer to context structure to initialize
* @param rom_filename Path to the ROM file to load (can be NULL to create empty context)
* @return YAZE_OK on success, error code on failure
*
* @note The caller is responsible for calling yaze_shutdown() to clean up the context
*/
yaze_status yaze_init(yaze_editor_context* context, const char* rom_filename);
/**
* @brief Shutdown and clean up a YAZE editor context
*
* Releases all resources associated with the context, including ROM data.
* After calling this function, the context should not be used.
*
* @param context Pointer to context to shutdown
* @return YAZE_OK on success, error code on failure
*/
yaze_status yaze_shutdown(yaze_editor_context* context);
/** @} */
/**
* @defgroup graphics Graphics and Bitmap Functions
* @{
*/
/**
* @brief Bitmap data structure
*
* Represents a bitmap image with pixel data and metadata.
*/
typedef struct yaze_bitmap {
int width; /**< Width in pixels */
int height; /**< Height in pixels */
uint8_t bpp; /**< Bits per pixel (1, 2, 4, 8) */
uint8_t* data; /**< Pixel data (caller owns memory) */
} yaze_bitmap;
/**
* @brief Load a bitmap from file
*
* Loads a bitmap image from the specified file. Supports common
* image formats and SNES-specific formats.
*
* @param filename Path to the image file
* @return Bitmap structure with loaded data, or empty bitmap on error
*
* @note The caller is responsible for freeing the data pointer
*/
yaze_bitmap yaze_load_bitmap(const char* filename);
/**
* @brief Free bitmap data
*
* Releases memory allocated for bitmap pixel data.
*
* @param bitmap Pointer to bitmap structure to free
*/
void yaze_free_bitmap(yaze_bitmap* bitmap);
/**
* @brief Create an empty bitmap
*
* Allocates a new bitmap with the specified dimensions.
*
* @param width Width in pixels
* @param height Height in pixels
* @param bpp Bits per pixel
* @return Initialized bitmap structure, or empty bitmap on error
*/
yaze_bitmap yaze_create_bitmap(int width, int height, uint8_t bpp);
/**
* @brief SNES color in 15-bit RGB format (BGR555)
*
* Represents a color in the SNES native format. Colors are stored
* as 8-bit values but only the lower 5 bits are used by the SNES.
*/
typedef struct snes_color {
uint16_t red; /**< Red component (0-255, but SNES uses 0-31) */
uint16_t green; /**< Green component (0-255, but SNES uses 0-31) */
uint16_t blue; /**< Blue component (0-255, but SNES uses 0-31) */
} snes_color;
/**
* @brief Convert RGB888 color to SNES color
*
* @param r Red component (0-255)
* @param g Green component (0-255)
* @param b Blue component (0-255)
* @return SNES color structure
*/
snes_color yaze_rgb_to_snes_color(uint8_t r, uint8_t g, uint8_t b);
/**
* @brief Convert SNES color to RGB888
*
* @param color SNES color to convert
* @param r Pointer to store red component (0-255)
* @param g Pointer to store green component (0-255)
* @param b Pointer to store blue component (0-255)
*/
void yaze_snes_color_to_rgb(snes_color color, uint8_t* r, uint8_t* g, uint8_t* b);
/**
* @brief SNES color palette
*
* Represents a color palette used by the SNES. Each palette contains
* up to 256 colors, though most modes use fewer colors per palette.
*/
typedef struct snes_palette {
uint16_t id; /**< Palette ID (0-255) */
uint16_t size; /**< Number of colors in palette (1-256) */
snes_color* colors; /**< Array of colors (caller owns memory) */
} snes_palette;
/**
* @brief Create an empty palette
*
* @param id Palette ID
* @param size Number of colors to allocate
* @return Initialized palette structure, or NULL on error
*/
snes_palette* yaze_create_palette(uint16_t id, uint16_t size);
/**
* @brief Free palette memory
*
* @param palette Pointer to palette to free
*/
void yaze_free_palette(snes_palette* palette);
/**
* @brief Load palette from ROM
*
* @param rom ROM to load palette from
* @param palette_id ID of palette to load
* @return Loaded palette, or NULL on error
*/
snes_palette* yaze_load_palette_from_rom(const zelda3_rom* rom, uint16_t palette_id);
/**
* @brief 8x8 SNES tile data
*
* Represents an 8x8 pixel tile with indexed color data.
* Each pixel value is an index into a palette.
*/
typedef struct snes_tile8 {
uint32_t id; /**< Tile ID for reference */
uint32_t palette_id; /**< Associated palette ID */
uint8_t data[64]; /**< 64 pixels in row-major order (y*8+x) */
} snes_tile8;
/**
* @brief Load tile data from ROM
*
* @param rom ROM to load from
* @param tile_id ID of tile to load
* @param bpp Bits per pixel (1, 2, 4, 8)
* @return Loaded tile data, or empty tile on error
*/
snes_tile8 yaze_load_tile_from_rom(const zelda3_rom* rom, uint32_t tile_id, uint8_t bpp);
/**
* @brief Convert tile data between different bit depths
*
* @param tile Source tile data
* @param from_bpp Source bits per pixel
* @param to_bpp Target bits per pixel
* @return Converted tile data
*/
snes_tile8 yaze_convert_tile_bpp(const snes_tile8* tile, uint8_t from_bpp, uint8_t to_bpp);
typedef struct snes_tile_info {
uint16_t id;
uint8_t palette;
bool priority;
bool vertical_mirror;
bool horizontal_mirror;
} snes_tile_info;
typedef struct snes_tile16 {
snes_tile_info tiles[4];
} snes_tile16;
typedef struct snes_tile32 {
uint16_t t0;
uint16_t t1;
uint16_t t2;
uint16_t t3;
} snes_tile32;
/** @} */
/**
* @defgroup rom ROM Manipulation
* @{
*/
/**
* @brief Load a ROM file
*
* Loads a Zelda 3 ROM file and validates its format.
*
* @param filename Path to ROM file (.sfc, .smc, etc.)
* @return Pointer to ROM structure, or NULL on error
*
* @note Caller must call yaze_unload_rom() to free memory
*/
zelda3_rom* yaze_load_rom_file(const char* filename);
/**
* @brief Validate ROM integrity
*
* Checks if the ROM data is valid and uncorrupted.
*
* @param rom ROM to validate
* @return YAZE_OK if valid, error code if corrupted
*/
yaze_status yaze_validate_rom(const zelda3_rom* rom);
/**
* @brief Get ROM information
*
* @param rom ROM to query
* @param version Pointer to store detected ROM version
* @param size Pointer to store ROM size in bytes
* @return YAZE_OK on success, error code on failure
*/
yaze_status yaze_get_rom_info(const zelda3_rom* rom, zelda3_version* version, uint64_t* size);
/**
* @brief Get a color from a palette set
*
* Retrieves a specific color from a palette set in the ROM.
*
* @param rom The ROM to get the color from
* @param palette_set The palette set index (0-255)
* @param palette The palette index within the set (0-15)
* @param color The color index within the palette (0-15)
* @return The color from the palette set
*/
snes_color yaze_get_color_from_paletteset(const zelda3_rom* rom,
int palette_set, int palette,
int color);
/** @} */
/**
* @defgroup overworld Overworld Functions
* @{
*/
/**
* @brief Load the overworld from ROM
*
* Loads and parses the overworld data from the ROM, including all maps,
* sprites, and related data structures.
*
* @param rom The ROM to load the overworld from
* @return Pointer to overworld structure, or NULL on error
*
* @note Caller must free the returned pointer when done
*/
zelda3_overworld* yaze_load_overworld(const zelda3_rom* rom);
/**
* @brief Free overworld data
*
* @param overworld Pointer to overworld to free
*/
void yaze_free_overworld(zelda3_overworld* overworld);
/**
* @brief Get overworld map by index
*
* @param overworld Overworld data
* @param map_index Map index (0-159 for most ROMs)
* @return Pointer to map data, or NULL if invalid index
*/
const zelda3_overworld_map* yaze_get_overworld_map(const zelda3_overworld* overworld, int map_index);
/**
* @brief Get total number of overworld maps
*
* @param overworld Overworld data
* @return Number of maps available
*/
int yaze_get_overworld_map_count(const zelda3_overworld* overworld);
/** @} */
/**
* @defgroup dungeon Dungeon Functions
* @{
*/
/**
* @brief Load all dungeon rooms from ROM
*
* Loads and parses all dungeon room data from the ROM.
*
* @param rom The ROM to load rooms from
* @param room_count Pointer to store the number of rooms loaded
* @return Array of room structures, or NULL on error
*
* @note Caller must free the returned array when done
*/
zelda3_dungeon_room* yaze_load_all_rooms(const zelda3_rom* rom, int* room_count);
/**
* @brief Load a specific dungeon room
*
* @param rom ROM to load from
* @param room_id Room ID to load (0-295 for most ROMs)
* @return Pointer to room data, or NULL on error
*/
const zelda3_dungeon_room* yaze_load_room(const zelda3_rom* rom, int room_id);
/**
* @brief Free dungeon room data
*
* @param rooms Array of rooms to free
* @param room_count Number of rooms in array
*/
void yaze_free_rooms(zelda3_dungeon_room* rooms, int room_count);
/** @} */
/**
* @defgroup messages Message System
* @{
*/
/**
* @brief Load all text messages from ROM
*
* Loads and parses all in-game text messages from the ROM.
*
* @param rom The ROM to load messages from
* @param messages Pointer to store array of messages
* @param message_count Pointer to store number of messages loaded
* @return YAZE_OK on success, error code on failure
*
* @note Caller must free the messages array when done
*/
yaze_status yaze_load_messages(const zelda3_rom* rom, zelda3_message** messages, int* message_count);
/**
* @brief Get a specific message by ID
*
* @param rom ROM to load from
* @param message_id Message ID to retrieve
* @return Pointer to message data, or NULL if not found
*/
const zelda3_message* yaze_get_message(const zelda3_rom* rom, int message_id);
/**
* @brief Free message data
*
* @param messages Array of messages to free
* @param message_count Number of messages in array
*/
void yaze_free_messages(zelda3_message* messages, int message_count);
/** @} */
/**
* @brief Function pointer to initialize the extension.
*
* @param context The editor context.
*/
typedef void (*yaze_initialize_func)(yaze_editor_context* context);
typedef void (*yaze_cleanup_func)(void);
/**
* @defgroup extensions Extension System
* @{
*/
/**
* @brief Extension interface for YAZE
*
* Defines the interface for YAZE extensions. Extensions can add new
* functionality to YAZE and can be written in C or other languages.
*/
typedef struct yaze_extension {
const char* name; /**< Extension name (must not be NULL) */
const char* version; /**< Extension version string */
const char* description; /**< Brief description of functionality */
const char* author; /**< Extension author */
int api_version; /**< Required YAZE API version */
/**
* @brief Initialize the extension
*
* Called when the extension is loaded. Use this to set up
* any resources or state needed by the extension.
*
* @param context Editor context provided by YAZE
* @return YAZE_OK on success, error code on failure
*/
yaze_status (*initialize)(yaze_editor_context* context);
/**
* @brief Clean up the extension
*
* Called when the extension is unloaded. Use this to clean up
* any resources or state used by the extension.
*/
void (*cleanup)(void);
/**
* @brief Get extension capabilities
*
* Returns a bitmask indicating what features this extension provides.
*
* @return Capability flags (see YAZE_EXT_CAP_* constants)
*/
uint32_t (*get_capabilities)(void);
} yaze_extension;
/** Extension capability flags */
#define YAZE_EXT_CAP_ROM_EDITING (1 << 0) /**< Can edit ROM data */
#define YAZE_EXT_CAP_GRAPHICS (1 << 1) /**< Provides graphics functions */
#define YAZE_EXT_CAP_AUDIO (1 << 2) /**< Provides audio functions */
#define YAZE_EXT_CAP_SCRIPTING (1 << 3) /**< Provides scripting support */
#define YAZE_EXT_CAP_IMPORT_EXPORT (1 << 4) /**< Can import/export data */
/**
* @brief Register an extension with YAZE
*
* @param extension Extension to register
* @return YAZE_OK on success, error code on failure
*/
yaze_status yaze_register_extension(const yaze_extension* extension);
/**
* @brief Unregister an extension
*
* @param name Name of extension to unregister
* @return YAZE_OK on success, error code on failure
*/
yaze_status yaze_unregister_extension(const char* name);
/** @} */
#ifdef __cplusplus
}
#endif
#endif // YAZE_H

499
incl/zelda.h Normal file
View File

@@ -0,0 +1,499 @@
#ifndef ZELDA_H
#define ZELDA_H
/**
* @file zelda.h
* @brief The Legend of Zelda: A Link to the Past - Data Structures and Constants
*
* This header defines data structures and constants specific to
* The Legend of Zelda: A Link to the Past ROM format and game data.
*
* @version 0.3.1
* @author YAZE Team
*/
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <stdint.h>
/**
* @defgroup rom_types ROM Types and Versions
* @{
*/
/**
* @brief Different versions of the game supported by YAZE
*
* YAZE supports multiple regional versions and ROM hacks of
* The Legend of Zelda: A Link to the Past.
*/
typedef enum zelda3_version {
ZELDA3_VERSION_UNKNOWN = 0, /**< Unknown or unsupported version */
ZELDA3_VERSION_US = 1, /**< US/North American version */
ZELDA3_VERSION_JP = 2, /**< Japanese version */
ZELDA3_VERSION_EU = 3, /**< European version */
ZELDA3_VERSION_PROTO = 4, /**< Prototype/development version */
ZELDA3_VERSION_RANDOMIZER = 5, /**< Randomizer ROM (experimental) */
// Legacy aliases for backward compatibility
US = ZELDA3_VERSION_US, /**< @deprecated Use ZELDA3_VERSION_US */
JP = ZELDA3_VERSION_JP, /**< @deprecated Use ZELDA3_VERSION_JP */
SD = ZELDA3_VERSION_PROTO, /**< @deprecated Use ZELDA3_VERSION_PROTO */
RANDO = ZELDA3_VERSION_RANDOMIZER, /**< @deprecated Use ZELDA3_VERSION_RANDOMIZER */
} zelda3_version;
/**
* @brief Detect ROM version from header data
*
* @param rom_data Pointer to ROM data
* @param size Size of ROM data in bytes
* @return Detected version, or ZELDA3_VERSION_UNKNOWN if not recognized
*/
zelda3_version zelda3_detect_version(const uint8_t* rom_data, size_t size);
/**
* @brief Get version name as string
*
* @param version Version enum value
* @return Human-readable version name
*/
const char* zelda3_version_to_string(zelda3_version version);
/**
* @brief ROM data pointers for different game versions
*
* Contains memory addresses where specific data structures are located
* within the ROM. These addresses vary between different regional versions.
*/
typedef struct zelda3_version_pointers {
// New Google C++ style names
uint32_t gfx_animated_pointer; /**< Animated graphics pointer */
uint32_t overworld_gfx_groups1; /**< Overworld graphics group 1 */
uint32_t overworld_gfx_groups2; /**< Overworld graphics group 2 */
uint32_t compressed_map32_pointers_high; /**< Map32 high pointers */
uint32_t compressed_map32_pointers_low; /**< Map32 low pointers */
uint32_t overworld_map_palette_group; /**< Map palette groups */
uint32_t overlay_pointers; /**< Overlay data pointers */
uint32_t overlay_pointers_bank; /**< Overlay bank number */
uint32_t overworld_tiles_type; /**< Tile type definitions */
uint32_t overworld_gfx_ptr1; /**< Graphics pointer 1 */
uint32_t overworld_gfx_ptr2; /**< Graphics pointer 2 */
uint32_t overworld_gfx_ptr3; /**< Graphics pointer 3 */
uint32_t map32_tile_tl; /**< 32x32 tile top-left */
uint32_t map32_tile_tr; /**< 32x32 tile top-right */
uint32_t map32_tile_bl; /**< 32x32 tile bottom-left */
uint32_t map32_tile_br; /**< 32x32 tile bottom-right */
uint32_t sprite_blockset_pointer; /**< Sprite graphics pointer */
uint32_t dungeon_palettes_groups; /**< Dungeon palette groups */
// Legacy aliases for backward compatibility (deprecated)
uint32_t kGfxAnimatedPointer; /**< @deprecated Use gfx_animated_pointer */
uint32_t kOverworldGfxGroups1; /**< @deprecated Use overworld_gfx_groups1 */
uint32_t kOverworldGfxGroups2; /**< @deprecated Use overworld_gfx_groups2 */
uint32_t kCompressedAllMap32PointersHigh; /**< @deprecated Use compressed_map32_pointers_high */
uint32_t kCompressedAllMap32PointersLow; /**< @deprecated Use compressed_map32_pointers_low */
uint32_t kOverworldMapPaletteGroup; /**< @deprecated Use overworld_map_palette_group */
uint32_t kOverlayPointers; /**< @deprecated Use overlay_pointers */
uint32_t kOverlayPointersBank; /**< @deprecated Use overlay_pointers_bank */
uint32_t kOverworldTilesType; /**< @deprecated Use overworld_tiles_type */
uint32_t kOverworldGfxPtr1; /**< @deprecated Use overworld_gfx_ptr1 */
uint32_t kOverworldGfxPtr2; /**< @deprecated Use overworld_gfx_ptr2 */
uint32_t kOverworldGfxPtr3; /**< @deprecated Use overworld_gfx_ptr3 */
uint32_t kMap32TileTL; /**< @deprecated Use map32_tile_tl */
uint32_t kMap32TileTR; /**< @deprecated Use map32_tile_tr */
uint32_t kMap32TileBL; /**< @deprecated Use map32_tile_bl */
uint32_t kMap32TileBR; /**< @deprecated Use map32_tile_br */
uint32_t kSpriteBlocksetPointer; /**< @deprecated Use sprite_blockset_pointer */
uint32_t kDungeonPalettesGroups; /**< @deprecated Use dungeon_palettes_groups */
} zelda3_version_pointers;
/**
* @brief Get version-specific pointers
*
* @param version ROM version
* @return Pointer to version-specific address structure
*/
const zelda3_version_pointers* zelda3_get_version_pointers(zelda3_version version);
const static zelda3_version_pointers zelda3_us_pointers = {
// New style names
0x10275, // gfx_animated_pointer
0x5D97, // overworld_gfx_groups1
0x6073, // overworld_gfx_groups2
0x1794D, // compressed_map32_pointers_high
0x17B2D, // compressed_map32_pointers_low
0x75504, // overworld_map_palette_group
0x77664, // overlay_pointers
0x0E, // overlay_pointers_bank
0x71459, // overworld_tiles_type
0x4F80, // overworld_gfx_ptr1
0x505F, // overworld_gfx_ptr2
0x513E, // overworld_gfx_ptr3
0x18000, // map32_tile_tl
0x1B400, // map32_tile_tr
0x20000, // map32_tile_bl
0x23400, // map32_tile_br
0x5B57, // sprite_blockset_pointer
0x75460, // dungeon_palettes_groups
// Legacy k-prefixed names (same values for backward compatibility)
0x10275, // kGfxAnimatedPointer
0x5D97, // kOverworldGfxGroups1
0x6073, // kOverworldGfxGroups2
0x1794D, // kCompressedAllMap32PointersHigh
0x17B2D, // kCompressedAllMap32PointersLow
0x75504, // kOverworldMapPaletteGroup
0x77664, // kOverlayPointers
0x0E, // kOverlayPointersBank
0x71459, // kOverworldTilesType
0x4F80, // kOverworldGfxPtr1
0x505F, // kOverworldGfxPtr2
0x513E, // kOverworldGfxPtr3
0x18000, // kMap32TileTL
0x1B400, // kMap32TileTR
0x20000, // kMap32TileBL
0x23400, // kMap32TileBR
0x5B57, // kSpriteBlocksetPointer
0x75460, // kDungeonPalettesGroups
};
const static zelda3_version_pointers zelda3_jp_pointers = {
// New style names
0x10624, // gfx_animated_pointer
0x5DD7, // overworld_gfx_groups1
0x60B3, // overworld_gfx_groups2
0x176B1, // compressed_map32_pointers_high
0x17891, // compressed_map32_pointers_low
0x67E74, // overworld_map_palette_group
0x3FAF4, // overlay_pointers
0x07, // overlay_pointers_bank
0x7FD94, // overworld_tiles_type
0x4FC0, // overworld_gfx_ptr1
0x509F, // overworld_gfx_ptr2
0x517E, // overworld_gfx_ptr3
0x18000, // map32_tile_tl
0x1B3C0, // map32_tile_tr
0x20000, // map32_tile_bl
0x233C0, // map32_tile_br
0x5B97, // sprite_blockset_pointer
0x67DD0, // dungeon_palettes_groups
// Legacy k-prefixed names (same values for backward compatibility)
0x10624, // kGfxAnimatedPointer
0x5DD7, // kOverworldGfxGroups1
0x60B3, // kOverworldGfxGroups2
0x176B1, // kCompressedAllMap32PointersHigh
0x17891, // kCompressedAllMap32PointersLow
0x67E74, // kOverworldMapPaletteGroup
0x3FAF4, // kOverlayPointers
0x07, // kOverlayPointersBank
0x7FD94, // kOverworldTilesType
0x4FC0, // kOverworldGfxPtr1
0x509F, // kOverworldGfxPtr2
0x517E, // kOverworldGfxPtr3
0x18000, // kMap32TileTL
0x1B3C0, // kMap32TileTR
0x20000, // kMap32TileBL
0x233C0, // kMap32TileBR
0x5B97, // kSpriteBlocksetPointer
0x67DD0, // kDungeonPalettesGroups
};
/**
* @brief ROM data structure
*
* Represents a loaded Zelda 3 ROM with its data and metadata.
*/
typedef struct zelda3_rom {
const char* filename; /**< Original filename (can be NULL) */
uint8_t* data; /**< ROM data (read-only for external users) */
uint64_t size; /**< Size of ROM data in bytes */
zelda3_version version; /**< Detected ROM version */
bool is_modified; /**< True if ROM has been modified */
void* impl; /**< Internal implementation pointer */
} zelda3_rom;
/** @} */
/**
* @defgroup rom_functions ROM File Operations
* @{
*/
/**
* @brief Load a ROM file
*
* @param filename Path to ROM file
* @return Loaded ROM structure, or NULL on error
*/
zelda3_rom* yaze_load_rom(const char* filename);
/**
* @brief Unload and free ROM data
*
* @param rom ROM to unload
*/
void yaze_unload_rom(zelda3_rom* rom);
/**
* @brief Save ROM to file
*
* @param rom ROM to save
* @param filename Output filename
* @return YAZE_OK on success, error code on failure
*/
int yaze_save_rom(zelda3_rom* rom, const char* filename);
/**
* @brief Create a copy of ROM data
*
* @param rom Source ROM
* @return Copy of ROM, or NULL on error
*/
zelda3_rom* yaze_copy_rom(const zelda3_rom* rom);
/** @} */
/**
* @defgroup messages Message Data Structures
* @{
*/
/**
* @brief In-game text message data
*
* Represents a text message from the game, including both raw
* ROM data and parsed/decoded text content.
*/
typedef struct zelda3_message {
uint16_t id; /**< Message ID (0-65535) */
uint32_t rom_address; /**< Address in ROM where message data starts */
uint16_t length; /**< Length of message data in bytes */
uint8_t* raw_data; /**< Raw message data from ROM */
char* parsed_text; /**< Decoded text content (UTF-8) */
bool is_compressed; /**< True if message uses compression */
uint8_t encoding_type; /**< Text encoding type used */
} zelda3_message;
/** @} */
/**
* @defgroup overworld Overworld Data Structures
* @{
*/
/**
* @brief Overworld map data
*
* Represents a single screen/area in the overworld, including
* graphics, palette, music, and sprite information.
*/
typedef struct zelda3_overworld_map {
uint16_t id; /**< Map ID (0-159 for most ROMs) */
uint8_t parent_id; /**< Parent map ID for sub-areas */
uint8_t quadrant_id; /**< Quadrant within parent (0-3) */
uint8_t world_id; /**< World number (Light/Dark) */
uint8_t game_state; /**< Game state requirements */
/* Graphics and Visual Properties */
uint8_t area_graphics; /**< Area graphics set ID */
uint8_t area_palette; /**< Area palette set ID */
uint8_t main_palette; /**< Main palette ID */
uint8_t animated_gfx; /**< Animated graphics ID */
/* Sprite Configuration */
uint8_t sprite_graphics[3]; /**< Sprite graphics sets */
uint8_t sprite_palette[3]; /**< Sprite palette sets */
/* Audio Configuration */
uint8_t area_music[4]; /**< Music tracks for different states */
/* Extended Graphics (ZSCustomOverworld) */
uint8_t static_graphics[16]; /**< Static graphics assignments */
uint8_t custom_tileset[8]; /**< Custom tileset assignments */
/* Screen Properties */
uint16_t area_specific_bg_color; /**< Background color override */
uint16_t subscreen_overlay; /**< Subscreen overlay settings */
/* Flags and Metadata */
bool is_large_map; /**< True for 32x32 maps */
bool has_special_gfx; /**< True if uses special graphics */
} zelda3_overworld_map;
/**
* @brief Complete overworld data
*
* Contains all overworld maps and related data for the entire game world.
*/
typedef struct zelda3_overworld {
void* impl; /**< Internal implementation pointer */
zelda3_overworld_map** maps; /**< Array of overworld maps */
int map_count; /**< Number of maps in array */
zelda3_version rom_version; /**< ROM version this data came from */
bool has_zsco_features; /**< True if ZSCustomOverworld features detected */
} zelda3_overworld;
/** @} */
/**
* @defgroup dungeon Dungeon Data Structures
* @{
*/
/**
* @brief Dungeon sprite definition
*
* Represents a sprite that can appear in dungeon rooms.
*/
typedef struct dungeon_sprite {
const char* name; /**< Sprite name (for debugging/display) */
uint8_t id; /**< Sprite type ID */
uint8_t subtype; /**< Sprite subtype/variant */
uint8_t x; /**< X position in room */
uint8_t y; /**< Y position in room */
uint8_t layer; /**< Layer (0=background, 1=foreground) */
uint16_t properties; /**< Additional sprite properties */
} dungeon_sprite;
/**
* @brief Background layer 2 effects
*
* Defines the different visual effects that can be applied to
* background layer 2 in dungeon rooms.
*/
typedef enum zelda3_bg2_effect {
ZELDA3_BG2_OFF = 0, /**< Background layer 2 disabled */
ZELDA3_BG2_PARALLAX = 1, /**< Parallax scrolling effect */
ZELDA3_BG2_DARK = 2, /**< Dark overlay effect */
ZELDA3_BG2_ON_TOP = 3, /**< Layer appears on top */
ZELDA3_BG2_TRANSLUCENT = 4, /**< Semi-transparent overlay */
ZELDA3_BG2_ADDITION = 5, /**< Additive blending */
ZELDA3_BG2_NORMAL = 6, /**< Normal blending */
ZELDA3_BG2_TRANSPARENT = 7, /**< Fully transparent */
ZELDA3_BG2_DARK_ROOM = 8 /**< Dark room effect */
} zelda3_bg2_effect;
// Legacy aliases for backward compatibility
typedef zelda3_bg2_effect background2;
#define Off ZELDA3_BG2_OFF
#define Parallax ZELDA3_BG2_PARALLAX
#define Dark ZELDA3_BG2_DARK
#define OnTop ZELDA3_BG2_ON_TOP
#define Translucent ZELDA3_BG2_TRANSLUCENT
#define Addition ZELDA3_BG2_ADDITION
#define Normal ZELDA3_BG2_NORMAL
#define Transparent ZELDA3_BG2_TRANSPARENT
#define DarkRoom ZELDA3_BG2_DARK_ROOM
/**
* @brief Dungeon door object
*
* Represents a door or passage between rooms.
*/
typedef struct object_door {
uint16_t id; /**< Door ID for reference */
uint8_t x; /**< X position in room (0-63) */
uint8_t y; /**< Y position in room (0-63) */
uint8_t size; /**< Door size (width/height) */
uint8_t type; /**< Door type (normal, locked, etc.) */
uint8_t layer; /**< Layer (0=background, 1=foreground) */
uint8_t key_type; /**< Required key type (0=none) */
bool is_locked; /**< True if door requires key */
} object_door;
/**
* @brief Staircase connection
*
* Represents stairs or holes that connect different rooms or levels.
*/
typedef struct staircase {
uint8_t id; /**< Staircase ID */
uint8_t room; /**< Target room ID (for backward compatibility) */
const char* label; /**< Description (for debugging) */
} staircase;
/**
* @brief Treasure chest
*
* Represents a chest containing an item.
*/
typedef struct chest {
uint8_t x; /**< X position in room */
uint8_t y; /**< Y position in room */
uint8_t item; /**< Item ID (for backward compatibility) */
bool picker; /**< Legacy field */
bool big_chest; /**< True for large chests */
} chest;
/**
* @brief Legacy chest data structure
*
* @deprecated Use chest structure instead
*/
typedef struct chest_data {
uint8_t id; /**< Chest ID */
bool size; /**< True for big chest */
} chest_data;
/**
* @brief Room transition destination
*
* Defines where the player goes when using stairs, holes, or other transitions.
*/
typedef struct destination {
uint8_t index; /**< Entrance index */
uint8_t target; /**< Target room ID */
uint8_t target_layer; /**< Target layer */
} destination;
/** @} */
/**
* @brief Complete dungeon room data
*
* Contains all objects, sprites, and properties for a single dungeon room.
*/
typedef struct zelda3_dungeon_room {
uint16_t id; /**< Room ID (0-295) */
background2 bg2; /**< Background layer 2 effect (legacy) */
/* Room Contents */
dungeon_sprite* sprites; /**< Array of sprites in room */
int sprite_count; /**< Number of sprites */
object_door* doors; /**< Array of doors */
int door_count; /**< Number of doors */
staircase* staircases; /**< Array of staircases */
int staircase_count; /**< Number of staircases */
chest* chests; /**< Array of chests */
int chest_count; /**< Number of chests */
/* Room Connections */
destination pits; /**< Pit fall destination */
destination stairs[4]; /**< Stair destinations (up to 4) */
/* Room Properties */
uint8_t floor_type; /**< Floor graphics type */
uint8_t wall_type; /**< Wall graphics type */
uint8_t palette_id; /**< Room palette ID */
uint8_t music_track; /**< Background music track */
/* Flags */
bool is_dark; /**< True if room requires lamp */
bool has_water; /**< True if room contains water */
bool blocks_items; /**< True if room blocks certain items */
} zelda3_dungeon_room;
/** @} */
#ifdef __cplusplus
}
#endif
#endif // ZELDA_H

143
scripts/README.md Normal file
View File

@@ -0,0 +1,143 @@
# YAZE Build Scripts
This directory contains build and setup scripts for YAZE development on different platforms.
## Windows Scripts
### Setup Scripts
- **`setup-windows-dev.ps1`** - Complete Windows development environment setup (PowerShell)
- **`setup-vcpkg-windows.ps1`** - vcpkg setup only (PowerShell)
- **`setup-vcpkg-windows.bat`** - vcpkg setup only (Batch)
### Build Scripts
- **`build-windows.ps1`** - Build YAZE on Windows (PowerShell)
- **`build-windows.bat`** - Build YAZE on Windows (Batch)
### Validation Scripts
- **`validate-windows-build.ps1`** - Validate Windows build environment
### Project Generation
- **`generate-vs-projects.py`** - Generate Visual Studio project files (Cross-platform Python)
- **`generate-vs-projects.ps1`** - Generate Visual Studio project files (PowerShell)
- **`generate-vs-projects.bat`** - Generate Visual Studio project files (Batch)
## Quick Start (Windows)
### Option 1: Automated Setup (Recommended)
```powershell
.\scripts\setup-windows-dev.ps1
```
### Option 2: Manual Setup
```powershell
# 1. Setup vcpkg
.\scripts\setup-vcpkg-windows.ps1
# 2. Generate project files
python scripts/generate-vs-projects.py
# 3. Build
.\scripts\build-windows.ps1
```
### Option 3: Using Batch Scripts
```batch
REM Setup vcpkg
.\scripts\setup-vcpkg-windows.bat
REM Generate project files
python scripts/generate-vs-projects.py
REM Build
.\scripts\build-windows.bat
```
## Script Options
### setup-windows-dev.ps1
- `-SkipVcpkg` - Skip vcpkg setup
- `-SkipVS` - Skip Visual Studio check
- `-SkipBuild` - Skip test build
### build-windows.ps1
- `-Configuration` - Build configuration (Debug, Release, RelWithDebInfo, MinSizeRel)
- `-Platform` - Target platform (x64, x86, ARM64)
- `-Clean` - Clean build directories before building
- `-Verbose` - Verbose build output
### build-windows.bat
- First argument: Configuration (Debug, Release, RelWithDebInfo, MinSizeRel)
- Second argument: Platform (x64, x86, ARM64)
- `clean` - Clean build directories
- `verbose` - Verbose build output
## Examples
```powershell
# Build Release x64 (default)
.\scripts\build-windows.ps1
# Build Debug x64
.\scripts\build-windows.ps1 -Configuration Debug -Platform x64
# Build Release x86
.\scripts\build-windows.ps1 -Configuration Release -Platform x86
# Clean build
.\scripts\build-windows.ps1 -Clean
# Verbose build
.\scripts\build-windows.ps1 -Verbose
# Validate environment
.\scripts\validate-windows-build.ps1
```
```batch
REM Build Release x64 (default)
.\scripts\build-windows.bat
REM Build Debug x64
.\scripts\build-windows.bat Debug x64
REM Build Release x86
.\scripts\build-windows.bat Release x86
REM Clean build
.\scripts\build-windows.bat clean
```
## Troubleshooting
### Common Issues
1. **PowerShell Execution Policy**
```powershell
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
```
2. **MSBuild Not Found**
- Install Visual Studio 2022 with C++ workload
- Or add MSBuild to PATH
3. **vcpkg Issues**
- Run `.\scripts\setup-vcpkg-windows.ps1` to reinstall
- Check internet connection for dependency downloads
4. **Python Not Found**
- Install Python 3.8+ from python.org
- Make sure Python is in PATH
### Getting Help
1. Run validation script: `.\scripts\validate-windows-build.ps1`
2. Check the [Windows Development Guide](../docs/windows-development-guide.md)
3. Review build output for specific error messages
## Other Scripts
- **`create_release.sh`** - Create GitHub releases (Linux/macOS)
- **`extract_changelog.py`** - Extract changelog for releases
- **`quality_check.sh`** - Code quality checks (Linux/macOS)
- **`test_asar_integration.py`** - Test Asar integration
- **`agent.sh`** - AI agent helper script (Linux/macOS)

369
scripts/agent.sh Executable file
View File

@@ -0,0 +1,369 @@
#!/usr/bin/env bash
set -euo pipefail
# Unified background agent script for YAZE (macOS launchd, Linux systemd)
# Subcommands:
# install [--build-type X] [--use-inotify] [--ubuntu-bootstrap] [--enable-linger]
# uninstall
# run-once # one-shot build & test
# watch # linux: inotify-based watch loop
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
BUILD_DIR_DEFAULT="${PROJECT_ROOT}/build"
BUILD_TYPE_DEFAULT="Debug"
usage() {
cat <<EOF
Usage: $0 <subcommand> [options]
Subcommands:
install Install background agent
--build-type X CMake build type (default: ${BUILD_TYPE_DEFAULT})
--use-inotify Linux: use long-lived inotify watcher
--ubuntu-bootstrap Install Ubuntu deps via apt (sudo)
--enable-linger Enable user lingering (Linux)
uninstall Remove installed background agent
run-once One-shot build and test
env: BUILD_DIR, BUILD_TYPE
watch Linux: inotify-based watch loop
env: BUILD_DIR, BUILD_TYPE, INTERVAL_SECONDS (fallback)
Environment:
BUILD_DIR Build directory (default: ${BUILD_DIR_DEFAULT})
BUILD_TYPE CMake build type (default: ${BUILD_TYPE_DEFAULT})
EOF
}
build_and_test() {
local build_dir="${BUILD_DIR:-${BUILD_DIR_DEFAULT}}"
local build_type="${BUILD_TYPE:-${BUILD_TYPE_DEFAULT}}"
local log_file="${LOG_FILE:-"${build_dir}/yaze_agent.log"}"
mkdir -p "${build_dir}"
{
echo "==== $(date '+%Y-%m-%d %H:%M:%S') | yaze agent run (type=${build_type}) ===="
echo "Project: ${PROJECT_ROOT}"
cmake -S "${PROJECT_ROOT}" -B "${build_dir}" -DCMAKE_BUILD_TYPE="${build_type}"
cmake --build "${build_dir}" --config "${build_type}" -j
if [[ -x "${build_dir}/bin/yaze_test" ]]; then
"${build_dir}/bin/yaze_test"
else
if command -v ctest >/dev/null 2>&1; then
ctest --test-dir "${build_dir}" --output-on-failure
else
echo "ctest not found and test binary missing. Skipping tests." >&2
exit 1
fi
fi
} >>"${log_file}" 2>&1
}
sub_run_once() {
build_and_test
}
sub_watch() {
local build_dir="${BUILD_DIR:-${BUILD_DIR_DEFAULT}}"
local build_type="${BUILD_TYPE:-${BUILD_TYPE_DEFAULT}}"
local interval="${INTERVAL_SECONDS:-5}"
mkdir -p "${build_dir}"
if command -v inotifywait >/dev/null 2>&1; then
echo "[agent] using inotifywait watcher"
while true; do
BUILD_DIR="${build_dir}" BUILD_TYPE="${build_type}" build_and_test || true
inotifywait -r -e modify,create,delete,move \
"${PROJECT_ROOT}/src" \
"${PROJECT_ROOT}/test" \
"${PROJECT_ROOT}/CMakeLists.txt" \
"${PROJECT_ROOT}/src/CMakeLists.txt" >/dev/null 2>&1 || true
done
else
echo "[agent] inotifywait not found; running periodic loop (${interval}s)"
while true; do
BUILD_DIR="${build_dir}" BUILD_TYPE="${build_type}" build_and_test || true
sleep "${interval}"
done
fi
}
ensure_exec() {
if [[ ! -x "$1" ]]; then
chmod +x "$1"
fi
}
ubuntu_bootstrap() {
if command -v apt-get >/dev/null 2>&1; then
sudo apt-get update
sudo apt-get install -y inotify-tools build-essential cmake ninja-build pkg-config \
libsdl2-dev libpng-dev libglew-dev libwavpack-dev libabsl-dev \
libboost-all-dev libboost-python-dev python3-dev libpython3-dev
else
echo "apt-get not found; skipping Ubuntu bootstrap" >&2
fi
}
enable_linger_linux() {
if command -v loginctl >/dev/null 2>&1; then
if sudo -n true 2>/dev/null; then
sudo loginctl enable-linger "$USER" || true
else
echo "Note: enabling linger may require sudo: sudo loginctl enable-linger $USER" >&2
fi
fi
}
# Wrapper to run systemctl --user with a session bus in headless shells
systemctl_user() {
# Only apply on Linux
if [[ "$(uname -s)" != "Linux" ]]; then
systemctl "$@"
return
fi
local uid
uid="$(id -u)"
export XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR:-/run/user/${uid}}"
export DBUS_SESSION_BUS_ADDRESS="${DBUS_SESSION_BUS_ADDRESS:-unix:path=${XDG_RUNTIME_DIR}/bus}"
if [[ ! -S "${XDG_RUNTIME_DIR}/bus" ]]; then
echo "[agent] Warning: user bus not found at ${XDG_RUNTIME_DIR}/bus. If this fails, run: sudo loginctl enable-linger $USER" >&2
fi
systemctl --user "$@"
}
is_systemd_available() {
# True if systemd is PID 1 and systemctl exists and a user bus likely available
if [[ ! -d /run/systemd/system ]]; then
return 1
fi
if ! command -v systemctl >/dev/null 2>&1; then
return 1
fi
return 0
}
start_userland_agent() {
local build_type="${1}"
local build_dir="${2}"
local agent_home="$HOME/.local/share/yaze-agent"
mkdir -p "${agent_home}"
local log_file="${agent_home}/agent.log"
nohup env BUILD_TYPE="${build_type}" BUILD_DIR="${build_dir}" "${SCRIPT_DIR}/agent.sh" watch >>"${log_file}" 2>&1 & echo $! > "${agent_home}/agent.pid"
echo "Userland agent started (PID $(cat "${agent_home}/agent.pid")) - logs: ${log_file}"
}
stop_userland_agent() {
local agent_home="$HOME/.local/share/yaze-agent"
local pid_file="${agent_home}/agent.pid"
if [[ -f "${pid_file}" ]]; then
local pid
pid="$(cat "${pid_file}")"
if kill -0 "${pid}" >/dev/null 2>&1; then
kill "${pid}" || true
fi
rm -f "${pid_file}"
echo "Stopped userland agent"
fi
}
install_macos() {
local build_type="${1}"
local build_dir="${2}"
local label="com.yaze.watchtest"
local plist_path="$HOME/Library/LaunchAgents/${label}.plist"
mkdir -p "${build_dir}"
cat >"$plist_path" <<PLIST
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>${label}</string>
<key>RunAtLoad</key>
<true/>
<key>ProgramArguments</key>
<array>
<string>/bin/zsh</string>
<string>-lc</string>
<string>"${SCRIPT_DIR}/agent.sh" run-once</string>
</array>
<key>WorkingDirectory</key>
<string>${PROJECT_ROOT}</string>
<key>WatchPaths</key>
<array>
<string>${PROJECT_ROOT}/src</string>
<string>${PROJECT_ROOT}/test</string>
<string>${PROJECT_ROOT}/CMakeLists.txt</string>
<string>${PROJECT_ROOT}/src/CMakeLists.txt</string>
</array>
<key>StandardOutPath</key>
<string>${build_dir}/yaze_agent.out.log</string>
<key>StandardErrorPath</key>
<string>${build_dir}/yaze_agent.err.log</string>
<key>EnvironmentVariables</key>
<dict>
<key>BUILD_TYPE</key><string>${build_type}</string>
<key>BUILD_DIR</key><string>${build_dir}</string>
</dict>
</dict>
</plist>
PLIST
launchctl unload -w "$plist_path" 2>/dev/null || true
launchctl load -w "$plist_path"
echo "LaunchAgent installed and loaded: ${plist_path}"
}
install_linux() {
local build_type="${1}"
local build_dir="${2}"
local use_inotify="${3}"
local systemd_dir="$HOME/.config/systemd/user"
local service_name="yaze-watchtest.service"
local path_name="yaze-watchtest.path"
mkdir -p "${systemd_dir}" "${build_dir}"
if ! is_systemd_available; then
echo "[agent] systemd not available; installing userland background agent"
start_userland_agent "${build_type}" "${build_dir}"
return
fi
if [[ "${use_inotify}" == "1" ]]; then
cat >"${systemd_dir}/yaze-watchtest-inotify.service" <<UNIT
[Unit]
Description=Yaze inotify watcher build-and-test
[Service]
Type=simple
Environment=BUILD_TYPE=${build_type}
Environment=BUILD_DIR=${build_dir}
WorkingDirectory=${PROJECT_ROOT}
ExecStart=/bin/bash -lc '"${SCRIPT_DIR}/agent.sh" watch'
Restart=always
RestartSec=2
[Install]
WantedBy=default.target
UNIT
systemctl_user daemon-reload
systemctl_user enable --now yaze-watchtest-inotify.service
echo "systemd user service enabled: yaze-watchtest-inotify.service"
return
fi
cat >"${systemd_dir}/${service_name}" <<UNIT
[Unit]
Description=Yaze build-and-test (one-shot)
[Service]
Type=oneshot
Environment=BUILD_TYPE=${build_type}
Environment=BUILD_DIR=${build_dir}
WorkingDirectory=${PROJECT_ROOT}
ExecStart=/bin/bash -lc '"${SCRIPT_DIR}/agent.sh" run-once'
UNIT
cat >"${systemd_dir}/${path_name}" <<UNIT
[Unit]
Description=Watch Yaze src/test for changes
[Path]
PathModified=${PROJECT_ROOT}/src
PathModified=${PROJECT_ROOT}/test
PathModified=${PROJECT_ROOT}/CMakeLists.txt
PathModified=${PROJECT_ROOT}/src/CMakeLists.txt
Unit=${service_name}
[Install]
WantedBy=default.target
UNIT
systemctl_user daemon-reload
systemctl_user enable --now "$path_name"
echo "systemd user path unit enabled: ${path_name}"
systemctl_user start "$service_name" || true
}
sub_install() {
local build_type="${BUILD_TYPE:-${BUILD_TYPE_DEFAULT}}"
local build_dir="${BUILD_DIR:-${BUILD_DIR_DEFAULT}}"
local use_inotify=0
local do_bootstrap=0
local do_linger=0
while [[ $# -gt 0 ]]; do
case "$1" in
--build-type) build_type="$2"; shift 2 ;;
--use-inotify) use_inotify=1; shift ;;
--ubuntu-bootstrap) do_bootstrap=1; shift ;;
--enable-linger) do_linger=1; shift ;;
-h|--help) usage; exit 0 ;;
*) echo "Unknown option for install: $1" >&2; usage; exit 1 ;;
esac
done
case "$(uname -s)" in
Darwin)
install_macos "${build_type}" "${build_dir}" ;;
Linux)
if (( do_bootstrap == 1 )); then ubuntu_bootstrap; fi
if (( do_linger == 1 )); then enable_linger_linux; fi
install_linux "${build_type}" "${build_dir}" "${use_inotify}" ;;
*)
echo "Unsupported platform" >&2; exit 1 ;;
esac
}
sub_uninstall() {
case "$(uname -s)" in
Darwin)
local label="com.yaze.watchtest"
local plist_path="$HOME/Library/LaunchAgents/${label}.plist"
launchctl unload -w "$plist_path" 2>/dev/null || true
rm -f "$plist_path"
echo "Removed LaunchAgent ${label}"
;;
Linux)
local systemd_dir="$HOME/.config/systemd/user"
if is_systemd_available; then
systemctl_user stop yaze-watchtest.path 2>/dev/null || true
systemctl_user disable yaze-watchtest.path 2>/dev/null || true
systemctl_user stop yaze-watchtest.service 2>/dev/null || true
systemctl_user stop yaze-watchtest-inotify.service 2>/dev/null || true
systemctl_user disable yaze-watchtest-inotify.service 2>/dev/null || true
rm -f "${systemd_dir}/yaze-watchtest.service" "${systemd_dir}/yaze-watchtest.path" "${systemd_dir}/yaze-watchtest-inotify.service"
systemctl_user daemon-reload || true
echo "Removed systemd user units"
fi
stop_userland_agent
;;
*) echo "Unsupported platform" >&2; exit 1 ;;
esac
}
main() {
ensure_exec "$0"
local subcmd="${1:-}"; shift || true
case "${subcmd}" in
install) sub_install "$@" ;;
uninstall) sub_uninstall ;;
run-once) sub_run_once ;;
watch) sub_watch ;;
-h|--help|help|"") usage ;;
*) echo "Unknown subcommand: ${subcmd}" >&2; usage; exit 1 ;;
esac
}
main "$@"

164
scripts/build-windows.bat Normal file
View File

@@ -0,0 +1,164 @@
@echo off
REM YAZE Windows Build Script (Batch Version)
REM This script builds the YAZE project on Windows using MSBuild
setlocal enabledelayedexpansion
REM Parse command line arguments
set BUILD_CONFIG=Release
set BUILD_PLATFORM=x64
set CLEAN_BUILD=0
set VERBOSE=0
:parse_args
if "%~1"=="" goto :args_done
if /i "%~1"=="Debug" set BUILD_CONFIG=Debug
if /i "%~1"=="Release" set BUILD_CONFIG=Release
if /i "%~1"=="RelWithDebInfo" set BUILD_CONFIG=RelWithDebInfo
if /i "%~1"=="MinSizeRel" set BUILD_CONFIG=MinSizeRel
if /i "%~1"=="x64" set BUILD_PLATFORM=x64
if /i "%~1"=="x86" set BUILD_PLATFORM=x86
if /i "%~1"=="ARM64" set BUILD_PLATFORM=ARM64
if /i "%~1"=="clean" set CLEAN_BUILD=1
if /i "%~1"=="verbose" set VERBOSE=1
shift
goto :parse_args
:args_done
echo ========================================
echo YAZE Windows Build Script
echo ========================================
REM Check if we're in the right directory
if not exist "YAZE.sln" (
echo ERROR: YAZE.sln not found. Please run this script from the project root directory.
pause
exit /b 1
)
echo ✓ YAZE.sln found
REM Check for MSBuild
where msbuild >nul 2>&1
if %errorlevel% neq 0 (
echo ERROR: MSBuild not found. Please install Visual Studio 2022 or later.
echo Make sure to install the C++ development workload.
pause
exit /b 1
)
echo ✓ MSBuild found
REM Check for vcpkg
if not exist "vcpkg.json" (
echo WARNING: vcpkg.json not found. vcpkg integration may not work properly.
)
echo Build Configuration: %BUILD_CONFIG%
echo Build Platform: %BUILD_PLATFORM%
REM Create build directories
echo Creating build directories...
if not exist "build" mkdir build
if not exist "build\bin" mkdir build\bin
if not exist "build\obj" mkdir build\obj
REM Clean build if requested
if %CLEAN_BUILD%==1 (
echo Cleaning build directories...
if exist "build\bin" rmdir /s /q "build\bin" 2>nul
if exist "build\obj" rmdir /s /q "build\obj" 2>nul
if not exist "build\bin" mkdir build\bin
if not exist "build\obj" mkdir build\obj
echo ✓ Build directories cleaned
)
REM Generate yaze_config.h if it doesn't exist
if not exist "yaze_config.h" (
echo Generating yaze_config.h...
if exist "src\yaze_config.h.in" (
copy "src\yaze_config.h.in" "yaze_config.h" >nul
powershell -Command "(Get-Content 'yaze_config.h') -replace '@yaze_VERSION_MAJOR@', '0' -replace '@yaze_VERSION_MINOR@', '3' -replace '@yaze_VERSION_PATCH@', '1' | Set-Content 'yaze_config.h'"
echo ✓ Generated yaze_config.h
) else (
echo WARNING: yaze_config.h.in not found, creating basic config
echo // yaze config file > yaze_config.h
echo #define YAZE_VERSION_MAJOR 0 >> yaze_config.h
echo #define YAZE_VERSION_MINOR 3 >> yaze_config.h
echo #define YAZE_VERSION_PATCH 1 >> yaze_config.h
)
)
REM Build using MSBuild
echo Building with MSBuild...
set MSBUILD_ARGS=YAZE.sln /p:Configuration=%BUILD_CONFIG% /p:Platform=%BUILD_PLATFORM% /p:VcpkgEnabled=true /p:VcpkgManifestInstall=true /m
if %VERBOSE%==1 (
set MSBUILD_ARGS=%MSBUILD_ARGS% /verbosity:detailed
) else (
set MSBUILD_ARGS=%MSBUILD_ARGS% /verbosity:minimal
)
echo Command: msbuild %MSBUILD_ARGS%
msbuild %MSBUILD_ARGS%
if %errorlevel% neq 0 (
echo ERROR: Build failed with exit code %errorlevel%
pause
exit /b 1
)
echo ✓ Build completed successfully
REM Verify executable was created
set EXE_PATH=build\bin\%BUILD_CONFIG%\yaze.exe
if not exist "%EXE_PATH%" (
echo ERROR: Executable not found at expected path: %EXE_PATH%
pause
exit /b 1
)
echo ✓ Executable created: %EXE_PATH%
REM Test that the executable runs (basic test)
echo Testing executable startup...
"%EXE_PATH%" --help >nul 2>&1
set EXIT_CODE=%errorlevel%
REM Check if it's the test main or app main
"%EXE_PATH%" --help 2>&1 | findstr /i "Google Test" >nul
if %errorlevel% equ 0 (
echo ERROR: Executable is running test main instead of app main!
pause
exit /b 1
)
echo ✓ Executable runs correctly (exit code: %EXIT_CODE%)
REM Display file info
for %%A in ("%EXE_PATH%") do set FILE_SIZE=%%~zA
set /a FILE_SIZE_MB=%FILE_SIZE% / 1024 / 1024
echo Executable size: %FILE_SIZE_MB% MB
echo ========================================
echo ✓ YAZE Windows build completed successfully!
echo ========================================
echo.
echo Build Configuration: %BUILD_CONFIG%
echo Build Platform: %BUILD_PLATFORM%
echo Executable: %EXE_PATH%
echo.
echo To run YAZE:
echo %EXE_PATH%
echo.
echo To build other configurations:
echo %~nx0 Debug x64
echo %~nx0 Release x86
echo %~nx0 RelWithDebInfo ARM64
echo %~nx0 clean
echo.
pause

220
scripts/build-windows.ps1 Normal file
View File

@@ -0,0 +1,220 @@
# YAZE Windows Build Script
# This script builds the YAZE project on Windows using MSBuild
param(
[string]$Configuration = "Release",
[string]$Platform = "x64",
[switch]$Clean,
[switch]$Verbose
)
# Set error handling
$ErrorActionPreference = "Continue"
# Colors for output
$Colors = @{
Success = "Green"
Warning = "Yellow"
Error = "Red"
Info = "Cyan"
White = "White"
}
function Write-Status {
param([string]$Message, [string]$Color = "White")
Write-Host $Message -ForegroundColor $Colors[$Color]
}
function Test-Command {
param([string]$Command)
try {
$null = Get-Command $Command -ErrorAction Stop
return $true
} catch {
return $false
}
}
function Get-MSBuildPath {
$vsWhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
if (Test-Path $vsWhere) {
$vsInstall = & $vsWhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath
if ($vsInstall) {
$msbuildPath = Join-Path $vsInstall "MSBuild\Current\Bin\MSBuild.exe"
if (Test-Path $msbuildPath) {
return $msbuildPath
}
}
}
return $null
}
# Main script
Write-Status "========================================" "Info"
Write-Status "YAZE Windows Build Script" "Info"
Write-Status "========================================" "Info"
# Validate parameters
$ValidConfigs = @("Debug", "Release", "RelWithDebInfo", "MinSizeRel")
$ValidPlatforms = @("x64", "x86", "ARM64")
if ($ValidConfigs -notcontains $Configuration) {
Write-Status "ERROR: Invalid configuration '$Configuration'. Valid options: $($ValidConfigs -join ', ')" "Error"
exit 1
}
if ($ValidPlatforms -notcontains $Platform) {
Write-Status "ERROR: Invalid platform '$Platform'. Valid options: $($ValidPlatforms -join ', ')" "Error"
exit 1
}
Write-Status "Build Configuration: $Configuration" "Warning"
Write-Status "Build Platform: $Platform" "Warning"
# Check if we're in the right directory
if (-not (Test-Path "YAZE.sln")) {
Write-Status "ERROR: YAZE.sln not found. Please run this script from the project root directory." "Error"
exit 1
}
Write-Status "✓ Found YAZE.sln" "Success"
# Check for MSBuild
$msbuildPath = Get-MSBuildPath
if (-not $msbuildPath) {
Write-Status "ERROR: MSBuild not found. Please install Visual Studio 2022 with C++ workload." "Error"
exit 1
}
Write-Status "✓ MSBuild found at: $msbuildPath" "Success"
# Check for vcpkg
if (-not (Test-Path "vcpkg.json")) {
Write-Status "WARNING: vcpkg.json not found. vcpkg integration may not work properly." "Warning"
}
# Create build directories
Write-Status "Creating build directories..." "Warning"
$directories = @("build", "build\bin", "build\obj")
foreach ($dir in $directories) {
if (-not (Test-Path $dir)) {
New-Item -ItemType Directory -Path $dir -Force | Out-Null
Write-Status "✓ Created directory: $dir" "Success"
}
}
# Clean build if requested
if ($Clean) {
Write-Status "Cleaning build directories..." "Warning"
if (Test-Path "build\bin") {
Remove-Item -Recurse -Force "build\bin\*" -ErrorAction SilentlyContinue
}
if (Test-Path "build\obj") {
Remove-Item -Recurse -Force "build\obj\*" -ErrorAction SilentlyContinue
}
Write-Status "✓ Build directories cleaned" "Success"
}
# Generate yaze_config.h if it doesn't exist
if (-not (Test-Path "yaze_config.h")) {
Write-Status "Generating yaze_config.h..." "Warning"
if (Test-Path "src\yaze_config.h.in") {
Copy-Item "src\yaze_config.h.in" "yaze_config.h"
$content = Get-Content "yaze_config.h" -Raw
$content = $content -replace '@yaze_VERSION_MAJOR@', '0'
$content = $content -replace '@yaze_VERSION_MINOR@', '3'
$content = $content -replace '@yaze_VERSION_PATCH@', '1'
Set-Content "yaze_config.h" $content
Write-Status "✓ Generated yaze_config.h" "Success"
} else {
Write-Status "WARNING: yaze_config.h.in not found, creating basic config" "Warning"
@"
// yaze config file
#define YAZE_VERSION_MAJOR 0
#define YAZE_VERSION_MINOR 3
#define YAZE_VERSION_PATCH 1
"@ | Out-File -FilePath "yaze_config.h" -Encoding UTF8
}
}
# Build using MSBuild
Write-Status "Building with MSBuild..." "Warning"
$msbuildArgs = @(
"YAZE.sln"
"/p:Configuration=$Configuration"
"/p:Platform=$Platform"
"/p:VcpkgEnabled=true"
"/p:VcpkgManifestInstall=true"
"/m"
)
if ($Verbose) {
$msbuildArgs += "/verbosity:detailed"
} else {
$msbuildArgs += "/verbosity:minimal"
}
$msbuildCommand = "& `"$msbuildPath`" $($msbuildArgs -join ' ')"
Write-Status "Command: $msbuildCommand" "Info"
try {
& $msbuildPath @msbuildArgs
if ($LASTEXITCODE -ne 0) {
throw "MSBuild failed with exit code $LASTEXITCODE"
}
Write-Status "✓ Build completed successfully" "Success"
} catch {
Write-Status "✗ Build failed: $_" "Error"
exit 1
}
# Verify executable was created
$exePath = "build\bin\$Configuration\yaze.exe"
if (-not (Test-Path $exePath)) {
Write-Status "ERROR: Executable not found at expected path: $exePath" "Error"
exit 1
}
Write-Status "✓ Executable created: $exePath" "Success"
# Test that the executable runs
Write-Status "Testing executable..." "Warning"
try {
$testResult = & $exePath --help 2>&1
$exitCode = $LASTEXITCODE
# Check if it's the test main or app main
if ($testResult -match "Google Test|gtest") {
Write-Status "ERROR: Executable is running test main instead of app main!" "Error"
Write-Status "Output: $testResult" "Error"
exit 1
}
Write-Status "✓ Executable runs correctly (exit code: $exitCode)" "Success"
} catch {
Write-Status "WARNING: Could not test executable: $_" "Warning"
}
# Display file info
$exeInfo = Get-Item $exePath
$fileSizeMB = [math]::Round($exeInfo.Length / 1MB, 2)
Write-Status "Executable size: $fileSizeMB MB" "Info"
Write-Status "========================================" "Info"
Write-Status "✓ YAZE Windows build completed successfully!" "Success"
Write-Status "========================================" "Info"
Write-Status ""
Write-Status "Build Configuration: $Configuration" "White"
Write-Status "Build Platform: $Platform" "White"
Write-Status "Executable: $exePath" "White"
Write-Status ""
Write-Status "To run YAZE:" "Warning"
Write-Status " $exePath" "White"
Write-Status ""
Write-Status "To build other configurations:" "Warning"
Write-Status " .\scripts\build-windows.ps1 -Configuration Debug -Platform x64" "White"
Write-Status " .\scripts\build-windows.ps1 -Configuration Release -Platform x86" "White"
Write-Status " .\scripts\build-windows.ps1 -Configuration RelWithDebInfo -Platform ARM64" "White"
Write-Status " .\scripts\build-windows.ps1 -Clean" "White"
Write-Status ""

64
scripts/create-macos-bundle.sh Executable file
View File

@@ -0,0 +1,64 @@
#!/bin/bash
set -e
# Create macOS bundle script
# Usage: create-macos-bundle.sh <version> <artifact_name>
VERSION_NUM="$1"
ARTIFACT_NAME="$2"
if [ -z "$VERSION_NUM" ] || [ -z "$ARTIFACT_NAME" ]; then
echo "Usage: $0 <version> <artifact_name>"
exit 1
fi
echo "Creating macOS bundle for version: $VERSION_NUM"
# macOS packaging
if [ -d "build/bin/yaze.app" ]; then
echo "Found macOS bundle, using it directly"
cp -r build/bin/yaze.app ./Yaze.app
# Add additional resources to the bundle
cp -r assets "Yaze.app/Contents/Resources/" 2>/dev/null || echo "assets directory not found"
# Update Info.plist with correct version
if [ -f "cmake/yaze.plist.in" ]; then
sed "s/@yaze_VERSION@/$VERSION_NUM/g" cmake/yaze.plist.in > "Yaze.app/Contents/Info.plist"
fi
else
echo "No bundle found, creating manual bundle"
mkdir -p "Yaze.app/Contents/MacOS"
mkdir -p "Yaze.app/Contents/Resources"
cp build/bin/yaze "Yaze.app/Contents/MacOS/"
cp -r assets "Yaze.app/Contents/Resources/" 2>/dev/null || echo "assets directory not found"
# Create Info.plist with correct version
cat > "Yaze.app/Contents/Info.plist" <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleExecutable</key>
<string>yaze</string>
<key>CFBundleIdentifier</key>
<string>com.yaze.editor</string>
<key>CFBundleName</key>
<string>Yaze</string>
<key>CFBundleVersion</key>
<string>$VERSION_NUM</string>
<key>CFBundleShortVersionString</key>
<string>$VERSION_NUM</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
</dict>
</plist>
EOF
fi
# Create DMG
mkdir dmg_staging
cp -r Yaze.app dmg_staging/
cp LICENSE dmg_staging/ 2>/dev/null || echo "LICENSE not found"
cp README.md dmg_staging/ 2>/dev/null || echo "README.md not found"
cp -r docs dmg_staging/ 2>/dev/null || echo "docs directory not found"
hdiutil create -srcfolder dmg_staging -format UDZO -volname "Yaze v$VERSION_NUM" "$ARTIFACT_NAME.dmg"
echo "macOS bundle creation completed successfully!"

138
scripts/create_release.sh Executable file
View File

@@ -0,0 +1,138 @@
#!/bin/bash
# Script to create a proper release tag for YAZE
# Usage: ./scripts/create_release.sh [version]
# Example: ./scripts/create_release.sh 0.3.0
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Function to print colored output
print_info() {
echo -e "${BLUE} $1${NC}"
}
print_success() {
echo -e "${GREEN}$1${NC}"
}
print_warning() {
echo -e "${YELLOW}⚠️ $1${NC}"
}
print_error() {
echo -e "${RED}$1${NC}"
}
# Check if we're in a git repository
if ! git rev-parse --git-dir > /dev/null 2>&1; then
print_error "Not in a git repository!"
exit 1
fi
# Check if we're on master branch
current_branch=$(git branch --show-current)
if [ "$current_branch" != "master" ]; then
print_warning "You're on branch '$current_branch', not 'master'"
read -p "Continue anyway? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
print_info "Switching to master branch..."
git checkout master
fi
fi
# Get version argument or prompt for it
if [ $# -eq 0 ]; then
echo
print_info "Enter the version number (e.g., 0.3.0, 1.0.0-beta, 2.1.0-rc1):"
read -p "Version: " version
else
version=$1
fi
# Validate version format
if [[ ! "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-.*)?$ ]]; then
print_error "Invalid version format: '$version'"
print_info "Version must follow semantic versioning (e.g., 1.2.3 or 1.2.3-beta)"
exit 1
fi
# Create tag with v prefix
tag="v$version"
# Check if tag already exists
if git tag -l | grep -q "^$tag$"; then
print_error "Tag '$tag' already exists!"
exit 1
fi
# Show current status
echo
print_info "Current repository status:"
git status --short
# Check for uncommitted changes
if ! git diff-index --quiet HEAD --; then
print_warning "You have uncommitted changes!"
read -p "Continue with creating release? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
print_info "Please commit your changes first, then run this script again."
exit 1
fi
fi
# Show what will happen
echo
print_info "Creating release for YAZE:"
echo " 📦 Version: $version"
echo " 🏷️ Tag: $tag"
echo " 🌿 Branch: $current_branch"
echo " 📝 Changelog: docs/C1-changelog.md"
echo
# Confirm
read -p "Create this release? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
print_info "Release creation cancelled."
exit 0
fi
# Create and push tag
print_info "Creating tag '$tag'..."
if git tag -a "$tag" -m "Release $tag"; then
print_success "Tag '$tag' created successfully!"
else
print_error "Failed to create tag!"
exit 1
fi
print_info "Pushing tag to origin..."
if git push origin "$tag"; then
print_success "Tag pushed successfully!"
else
print_error "Failed to push tag!"
print_info "You can manually push with: git push origin $tag"
exit 1
fi
echo
print_success "🎉 Release $tag created successfully!"
print_info "The GitHub Actions release workflow will now:"
echo " • Build packages for Windows, macOS, and Linux"
echo " • Extract changelog from docs/C1-changelog.md"
echo " • Create GitHub release with all assets"
echo " • Include themes, fonts, layouts, and documentation"
echo
print_info "Check the release progress at:"
echo " https://github.com/scawful/yaze/actions"
echo
print_info "The release will be available at:"
echo " https://github.com/scawful/yaze/releases/tag/$tag"

94
scripts/extract_changelog.py Executable file
View File

@@ -0,0 +1,94 @@
#!/usr/bin/env python3
"""
Extract changelog section for a specific version from docs/C1-changelog.md
Usage: python3 extract_changelog.py <version>
Example: python3 extract_changelog.py 0.3.0
"""
import re
import sys
import os
def extract_version_changelog(version_num, changelog_file):
"""Extract changelog section for specific version"""
try:
with open(changelog_file, 'r') as f:
content = f.read()
# Find the section for this version
version_pattern = rf"## {re.escape(version_num)}\s*\([^)]+\)"
next_version_pattern = r"## \d+\.\d+\.\d+\s*\([^)]+\)"
# Find start of current version section
version_match = re.search(version_pattern, content)
if not version_match:
return f"Changelog section not found for version {version_num}."
start_pos = version_match.end()
# Find start of next version section
remaining_content = content[start_pos:]
next_match = re.search(next_version_pattern, remaining_content)
if next_match:
end_pos = start_pos + next_match.start()
section_content = content[start_pos:end_pos].strip()
else:
section_content = remaining_content.strip()
return section_content
except Exception as e:
return f"Error reading changelog: {str(e)}"
def main():
if len(sys.argv) != 2:
print("Usage: python3 extract_changelog.py <version>")
sys.exit(1)
version_num = sys.argv[1]
changelog_file = "docs/C1-changelog.md"
# Check if changelog file exists
if not os.path.exists(changelog_file):
print(f"Error: Changelog file {changelog_file} not found")
sys.exit(1)
# Extract changelog content
changelog_content = extract_version_changelog(version_num, changelog_file)
# Generate full release notes
release_notes = f"""# Yaze v{version_num} Release Notes
{changelog_content}
## Download Instructions
### Windows
- Download `yaze-windows-x64.zip` for 64-bit Windows
- Download `yaze-windows-x86.zip` for 32-bit Windows
- Extract and run `yaze.exe`
### macOS
- Download `yaze-macos.dmg`
- Mount the DMG and drag Yaze to Applications
- You may need to allow the app in System Preferences > Security & Privacy
### Linux
- Download `yaze-linux-x64.tar.gz`
- Extract: `tar -xzf yaze-linux-x64.tar.gz`
- Run: `./yaze`
## System Requirements
- **Windows**: Windows 10 or later (64-bit recommended)
- **macOS**: macOS 10.15 (Catalina) or later
- **Linux**: Ubuntu 20.04 or equivalent, with X11 or Wayland
## Support
For issues and questions, please visit our [GitHub Issues](https://github.com/scawful/yaze/issues) page.
"""
print(release_notes)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,328 @@
#!/usr/bin/env python3
"""
Simple Visual Studio project generator for YAZE
This script creates Visual Studio project files without complex CMake dependencies
"""
import os
import sys
from pathlib import Path
def generate_vcxproj():
"""Generate the YAZE.vcxproj file with all source files"""
# Source file lists (from CMake files)
app_core_src = [
"app/core/controller.cc",
"app/emu/emulator.cc",
"app/core/project.cc",
"app/core/window.cc",
"app/core/asar_wrapper.cc",
"app/core/platform/font_loader.cc",
"app/core/platform/clipboard.cc",
"app/core/platform/file_dialog.cc"
]
app_emu_src = [
"app/emu/audio/apu.cc",
"app/emu/audio/spc700.cc",
"app/emu/audio/dsp.cc",
"app/emu/audio/internal/addressing.cc",
"app/emu/audio/internal/instructions.cc",
"app/emu/cpu/internal/addressing.cc",
"app/emu/cpu/internal/instructions.cc",
"app/emu/cpu/cpu.cc",
"app/emu/video/ppu.cc",
"app/emu/memory/dma.cc",
"app/emu/memory/memory.cc",
"app/emu/snes.cc"
]
app_editor_src = [
"app/editor/editor_manager.cc",
"app/editor/dungeon/dungeon_editor.cc",
"app/editor/dungeon/dungeon_room_selector.cc",
"app/editor/dungeon/dungeon_canvas_viewer.cc",
"app/editor/dungeon/dungeon_object_selector.cc",
"app/editor/dungeon/dungeon_toolset.cc",
"app/editor/dungeon/dungeon_object_interaction.cc",
"app/editor/dungeon/dungeon_renderer.cc",
"app/editor/dungeon/dungeon_room_loader.cc",
"app/editor/dungeon/dungeon_usage_tracker.cc",
"app/editor/overworld/overworld_editor.cc",
"app/editor/overworld/overworld_editor_manager.cc",
"app/editor/sprite/sprite_editor.cc",
"app/editor/music/music_editor.cc",
"app/editor/message/message_editor.cc",
"app/editor/message/message_data.cc",
"app/editor/message/message_preview.cc",
"app/editor/code/assembly_editor.cc",
"app/editor/graphics/screen_editor.cc",
"app/editor/graphics/graphics_editor.cc",
"app/editor/graphics/palette_editor.cc",
"app/editor/overworld/tile16_editor.cc",
"app/editor/overworld/map_properties.cc",
"app/editor/graphics/gfx_group_editor.cc",
"app/editor/overworld/entity.cc",
"app/editor/system/settings_editor.cc",
"app/editor/system/command_manager.cc",
"app/editor/system/extension_manager.cc",
"app/editor/system/shortcut_manager.cc",
"app/editor/system/popup_manager.cc",
"app/test/test_manager.cc"
]
app_gfx_src = [
"app/gfx/arena.cc",
"app/gfx/background_buffer.cc",
"app/gfx/bitmap.cc",
"app/gfx/compression.cc",
"app/gfx/scad_format.cc",
"app/gfx/snes_palette.cc",
"app/gfx/snes_tile.cc",
"app/gfx/snes_color.cc",
"app/gfx/tilemap.cc"
]
app_zelda3_src = [
"app/zelda3/hyrule_magic.cc",
"app/zelda3/overworld/overworld_map.cc",
"app/zelda3/overworld/overworld.cc",
"app/zelda3/screen/inventory.cc",
"app/zelda3/screen/title_screen.cc",
"app/zelda3/screen/dungeon_map.cc",
"app/zelda3/sprite/sprite.cc",
"app/zelda3/sprite/sprite_builder.cc",
"app/zelda3/music/tracker.cc",
"app/zelda3/dungeon/room.cc",
"app/zelda3/dungeon/room_object.cc",
"app/zelda3/dungeon/object_parser.cc",
"app/zelda3/dungeon/object_renderer.cc",
"app/zelda3/dungeon/room_layout.cc",
"app/zelda3/dungeon/dungeon_editor_system.cc",
"app/zelda3/dungeon/dungeon_object_editor.cc"
]
gui_src = [
"app/gui/modules/asset_browser.cc",
"app/gui/modules/text_editor.cc",
"app/gui/canvas.cc",
"app/gui/canvas_utils.cc",
"app/gui/enhanced_palette_editor.cc",
"app/gui/input.cc",
"app/gui/style.cc",
"app/gui/color.cc",
"app/gui/zeml.cc",
"app/gui/theme_manager.cc",
"app/gui/background_renderer.cc"
]
util_src = [
"util/bps.cc",
"util/flag.cc",
"util/hex.cc"
]
# Combine all source files
all_source_files = (
["yaze.cc", "app/main.cc", "app/rom.cc"] +
app_core_src + app_emu_src + app_editor_src +
app_gfx_src + app_zelda3_src + gui_src + util_src
)
# Header files
header_files = [
"incl/yaze.h",
"incl/zelda.h",
"src/yaze_config.h.in"
]
# Generate the .vcxproj file content
vcxproj_content = '''<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="17.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>17.0</VCProjectVersion>
<ProjectGuid>{B2C3D4E5-F6G7-8901-BCDE-F23456789012}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>YAZE</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<ProjectName>YAZE</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)build\\bin\\$(Configuration)\\</OutDir>
<IntDir>$(SolutionDir)build\\obj\\$(Configuration)\\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)build\\bin\\$(Configuration)\\</OutDir>
<IntDir>$(SolutionDir)build\\obj\\$(Configuration)\\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(ProjectDir)src;$(ProjectDir)incl;$(ProjectDir)src\\lib;$(ProjectDir)vcpkg\\installed\\x64-windows\\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp23</LanguageStandard>
<BigObj>true</BigObj>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(ProjectDir)vcpkg\\installed\\x64-windows\\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>SDL2.lib;SDL2main.lib;libpng16.lib;zlib.lib;absl_base.lib;absl_strings.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(ProjectDir)src;$(ProjectDir)incl;$(ProjectDir)src\\lib;$(ProjectDir)vcpkg\\installed\\x64-windows\\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp23</LanguageStandard>
<BigObj>true</BigObj>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(ProjectDir)vcpkg\\installed\\x64-windows\\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>SDL2.lib;SDL2main.lib;libpng16.lib;zlib.lib;absl_base.lib;absl_strings.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
'''
for header in header_files:
vcxproj_content += f' <ClInclude Include="{header}" />\n'
vcxproj_content += ''' </ItemGroup>
<ItemGroup>
'''
for source in all_source_files:
vcxproj_content += f' <ClCompile Include="src\\{source}" />\n'
vcxproj_content += ''' </ItemGroup>
<ItemGroup>
<None Include="CMakeLists.txt" />
<None Include="vcpkg.json" />
<None Include="README.md" />
<None Include="LICENSE" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>'''
return vcxproj_content
def generate_solution():
"""Generate the YAZE.sln file"""
return '''Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "YAZE", "YAZE.vcxproj", "{B2C3D4E5-F6G7-8901-BCDE-F23456789012}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B2C3D4E5-F6G7-8901-BCDE-F23456789012}.Debug|x64.ActiveCfg = Debug|x64
{B2C3D4E5-F6G7-8901-BCDE-F23456789012}.Debug|x64.Build.0 = Debug|x64
{B2C3D4E5-F6G7-8901-BCDE-F23456789012}.Release|x64.ActiveCfg = Release|x64
{B2C3D4E5-F6G7-8901-BCDE-F23456789012}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}
EndGlobalSection
EndGlobal'''
def main():
"""Main function to generate Visual Studio project files"""
print("Generating simple Visual Studio project files for YAZE...")
# Get the project root directory
script_dir = Path(__file__).parent
project_root = script_dir.parent
# Generate .vcxproj file
vcxproj_content = generate_vcxproj()
vcxproj_path = project_root / "YAZE.vcxproj"
with open(vcxproj_path, 'w', encoding='utf-8') as f:
f.write(vcxproj_content)
print(f"Generated: {vcxproj_path}")
# Generate .sln file
solution_content = generate_solution()
solution_path = project_root / "YAZE.sln"
with open(solution_path, 'w', encoding='utf-8') as f:
f.write(solution_content)
print(f"Generated: {solution_path}")
print("Visual Studio project files generated successfully!")
print("")
print("IMPORTANT: Before building in Visual Studio:")
print("1. Make sure vcpkg is set up: .\\scripts\\setup-vcpkg-windows.ps1")
print("2. Install dependencies: .\\vcpkg\\vcpkg.exe install --triplet x64-windows")
print("3. Open YAZE.sln in Visual Studio 2022")
print("4. Build the solution (Ctrl+Shift+B)")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,200 @@
@echo off
REM Configure Visual Studio project files for YAZE
REM This script configures CMake build system to work with existing Visual Studio project files
setlocal enabledelayedexpansion
REM Default values
set CONFIGURATION=Debug
set ARCHITECTURE=x64
set CLEAN=false
REM Parse command line arguments
:parse_args
if "%~1"=="" goto :args_done
if "%~1"=="--clean" set CLEAN=true
if "%~1"=="--release" set CONFIGURATION=Release
if "%~1"=="--x86" set ARCHITECTURE=Win32
if "%~1"=="--x64" set ARCHITECTURE=x64
if "%~1"=="--arm64" set ARCHITECTURE=ARM64
shift
goto :parse_args
:args_done
REM Validate architecture
if not "%ARCHITECTURE%"=="x64" if not "%ARCHITECTURE%"=="Win32" if not "%ARCHITECTURE%"=="ARM64" (
echo Invalid architecture: %ARCHITECTURE%
echo Valid architectures: x64, Win32, ARM64
exit /b 1
)
echo Generating Visual Studio project files for YAZE...
REM Check if we're on Windows
if not "%OS%"=="Windows_NT" (
echo This script is designed for Windows. Use CMake presets on other platforms.
echo Available presets:
echo - windows-debug
echo - windows-release
echo - windows-dev
exit /b 1
)
REM Check if CMake is available
where cmake >nul 2>&1
if errorlevel 1 (
REM Try common CMake installation paths
if exist "C:\Program Files\CMake\bin\cmake.exe" (
echo Found CMake at: C:\Program Files\CMake\bin\cmake.exe
set "PATH=%PATH%;C:\Program Files\CMake\bin"
goto :cmake_found
)
if exist "C:\Program Files (x86)\CMake\bin\cmake.exe" (
echo Found CMake at: C:\Program Files (x86)\CMake\bin\cmake.exe
set "PATH=%PATH%;C:\Program Files (x86)\CMake\bin"
goto :cmake_found
)
if exist "C:\cmake\bin\cmake.exe" (
echo Found CMake at: C:\cmake\bin\cmake.exe
set "PATH=%PATH%;C:\cmake\bin"
goto :cmake_found
)
REM If we get here, CMake is not found
echo CMake not found in PATH. Attempting to install...
REM Try to install CMake via Chocolatey
where choco >nul 2>&1
if not errorlevel 1 (
echo Installing CMake via Chocolatey...
choco install -y cmake
if errorlevel 1 (
echo Failed to install CMake via Chocolatey
) else (
echo CMake installed successfully
REM Refresh PATH
call refreshenv
)
) else (
echo Chocolatey not found. Please install CMake manually:
echo 1. Download from: https://cmake.org/download/
echo 2. Or install Chocolatey first: https://chocolatey.org/install
echo 3. Then run: choco install cmake
exit /b 1
)
REM Check again after installation
where cmake >nul 2>&1
if errorlevel 1 (
echo CMake still not found after installation. Please restart your terminal or add CMake to PATH manually.
exit /b 1
)
)
:cmake_found
echo CMake found and ready to use
REM Set up paths
set SOURCE_DIR=%~dp0..
set BUILD_DIR=%SOURCE_DIR%\build-vs
echo Source directory: %SOURCE_DIR%
echo Build directory: %BUILD_DIR%
REM Clean build directory if requested
if "%CLEAN%"=="true" (
if exist "%BUILD_DIR%" (
echo Cleaning build directory...
rmdir /s /q "%BUILD_DIR%"
)
)
REM Create build directory
if not exist "%BUILD_DIR%" mkdir "%BUILD_DIR%"
REM Check if vcpkg is available
set VCPKG_PATH=%SOURCE_DIR%\vcpkg\scripts\buildsystems\vcpkg.cmake
if exist "%VCPKG_PATH%" (
echo Using vcpkg toolchain: %VCPKG_PATH%
set USE_VCPKG=true
) else (
echo vcpkg not found, using system libraries
set USE_VCPKG=false
)
REM Build CMake command
set CMAKE_ARGS=-B "%BUILD_DIR%" -G "Visual Studio 17 2022" -A %ARCHITECTURE% -DCMAKE_BUILD_TYPE=%CONFIGURATION% -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -DCMAKE_POLICY_VERSION_MAXIMUM=3.28 -DCMAKE_WARN_DEPRECATED=OFF -DABSL_PROPAGATE_CXX_STD=ON -DTHREADS_PREFER_PTHREAD_FLAG=OFF -DYAZE_BUILD_TESTS=ON -DYAZE_BUILD_APP=ON -DYAZE_BUILD_LIB=ON -DYAZE_BUILD_EMU=ON -DYAZE_BUILD_Z3ED=ON -DYAZE_ENABLE_ROM_TESTS=OFF -DYAZE_ENABLE_EXPERIMENTAL_TESTS=ON -DYAZE_ENABLE_UI_TESTS=ON -DYAZE_INSTALL_LIB=OFF
if "%USE_VCPKG%"=="true" (
set CMAKE_ARGS=%CMAKE_ARGS% -DCMAKE_TOOLCHAIN_FILE="%VCPKG_PATH%" -DVCPKG_TARGET_TRIPLET=%ARCHITECTURE%-windows -DVCPKG_MANIFEST_MODE=ON
)
REM Run CMake configuration
echo Configuring CMake...
echo Command: cmake %CMAKE_ARGS% "%SOURCE_DIR%"
cmake %CMAKE_ARGS% "%SOURCE_DIR%"
if errorlevel 1 (
echo CMake configuration failed!
exit /b 1
)
REM Check if the existing solution file is present and valid
set EXISTING_SOLUTION_FILE=%SOURCE_DIR%\YAZE.sln
if exist "%EXISTING_SOLUTION_FILE%" (
echo ✅ Using existing Visual Studio solution: %EXISTING_SOLUTION_FILE%
REM Verify the solution file references the project file
findstr /C:"YAZE.vcxproj" "%EXISTING_SOLUTION_FILE%" >nul
if not errorlevel 1 (
echo ✅ Solution file references YAZE.vcxproj correctly
REM Check if project configurations are set up
findstr /C:"ProjectConfigurationPlatforms" "%EXISTING_SOLUTION_FILE%" >nul
if not errorlevel 1 (
echo ✅ Project configurations are properly set up
) else (
echo ⚠️ Warning: Project configurations may not be set up
)
) else (
echo ❌ Solution file does not reference YAZE.vcxproj
echo Please ensure the solution file includes the YAZE project
)
REM Try to open solution in Visual Studio
where devenv >nul 2>&1
if not errorlevel 1 (
echo Opening solution in Visual Studio...
start "" devenv "%EXISTING_SOLUTION_FILE%"
) else (
echo Visual Studio solution ready: %EXISTING_SOLUTION_FILE%
)
) else (
echo ❌ Existing solution file not found: %EXISTING_SOLUTION_FILE%
echo Please ensure YAZE.sln exists in the project root
exit /b 1
)
echo.
echo 🎉 Visual Studio project configuration complete!
echo.
echo Next steps:
echo 1. Open YAZE.sln in Visual Studio
echo 2. Select configuration: %CONFIGURATION%
echo 3. Select platform: %ARCHITECTURE%
echo 4. Build the solution (Ctrl+Shift+B)
echo.
echo Available configurations:
echo - Debug (with debugging symbols)
echo - Release (optimized)
echo - RelWithDebInfo (optimized with debug info)
echo - MinSizeRel (minimum size)
echo.
echo Available architectures:
echo - x64 (64-bit Intel/AMD)
echo - x86 (32-bit Intel/AMD)
echo - ARM64 (64-bit ARM)
pause

View File

@@ -0,0 +1,251 @@
# Configure Visual Studio project files for YAZE
# This script configures CMake build system to work with existing Visual Studio project files
param(
[string]$Configuration = "Debug",
[string]$Architecture = "x64",
[switch]$Clean = $false,
[switch]$UseVcpkg = $false,
[switch]$Help = $false
)
# Show help if requested
if ($Help) {
Write-Host "Usage: .\generate-vs-projects.ps1 [options]"
Write-Host ""
Write-Host "Options:"
Write-Host " -Configuration <config> Build configuration (Debug, Release, RelWithDebInfo, MinSizeRel)"
Write-Host " -Architecture <arch> Target architecture (x64, x86, ARM64)"
Write-Host " -Clean Clean build directory before configuring"
Write-Host " -UseVcpkg Use vcpkg for dependency management"
Write-Host " -Help Show this help message"
Write-Host ""
Write-Host "Examples:"
Write-Host " .\generate-vs-projects.ps1 # Default: Debug x64"
Write-Host " .\generate-vs-projects.ps1 -Configuration Release -Architecture x86"
Write-Host " .\generate-vs-projects.ps1 -Clean -UseVcpkg"
Write-Host ""
Write-Host "Note: This script configures CMake to work with existing YAZE.sln and YAZE.vcxproj files"
exit 0
}
# Validate architecture parameter
$ValidArchitectures = @("x64", "x86", "ARM64")
if ($Architecture -notin $ValidArchitectures) {
Write-Host "Invalid architecture: $Architecture" -ForegroundColor Red
Write-Host "Valid architectures: $($ValidArchitectures -join ', ')" -ForegroundColor Yellow
exit 1
}
Write-Host "Generating Visual Studio project files for YAZE..." -ForegroundColor Green
# Check if we're on Windows
if ($env:OS -ne "Windows_NT") {
Write-Host "This script is designed for Windows. Use CMake presets on other platforms." -ForegroundColor Yellow
Write-Host "Available presets:" -ForegroundColor Cyan
Write-Host " - windows-debug" -ForegroundColor Gray
Write-Host " - windows-release" -ForegroundColor Gray
Write-Host " - windows-dev" -ForegroundColor Gray
exit 1
}
# Check if CMake is available
$cmakePath = Get-Command cmake -ErrorAction SilentlyContinue
if (-not $cmakePath) {
# Try common CMake installation paths
$commonPaths = @(
"C:\Program Files\CMake\bin\cmake.exe",
"C:\Program Files (x86)\CMake\bin\cmake.exe",
"C:\cmake\bin\cmake.exe"
)
foreach ($path in $commonPaths) {
if (Test-Path $path) {
Write-Host "Found CMake at: $path" -ForegroundColor Green
$env:Path += ";$(Split-Path $path)"
$cmakePath = Get-Command cmake -ErrorAction SilentlyContinue
if ($cmakePath) {
break
}
}
}
}
if (-not $cmakePath) {
Write-Host "CMake not found in PATH. Attempting to install..." -ForegroundColor Yellow
# Try to install CMake via Chocolatey
if (Get-Command choco -ErrorAction SilentlyContinue) {
Write-Host "Installing CMake via Chocolatey..." -ForegroundColor Yellow
choco install -y cmake
if ($LASTEXITCODE -eq 0) {
Write-Host "CMake installed successfully" -ForegroundColor Green
# Refresh PATH
$env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User")
} else {
Write-Host "Failed to install CMake via Chocolatey" -ForegroundColor Red
}
} else {
Write-Host "Chocolatey not found. Please install CMake manually:" -ForegroundColor Red
Write-Host "1. Download from: https://cmake.org/download/" -ForegroundColor Yellow
Write-Host "2. Or install Chocolatey first: https://chocolatey.org/install" -ForegroundColor Yellow
Write-Host "3. Then run: choco install cmake" -ForegroundColor Yellow
exit 1
}
# Check again after installation
$cmakePath = Get-Command cmake -ErrorAction SilentlyContinue
if (-not $cmakePath) {
Write-Host "CMake still not found after installation. Please restart your terminal or add CMake to PATH manually." -ForegroundColor Red
exit 1
}
}
Write-Host "CMake found: $($cmakePath.Source)" -ForegroundColor Green
# Check if Visual Studio is available
$vsWhere = Get-Command "C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -ErrorAction SilentlyContinue
if (-not $vsWhere) {
$vsWhere = Get-Command vswhere -ErrorAction SilentlyContinue
}
if ($vsWhere) {
$vsInstallPath = & $vsWhere.Source -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath
if ($vsInstallPath) {
Write-Host "Visual Studio found at: $vsInstallPath" -ForegroundColor Green
} else {
Write-Host "Visual Studio 2022 not found. Please install Visual Studio 2022 with C++ workload." -ForegroundColor Yellow
}
} else {
Write-Host "vswhere not found. Assuming Visual Studio is available." -ForegroundColor Yellow
}
# Set up paths
$SourceDir = Split-Path -Parent $PSScriptRoot
$BuildDir = Join-Path $SourceDir "build-vs"
Write-Host "Source directory: $SourceDir" -ForegroundColor Cyan
Write-Host "Build directory: $BuildDir" -ForegroundColor Cyan
# Clean build directory if requested
if ($Clean -and (Test-Path $BuildDir)) {
Write-Host "Cleaning build directory..." -ForegroundColor Yellow
Remove-Item -Recurse -Force $BuildDir
}
# Create build directory
if (-not (Test-Path $BuildDir)) {
New-Item -ItemType Directory -Path $BuildDir | Out-Null
}
# Check if vcpkg is available
$VcpkgPath = Join-Path $SourceDir "vcpkg\scripts\buildsystems\vcpkg.cmake"
$UseVcpkg = Test-Path $VcpkgPath
if ($UseVcpkg) {
Write-Host "Using vcpkg toolchain: $VcpkgPath" -ForegroundColor Green
} else {
Write-Host "vcpkg not found, using system libraries" -ForegroundColor Yellow
}
# Determine generator and architecture
$Generator = "Visual Studio 17 2022"
$ArchFlag = if ($Architecture -eq "x64") { "-A x64" } else { "-A Win32" }
# Build CMake command
$CmakeArgs = @(
"-B", $BuildDir,
"-G", "`"$Generator`"",
$ArchFlag,
"-DCMAKE_BUILD_TYPE=$Configuration",
"-DCMAKE_POLICY_VERSION_MINIMUM=3.5",
"-DCMAKE_POLICY_VERSION_MAXIMUM=3.28",
"-DCMAKE_WARN_DEPRECATED=OFF",
"-DABSL_PROPAGATE_CXX_STD=ON",
"-DTHREADS_PREFER_PTHREAD_FLAG=OFF",
"-DYAZE_BUILD_TESTS=ON",
"-DYAZE_BUILD_APP=ON",
"-DYAZE_BUILD_LIB=ON",
"-DYAZE_BUILD_EMU=ON",
"-DYAZE_BUILD_Z3ED=ON",
"-DYAZE_ENABLE_ROM_TESTS=OFF",
"-DYAZE_ENABLE_EXPERIMENTAL_TESTS=ON",
"-DYAZE_ENABLE_UI_TESTS=ON",
"-DYAZE_INSTALL_LIB=OFF"
)
if ($UseVcpkg) {
$CmakeArgs += @(
"-DCMAKE_TOOLCHAIN_FILE=`"$VcpkgPath`"",
"-DVCPKG_TARGET_TRIPLET=$Architecture-windows",
"-DVCPKG_MANIFEST_MODE=ON"
)
}
# Configure CMake to generate build files (but don't overwrite existing project files)
Write-Host "Configuring CMake for build system..." -ForegroundColor Yellow
Write-Host "Command: cmake $($CmakeArgs -join ' ')" -ForegroundColor Gray
& cmake @CmakeArgs $SourceDir
if ($LASTEXITCODE -ne 0) {
Write-Host "CMake configuration failed!" -ForegroundColor Red
exit 1
}
# Check if the existing solution file is present and valid
$ExistingSolutionFile = Join-Path $SourceDir "YAZE.sln"
if (Test-Path $ExistingSolutionFile) {
Write-Host "✅ Using existing Visual Studio solution: $ExistingSolutionFile" -ForegroundColor Green
# Verify the solution file is properly structured
$SolutionContent = Get-Content $ExistingSolutionFile -Raw
if ($SolutionContent -match "YAZE\.vcxproj") {
Write-Host "✅ Solution file references YAZE.vcxproj correctly" -ForegroundColor Green
# Check if project configurations are set up
if ($SolutionContent -match "ProjectConfigurationPlatforms") {
Write-Host "✅ Project configurations are properly set up" -ForegroundColor Green
} else {
Write-Host "⚠️ Warning: Project configurations may not be set up" -ForegroundColor Yellow
}
} else {
Write-Host "❌ Solution file does not reference YAZE.vcxproj" -ForegroundColor Red
Write-Host "Please ensure the solution file includes the YAZE project" -ForegroundColor Yellow
}
# Open solution in Visual Studio if available
if (Get-Command "devenv" -ErrorAction SilentlyContinue) {
Write-Host "Opening solution in Visual Studio..." -ForegroundColor Yellow
& devenv $ExistingSolutionFile
} elseif (Get-Command "code" -ErrorAction SilentlyContinue) {
Write-Host "Opening solution in VS Code..." -ForegroundColor Yellow
& code $ExistingSolutionFile
} else {
Write-Host "Visual Studio solution ready: $ExistingSolutionFile" -ForegroundColor Cyan
}
} else {
Write-Host "❌ Existing solution file not found: $ExistingSolutionFile" -ForegroundColor Red
Write-Host "Please ensure YAZE.sln exists in the project root" -ForegroundColor Yellow
exit 1
}
Write-Host ""
Write-Host "🎉 Visual Studio project configuration complete!" -ForegroundColor Green
Write-Host ""
Write-Host "Next steps:" -ForegroundColor Cyan
Write-Host "1. Open YAZE.sln in Visual Studio" -ForegroundColor White
Write-Host "2. Select configuration: $Configuration" -ForegroundColor White
Write-Host "3. Select platform: $Architecture" -ForegroundColor White
Write-Host "4. Build the solution (Ctrl+Shift+B)" -ForegroundColor White
Write-Host ""
Write-Host "Available configurations:" -ForegroundColor Cyan
Write-Host " - Debug (with debugging symbols)" -ForegroundColor Gray
Write-Host " - Release (optimized)" -ForegroundColor Gray
Write-Host " - RelWithDebInfo (optimized with debug info)" -ForegroundColor Gray
Write-Host " - MinSizeRel (minimum size)" -ForegroundColor Gray
Write-Host ""
Write-Host "Available architectures:" -ForegroundColor Cyan
Write-Host " - x64 (64-bit Intel/AMD)" -ForegroundColor Gray
Write-Host " - x86 (32-bit Intel/AMD)" -ForegroundColor Gray
Write-Host " - ARM64 (64-bit ARM)" -ForegroundColor Gray

View File

@@ -0,0 +1,543 @@
#!/usr/bin/env python3
"""
Python script to generate proper Visual Studio project files for YAZE
This script creates a comprehensive .vcxproj file with all necessary source files
"""
import os
import sys
from pathlib import Path
def generate_vcxproj():
"""Generate the YAZE.vcxproj file with all source files"""
# Source file lists (from CMake files)
app_core_src = [
"app/core/controller.cc",
"app/emu/emulator.cc",
"app/core/project.cc",
"app/core/window.cc",
"app/core/asar_wrapper.cc",
"app/core/platform/font_loader.cc",
"app/core/platform/clipboard.cc",
"app/core/platform/file_dialog.cc"
]
app_emu_src = [
"app/emu/audio/apu.cc",
"app/emu/audio/spc700.cc",
"app/emu/audio/dsp.cc",
"app/emu/audio/internal/addressing.cc",
"app/emu/audio/internal/instructions.cc",
"app/emu/cpu/internal/addressing.cc",
"app/emu/cpu/internal/instructions.cc",
"app/emu/cpu/cpu.cc",
"app/emu/video/ppu.cc",
"app/emu/memory/dma.cc",
"app/emu/memory/memory.cc",
"app/emu/snes.cc"
]
app_editor_src = [
"app/editor/editor_manager.cc",
"app/editor/dungeon/dungeon_editor.cc",
"app/editor/dungeon/dungeon_room_selector.cc",
"app/editor/dungeon/dungeon_canvas_viewer.cc",
"app/editor/dungeon/dungeon_object_selector.cc",
"app/editor/dungeon/dungeon_toolset.cc",
"app/editor/dungeon/dungeon_object_interaction.cc",
"app/editor/dungeon/dungeon_renderer.cc",
"app/editor/dungeon/dungeon_room_loader.cc",
"app/editor/dungeon/dungeon_usage_tracker.cc",
"app/editor/overworld/overworld_editor.cc",
"app/editor/overworld/overworld_editor_manager.cc",
"app/editor/sprite/sprite_editor.cc",
"app/editor/music/music_editor.cc",
"app/editor/message/message_editor.cc",
"app/editor/message/message_data.cc",
"app/editor/message/message_preview.cc",
"app/editor/code/assembly_editor.cc",
"app/editor/graphics/screen_editor.cc",
"app/editor/graphics/graphics_editor.cc",
"app/editor/graphics/palette_editor.cc",
"app/editor/overworld/tile16_editor.cc",
"app/editor/overworld/map_properties.cc",
"app/editor/graphics/gfx_group_editor.cc",
"app/editor/overworld/entity.cc",
"app/editor/system/settings_editor.cc",
"app/editor/system/command_manager.cc",
"app/editor/system/extension_manager.cc",
"app/editor/system/shortcut_manager.cc",
"app/editor/system/popup_manager.cc",
"app/test/test_manager.cc"
]
app_gfx_src = [
"app/gfx/arena.cc",
"app/gfx/background_buffer.cc",
"app/gfx/bitmap.cc",
"app/gfx/compression.cc",
"app/gfx/scad_format.cc",
"app/gfx/snes_palette.cc",
"app/gfx/snes_tile.cc",
"app/gfx/snes_color.cc",
"app/gfx/tilemap.cc"
]
app_zelda3_src = [
"app/zelda3/hyrule_magic.cc",
"app/zelda3/overworld/overworld_map.cc",
"app/zelda3/overworld/overworld.cc",
"app/zelda3/screen/inventory.cc",
"app/zelda3/screen/title_screen.cc",
"app/zelda3/screen/dungeon_map.cc",
"app/zelda3/sprite/sprite.cc",
"app/zelda3/sprite/sprite_builder.cc",
"app/zelda3/music/tracker.cc",
"app/zelda3/dungeon/room.cc",
"app/zelda3/dungeon/room_object.cc",
"app/zelda3/dungeon/object_parser.cc",
"app/zelda3/dungeon/object_renderer.cc",
"app/zelda3/dungeon/room_layout.cc",
"app/zelda3/dungeon/dungeon_editor_system.cc",
"app/zelda3/dungeon/dungeon_object_editor.cc"
]
gui_src = [
"app/gui/modules/asset_browser.cc",
"app/gui/modules/text_editor.cc",
"app/gui/canvas.cc",
"app/gui/canvas_utils.cc",
"app/gui/enhanced_palette_editor.cc",
"app/gui/input.cc",
"app/gui/style.cc",
"app/gui/color.cc",
"app/gui/zeml.cc",
"app/gui/theme_manager.cc",
"app/gui/background_renderer.cc"
]
util_src = [
"util/bps.cc",
"util/flag.cc",
"util/hex.cc"
]
# Combine all source files
all_source_files = (
["yaze.cc", "app/main.cc", "app/rom.cc"] +
app_core_src + app_emu_src + app_editor_src +
app_gfx_src + app_zelda3_src + gui_src + util_src
)
# Header files
header_files = [
"incl/yaze.h",
"incl/zelda.h",
"src/yaze_config.h.in"
]
# Generate the .vcxproj file content
vcxproj_content = '''<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="17.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x86">
<Configuration>Debug</Configuration>
<Platform>x86</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|ARM64">
<Configuration>Debug</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x86">
<Configuration>Release</Configuration>
<Platform>x86</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM64">
<Configuration>Release</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="RelWithDebInfo|x64">
<Configuration>RelWithDebInfo</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="RelWithDebInfo|x86">
<Configuration>RelWithDebInfo</Configuration>
<Platform>x86</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="RelWithDebInfo|ARM64">
<Configuration>RelWithDebInfo</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="MinSizeRel|x64">
<Configuration>MinSizeRel</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="MinSizeRel|x86">
<Configuration>MinSizeRel</Configuration>
<Platform>x86</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="MinSizeRel|ARM64">
<Configuration>MinSizeRel</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>17.0</VCProjectVersion>
<ProjectGuid>{B2C3D4E5-F6G7-8901-BCDE-F23456789012}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>YAZE</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<ProjectName>YAZE</ProjectName>
<VcpkgEnabled>true</VcpkgEnabled>
<VcpkgManifestInstall>true</VcpkgManifestInstall>
<VcpkgTriplet Condition="'$(Platform)'=='Win32'">x86-windows</VcpkgTriplet>
<VcpkgTriplet Condition="'$(Platform)'=='x64'">x64-windows</VcpkgTriplet>
<VcpkgTriplet Condition="'$(Platform)'=='ARM64'">arm64-windows</VcpkgTriplet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x86'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='RelWithDebInfo|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='RelWithDebInfo|x86'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='RelWithDebInfo|ARM64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='MinSizeRel|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='MinSizeRel|x86'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='MinSizeRel|ARM64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x86'">
<Import Project="$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<Import Project="$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x86'">
<Import Project="$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<Import Project="$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='RelWithDebInfo|x64'">
<Import Project="$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='RelWithDebInfo|x86'">
<Import Project="$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='RelWithDebInfo|ARM64'">
<Import Project="$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='MinSizeRel|x64'">
<Import Project="$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='MinSizeRel|x86'">
<Import Project="$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='MinSizeRel|ARM64'">
<Import Project="$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)build\\bin\\$(Configuration)\\</OutDir>
<IntDir>$(SolutionDir)build\\obj\\$(Configuration)\\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x86'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)build\\bin\\$(Configuration)\\</OutDir>
<IntDir>$(SolutionDir)build\\obj\\$(Configuration)\\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)build\\bin\\$(Configuration)\\</OutDir>
<IntDir>$(SolutionDir)build\\obj\\$(Configuration)\\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)build\\bin\\$(Configuration)\\</OutDir>
<IntDir>$(SolutionDir)build\\obj\\$(Configuration)\\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)build\\bin\\$(Configuration)\\</OutDir>
<IntDir>$(SolutionDir)build\\obj\\$(Configuration)\\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)build\\bin\\$(Configuration)\\</OutDir>
<IntDir>$(SolutionDir)build\\obj\\$(Configuration)\\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='RelWithDebInfo|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)build\\bin\\$(Configuration)\\</OutDir>
<IntDir>$(SolutionDir)build\\obj\\$(Configuration)\\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='RelWithDebInfo|x86'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)build\\bin\\$(Configuration)\\</OutDir>
<IntDir>$(SolutionDir)build\\obj\\$(Configuration)\\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='RelWithDebInfo|ARM64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)build\\bin\\$(Configuration)\\</OutDir>
<IntDir>$(SolutionDir)build\\obj\\$(Configuration)\\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='MinSizeRel|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)build\\bin\\$(Configuration)\\</OutDir>
<IntDir>$(SolutionDir)build\\obj\\$(Configuration)\\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='MinSizeRel|x86'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)build\\bin\\$(Configuration)\\</OutDir>
<IntDir>$(SolutionDir)build\\obj\\$(Configuration)\\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='MinSizeRel|ARM64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)build\\bin\\$(Configuration)\\</OutDir>
<IntDir>$(SolutionDir)build\\obj\\$(Configuration)\\</IntDir>
</PropertyGroup>'''
# Add compiler and linker settings for all configurations
configurations = ["Debug", "Release", "RelWithDebInfo", "MinSizeRel"]
platforms = ["x64", "x86", "ARM64"]
for config in configurations:
for platform in platforms:
is_debug = (config == "Debug")
debug_flags = "_DEBUG;_CONSOLE;%(PreprocessorDefinitions)" if is_debug else "NDEBUG;_CONSOLE;%(PreprocessorDefinitions)"
link_incremental = "true" if is_debug else "false"
generate_debug_info = "false" if config == "MinSizeRel" else "true"
vcxproj_content += f'''
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='{config}|{platform}'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>{debug_flags}</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(ProjectDir)src;$(ProjectDir)incl;$(ProjectDir)src\\lib;$(ProjectDir)src\\lib\\asar\\src;$(ProjectDir)src\\lib\\asar\\src\\asar;$(ProjectDir)src\\lib\\asar\\src\\asar-dll-bindings\\c;$(ProjectDir)src\\lib\\imgui;$(ProjectDir)src\\lib\\imgui_test_engine;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp23</LanguageStandard>
<BigObj>true</BigObj>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<RuntimeLibrary>MultiThreaded{"Debug" if is_debug else ""}DLL</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>{generate_debug_info}</GenerateDebugInformation>
<EnableCOMDATFolding>{"false" if is_debug else "true"}</EnableCOMDATFolding>
<OptimizeReferences>{"false" if is_debug else "true"}</OptimizeReferences>
</Link>
</ItemDefinitionGroup>'''
# Add source files
vcxproj_content += '''
<ItemGroup>
'''
for header in header_files:
vcxproj_content += f' <ClInclude Include="{header}" />\n'
vcxproj_content += ''' </ItemGroup>
<ItemGroup>
'''
for source in all_source_files:
vcxproj_content += f' <ClCompile Include="src\\{source}" />\n'
vcxproj_content += ''' </ItemGroup>
<ItemGroup>
<None Include="CMakeLists.txt" />
<None Include="CMakePresets.json" />
<None Include="vcpkg.json" />
<None Include="README.md" />
<None Include="LICENSE" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>'''
return vcxproj_content
def generate_solution():
"""Generate the YAZE.sln file"""
return '''Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "YAZE", "YAZE.vcxproj", "{B2C3D4E5-F6G7-8901-BCDE-F23456789012}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Debug|ARM64 = Debug|ARM64
Release|x64 = Release|x64
Release|x86 = Release|x86
Release|ARM64 = Release|ARM64
RelWithDebInfo|x64 = RelWithDebInfo|x64
RelWithDebInfo|x86 = RelWithDebInfo|x86
RelWithDebInfo|ARM64 = RelWithDebInfo|ARM64
MinSizeRel|x64 = MinSizeRel|x64
MinSizeRel|x86 = MinSizeRel|x86
MinSizeRel|ARM64 = MinSizeRel|ARM64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B2C3D4E5-F6G7-8901-BCDE-F23456789012}.Debug|x64.ActiveCfg = Debug|x64
{B2C3D4E5-F6G7-8901-BCDE-F23456789012}.Debug|x64.Build.0 = Debug|x64
{B2C3D4E5-F6G7-8901-BCDE-F23456789012}.Debug|x86.ActiveCfg = Debug|x86
{B2C3D4E5-F6G7-8901-BCDE-F23456789012}.Debug|x86.Build.0 = Debug|x86
{B2C3D4E5-F6G7-8901-BCDE-F23456789012}.Debug|ARM64.ActiveCfg = Debug|ARM64
{B2C3D4E5-F6G7-8901-BCDE-F23456789012}.Debug|ARM64.Build.0 = Debug|ARM64
{B2C3D4E5-F6G7-8901-BCDE-F23456789012}.Release|x64.ActiveCfg = Release|x64
{B2C3D4E5-F6G7-8901-BCDE-F23456789012}.Release|x64.Build.0 = Release|x64
{B2C3D4E5-F6G7-8901-BCDE-F23456789012}.Release|x86.ActiveCfg = Release|x86
{B2C3D4E5-F6G7-8901-BCDE-F23456789012}.Release|x86.Build.0 = Release|x86
{B2C3D4E5-F6G7-8901-BCDE-F23456789012}.Release|ARM64.ActiveCfg = Release|ARM64
{B2C3D4E5-F6G7-8901-BCDE-F23456789012}.Release|ARM64.Build.0 = Release|ARM64
{B2C3D4E5-F6G7-8901-BCDE-F23456789012}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
{B2C3D4E5-F6G7-8901-BCDE-F23456789012}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
{B2C3D4E5-F6G7-8901-BCDE-F23456789012}.RelWithDebInfo|x86.ActiveCfg = RelWithDebInfo|x86
{B2C3D4E5-F6G7-8901-BCDE-F23456789012}.RelWithDebInfo|x86.Build.0 = RelWithDebInfo|x86
{B2C3D4E5-F6G7-8901-BCDE-F23456789012}.RelWithDebInfo|ARM64.ActiveCfg = RelWithDebInfo|ARM64
{B2C3D4E5-F6G7-8901-BCDE-F23456789012}.RelWithDebInfo|ARM64.Build.0 = RelWithDebInfo|ARM64
{B2C3D4E5-F6G7-8901-BCDE-F23456789012}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
{B2C3D4E5-F6G7-8901-BCDE-F23456789012}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
{B2C3D4E5-F6G7-8901-BCDE-F23456789012}.MinSizeRel|x86.ActiveCfg = MinSizeRel|x86
{B2C3D4E5-F6G7-8901-BCDE-F23456789012}.MinSizeRel|x86.Build.0 = MinSizeRel|x86
{B2C3D4E5-F6G7-8901-BCDE-F23456789012}.MinSizeRel|ARM64.ActiveCfg = MinSizeRel|ARM64
{B2C3D4E5-F6G7-8901-BCDE-F23456789012}.MinSizeRel|ARM64.Build.0 = MinSizeRel|ARM64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}
EndGlobalSection
EndGlobal'''
def main():
"""Main function to generate Visual Studio project files"""
print("Generating Visual Studio project files for YAZE...")
# Get the project root directory
script_dir = Path(__file__).parent
project_root = script_dir.parent
# Generate .vcxproj file
vcxproj_content = generate_vcxproj()
vcxproj_path = project_root / "YAZE.vcxproj"
with open(vcxproj_path, 'w', encoding='utf-8') as f:
f.write(vcxproj_content)
print(f"Generated: {vcxproj_path}")
# Generate .sln file
solution_content = generate_solution()
solution_path = project_root / "YAZE.sln"
with open(solution_path, 'w', encoding='utf-8') as f:
f.write(solution_content)
print(f"Generated: {solution_path}")
print("Visual Studio project files generated successfully!")
print("")
print("To build:")
print("1. Open YAZE.sln in Visual Studio 2022")
print("2. Ensure vcpkg is installed and configured")
print("3. Select your desired configuration (Debug/Release) and platform (x64/x86/ARM64)")
print("4. Build the solution (Ctrl+Shift+B)")
if __name__ == "__main__":
main()

54
scripts/quality_check.sh Executable file
View File

@@ -0,0 +1,54 @@
#!/bin/bash
# Quality check script for YAZE codebase
# This script runs various code quality checks to ensure CI/CD pipeline passes
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
cd "${PROJECT_ROOT}"
echo "🔍 Running code quality checks for YAZE..."
# Check if required tools are available
command -v clang-format >/dev/null 2>&1 || { echo "❌ clang-format not found. Please install it."; exit 1; }
command -v cppcheck >/dev/null 2>&1 || { echo "❌ cppcheck not found. Please install it."; exit 1; }
# Create .clang-format config if it doesn't exist
if [ ! -f .clang-format ]; then
echo "📝 Creating .clang-format configuration..."
clang-format --style=Google --dump-config > .clang-format
fi
echo "✅ Code formatting check..."
# Check formatting without modifying files
FORMATTING_ISSUES=$(find src test -name "*.cc" -o -name "*.h" | head -50 | xargs clang-format --dry-run --Werror --style=Google 2>&1 || true)
if [ -n "$FORMATTING_ISSUES" ]; then
echo "⚠️ Formatting issues found. Run 'make format' to fix them."
echo "$FORMATTING_ISSUES" | head -20
else
echo "✅ All files are properly formatted"
fi
echo "🔍 Running static analysis..."
# Run cppcheck on main source directories
cppcheck --enable=all --error-exitcode=0 \
--suppress=missingIncludeSystem \
--suppress=unusedFunction \
--suppress=unmatchedSuppression \
--suppress=unreadVariable \
--suppress=cstyleCast \
--suppress=variableScope \
src/ 2>&1 | head -30
echo "✅ Quality checks completed!"
echo ""
echo "💡 To fix formatting issues automatically, run:"
echo " find src test -name '*.cc' -o -name '*.h' | xargs clang-format -i --style=Google"
echo ""
echo "💡 For CI/CD pipeline compatibility, ensure:"
echo " - All formatting issues are resolved"
echo " - absl::Status return values are handled with RETURN_IF_ERROR() or PRINT_IF_ERROR()"
echo " - Use Google C++ style for consistency"

View File

@@ -0,0 +1,81 @@
@echo off
REM YAZE vcpkg Setup Script (Batch Version)
REM This script sets up vcpkg for YAZE development on Windows
setlocal enabledelayedexpansion
echo ========================================
echo YAZE vcpkg Setup Script
echo ========================================
REM Check if we're in the right directory
if not exist "vcpkg.json" (
echo ERROR: vcpkg.json not found. Please run this script from the project root directory.
pause
exit /b 1
)
echo ✓ vcpkg.json found
REM Check for Git
where git >nul 2>&1
if %errorlevel% neq 0 (
echo ERROR: Git not found. Please install Git for Windows.
echo Download from: https://git-scm.com/download/win
pause
exit /b 1
)
echo ✓ Git found
REM Clone vcpkg if needed
if not exist "vcpkg" (
echo Cloning vcpkg...
git clone https://github.com/Microsoft/vcpkg.git vcpkg
if %errorlevel% neq 0 (
echo ERROR: Failed to clone vcpkg
pause
exit /b 1
)
echo ✓ vcpkg cloned successfully
) else (
echo ✓ vcpkg directory already exists
)
REM Bootstrap vcpkg
if not exist "vcpkg\vcpkg.exe" (
echo Bootstrapping vcpkg...
cd vcpkg
call bootstrap-vcpkg.bat
if %errorlevel% neq 0 (
echo ERROR: Failed to bootstrap vcpkg
cd ..
pause
exit /b 1
)
cd ..
echo ✓ vcpkg bootstrapped successfully
) else (
echo ✓ vcpkg already bootstrapped
)
REM Install dependencies
echo Installing dependencies...
vcpkg\vcpkg.exe install --triplet x64-windows
if %errorlevel% neq 0 (
echo WARNING: Some dependencies may not have installed correctly
) else (
echo ✓ Dependencies installed successfully
)
echo ========================================
echo ✓ vcpkg setup complete!
echo ========================================
echo.
echo You can now build YAZE using:
echo .\scripts\build-windows.ps1
echo or
echo .\scripts\build-windows.bat
echo.
pause

View File

@@ -0,0 +1,106 @@
# YAZE vcpkg Setup Script
# This script sets up vcpkg for YAZE development on Windows
param(
[string]$Triplet = "x64-windows"
)
# Set error handling
$ErrorActionPreference = "Continue"
# Colors for output
$Colors = @{
Success = "Green"
Warning = "Yellow"
Error = "Red"
Info = "Cyan"
White = "White"
}
function Write-Status {
param([string]$Message, [string]$Color = "White")
Write-Host $Message -ForegroundColor $Colors[$Color]
}
function Test-Command {
param([string]$Command)
try {
$null = Get-Command $Command -ErrorAction Stop
return $true
} catch {
return $false
}
}
# Main script
Write-Status "========================================" "Info"
Write-Status "YAZE vcpkg Setup Script" "Info"
Write-Status "========================================" "Info"
Write-Status "Target triplet: $Triplet" "Warning"
# Check if we're in the right directory
if (-not (Test-Path "vcpkg.json")) {
Write-Status "ERROR: vcpkg.json not found. Please run this script from the project root directory." "Error"
exit 1
}
Write-Status "✓ Found vcpkg.json" "Success"
# Check for Git
if (-not (Test-Command "git")) {
Write-Status "ERROR: Git not found. Please install Git for Windows." "Error"
Write-Status "Download from: https://git-scm.com/download/win" "Info"
exit 1
}
Write-Status "✓ Git found" "Success"
# Clone vcpkg if needed
if (-not (Test-Path "vcpkg")) {
Write-Status "Cloning vcpkg..." "Warning"
& git clone https://github.com/Microsoft/vcpkg.git vcpkg
if ($LASTEXITCODE -eq 0) {
Write-Status "✓ vcpkg cloned successfully" "Success"
} else {
Write-Status "✗ Failed to clone vcpkg" "Error"
exit 1
}
} else {
Write-Status "✓ vcpkg directory already exists" "Success"
}
# Bootstrap vcpkg
$vcpkgExe = "vcpkg\vcpkg.exe"
if (-not (Test-Path $vcpkgExe)) {
Write-Status "Bootstrapping vcpkg..." "Warning"
Push-Location vcpkg
& .\bootstrap-vcpkg.bat
if ($LASTEXITCODE -eq 0) {
Write-Status "✓ vcpkg bootstrapped successfully" "Success"
} else {
Write-Status "✗ Failed to bootstrap vcpkg" "Error"
Pop-Location
exit 1
}
Pop-Location
} else {
Write-Status "✓ vcpkg already bootstrapped" "Success"
}
# Install dependencies
Write-Status "Installing dependencies for triplet: $Triplet" "Warning"
& $vcpkgExe install --triplet $Triplet
if ($LASTEXITCODE -eq 0) {
Write-Status "✓ Dependencies installed successfully" "Success"
} else {
Write-Status "⚠ Some dependencies may not have installed correctly" "Warning"
}
Write-Status "========================================" "Info"
Write-Status "✓ vcpkg setup complete!" "Success"
Write-Status "========================================" "Info"
Write-Status ""
Write-Status "You can now build YAZE using:" "Warning"
Write-Status " .\scripts\build-windows.ps1" "White"
Write-Status ""

View File

@@ -0,0 +1,219 @@
# YAZE Windows Development Setup Script
# Sequential approach with no functions and minimal conditionals
param(
[switch]$SkipVcpkg,
[switch]$SkipVS,
[switch]$SkipBuild
)
$ErrorActionPreference = "Continue"
Write-Host "========================================" -ForegroundColor Cyan
Write-Host "YAZE Windows Development Setup" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
# Step 1: Check project directory
Write-Host "Step 1: Checking project directory..." -ForegroundColor Yellow
$projectValid = Test-Path "CMakeLists.txt"
switch ($projectValid) {
$true { Write-Host "✓ CMakeLists.txt found" -ForegroundColor Green }
$false {
Write-Host "✗ CMakeLists.txt not found" -ForegroundColor Red
Write-Host "Please run this script from the YAZE project root directory" -ForegroundColor Yellow
exit 1
}
}
# Step 2: Check Visual Studio
Write-Host "Step 2: Checking Visual Studio..." -ForegroundColor Yellow
switch ($SkipVS) {
$true { Write-Host "Skipping Visual Studio check" -ForegroundColor Yellow }
$false {
$vsWhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
$vsFound = $false
$vsExists = Test-Path $vsWhere
switch ($vsExists) {
$true {
$vsInstall = & $vsWhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath
switch ($null -ne $vsInstall) {
$true {
$msbuildPath = Join-Path $vsInstall "MSBuild\Current\Bin\MSBuild.exe"
$vsFound = Test-Path $msbuildPath
}
}
}
}
switch ($vsFound) {
$true { Write-Host "✓ Visual Studio 2022 with C++ workload found" -ForegroundColor Green }
$false {
Write-Host "⚠ Visual Studio 2022 with C++ workload not found" -ForegroundColor Yellow
Write-Host "Please install Visual Studio 2022 with 'Desktop development with C++' workload" -ForegroundColor White
}
}
}
}
# Step 3: Check Git
Write-Host "Step 3: Checking Git..." -ForegroundColor Yellow
$gitFound = $false
try {
$null = Get-Command git -ErrorAction Stop
$gitFound = $true
} catch {
$gitFound = $false
}
switch ($gitFound) {
$true {
$gitVersion = & git --version
Write-Host "✓ Git found: $gitVersion" -ForegroundColor Green
}
$false {
Write-Host "⚠ Git not found" -ForegroundColor Yellow
Write-Host "Please install Git for Windows from: https://git-scm.com/download/win" -ForegroundColor White
}
}
# Step 4: Check Python
Write-Host "Step 4: Checking Python..." -ForegroundColor Yellow
$pythonFound = $false
try {
$null = Get-Command python -ErrorAction Stop
$pythonFound = $true
} catch {
$pythonFound = $false
}
switch ($pythonFound) {
$true {
$pythonVersion = & python --version
Write-Host "✓ Python found: $pythonVersion" -ForegroundColor Green
}
$false {
Write-Host "⚠ Python not found" -ForegroundColor Yellow
Write-Host "Please install Python 3.8+ from: https://www.python.org/downloads/" -ForegroundColor White
}
}
# Step 5: Setup vcpkg
Write-Host "Step 5: Setting up vcpkg..." -ForegroundColor Yellow
switch ($SkipVcpkg) {
$true { Write-Host "Skipping vcpkg setup" -ForegroundColor Yellow }
$false {
# Clone vcpkg
$vcpkgExists = Test-Path "vcpkg"
switch ($vcpkgExists) {
$false {
Write-Host "Cloning vcpkg..." -ForegroundColor Yellow
switch ($gitFound) {
$true {
& git clone https://github.com/Microsoft/vcpkg.git vcpkg
$cloneSuccess = ($LASTEXITCODE -eq 0)
switch ($cloneSuccess) {
$true { Write-Host "✓ vcpkg cloned successfully" -ForegroundColor Green }
$false {
Write-Host "✗ Failed to clone vcpkg" -ForegroundColor Red
exit 1
}
}
}
$false {
Write-Host "✗ Git is required to clone vcpkg" -ForegroundColor Red
exit 1
}
}
}
$true { Write-Host "✓ vcpkg directory already exists" -ForegroundColor Green }
}
# Bootstrap vcpkg
$vcpkgExe = "vcpkg\vcpkg.exe"
$vcpkgBootstrapped = Test-Path $vcpkgExe
switch ($vcpkgBootstrapped) {
$false {
Write-Host "Bootstrapping vcpkg..." -ForegroundColor Yellow
Push-Location vcpkg
& .\bootstrap-vcpkg.bat
$bootstrapSuccess = ($LASTEXITCODE -eq 0)
Pop-Location
switch ($bootstrapSuccess) {
$true { Write-Host "✓ vcpkg bootstrapped successfully" -ForegroundColor Green }
$false {
Write-Host "✗ Failed to bootstrap vcpkg" -ForegroundColor Red
exit 1
}
}
}
$true { Write-Host "✓ vcpkg already bootstrapped" -ForegroundColor Green }
}
# Install dependencies
Write-Host "Installing dependencies..." -ForegroundColor Yellow
& $vcpkgExe install --triplet x64-windows
$installSuccess = ($LASTEXITCODE -eq 0)
switch ($installSuccess) {
$true { Write-Host "✓ Dependencies installed successfully" -ForegroundColor Green }
$false { Write-Host "⚠ Some dependencies may not have installed correctly" -ForegroundColor Yellow }
}
}
}
# Step 6: Generate project files
Write-Host "Step 6: Generating Visual Studio project files..." -ForegroundColor Yellow
switch ($pythonFound) {
$true {
& python scripts/generate-vs-projects-simple.py
$generateSuccess = ($LASTEXITCODE -eq 0)
switch ($generateSuccess) {
$true { Write-Host "✓ Project files generated successfully" -ForegroundColor Green }
$false {
Write-Host "⚠ Failed to generate project files with simple generator, trying original..." -ForegroundColor Yellow
& python scripts/generate-vs-projects.py
$generateSuccess2 = ($LASTEXITCODE -eq 0)
switch ($generateSuccess2) {
$true { Write-Host "✓ Project files generated successfully" -ForegroundColor Green }
$false { Write-Host "⚠ Failed to generate project files" -ForegroundColor Yellow }
}
}
}
}
$false { Write-Host "⚠ Python required to generate project files" -ForegroundColor Yellow }
}
# Step 7: Test build
Write-Host "Step 7: Testing build..." -ForegroundColor Yellow
switch ($SkipBuild) {
$true { Write-Host "Skipping test build" -ForegroundColor Yellow }
$false {
$buildScriptExists = Test-Path "scripts\build-windows.ps1"
switch ($buildScriptExists) {
$true {
& .\scripts\build-windows.ps1 -Configuration Release -Platform x64
$buildSuccess = ($LASTEXITCODE -eq 0)
switch ($buildSuccess) {
$true { Write-Host "✓ Test build successful" -ForegroundColor Green }
$false { Write-Host "⚠ Test build failed, but setup is complete" -ForegroundColor Yellow }
}
}
$false { Write-Host "⚠ Build script not found" -ForegroundColor Yellow }
}
}
}
# Final instructions
Write-Host "========================================" -ForegroundColor Cyan
Write-Host "✓ YAZE Windows development setup complete!" -ForegroundColor Green
Write-Host "========================================" -ForegroundColor Cyan
Write-Host ""
Write-Host "Next steps:" -ForegroundColor Yellow
Write-Host "1. Visual Studio project files have been generated" -ForegroundColor White
Write-Host "2. Open YAZE.sln in Visual Studio 2022" -ForegroundColor White
Write-Host "3. Select configuration (Debug/Release) and platform (x64/x86/ARM64)" -ForegroundColor White
Write-Host "4. Build the solution (Ctrl+Shift+B)" -ForegroundColor White
Write-Host ""
Write-Host "Or use command line:" -ForegroundColor Yellow
Write-Host " .\scripts\build-windows.ps1 -Configuration Release -Platform x64" -ForegroundColor White
Write-Host ""
Write-Host "For more information, see docs/windows-development-guide.md" -ForegroundColor Cyan

150
scripts/test_asar_integration.py Executable file
View File

@@ -0,0 +1,150 @@
#!/usr/bin/env python3
"""
Asar Integration Test Script for Yaze
Tests the Asar 65816 assembler integration with real ROM files
"""
import os
import sys
import subprocess
import shutil
import tempfile
from pathlib import Path
def find_project_root():
"""Find the yaze project root directory"""
current = Path(__file__).parent
while current != current.parent:
if (current / "CMakeLists.txt").exists():
return current
current = current.parent
raise FileNotFoundError("Could not find yaze project root")
def main():
print("🧪 Yaze Asar Integration Test")
print("=" * 50)
project_root = find_project_root()
build_dir = project_root / "build_test"
rom_path = build_dir / "bin" / "zelda3.sfc"
test_patch = project_root / "test" / "assets" / "test_patch.asm"
# Check if ROM file exists
if not rom_path.exists():
print(f"❌ ROM file not found: {rom_path}")
print(" Please ensure you have a test ROM at the expected location")
return 1
print(f"✅ Found ROM file: {rom_path}")
print(f" Size: {rom_path.stat().st_size:,} bytes")
# Check if test patch exists
if not test_patch.exists():
print(f"❌ Test patch not found: {test_patch}")
return 1
print(f"✅ Found test patch: {test_patch}")
# Check if z3ed tool exists
z3ed_path = build_dir / "bin" / "z3ed"
if not z3ed_path.exists():
print(f"❌ z3ed CLI tool not found: {z3ed_path}")
print(" Run: cmake --build build_test --target z3ed")
return 1
print(f"✅ Found z3ed CLI tool: {z3ed_path}")
# Create temporary directory for testing
with tempfile.TemporaryDirectory() as temp_dir:
temp_path = Path(temp_dir)
test_rom_path = temp_path / "test_rom.sfc"
patched_rom_path = temp_path / "patched_rom.sfc"
# Copy ROM to temporary location
shutil.copy2(rom_path, test_rom_path)
print(f"📋 Copied ROM to: {test_rom_path}")
# Test 1: Apply patch using z3ed CLI
print("\n🔧 Test 1: Applying patch with z3ed CLI")
try:
cmd = [str(z3ed_path), "asar", str(test_patch), str(test_rom_path)]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
if result.returncode == 0:
print("✅ Patch applied successfully!")
if result.stdout:
print(f" Output: {result.stdout.strip()}")
else:
print(f"❌ Patch failed with return code: {result.returncode}")
if result.stderr:
print(f" Error: {result.stderr.strip()}")
return 1
except subprocess.TimeoutExpired:
print("❌ Patch operation timed out")
return 1
except Exception as e:
print(f"❌ Error running patch: {e}")
return 1
# Test 2: Verify ROM was modified
print("\n🔍 Test 2: Verifying ROM modification")
original_size = rom_path.stat().st_size
modified_size = test_rom_path.stat().st_size
print(f" Original ROM size: {original_size:,} bytes")
print(f" Modified ROM size: {modified_size:,} bytes")
# Read first few bytes to check for changes
with open(rom_path, 'rb') as orig_file, open(test_rom_path, 'rb') as mod_file:
orig_bytes = orig_file.read(1024)
mod_bytes = mod_file.read(1024)
if orig_bytes != mod_bytes:
print("✅ ROM was successfully modified!")
# Count different bytes
diff_count = sum(1 for a, b in zip(orig_bytes, mod_bytes) if a != b)
print(f" {diff_count} bytes differ in first 1KB")
else:
print("⚠️ No differences detected in first 1KB")
print(" (Patch may have been applied to a different region)")
# Test 3: Run unit tests if available
yaze_test_path = build_dir / "bin" / "yaze_test"
if yaze_test_path.exists():
print("\n🧪 Test 3: Running Asar unit tests")
try:
# Run only the Asar-related tests
cmd = [str(yaze_test_path), "--gtest_filter=*Asar*", "--gtest_brief=1"]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=60)
print(f" Exit code: {result.returncode}")
if result.stdout:
# Extract test results
lines = result.stdout.split('\n')
for line in lines:
if 'PASSED' in line or 'FAILED' in line or 'RUN' in line:
print(f" {line}")
if result.returncode == 0:
print("✅ Unit tests passed!")
else:
print("⚠️ Some unit tests failed (this may be expected)")
except subprocess.TimeoutExpired:
print("❌ Unit tests timed out")
except Exception as e:
print(f"⚠️ Error running unit tests: {e}")
else:
print("\n⚠️ Test 3: yaze_test executable not found")
print("\n🎉 Asar integration test completed!")
print("\nNext steps:")
print("- Run full test suite with: ctest --test-dir build_test")
print("- Test Asar functionality in the main yaze application")
print("- Create custom assembly patches for your ROM hacking projects")
return 0
if __name__ == "__main__":
sys.exit(main())

View File

@@ -0,0 +1,132 @@
# YAZE Windows Build Validation Script
# This script validates that the Windows build environment is properly set up
# Set error handling
$ErrorActionPreference = "Continue"
# Colors for output
$Colors = @{
Success = "Green"
Warning = "Yellow"
Error = "Red"
Info = "Cyan"
White = "White"
}
function Write-Status {
param([string]$Message, [string]$Color = "White")
Write-Host $Message -ForegroundColor $Colors[$Color]
}
function Test-Command {
param([string]$Command)
try {
$null = Get-Command $Command -ErrorAction Stop
return $true
} catch {
return $false
}
}
function Test-VisualStudio {
$vsWhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
if (Test-Path $vsWhere) {
$vsInstall = & $vsWhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath
if ($vsInstall) {
$msbuildPath = Join-Path $vsInstall "MSBuild\Current\Bin\MSBuild.exe"
if (Test-Path $msbuildPath) {
return $true
}
}
}
return $false
}
# Main script
Write-Status "========================================" "Info"
Write-Status "YAZE Windows Build Validation" "Info"
Write-Status "========================================" "Info"
$allGood = $true
# Check if we're in the right directory
if (-not (Test-Path "YAZE.sln")) {
Write-Status "✗ YAZE.sln not found" "Error"
$allGood = $false
} else {
Write-Status "✓ YAZE.sln found" "Success"
}
# Check for vcpkg.json
if (-not (Test-Path "vcpkg.json")) {
Write-Status "✗ vcpkg.json not found" "Error"
$allGood = $false
} else {
Write-Status "✓ vcpkg.json found" "Success"
}
# Check for Visual Studio
if (Test-VisualStudio) {
Write-Status "✓ Visual Studio 2022 with C++ workload found" "Success"
} else {
Write-Status "✗ Visual Studio 2022 with C++ workload not found" "Error"
$allGood = $false
}
# Check for Git
if (Test-Command "git") {
$gitVersion = & git --version
Write-Status "✓ Git found: $gitVersion" "Success"
} else {
Write-Status "✗ Git not found" "Error"
$allGood = $false
}
# Check for Python
if (Test-Command "python") {
$pythonVersion = & python --version
Write-Status "✓ Python found: $pythonVersion" "Success"
} else {
Write-Status "✗ Python not found" "Error"
$allGood = $false
}
# Check for vcpkg
if (Test-Path "vcpkg\vcpkg.exe") {
Write-Status "✓ vcpkg found and bootstrapped" "Success"
} else {
Write-Status "✗ vcpkg not found or not bootstrapped" "Error"
$allGood = $false
}
# Check for generated project files
if (Test-Path "YAZE.vcxproj") {
Write-Status "✓ Visual Studio project file found" "Success"
} else {
Write-Status "✗ Visual Studio project file not found" "Error"
Write-Status " Run: python scripts/generate-vs-projects.py" "Info"
$allGood = $false
}
# Check for config file
if (Test-Path "yaze_config.h") {
Write-Status "✓ yaze_config.h found" "Success"
} else {
Write-Status "⚠ yaze_config.h not found (will be generated during build)" "Warning"
}
Write-Status "========================================" "Info"
if ($allGood) {
Write-Status "✓ All checks passed! Build environment is ready." "Success"
Write-Status ""
Write-Status "You can now build YAZE using:" "Warning"
Write-Status " .\scripts\build-windows.ps1" "White"
Write-Status " or" "White"
Write-Status " .\scripts\build-windows.bat" "White"
} else {
Write-Status "✗ Some checks failed. Please fix the issues above." "Error"
Write-Status ""
Write-Status "Run the setup script to fix issues:" "Warning"
Write-Status " .\scripts\setup-windows-dev.ps1" "White"
}
Write-Status "========================================" "Info"

View File

@@ -1,32 +1,3 @@
set(
YAZE_APP_CORE_SRC
app/core/common.cc
app/core/controller.cc
app/core/labeling.cc
app/emu/emulator.cc
)
set(
YAZE_APP_GFX_SRC
app/gfx/bitmap.cc
app/gfx/compression.cc
app/gfx/scad_format.cc
app/gfx/snes_palette.cc
app/gfx/snes_tile.cc
app/gfx/snes_color.cc
app/gfx/tilesheet.cc
)
set(
YAZE_GUI_SRC
app/gui/asset_browser.cc
app/gui/canvas.cc
app/gui/input.cc
app/gui/style.cc
app/gui/color.cc
app/gui/zeml.cc
)
set( set(
YAZE_APP_EMU_SRC YAZE_APP_EMU_SRC
app/emu/audio/apu.cc app/emu/audio/apu.cc
@@ -43,53 +14,83 @@ set(
app/emu/snes.cc app/emu/snes.cc
) )
set(SDL_TARGETS SDL2::SDL2) set(
YAZE_UTIL_SRC
util/bps.cc
util/flag.cc
util/hex.cc
)
if(WIN32 OR MINGW) set(YAZE_RESOURCE_FILES
list(PREPEND SDL_TARGETS SDL2::SDL2main ws2_32) ${CMAKE_SOURCE_DIR}/assets/font/Karla-Regular.ttf
add_definitions(-DSDL_MAIN_HANDLED) ${CMAKE_SOURCE_DIR}/assets/font/Roboto-Medium.ttf
endif() ${CMAKE_SOURCE_DIR}/assets/font/Cousine-Regular.ttf
${CMAKE_SOURCE_DIR}/assets/font/DroidSans.ttf
${CMAKE_SOURCE_DIR}/assets/font/NotoSansJP.ttf
${CMAKE_SOURCE_DIR}/assets/font/IBMPlexSansJP-Bold.ttf
${CMAKE_SOURCE_DIR}/assets/font/MaterialIcons-Regular.ttf
)
if (WIN32 OR MINGW OR UNIX AND NOT APPLE) # Add theme files for macOS bundle (replacing the glob pattern with explicit files)
list(APPEND YAZE_APP_CORE_SRC file(GLOB YAZE_THEME_FILES "${CMAKE_SOURCE_DIR}/assets/themes/*.theme")
app/core/platform/font_loader.cc list(APPEND YAZE_RESOURCE_FILES ${YAZE_THEME_FILES})
app/core/platform/clipboard.cc
foreach (FILE ${YAZE_RESOURCE_FILES})
file(RELATIVE_PATH NEW_FILE "${CMAKE_SOURCE_DIR}/assets" ${FILE})
get_filename_component(NEW_FILE_PATH ${NEW_FILE} DIRECTORY)
set_source_files_properties(${FILE}
PROPERTIES
MACOSX_PACKAGE_LOCATION "Resources/${NEW_FILE_PATH}"
) )
endif() endforeach()
if(APPLE) # Conditionally add native file dialog (optional for CI builds)
list(APPEND YAZE_APP_CORE_SRC if(NOT YAZE_MINIMAL_BUILD)
app/core/platform/file_dialog.mm # Check if we can build NFD before adding it
app/core/platform/app_delegate.mm find_package(PkgConfig QUIET)
app/core/platform/font_loader.mm if(PKG_CONFIG_FOUND AND UNIX AND NOT APPLE)
app/core/platform/clipboard.mm pkg_check_modules(GTK3 QUIET gtk+-3.0)
app/core/platform/file_path.mm if(GTK3_FOUND)
) add_subdirectory(lib/nativefiledialog-extended)
set(YAZE_HAS_NFD ON)
find_library(COCOA_LIBRARY Cocoa) message(STATUS "NFD enabled with GTK3 support")
if(NOT COCOA_LIBRARY) else()
message(FATAL_ERROR "Cocoa not found") set(YAZE_HAS_NFD OFF)
message(STATUS "NFD disabled - GTK3 not found")
endif() endif()
set(CMAKE_EXE_LINKER_FLAGS "-framework ServiceManagement -framework Foundation -framework Cocoa") elseif(WIN32 OR APPLE)
add_subdirectory(lib/nativefiledialog-extended)
set(YAZE_HAS_NFD ON)
message(STATUS "NFD enabled for Windows/macOS")
else()
set(YAZE_HAS_NFD OFF)
message(STATUS "NFD disabled - no platform support")
endif()
else()
set(YAZE_HAS_NFD OFF)
message(STATUS "NFD disabled for minimal build")
endif() endif()
include(app/CMakeLists.txt) if (YAZE_BUILD_APP)
# include(cli/CMakeLists.txt) Excluded for now, macOS include breaks action build include(app/app.cmake)
endif()
if (UNIX) if (YAZE_BUILD_EMU)
target_compile_definitions(yaze PRIVATE "linux") include(app/emu/emu.cmake)
target_compile_definitions(yaze PRIVATE "stricmp=strcasecmp") endif()
if (YAZE_BUILD_Z3ED)
include(cli/z3ed.cmake)
endif() endif()
if(MACOS) if(MACOS)
set(MACOSX_BUNDLE_ICON_FILE ${CMAKE_SOURCE_DIR}/yaze.ico)
set_target_properties(yaze set_target_properties(yaze
PROPERTIES PROPERTIES
BUNDLE True BUNDLE True
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" OUTPUT_NAME "yaze"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/cmake/yaze.plist.in RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/cmake/yaze.plist.in
RESOURCE ${YAZE_RESOURCE_FILES}
) )
elseif(UNIX) elseif(UNIX)
set_target_properties(yaze set_target_properties(yaze
@@ -99,14 +100,146 @@ elseif(UNIX)
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
) )
target_compile_definitions(yaze PRIVATE "linux")
target_compile_definitions(yaze PRIVATE "stricmp=strcasecmp")
else() else()
set_target_properties(yaze if(YAZE_MINIMAL_BUILD)
PROPERTIES # Skip Windows resource file in CI/minimal builds to avoid architecture conflicts
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" set_target_properties(yaze
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
LINK_FLAGS "${CMAKE_CURRENT_SOURCE_DIR}/yaze.res" LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
) RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
)
else()
set_target_properties(yaze
PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
LINK_FLAGS "${CMAKE_CURRENT_SOURCE_DIR}/win32/yaze.res"
)
endif()
endif() endif()
add_subdirectory(test) # Yaze Core Library (for testing and C API)
if (YAZE_BUILD_LIB)
# Create core library for testing (includes editor and zelda3 components needed by tests)
set(YAZE_CORE_SOURCES
app/rom.cc
${YAZE_APP_CORE_SRC}
${YAZE_APP_GFX_SRC}
${YAZE_APP_EDITOR_SRC}
${YAZE_APP_ZELDA3_SRC}
${YAZE_APP_EMU_SRC}
${YAZE_GUI_SRC}
${YAZE_UTIL_SRC}
)
# Create full library for C API
set(YAZE_C_SOURCES
./yaze.cc
${YAZE_CORE_SOURCES}
${YAZE_GUI_SRC}
${IMGUI_SRC}
)
# Add emulator sources (required for comprehensive testing)
list(APPEND YAZE_C_SOURCES ${YAZE_APP_EMU_SRC})
# Only add ImGui Test Engine sources if UI tests are enabled
if(YAZE_ENABLE_UI_TESTS)
list(APPEND YAZE_C_SOURCES ${IMGUI_TEST_ENGINE_SOURCES})
endif()
# Create the core library (static for testing)
add_library(yaze_core STATIC ${YAZE_CORE_SOURCES})
# Create the full C API library (static for CI, shared for release)
if(YAZE_MINIMAL_BUILD)
add_library(yaze_c STATIC ${YAZE_C_SOURCES})
else()
add_library(yaze_c SHARED ${YAZE_C_SOURCES})
endif()
# Configure core library (for testing)
target_include_directories(
yaze_core PUBLIC
${CMAKE_SOURCE_DIR}/src/lib/
${CMAKE_SOURCE_DIR}/src/app/
${CMAKE_SOURCE_DIR}/src/lib/asar/src
${CMAKE_SOURCE_DIR}/src/lib/asar/src/asar
${CMAKE_SOURCE_DIR}/src/lib/asar/src/asar-dll-bindings/c
${CMAKE_SOURCE_DIR}/incl/
${CMAKE_SOURCE_DIR}/src/
${CMAKE_SOURCE_DIR}/src/lib/imgui
${CMAKE_SOURCE_DIR}/src/lib/imgui_test_engine
${SDL2_INCLUDE_DIR}
${PROJECT_BINARY_DIR}
)
target_link_libraries(
yaze_core PUBLIC
asar-static
${ABSL_TARGETS}
${SDL_TARGETS}
${CMAKE_DL_LIBS}
ImGui
)
# Configure full C API library
target_include_directories(
yaze_c PUBLIC
${CMAKE_SOURCE_DIR}/src/lib/
${CMAKE_SOURCE_DIR}/src/app/
${CMAKE_SOURCE_DIR}/src/lib/asar/src
${CMAKE_SOURCE_DIR}/src/lib/asar/src/asar
${CMAKE_SOURCE_DIR}/src/lib/asar/src/asar-dll-bindings/c
${CMAKE_SOURCE_DIR}/incl/
${CMAKE_SOURCE_DIR}/src/
${CMAKE_SOURCE_DIR}/src/lib/imgui_test_engine
${SDL2_INCLUDE_DIR}
${PROJECT_BINARY_DIR}
)
# Conditionally add PNG include dirs if available
if(PNG_FOUND)
target_include_directories(yaze_c PUBLIC ${PNG_INCLUDE_DIRS})
target_include_directories(yaze_core PUBLIC ${PNG_INCLUDE_DIRS})
endif()
target_link_libraries(
yaze_c PRIVATE
yaze_core
ImGui
)
# Conditionally link ImGui Test Engine and set definitions
if(YAZE_ENABLE_UI_TESTS AND TARGET ImGuiTestEngine)
target_link_libraries(yaze_c PRIVATE ImGuiTestEngine)
target_compile_definitions(yaze_c PRIVATE YAZE_ENABLE_IMGUI_TEST_ENGINE=1)
else()
target_compile_definitions(yaze_c PRIVATE YAZE_ENABLE_IMGUI_TEST_ENGINE=0)
endif()
# Conditionally link PNG if available
if(PNG_FOUND)
target_link_libraries(yaze_c PRIVATE ${PNG_LIBRARIES})
target_link_libraries(yaze_core PRIVATE ${PNG_LIBRARIES})
endif()
if (YAZE_INSTALL_LIB)
install(TARGETS yaze_c
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib/static)
install(
FILES
incl/yaze.h
incl/zelda.h
DESTINATION
include
)
endif()
endif()

View File

@@ -1,40 +0,0 @@
include(app/editor/CMakeLists.txt)
include(app/zelda3/CMakeLists.txt)
add_executable(
yaze
app/yaze.cc
app/rom.cc
${YAZE_APP_EMU_SRC}
${YAZE_APP_CORE_SRC}
${YAZE_APP_EDITOR_SRC}
${YAZE_APP_GFX_SRC}
${YAZE_APP_ZELDA3_SRC}
${YAZE_GUI_SRC}
${IMGUI_SRC}
${IMGUI_TEST_ENGINE_SOURCES}
)
target_include_directories(
yaze PUBLIC
lib/
app/
${CMAKE_SOURCE_DIR}/src/
${CMAKE_SOURCE_DIR}/src/lib/imgui_test_engine
${PNG_INCLUDE_DIRS}
${SDL2_INCLUDE_DIR}
)
target_link_libraries(
yaze PUBLIC
${ABSL_TARGETS}
${SDL_TARGETS}
${PNG_LIBRARIES}
${CMAKE_DL_LIBS}
ImGuiTestEngine
ImGui
)
if (APPLE)
target_link_libraries(yaze PUBLIC ${COCOA_LIBRARY})
endif()

127
src/app/app.cmake Normal file
View File

@@ -0,0 +1,127 @@
include(app/core/core.cmake)
include(app/editor/editor.cmake)
include(app/gfx/gfx.cmake)
include(app/gui/gui.cmake)
include(app/zelda3/zelda3.cmake)
if (APPLE)
add_executable(
yaze
MACOSX_BUNDLE
app/main.cc
app/rom.cc
${YAZE_APP_EMU_SRC}
${YAZE_APP_CORE_SRC}
${YAZE_APP_EDITOR_SRC}
${YAZE_APP_GFX_SRC}
${YAZE_APP_ZELDA3_SRC}
${YAZE_UTIL_SRC}
${YAZE_GUI_SRC}
${IMGUI_SRC}
# Bundled Resources
${YAZE_RESOURCE_FILES}
)
# Add the app icon to the macOS bundle
set(ICON_FILE "${CMAKE_SOURCE_DIR}/assets/yaze.icns")
target_sources(yaze PRIVATE ${ICON_FILE})
set_source_files_properties(${ICON_FILE} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
# Set macOS bundle properties
set_target_properties(yaze PROPERTIES
MACOSX_BUNDLE_ICON_FILE "yaze.icns"
MACOSX_BUNDLE_BUNDLE_NAME "Yaze"
MACOSX_BUNDLE_EXECUTABLE_NAME "yaze"
MACOSX_BUNDLE_GUI_IDENTIFIER "com.scawful.yaze"
MACOSX_BUNDLE_INFO_STRING "Yet Another Zelda3 Editor"
MACOSX_BUNDLE_LONG_VERSION_STRING "${PROJECT_VERSION}"
MACOSX_BUNDLE_SHORT_VERSION_STRING "${PROJECT_VERSION}"
MACOSX_BUNDLE_BUNDLE_VERSION "${PROJECT_VERSION}"
MACOSX_BUNDLE_COPYRIGHT "Copyright © 2024 scawful. All rights reserved."
)
else()
add_executable(
yaze
app/main.cc
app/rom.cc
${YAZE_APP_EMU_SRC}
${YAZE_APP_CORE_SRC}
${YAZE_APP_EDITOR_SRC}
${YAZE_APP_GFX_SRC}
${YAZE_APP_ZELDA3_SRC}
${YAZE_UTIL_SRC}
${YAZE_GUI_SRC}
${IMGUI_SRC}
)
endif()
target_include_directories(
yaze PUBLIC
${CMAKE_SOURCE_DIR}/src/lib/
${CMAKE_SOURCE_DIR}/src/app/
${CMAKE_SOURCE_DIR}/src/lib/asar/src
${CMAKE_SOURCE_DIR}/src/lib/asar/src/asar
${CMAKE_SOURCE_DIR}/src/lib/asar/src/asar-dll-bindings/c
${CMAKE_SOURCE_DIR}/incl/
${CMAKE_SOURCE_DIR}/src/
${CMAKE_SOURCE_DIR}/src/lib/imgui_test_engine
${SDL2_INCLUDE_DIR}
${PROJECT_BINARY_DIR}
)
# Conditionally add PNG include dirs if available
if(PNG_FOUND)
target_include_directories(yaze PUBLIC ${PNG_INCLUDE_DIRS})
endif()
# Conditionally link nfd if available
if(YAZE_HAS_NFD)
target_link_libraries(yaze PRIVATE nfd)
target_compile_definitions(yaze PRIVATE YAZE_ENABLE_NFD=1)
else()
target_compile_definitions(yaze PRIVATE YAZE_ENABLE_NFD=0)
endif()
target_link_libraries(
yaze PUBLIC
asar-static
${ABSL_TARGETS}
${SDL_TARGETS}
${CMAKE_DL_LIBS}
ImGui
)
# Conditionally link ImGui Test Engine
if(YAZE_ENABLE_UI_TESTS)
if(TARGET ImGuiTestEngine)
target_include_directories(yaze PUBLIC ${CMAKE_SOURCE_DIR}/src/lib/imgui_test_engine)
target_link_libraries(yaze PUBLIC ImGuiTestEngine)
target_compile_definitions(yaze PRIVATE
YAZE_ENABLE_IMGUI_TEST_ENGINE=1
${IMGUI_TEST_ENGINE_DEFINITIONS})
else()
target_compile_definitions(yaze PRIVATE YAZE_ENABLE_IMGUI_TEST_ENGINE=0)
endif()
else()
target_compile_definitions(yaze PRIVATE YAZE_ENABLE_IMGUI_TEST_ENGINE=0)
endif()
# Link Google Test if available for integrated testing (but NOT gtest_main to avoid main() conflicts)
if(YAZE_BUILD_TESTS AND TARGET gtest)
target_link_libraries(yaze PRIVATE gtest)
target_compile_definitions(yaze PRIVATE YAZE_ENABLE_GTEST=1)
target_compile_definitions(yaze PRIVATE YAZE_ENABLE_TESTING=1)
else()
target_compile_definitions(yaze PRIVATE YAZE_ENABLE_GTEST=0)
target_compile_definitions(yaze PRIVATE YAZE_ENABLE_TESTING=0)
endif()
# Conditionally link PNG if available
if(PNG_FOUND)
target_link_libraries(yaze PUBLIC ${PNG_LIBRARIES})
endif()
if (APPLE)
target_link_libraries(yaze PUBLIC ${COCOA_LIBRARY})
endif()

View File

@@ -0,0 +1,297 @@
#include "app/core/asar_wrapper.h"
#include <fstream>
#include <sstream>
#include <iostream>
#include <filesystem>
#include "absl/strings/str_format.h"
#include "absl/strings/str_join.h"
// Include Asar C bindings
#include "asar-dll-bindings/c/asar.h"
namespace yaze {
namespace app {
namespace core {
AsarWrapper::AsarWrapper() : initialized_(false) {}
AsarWrapper::~AsarWrapper() {
if (initialized_) {
Shutdown();
}
}
absl::Status AsarWrapper::Initialize() {
if (initialized_) {
return absl::OkStatus();
}
// Verify API version compatibility
int api_version = asar_apiversion();
if (api_version < 300) { // Require at least API version 3.0
return absl::InternalError(absl::StrFormat(
"Asar API version %d is too old (required: 300+)", api_version));
}
initialized_ = true;
return absl::OkStatus();
}
void AsarWrapper::Shutdown() {
if (initialized_) {
// Note: Static library doesn't have asar_close()
initialized_ = false;
}
}
std::string AsarWrapper::GetVersion() const {
if (!initialized_) {
return "Not initialized";
}
int version = asar_version();
int major = version / 10000;
int minor = (version / 100) % 100;
int patch = version % 100;
return absl::StrFormat("%d.%d.%d", major, minor, patch);
}
int AsarWrapper::GetApiVersion() const {
if (!initialized_) {
return 0;
}
return asar_apiversion();
}
absl::StatusOr<AsarPatchResult> AsarWrapper::ApplyPatch(
const std::string& patch_path,
std::vector<uint8_t>& rom_data,
const std::vector<std::string>& include_paths) {
if (!initialized_) {
return absl::FailedPreconditionError("Asar not initialized");
}
// Reset previous state
Reset();
AsarPatchResult result;
result.success = false;
// Prepare ROM data
int rom_size = static_cast<int>(rom_data.size());
int buffer_size = std::max(rom_size, 16 * 1024 * 1024); // At least 16MB buffer
// Resize ROM data if needed
if (rom_data.size() < buffer_size) {
rom_data.resize(buffer_size, 0);
}
// Apply the patch
bool patch_success = asar_patch(
patch_path.c_str(),
reinterpret_cast<char*>(rom_data.data()),
buffer_size,
&rom_size);
// Process results
ProcessErrors();
ProcessWarnings();
result.errors = last_errors_;
result.warnings = last_warnings_;
result.success = patch_success && last_errors_.empty();
if (result.success) {
// Resize ROM data to actual size
rom_data.resize(rom_size);
result.rom_size = rom_size;
// Extract symbols
ExtractSymbolsFromLastOperation();
result.symbols.reserve(symbol_table_.size());
for (const auto& [name, symbol] : symbol_table_) {
result.symbols.push_back(symbol);
}
// Calculate CRC32 if available
// Note: Asar might provide this, check if function exists
result.crc32 = 0; // TODO: Implement CRC32 calculation
} else {
return absl::InternalError(absl::StrFormat(
"Patch failed: %s", absl::StrJoin(last_errors_, "; ")));
}
return result;
}
absl::StatusOr<AsarPatchResult> AsarWrapper::ApplyPatchFromString(
const std::string& patch_content,
std::vector<uint8_t>& rom_data,
const std::string& base_path) {
// Create temporary file for patch content
std::string temp_path = "/tmp/yaze_temp_patch.asm";
if (!base_path.empty()) {
// Ensure directory exists
std::filesystem::create_directories(base_path);
temp_path = base_path + "/temp_patch.asm";
}
std::ofstream temp_file(temp_path);
if (!temp_file) {
return absl::InternalError(absl::StrFormat(
"Failed to create temporary patch file at: %s", temp_path));
}
temp_file << patch_content;
temp_file.close();
auto result = ApplyPatch(temp_path, rom_data);
// Clean up temporary file
std::remove(temp_path.c_str());
return result;
}
absl::StatusOr<std::vector<AsarSymbol>> AsarWrapper::ExtractSymbols(
const std::string& asm_path,
const std::vector<std::string>& include_paths) {
if (!initialized_) {
return absl::FailedPreconditionError("Asar not initialized");
}
// Create a dummy ROM for symbol extraction
std::vector<uint8_t> dummy_rom(1024 * 1024, 0); // 1MB dummy ROM
auto result = ApplyPatch(asm_path, dummy_rom, include_paths);
if (!result.ok()) {
return result.status();
}
return result->symbols;
}
std::map<std::string, AsarSymbol> AsarWrapper::GetSymbolTable() const {
return symbol_table_;
}
std::optional<AsarSymbol> AsarWrapper::FindSymbol(const std::string& name) const {
auto it = symbol_table_.find(name);
if (it != symbol_table_.end()) {
return it->second;
}
return std::nullopt;
}
std::vector<AsarSymbol> AsarWrapper::GetSymbolsAtAddress(uint32_t address) const {
std::vector<AsarSymbol> symbols;
for (const auto& [name, symbol] : symbol_table_) {
if (symbol.address == address) {
symbols.push_back(symbol);
}
}
return symbols;
}
void AsarWrapper::Reset() {
if (initialized_) {
asar_reset();
}
symbol_table_.clear();
last_errors_.clear();
last_warnings_.clear();
}
absl::Status AsarWrapper::CreatePatch(
const std::vector<uint8_t>& original_rom,
const std::vector<uint8_t>& modified_rom,
const std::string& patch_path) {
// This is a complex operation that would require:
// 1. Analyzing differences between ROMs
// 2. Generating appropriate assembly code
// 3. Writing the patch file
// For now, return not implemented
return absl::UnimplementedError(
"Patch creation from ROM differences not yet implemented");
}
absl::Status AsarWrapper::ValidateAssembly(const std::string& asm_path) {
// Create a dummy ROM for validation
std::vector<uint8_t> dummy_rom(1024, 0);
auto result = ApplyPatch(asm_path, dummy_rom);
if (!result.ok()) {
return result.status();
}
if (!result->success) {
return absl::InvalidArgumentError(absl::StrFormat(
"Assembly validation failed: %s",
absl::StrJoin(result->errors, "; ")));
}
return absl::OkStatus();
}
void AsarWrapper::ProcessErrors() {
last_errors_.clear();
int error_count = 0;
const errordata* errors = asar_geterrors(&error_count);
for (int i = 0; i < error_count; ++i) {
last_errors_.push_back(std::string(errors[i].fullerrdata));
}
}
void AsarWrapper::ProcessWarnings() {
last_warnings_.clear();
int warning_count = 0;
const errordata* warnings = asar_getwarnings(&warning_count);
for (int i = 0; i < warning_count; ++i) {
last_warnings_.push_back(std::string(warnings[i].fullerrdata));
}
}
void AsarWrapper::ExtractSymbolsFromLastOperation() {
symbol_table_.clear();
// Extract labels using the correct API function
int symbol_count = 0;
const labeldata* labels = asar_getalllabels(&symbol_count);
for (int i = 0; i < symbol_count; ++i) {
AsarSymbol symbol;
symbol.name = std::string(labels[i].name);
symbol.address = labels[i].location;
symbol.file = ""; // Not available in basic API
symbol.line = 0; // Not available in basic API
symbol.opcode = ""; // Would need additional processing
symbol.comment = "";
symbol_table_[symbol.name] = symbol;
}
}
AsarSymbol AsarWrapper::ConvertAsarSymbol(const void* asar_symbol_data) const {
// This would convert from Asar's internal symbol representation
// to our AsarSymbol struct. Implementation depends on Asar's API.
AsarSymbol symbol;
// Placeholder implementation
return symbol;
}
} // namespace core
} // namespace app
} // namespace yaze

212
src/app/core/asar_wrapper.h Normal file
View File

@@ -0,0 +1,212 @@
#ifndef YAZE_APP_CORE_ASAR_WRAPPER_H
#define YAZE_APP_CORE_ASAR_WRAPPER_H
#include <string>
#include <vector>
#include <map>
#include <memory>
#include <optional>
#include "absl/status/status.h"
#include "absl/status/statusor.h"
namespace yaze {
namespace app {
namespace core {
/**
* @brief Symbol information extracted from Asar assembly
*/
struct AsarSymbol {
std::string name; // Symbol name
uint32_t address; // Memory address
std::string opcode; // Associated opcode if available
std::string file; // Source file
int line; // Line number in source
std::string comment; // Optional comment
};
/**
* @brief Asar patch result information
*/
struct AsarPatchResult {
bool success; // Whether patch was successful
std::vector<std::string> errors; // Error messages if any
std::vector<std::string> warnings; // Warning messages
std::vector<AsarSymbol> symbols; // Extracted symbols
uint32_t rom_size; // Final ROM size after patching
uint32_t crc32; // CRC32 checksum of patched ROM
};
/**
* @brief Modern C++ wrapper for Asar 65816 assembler integration
*
* This class provides a high-level interface for:
* - Patching ROMs with assembly code
* - Extracting symbol names and opcodes
* - Cross-platform compatibility (Windows, macOS, Linux)
*/
class AsarWrapper {
public:
AsarWrapper();
~AsarWrapper();
// Disable copy constructor and assignment
AsarWrapper(const AsarWrapper&) = delete;
AsarWrapper& operator=(const AsarWrapper&) = delete;
// Enable move constructor and assignment
AsarWrapper(AsarWrapper&&) = default;
AsarWrapper& operator=(AsarWrapper&&) = default;
/**
* @brief Initialize the Asar library
* @return Status indicating success or failure
*/
absl::Status Initialize();
/**
* @brief Clean up and close the Asar library
*/
void Shutdown();
/**
* @brief Check if Asar is initialized and ready
* @return True if initialized, false otherwise
*/
bool IsInitialized() const { return initialized_; }
/**
* @brief Get Asar version information
* @return Version string
*/
std::string GetVersion() const;
/**
* @brief Get Asar API version
* @return API version number
*/
int GetApiVersion() const;
/**
* @brief Apply an assembly patch to a ROM
* @param patch_path Path to the .asm patch file
* @param rom_data ROM data to patch (will be modified)
* @param include_paths Additional include paths for assembly files
* @return Patch result with status and extracted information
*/
absl::StatusOr<AsarPatchResult> ApplyPatch(
const std::string& patch_path,
std::vector<uint8_t>& rom_data,
const std::vector<std::string>& include_paths = {});
/**
* @brief Apply an assembly patch from string content
* @param patch_content Assembly source code as string
* @param rom_data ROM data to patch (will be modified)
* @param base_path Base path for resolving includes
* @return Patch result with status and extracted information
*/
absl::StatusOr<AsarPatchResult> ApplyPatchFromString(
const std::string& patch_content,
std::vector<uint8_t>& rom_data,
const std::string& base_path = "");
/**
* @brief Extract symbols from an assembly file without patching
* @param asm_path Path to the assembly file
* @param include_paths Additional include paths
* @return Vector of extracted symbols
*/
absl::StatusOr<std::vector<AsarSymbol>> ExtractSymbols(
const std::string& asm_path,
const std::vector<std::string>& include_paths = {});
/**
* @brief Get all available symbols from the last patch operation
* @return Map of symbol names to symbol information
*/
std::map<std::string, AsarSymbol> GetSymbolTable() const;
/**
* @brief Find a symbol by name
* @param name Symbol name to search for
* @return Symbol information if found
*/
std::optional<AsarSymbol> FindSymbol(const std::string& name) const;
/**
* @brief Get symbols at a specific address
* @param address Memory address to search
* @return Vector of symbols at that address
*/
std::vector<AsarSymbol> GetSymbolsAtAddress(uint32_t address) const;
/**
* @brief Reset the Asar state (clear errors, warnings, symbols)
*/
void Reset();
/**
* @brief Get the last error messages
* @return Vector of error strings
*/
std::vector<std::string> GetLastErrors() const { return last_errors_; }
/**
* @brief Get the last warning messages
* @return Vector of warning strings
*/
std::vector<std::string> GetLastWarnings() const { return last_warnings_; }
/**
* @brief Create a patch that can be applied to transform one ROM to another
* @param original_rom Original ROM data
* @param modified_rom Modified ROM data
* @param patch_path Output path for the generated patch
* @return Status indicating success or failure
*/
absl::Status CreatePatch(
const std::vector<uint8_t>& original_rom,
const std::vector<uint8_t>& modified_rom,
const std::string& patch_path);
/**
* @brief Validate an assembly file for syntax errors
* @param asm_path Path to the assembly file
* @return Status indicating validation result
*/
absl::Status ValidateAssembly(const std::string& asm_path);
private:
bool initialized_;
std::map<std::string, AsarSymbol> symbol_table_;
std::vector<std::string> last_errors_;
std::vector<std::string> last_warnings_;
/**
* @brief Process errors from Asar and store them
*/
void ProcessErrors();
/**
* @brief Process warnings from Asar and store them
*/
void ProcessWarnings();
/**
* @brief Extract symbols from the last Asar operation
*/
void ExtractSymbolsFromLastOperation();
/**
* @brief Convert Asar symbol data to AsarSymbol struct
*/
AsarSymbol ConvertAsarSymbol(const void* asar_symbol_data) const;
};
} // namespace core
} // namespace app
} // namespace yaze
#endif // YAZE_APP_CORE_ASAR_WRAPPER_H

View File

@@ -1,187 +0,0 @@
#include "common.h"
#include "imgui/imgui.h"
#include <chrono>
#include <cstdint>
#include <functional>
#include <memory>
#include <stack>
#include <string>
#include "absl/strings/str_format.h"
namespace yaze {
namespace app {
namespace core {
std::shared_ptr<ExperimentFlags::Flags> ExperimentFlags::flags_;
std::string UppercaseHexByte(uint8_t byte, bool leading) {
if (leading) {
std::string result = absl::StrFormat("0x%02X", byte);
return result;
}
std::string result = absl::StrFormat("%02X", byte);
return result;
}
std::string UppercaseHexWord(uint16_t word) {
std::string result = absl::StrFormat("0x%04X", word);
return result;
}
std::string UppercaseHexLong(uint32_t dword) {
std::string result = absl::StrFormat("0x%06X", dword);
return result;
}
uint32_t SnesToPc(uint32_t addr) {
if (addr >= 0x808000) {
addr -= 0x808000;
}
uint32_t temp = (addr & 0x7FFF) + ((addr / 2) & 0xFF8000);
return (temp + 0x0);
}
uint32_t PcToSnes(uint32_t addr) {
uint8_t *b = reinterpret_cast<uint8_t *>(&addr);
b[2] = static_cast<uint8_t>(b[2] * 2);
if (b[1] >= 0x80) {
b[2] += 1;
} else {
b[1] += 0x80;
}
return addr;
}
uint32_t MapBankToWordAddress(uint8_t bank, uint16_t addr) {
uint32_t result = 0;
result = (bank << 16) | addr;
return result;
}
int AddressFromBytes(uint8_t addr1, uint8_t addr2, uint8_t addr3) {
return (addr1 << 16) | (addr2 << 8) | addr3;
}
// hextodec has been imported from SNESDisasm to parse hex numbers
int HexToDec(char *input, int length) {
int result = 0;
int value;
int ceiling = length - 1;
int power16 = 16;
int j = ceiling;
for (; j >= 0; j--) {
if (input[j] >= 'A' && input[j] <= 'F') {
value = input[j] - 'F';
value += 15;
} else {
value = input[j] - '9';
value += 9;
}
if (j == ceiling) {
result += value;
continue;
}
result += (value * power16);
power16 *= 16;
}
return result;
}
bool StringReplace(std::string &str, const std::string &from,
const std::string &to) {
size_t start = str.find(from);
if (start == std::string::npos) return false;
str.replace(start, from.length(), to);
return true;
}
void stle(uint8_t *const p_arr, size_t const p_index, unsigned const p_val) {
uint8_t v = (p_val >> (8 * p_index)) & 0xff;
p_arr[p_index] = v;
}
void stle0(uint8_t *const p_arr, unsigned const p_val) {
stle(p_arr, 0, p_val);
}
void stle1(uint8_t *const p_arr, unsigned const p_val) {
stle(p_arr, 1, p_val);
}
void stle2(uint8_t *const p_arr, unsigned const p_val) {
stle(p_arr, 2, p_val);
}
void stle3(uint8_t *const p_arr, unsigned const p_val) {
stle(p_arr, 3, p_val);
}
void stle16b(uint8_t *const p_arr, uint16_t const p_val) {
stle0(p_arr, p_val);
stle1(p_arr, p_val);
}
// "Store little endian 16-bit value using a byte pointer, offset by an
// index before dereferencing"
void stle16b_i(uint8_t *const p_arr, size_t const p_index,
uint16_t const p_val) {
stle16b(p_arr + (p_index * 2), p_val);
}
// "load little endian value at the given byte offset and shift to get its
// value relative to the base offset (powers of 256, essentially)"
unsigned ldle(uint8_t const *const p_arr, unsigned const p_index) {
uint32_t v = p_arr[p_index];
v <<= (8 * p_index);
return v;
}
// Helper function to get the first byte in a little endian number
uint32_t ldle0(uint8_t const *const p_arr) { return ldle(p_arr, 0); }
// Helper function to get the second byte in a little endian number
uint32_t ldle1(uint8_t const *const p_arr) { return ldle(p_arr, 1); }
// Helper function to get the third byte in a little endian number
uint32_t ldle2(uint8_t const *const p_arr) { return ldle(p_arr, 2); }
// Helper function to get the third byte in a little endian number
uint32_t ldle3(uint8_t const *const p_arr) { return ldle(p_arr, 3); }
// Load little endian halfword (16-bit) dereferenced from
uint16_t ldle16b(uint8_t const *const p_arr) {
uint16_t v = 0;
v |= (ldle0(p_arr) | ldle1(p_arr));
return v;
}
// Load little endian halfword (16-bit) dereferenced from an arrays of bytes.
// This version provides an index that will be multiplied by 2 and added to the
// base address.
uint16_t ldle16b_i(uint8_t const *const p_arr, size_t const p_index) {
return ldle16b(p_arr + (2 * p_index));
}
// Initialize the static member
std::stack<ImGuiID> ImGuiIdIssuer::idStack;
uint32_t Get24LocalFromPC(uint8_t *data, int addr, bool pc) {
uint32_t ret = (PcToSnes(addr) & 0xFF0000) | (data[addr + 1] << 8) | data[addr];
if (pc) {
return SnesToPc(ret);
}
return ret;
}
} // namespace core
} // namespace app
} // namespace yaze

View File

@@ -1,234 +0,0 @@
#ifndef YAZE_CORE_COMMON_H
#define YAZE_CORE_COMMON_H
#include "imgui/imgui.h"
#include <chrono>
#include <cstdint>
#include <fstream>
#include <functional>
#include <iostream>
#include <memory>
#include <stack>
#include <string>
namespace yaze {
namespace app {
/**
* @namespace yaze::app::core
* @brief Core application logic and utilities.
*/
namespace core {
/**
* @class ExperimentFlags
* @brief A class to manage experimental feature flags.
*/
class ExperimentFlags {
public:
struct Flags {
// Bitmap manager abstraction to manage graphics bin of Rom.
bool kUseBitmapManager = true;
// Log instructions to the GUI debugger.
bool kLogInstructions = true;
// Flag to enable ImGui input config flags. Currently is
// handled manually by controller class but should be
// ported away from that eventually.
bool kUseNewImGuiInput = false;
// Flag to enable the saving of all palettes to the Rom.
bool kSaveAllPalettes = false;
// Flag to enable the saving of gfx groups to the rom.
bool kSaveGfxGroups = false;
// Flag to enable the change queue, which could have any anonymous
// save routine for the Rom. In practice, just the overworld tilemap
// and tile32 save.
bool kSaveWithChangeQueue = false;
// Attempt to run the dungeon room draw routine when opening a room.
bool kDrawDungeonRoomGraphics = true;
// Use the new platform specific file dialog wrappers.
bool kNewFileDialogWrapper = true;
// Platform specific loading of fonts from the system. Currently
// only supports macOS.
bool kLoadSystemFonts = true;
// Uses texture streaming from SDL for my dynamic updates.
bool kLoadTexturesAsStreaming = true;
// Save dungeon map edits to the Rom.
bool kSaveDungeonMaps = false;
// Log to the console.
bool kLogToConsole = false;
// Load audio device for emulator
bool kLoadAudioDevice = false;
// Overworld flags
struct Overworld {
// Load and render overworld sprites to the screen. Unstable.
bool kDrawOverworldSprites = false;
// Save overworld map edits to the Rom.
bool kSaveOverworldMaps = true;
// Save overworld entrances to the Rom.
bool kSaveOverworldEntrances = true;
// Save overworld exits to the Rom.
bool kSaveOverworldExits = true;
// Save overworld items to the Rom.
bool kSaveOverworldItems = true;
// Save overworld properties to the Rom.
bool kSaveOverworldProperties = true;
} overworld;
};
ExperimentFlags() = default;
virtual ~ExperimentFlags() = default;
auto flags() const {
if (!flags_) {
flags_ = std::make_shared<Flags>();
}
Flags *flags = flags_.get();
return flags;
}
Flags *mutable_flags() {
if (!flags_) {
flags_ = std::make_shared<Flags>();
}
return flags_.get();
}
private:
static std::shared_ptr<Flags> flags_;
};
/**
* @class NotifyValue
* @brief A class to manage a value that can be modified and notify when it
* changes.
*/
template <typename T>
class NotifyValue {
public:
NotifyValue() : value_(), modified_(false), temp_value_() {}
NotifyValue(const T &value)
: value_(value), modified_(false), temp_value_() {}
void set(const T &value) {
value_ = value;
modified_ = true;
}
const T &get() {
modified_ = false;
return value_;
}
T &mutable_get() {
modified_ = false;
temp_value_ = value_;
return temp_value_;
}
void apply_changes() {
if (temp_value_ != value_) {
value_ = temp_value_;
modified_ = true;
}
}
void operator=(const T &value) { set(value); }
operator T() { return get(); }
bool modified() const { return modified_; }
private:
T value_;
bool modified_;
T temp_value_;
};
class ImGuiIdIssuer {
private:
static std::stack<ImGuiID> idStack;
public:
// Generate and push a new ID onto the stack
static ImGuiID GetNewID() {
static int counter = 1; // Start from 1 to ensure uniqueness
ImGuiID child_id = ImGui::GetID((void *)(intptr_t)counter++);
idStack.push(child_id);
return child_id;
}
// Pop all IDs from the stack (can be called explicitly or upon program exit)
static void Cleanup() {
while (!idStack.empty()) {
idStack.pop();
}
}
};
class Logger {
public:
static void log(std::string message) {
static std::ofstream fout("log.txt", std::ios::out | std::ios::app);
fout << message << std::endl;
}
// log to console
static void logc(std::string message) { logs.emplace_back(message); }
static std::vector<std::string> logs;
};
std::string UppercaseHexByte(uint8_t byte, bool leading = false);
std::string UppercaseHexWord(uint16_t word);
std::string UppercaseHexLong(uint32_t dword);
uint32_t SnesToPc(uint32_t addr);
uint32_t PcToSnes(uint32_t addr);
uint32_t MapBankToWordAddress(uint8_t bank, uint16_t addr);
int AddressFromBytes(uint8_t addr1, uint8_t addr2, uint8_t addr3);
int HexToDec(char *input, int length);
bool StringReplace(std::string &str, const std::string &from,
const std::string &to);
void stle16b_i(uint8_t *const p_arr, size_t const p_index,
uint16_t const p_val);
uint16_t ldle16b_i(uint8_t const *const p_arr, size_t const p_index);
uint16_t ldle16b(uint8_t const *const p_arr);
void stle16b(uint8_t *const p_arr, uint16_t const p_val);
struct FolderItem {
std::string name;
std::vector<FolderItem> subfolders;
std::vector<std::string> files;
};
typedef struct FolderItem FolderItem;
uint32_t Get24LocalFromPC(uint8_t *data, int addr, bool pc = true);
} // namespace core
} // namespace app
} // namespace yaze
#endif

View File

@@ -1,852 +0,0 @@
#ifndef YAZE_APP_CORE_CONSTANTS_H
#define YAZE_APP_CORE_CONSTANTS_H
#include <vector>
#include "absl/strings/string_view.h"
#define TAB_BAR(w) if (ImGui::BeginTabBar(w)) {
#define END_TAB_BAR() \
ImGui::EndTabBar(); \
}
#define TAB_ITEM(w) if (ImGui::BeginTabItem(w)) {
#define END_TAB_ITEM() \
ImGui::EndTabItem(); \
}
#define MENU_ITEM(w) if (ImGui::MenuItem(w))
#define MENU_ITEM2(w, v) if (ImGui::MenuItem(w, v))
#define BUTTON_COLUMN(w) \
ImGui::TableNextColumn(); \
ImGui::Button(w);
#define TEXT_COLUMN(w) \
ImGui::TableNextColumn(); \
ImGui::Text(w);
#define BEGIN_TABLE(l, n, f) if (ImGui::BeginTable(l, n, f, ImVec2(0, 0))) {
#define SETUP_COLUMN(l) ImGui::TableSetupColumn(l);
#define TABLE_HEADERS() \
ImGui::TableHeadersRow(); \
ImGui::TableNextRow();
#define NEXT_COLUMN() ImGui::TableNextColumn();
#define END_TABLE() \
ImGui::EndTable(); \
}
#define HOVER_HINT(string) \
if (ImGui::IsItemHovered()) ImGui::SetTooltip(string);
#define PRINT_IF_ERROR(expression) \
{ \
auto error = expression; \
if (!error.ok()) { \
std::cout << error.ToString() << std::endl; \
} \
}
#define EXIT_IF_ERROR(expression) \
{ \
auto error = expression; \
if (!error.ok()) { \
std::cout << error.ToString() << std::endl; \
return EXIT_FAILURE; \
} \
}
#define RETURN_VOID_IF_ERROR(expression) \
{ \
auto error = expression; \
if (!error.ok()) { \
std::cout << error.ToString() << std::endl; \
return; \
} \
}
#define RETURN_IF_ERROR(expression) \
{ \
auto error = expression; \
if (!error.ok()) { \
return error; \
} \
}
#define ASSIGN_OR_RETURN(type_variable_name, expression) \
ASSIGN_OR_RETURN_IMPL(APPEND_NUMBER(error_or_value, __LINE__), \
type_variable_name, expression)
#define ASSIGN_OR_RETURN_IMPL(error_or_value, type_variable_name, expression) \
auto error_or_value = expression; \
if (!error_or_value.ok()) { \
return error_or_value.status(); \
} \
type_variable_name = std::move(*error_or_value);
#define ASSIGN_OR_LOG_ERROR(type_variable_name, expression) \
ASSIGN_OR_LOG_ERROR_IMPL(APPEND_NUMBER(error_or_value, __LINE__), \
type_variable_name, expression)
#define ASSIGN_OR_LOG_ERROR_IMPL(error_or_value, type_variable_name, \
expression) \
auto error_or_value = expression; \
if (!error_or_value.ok()) { \
std::cout << error_or_value.status().ToString() << std::endl; \
} \
type_variable_name = std::move(*error_or_value);
#define APPEND_NUMBER(expression, number) \
APPEND_NUMBER_INNER(expression, number)
#define APPEND_NUMBER_INNER(expression, number) expression##number
#define TEXT_WITH_SEPARATOR(text) \
ImGui::Text(text); \
ImGui::Separator();
#define TABLE_BORDERS_RESIZABLE \
ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable
#define CLEAR_AND_RETURN_STATUS(status) \
if (!status.ok()) { \
auto temp = status; \
status = absl::OkStatus(); \
return temp; \
}
using ushort = unsigned short;
using uint = unsigned int;
using uchar = unsigned char;
using Bytes = std::vector<uint8_t>;
using OWBlockset = std::vector<std::vector<uint16_t>>;
struct OWMapTiles {
OWBlockset light_world; // 64 maps
OWBlockset dark_world; // 64 maps
OWBlockset special_world; // 32 maps
};
using OWMapTiles = struct OWMapTiles;
namespace yaze {
namespace app {
namespace core {
constexpr uint32_t kRedPen = 0xFF0000FF;
constexpr float kYazeVersion = 0.2;
// ============================================================================
// Magic numbers
// ============================================================================
/// Bit set for object priority
constexpr ushort TilePriorityBit = 0x2000;
/// Bit set for object hflip
constexpr ushort TileHFlipBit = 0x4000;
/// Bit set for object vflip
constexpr ushort TileVFlipBit = 0x8000;
/// Bits used for tile name
constexpr ushort TileNameMask = 0x03FF;
constexpr int Uncompressed3BPPSize = 0x0600;
constexpr int UncompressedSheetSize = 0x0800;
constexpr int NumberOfRooms = 296;
constexpr int NumberOfColors = 3143;
// ============================================================================
// Game Graphics
// ============================================================================
constexpr int tile_address = 0x1B52; // JP = Same
constexpr int tile_address_floor = 0x1B5A; // JP = Same
constexpr int subtype1_tiles = 0x8000; // JP = Same
constexpr int subtype2_tiles = 0x83F0; // JP = Same
constexpr int subtype3_tiles = 0x84F0; // JP = Same
constexpr int gfx_animated_pointer = 0x10275; // JP 0x10624 //long pointer
constexpr int hud_palettes = 0xDD660;
constexpr int maxGfx = 0xC3FB5;
constexpr int kTilesheetWidth = 128;
constexpr int kTilesheetHeight = 32;
constexpr int kTilesheetDepth = 8;
// TEXT EDITOR RELATED CONSTANTS
constexpr int gfx_font = 0x70000; // 2bpp format
constexpr int text_data = 0xE0000;
constexpr int text_data2 = 0x75F40;
constexpr int pointers_dictionaries = 0x74703;
constexpr int characters_width = 0x74ADF;
constexpr int entrance_gfx_group = 0x5D97;
// ============================================================================
// Gravestones related variables
// ============================================================================
constexpr int GravesYTilePos = 0x49968; // short (0x0F entries)
constexpr int GravesXTilePos = 0x49986; // short (0x0F entries)
constexpr int GravesTilemapPos = 0x499A4; // short (0x0F entries)
constexpr int GravesGFX = 0x499C2; // short (0x0F entries)
constexpr int GravesXPos = 0x4994A; // short (0x0F entries)
constexpr int GravesYLine = 0x4993A; // short (0x08 entries)
constexpr int GravesCountOnY = 0x499E0; // Byte 0x09 entries
constexpr int GraveLinkSpecialHole = 0x46DD9; // short
constexpr int GraveLinkSpecialStairs = 0x46DE0; // short
// ============================================================================
// Names
// ============================================================================
static const std::string RoomEffect[] = {"Nothing",
"Nothing",
"Moving Floor",
"Moving Water",
"Trinexx Shell",
"Red Flashes",
"Light Torch to See Floor",
"Ganon's Darkness"};
static const std::string RoomTag[] = {"Nothing",
"NW Kill Enemy to Open",
"NE Kill Enemy to Open",
"SW Kill Enemy to Open",
"SE Kill Enemy to Open",
"W Kill Enemy to Open",
"E Kill Enemy to Open",
"N Kill Enemy to Open",
"S Kill Enemy to Open",
"Clear Quadrant to Open",
"Clear Full Tile to Open",
"NW Push Block to Open",
"NE Push Block to Open",
"SW Push Block to Open",
"SE Push Block to Open",
"W Push Block to Open",
"E Push Block to Open",
"N Push Block to Open",
"S Push Block to Open",
"Push Block to Open",
"Pull Lever to Open",
"Collect Prize to Open",
"Hold Switch Open Door",
"Toggle Switch to Open Door",
"Turn off Water",
"Turn on Water",
"Water Gate",
"Water Twin",
"Moving Wall Right",
"Moving Wall Left",
"Crash",
"Crash",
"Push Switch Exploding Wall",
"Holes 0",
"Open Chest (Holes 0)",
"Holes 1",
"Holes 2",
"Defeat Boss for Dungeon Prize",
"SE Kill Enemy to Push Block",
"Trigger Switch Chest",
"Pull Lever Exploding Wall",
"NW Kill Enemy for Chest",
"NE Kill Enemy for Chest",
"SW Kill Enemy for Chest",
"SE Kill Enemy for Chest",
"W Kill Enemy for Chest",
"E Kill Enemy for Chest",
"N Kill Enemy for Chest",
"S Kill Enemy for Chest",
"Clear Quadrant for Chest",
"Clear Full Tile for Chest",
"Light Torches to Open",
"Holes 3",
"Holes 4",
"Holes 5",
"Holes 6",
"Agahnim Room",
"Holes 7",
"Holes 8",
"Open Chest for Holes 8",
"Push Block for Chest",
"Clear Room for Triforce Door",
"Light Torches for Chest",
"Kill Boss Again"};
static const std::string SecretItemNames[] = {
"Nothing", "Green Rupee", "Rock hoarder", "Bee", "Health pack",
"Bomb", "Heart ", "Blue Rupee",
"Key", "Arrow", "Bomb", "Heart", "Magic",
"Full Magic", "Cucco", "Green Soldier", "Bush Stal", "Blue Soldier",
"Landmine", "Heart", "Fairy", "Heart",
"Nothing ", // 22
"Hole", "Warp", "Staircase", "Bombable", "Switch"};
static const std::string TileTypeNames[] = {
"$00 Nothing (standard floor)",
"$01 Collision",
"$02 Collision",
"$03 Collision",
"$04 Collision",
"$05 Nothing (unused?)",
"$06 Nothing (unused?)",
"$07 Nothing (unused?)",
"$08 Deep water",
"$09 Shallow water",
"$0A Unknown? Possibly unused",
"$0B Collision (different in Overworld and unknown)",
"$0C Overlay mask",
"$0D Spike floor",
"$0E GT ice",
"$0F Ice palace ice",
"$10 Slope ◤",
"$11 Slope ◥",
"$12 Slope ◣",
"$13 Slope ◢",
"$14 Nothing (unused?)",
"$15 Nothing (unused?)",
"$16 Nothing (unused?)",
"$17 Nothing (unused?)",
"$18 Slope ◤",
"$19 Slope ◥",
"$1A Slope ◣",
"$1B Slope ◢",
"$1C Layer 2 overlay",
"$1D North single-layer auto stairs",
"$1E North layer-swap auto stairs",
"$1F North layer-swap auto stairs",
"$20 Pit",
"$21 Nothing (unused?)",
"$22 Manual stairs",
"$23 Pot switch",
"$24 Pressure switch",
"$25 Nothing (unused but referenced by somaria blocks)",
"$26 Collision (near stairs?)",
"$27 Brazier/Fence/Statue/Block/General hookable things",
"$28 North ledge",
"$29 South ledge",
"$2A East ledge",
"$2B West ledge",
"$2C ◤ ledge",
"$2D ◣ ledge",
"$2E ◥ ledge",
"$2F ◢ ledge",
"$30 Straight inter-room stairs south/up 0",
"$31 Straight inter-room stairs south/up 1",
"$32 Straight inter-room stairs south/up 2",
"$33 Straight inter-room stairs south/up 3",
"$34 Straight inter-room stairs north/down 0",
"$35 Straight inter-room stairs north/down 1",
"$36 Straight inter-room stairs north/down 2",
"$37 Straight inter-room stairs north/down 3",
"$38 Straight inter-room stairs north/down edge",
"$39 Straight inter-room stairs south/up edge",
"$3A Star tile (inactive on load)",
"$3B Star tile (active on load)",
"$3C Nothing (unused?)",
"$3D South single-layer auto stairs",
"$3E South layer-swap auto stairs",
"$3F South layer-swap auto stairs",
"$40 Thick grass",
"$41 Nothing (unused?)",
"$42 Gravestone / Tower of hera ledge shadows??",
"$43 Skull Woods entrance/Hera columns???",
"$44 Spike",
"$45 Nothing (unused?)",
"$46 Desert Tablet",
"$47 Nothing (unused?)",
"$48 Diggable ground",
"$49 Nothing (unused?)",
"$4A Diggable ground",
"$4B Warp tile",
"$4C Nothing (unused?) | Something unknown in overworld",
"$4D Nothing (unused?) | Something unknown in overworld",
"$4E Square corners in EP overworld",
"$4F Square corners in EP overworld",
"$50 Green bush",
"$51 Dark bush",
"$52 Gray rock",
"$53 Black rock",
"$54 Hint tile/Sign",
"$55 Big gray rock",
"$56 Big black rock",
"$57 Bonk rocks",
"$58 Chest 0",
"$59 Chest 1",
"$5A Chest 2",
"$5B Chest 3",
"$5C Chest 4",
"$5D Chest 5",
"$5E Spiral stairs",
"$5F Spiral stairs",
"$60 Rupee tile",
"$61 Nothing (unused?)",
"$62 Bombable floor",
"$63 Minigame chest",
"$64 Nothing (unused?)",
"$65 Nothing (unused?)",
"$66 Crystal peg down",
"$67 Crystal peg up",
"$68 Upwards conveyor",
"$69 Downwards conveyor",
"$6A Leftwards conveyor",
"$6B Rightwards conveyor",
"$6C North vines",
"$6D South vines",
"$6E West vines",
"$6F East vines",
"$70 Pot/Hammer peg/Push block 00",
"$71 Pot/Hammer peg/Push block 01",
"$72 Pot/Hammer peg/Push block 02",
"$73 Pot/Hammer peg/Push block 03",
"$74 Pot/Hammer peg/Push block 04",
"$75 Pot/Hammer peg/Push block 05",
"$76 Pot/Hammer peg/Push block 06",
"$77 Pot/Hammer peg/Push block 07",
"$78 Pot/Hammer peg/Push block 08",
"$79 Pot/Hammer peg/Push block 09",
"$7A Pot/Hammer peg/Push block 0A",
"$7B Pot/Hammer peg/Push block 0B",
"$7C Pot/Hammer peg/Push block 0C",
"$7D Pot/Hammer peg/Push block 0D",
"$7E Pot/Hammer peg/Push block 0E",
"$7F Pot/Hammer peg/Push block 0F",
"$80 North/South door",
"$81 East/West door",
"$82 North/South shutter door",
"$83 East/West shutter door",
"$84 North/South layer 2 door",
"$85 East/West layer 2 door",
"$86 North/South layer 2 shutter door",
"$87 East/West layer 2 shutter door",
"$88 Some type of door (?)",
"$89 East/West transport door",
"$8A Some type of door (?)",
"$8B Some type of door (?)",
"$8C Some type of door (?)",
"$8D Some type of door (?)",
"$8E Entrance door",
"$8F Entrance door",
"$90 Layer toggle shutter door (?)",
"$91 Layer toggle shutter door (?)",
"$92 Layer toggle shutter door (?)",
"$93 Layer toggle shutter door (?)",
"$94 Layer toggle shutter door (?)",
"$95 Layer toggle shutter door (?)",
"$96 Layer toggle shutter door (?)",
"$97 Layer toggle shutter door (?)",
"$98 Layer+Dungeon toggle shutter door (?)",
"$99 Layer+Dungeon toggle shutter door (?)",
"$9A Layer+Dungeon toggle shutter door (?)",
"$9B Layer+Dungeon toggle shutter door (?)",
"$9C Layer+Dungeon toggle shutter door (?)",
"$9D Layer+Dungeon toggle shutter door (?)",
"$9E Layer+Dungeon toggle shutter door (?)",
"$9F Layer+Dungeon toggle shutter door (?)",
"$A0 North/South Dungeon swap door",
"$A1 Dungeon toggle door (?)",
"$A2 Dungeon toggle door (?)",
"$A3 Dungeon toggle door (?)",
"$A4 Dungeon toggle door (?)",
"$A5 Dungeon toggle door (?)",
"$A6 Nothing (unused?)",
"$A7 Nothing (unused?)",
"$A8 Layer+Dungeon toggle shutter door (?)",
"$A9 Layer+Dungeon toggle shutter door (?)",
"$AA Layer+Dungeon toggle shutter door (?)",
"$AB Layer+Dungeon toggle shutter door (?)",
"$AC Layer+Dungeon toggle shutter door (?)",
"$AD Layer+Dungeon toggle shutter door (?)",
"$AE Layer+Dungeon toggle shutter door (?)",
"$AF Layer+Dungeon toggle shutter door (?)",
"$B0 Somaria ─",
"$B1 Somaria │",
"$B2 Somaria ┌",
"$B3 Somaria └",
"$B4 Somaria ┐",
"$B5 Somaria ┘",
"$B6 Somaria ⍰ 1 way",
"$B7 Somaria ┬",
"$B8 Somaria ┴",
"$B9 Somaria ├",
"$BA Somaria ┤",
"$BB Somaria ┼",
"$BC Somaria ⍰ 2 way",
"$BD Somaria ┼ crossover",
"$BE Pipe entrance",
"$BF Nothing (unused?)",
"$C0 Torch 00",
"$C1 Torch 01",
"$C2 Torch 02",
"$C3 Torch 03",
"$C4 Torch 04",
"$C5 Torch 05",
"$C6 Torch 06",
"$C7 Torch 07",
"$C8 Torch 08",
"$C9 Torch 09",
"$CA Torch 0A",
"$CB Torch 0B",
"$CC Torch 0C",
"$CD Torch 0D",
"$CE Torch 0E",
"$CF Torch 0F",
"$D0 Nothing (unused?)",
"$D1 Nothing (unused?)",
"$D2 Nothing (unused?)",
"$D3 Nothing (unused?)",
"$D4 Nothing (unused?)",
"$D5 Nothing (unused?)",
"$D6 Nothing (unused?)",
"$D7 Nothing (unused?)",
"$D8 Nothing (unused?)",
"$D9 Nothing (unused?)",
"$DA Nothing (unused?)",
"$DB Nothing (unused?)",
"$DC Nothing (unused?)",
"$DD Nothing (unused?)",
"$DE Nothing (unused?)",
"$DF Nothing (unused?)",
"$E0 Nothing (unused?)",
"$E1 Nothing (unused?)",
"$E2 Nothing (unused?)",
"$E3 Nothing (unused?)",
"$E4 Nothing (unused?)",
"$E5 Nothing (unused?)",
"$E6 Nothing (unused?)",
"$E7 Nothing (unused?)",
"$E8 Nothing (unused?)",
"$E9 Nothing (unused?)",
"$EA Nothing (unused?)",
"$EB Nothing (unused?)",
"$EC Nothing (unused?)",
"$ED Nothing (unused?)",
"$EE Nothing (unused?)",
"$EF Nothing (unused?)",
"$F0 Door 0 bottom",
"$F1 Door 1 bottom",
"$F2 Door 2 bottom",
"$F3 Door 3 bottom",
"$F4 Door X bottom? (unused?)",
"$F5 Door X bottom? (unused?)",
"$F6 Door X bottom? (unused?)",
"$F7 Door X bottom? (unused?)",
"$F8 Door 0 top",
"$F9 Door 1 top",
"$FA Door 2 top",
"$FB Door 3 top",
"$FC Door X top? (unused?)",
"$FD Door X top? (unused?)",
"$FE Door X top? (unused?)",
"$FF Door X top? (unused?)"};
static const std::string kSpriteDefaultNames[]{
"00 Raven",
"01 Vulture",
"02 Flying Stalfos Head",
"03 No Pointer (Empty",
"04 Pull Switch (good",
"05 Pull Switch (unused",
"06 Pull Switch (bad",
"07 Pull Switch (unused",
"08 Octorock (one way",
"09 Moldorm (Boss",
"0A Octorock (four way",
"0B Chicken",
"0C Octorock (?",
"0D Buzzblock",
"0E Snapdragon",
"0F Octoballoon",
"10 Octoballon Hatchlings",
"11 Hinox",
"12 Moblin",
"13 Mini Helmasaure",
"14 Gargoyle's Domain Gate",
"15 Antifairy",
"16 Sahasrahla / Aginah",
"17 Bush Hoarder",
"18 Mini Moldorm",
"19 Poe",
"1A Dwarves",
"1B Arrow in wall",
"1C Statue",
"1D Weathervane",
"1E Crystal Switch",
"1F Bug-Catching Kid",
"20 Sluggula",
"21 Push Switch",
"22 Ropa",
"23 Red Bari",
"24 Blue Bari",
"25 Talking Tree",
"26 Hardhat Beetle",
"27 Deadrock",
"28 Storytellers",
"29 Blind Hideout attendant",
"2A Sweeping Lady",
"2B Storytellers",
"2C Lumberjacks",
"2D Telepathic Stones",
"2E Multipurpose Sprite",
"2F Race Npc",
"30 Person?",
"31 Fortune Teller",
"32 Angry Brothers",
"33 Pull for items",
"34 Scared Girl",
"35 Innkeeper",
"36 Witch",
"37 Waterfall",
"38 Arrow Target",
"39 Average Middle",
"3A Half Magic Bat",
"3B Dash Item",
"3C Village Kid",
"3D Signs? Chicken lady also showed up / Scared ladies outside houses.",
"3E Rock Hoarder",
"3F Tutorial Soldier",
"40 Lightning Lock",
"41 Blue Sword Soldier / Used by guards to detect player",
"42 Green Sword Soldier",
"43 Red Spear Soldier",
"44 Assault Sword Soldier",
"45 Green Spear Soldier",
"46 Blue Archer",
"47 Green Archer",
"48 Red Javelin Soldier",
"49 Red Javelin Soldier 2",
"4A Red Bomb Soldiers",
"4B Green Soldier Recruits",
"4C Geldman",
"4D Rabbit",
"4E Popo",
"4F Popo 2",
"50 Cannon Balls",
"51 Armos",
"52 Giant Zora",
"53 Armos Knights (Boss",
"54 Lanmolas (Boss",
"55 Fireball Zora",
"56 Walking Zora",
"57 Desert Palace Barriers",
"58 Crab",
"59 Bird",
"5A Squirrel",
"5B Spark (Left to Right",
"5C Spark (Right to Left",
"5D Roller (vertical moving",
"5E Roller (vertical moving",
"5F Roller",
"60 Roller (horizontal moving",
"61 Beamos",
"62 Master Sword",
"63 Devalant (Non",
"64 Devalant (Shooter",
"65 Shooting Gallery Proprietor",
"66 Moving Cannon Ball Shooters (Right",
"67 Moving Cannon Ball Shooters (Left",
"68 Moving Cannon Ball Shooters (Down",
"69 Moving Cannon Ball Shooters (Up",
"6A Ball N' Chain Trooper",
"6B Cannon Soldier",
"6C Mirror Portal",
"6D Rat",
"6E Rope",
"6F Keese",
"70 Helmasaur King Fireball",
"71 Leever",
"72 Activator for the ponds (where you throw in items",
"73 Uncle / Priest",
"74 Running Man",
"75 Bottle Salesman",
"76 Princess Zelda",
"77 Antifairy (Alternate",
"78 Village Elder",
"79 Bee",
"7A Agahnim",
"7B Agahnim Energy Ball",
"7C Hyu",
"7D Big Spike Trap",
"7E Guruguru Bar (Clockwise",
"7F Guruguru Bar (Counter Clockwise",
"80 Winder",
"81 Water Tektite",
"82 Antifairy Circle",
"83 Green Eyegore",
"84 Red Eyegore",
"85 Yellow Stalfos",
"86 Kodongos",
"87 Flames",
"88 Mothula (Boss",
"89 Mothula's Beam",
"8A Spike Trap",
"8B Gibdo",
"8C Arrghus (Boss",
"8D Arrghus spawn",
"8E Terrorpin",
"8F Slime",
"90 Wallmaster",
"91 Stalfos Knight",
"92 Helmasaur King",
"93 Bumper",
"94 Swimmers",
"95 Eye Laser (Right",
"96 Eye Laser (Left",
"97 Eye Laser (Down",
"98 Eye Laser (Up",
"99 Pengator",
"9A Kyameron",
"9B Wizzrobe",
"9C Tadpoles",
"9D Tadpoles",
"9E Ostrich (Haunted Grove",
"9F Flute",
"A0 Birds (Haunted Grove",
"A1 Freezor",
"A2 Kholdstare (Boss",
"A3 Kholdstare's Shell",
"A4 Falling Ice",
"A5 Zazak Fireball",
"A6 Red Zazak",
"A7 Stalfos",
"A8 Bomber Flying Creatures from Darkworld",
"A9 Bomber Flying Creatures from Darkworld",
"AA Pikit",
"AB Maiden",
"AC Apple",
"AD Lost Old Man",
"AE Down Pipe",
"AF Up Pipe",
"B0 Right Pip",
"B1 Left Pipe",
"B2 Good bee again?",
"B3 Hylian Inscription",
"B4 Thief?s chest (not the one that follows you",
"B5 Bomb Salesman",
"B6 Kiki",
"B7 Maiden following you in Blind Dungeon",
"B8 Monologue Testing Sprite",
"B9 Feuding Friends on Death Mountain",
"BA Whirlpool",
"BB Salesman / chestgame guy / 300 rupee giver guy / Chest game thief",
"BC Drunk in the inn",
"BD Vitreous (Large Eyeball",
"BE Vitreous (Small Eyeball",
"BF Vitreous' Lightning",
"C0 Monster in Lake of Ill Omen / Quake Medallion",
"C1 Agahnim teleporting Zelda to dark world",
"C2 Boulders",
"C3 Gibo",
"C4 Thief",
"C5 Medusa",
"C6 Four Way Fireball Spitters (spit when you use your sword",
"C7 Hokku",
"C8 Big Fairy who heals you",
"C9 Tektite",
"CA Chain Chomp",
"CB Trinexx",
"CC Another part of trinexx",
"CD Yet another part of trinexx",
"CE Blind The Thief (Boss)",
"CF Swamola",
"D0 Lynel",
"D1 Bunny Beam",
"D2 Flopping fish",
"D3 Stal",
"D4 Landmine",
"D5 Digging Game Proprietor",
"D6 Ganon",
"D7 Copy of Ganon",
"D8 Heart",
"D9 Green Rupee",
"DA Blue Rupee",
"DB Red Rupee",
"DC Bomb Refill (1)",
"DD Bomb Refill (4)",
"DE Bomb Refill (8)",
"DF Small Magic Refill",
"E0 Full Magic Refill",
"E1 Arrow Refill (5)",
"E2 Arrow Refill (10)",
"E3 Fairy",
"E4 Key",
"E5 Big Key",
"E6 Shield",
"E7 Mushroom",
"E8 Fake Master Sword",
"E9 Magic Shop dude / His items",
"EA Heart Container",
"EB Heart Piece",
"EC Bushes",
"ED Cane Of Somaria Platform",
"EE Mantle",
"EF Cane of Somaria Platform (Unused)",
"F0 Cane of Somaria Platform (Unused)",
"F1 Cane of Somaria Platform (Unused)",
"F2 Medallion Tablet",
"F3",
"F4 Falling Rocks",
"F5",
"F6",
"F7",
"F8",
"F9",
"FA",
"FB",
"FC",
"FD",
"FE",
"FF",
};
static const std::string overlordnames[] = {
"Overlord_SpritePositionTarget",
"Overlord_AllDirectionMetalBallFactory",
"Overlord_CascadeMetalBallFactory",
"Overlord_StalfosFactory",
"Overlord_StalfosTrap",
"Overlord_SnakeTrap",
"Overlord_MovingFloor",
"Overlord_ZolFactory",
"Overlord_WallMasterFactory",
"Overlord_CrumbleTilePath 1",
"Overlord_CrumbleTilePath 2",
"Overlord_CrumbleTilePath 3",
"Overlord_CrumbleTilePath 4",
"Overlord_CrumbleTilePath 5",
"Overlord_CrumbleTilePath 6",
"Overlord_PirogusuFactory 1",
"Overlord_PirogusuFactory 2",
"Overlord_PirogusuFactory 3",
"Overlord_PirogusuFactory 4",
"Overlord_FlyingTileFactory",
"Overlord_WizzrobeFactory",
"Overlord_ZoroFactory",
"Overlord_StalfosTrapTriggerWindow",
"Overlord_RedStalfosTrap",
"Overlord_ArmosCoordinator",
"Overlord_BombTrap",
};
} // namespace core
} // namespace app
} // namespace yaze
#endif

View File

@@ -2,582 +2,82 @@
#include <SDL.h> #include <SDL.h>
#include "absl/status/status.h"
#include "app/core/window.h"
#include "app/editor/editor_manager.h"
#include "app/gui/background_renderer.h"
#include "app/gui/theme_manager.h"
#include "imgui/backends/imgui_impl_sdl2.h" #include "imgui/backends/imgui_impl_sdl2.h"
#include "imgui/backends/imgui_impl_sdlrenderer2.h" #include "imgui/backends/imgui_impl_sdlrenderer2.h"
#include "imgui/imgui.h" #include "imgui/imgui.h"
#include "imgui/imgui_internal.h"
#if defined(__APPLE__) && defined(__MACH__)
#include <TargetConditionals.h>
#if TARGET_IPHONE_SIMULATOR == 1
#include "imgui/backends/imgui_impl_metal.h"
#elif TARGET_OS_IPHONE == 1
#include "imgui/backends/imgui_impl_metal.h"
#elif TARGET_OS_MAC == 1
#endif
#endif
#include <memory>
#include "absl/status/status.h"
#include "absl/strings/str_format.h"
#include "app/core/platform/font_loader.h"
#include "app/editor/master_editor.h"
#include "app/gui/icons.h"
#include "app/gui/style.h"
namespace yaze { namespace yaze {
namespace app {
namespace core { namespace core {
namespace {
constexpr ImGuiWindowFlags kMainEditorFlags =
ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse |
ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_MenuBar |
ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoTitleBar;
using ::ImVec2;
using ImGui::Begin;
using ImGui::End;
using ImGui::GetIO;
using ImGui::NewFrame;
using ImGui::SetNextWindowPos;
using ImGui::SetNextWindowSize;
void NewMasterFrame() {
const ImGuiIO &io = GetIO();
ImGui_ImplSDLRenderer2_NewFrame();
ImGui_ImplSDL2_NewFrame();
NewFrame();
SetNextWindowPos(gui::kZeroPos);
ImVec2 dimensions(io.DisplaySize.x, io.DisplaySize.y);
SetNextWindowSize(dimensions, ImGuiCond_Always);
if (!Begin("##YazeMain", nullptr, kMainEditorFlags)) {
End();
return;
}
}
void InitializeKeymap() {
ImGuiIO &io = ImGui::GetIO();
io.KeyMap[ImGuiKey_LeftSuper] = SDL_GetScancodeFromKey(SDLK_LGUI);
io.KeyMap[ImGuiKey_Backspace] = SDL_GetScancodeFromKey(SDLK_BACKSPACE);
io.KeyMap[ImGuiKey_LeftShift] = SDL_GetScancodeFromKey(SDLK_LSHIFT);
io.KeyMap[ImGuiKey_Enter] = SDL_GetScancodeFromKey(SDLK_RETURN);
io.KeyMap[ImGuiKey_UpArrow] = SDL_GetScancodeFromKey(SDLK_UP);
io.KeyMap[ImGuiKey_DownArrow] = SDL_GetScancodeFromKey(SDLK_DOWN);
io.KeyMap[ImGuiKey_LeftArrow] = SDL_GetScancodeFromKey(SDLK_LEFT);
io.KeyMap[ImGuiKey_RightArrow] = SDL_GetScancodeFromKey(SDLK_RIGHT);
io.KeyMap[ImGuiKey_Delete] = SDL_GetScancodeFromKey(SDLK_DELETE);
io.KeyMap[ImGuiKey_Escape] = SDL_GetScancodeFromKey(SDLK_ESCAPE);
io.KeyMap[ImGuiKey_Tab] = SDL_GetScancodeFromKey(SDLK_TAB);
io.KeyMap[ImGuiKey_LeftCtrl] = SDL_GetScancodeFromKey(SDLK_LCTRL);
io.KeyMap[ImGuiKey_PageUp] = SDL_GetScancodeFromKey(SDLK_PAGEUP);
io.KeyMap[ImGuiKey_PageDown] = SDL_GetScancodeFromKey(SDLK_PAGEDOWN);
io.KeyMap[ImGuiKey_Home] = SDL_GetScancodeFromKey(SDLK_HOME);
io.KeyMap[ImGuiKey_Space] = SDL_GetScancodeFromKey(SDLK_SPACE);
io.KeyMap[ImGuiKey_1] = SDL_GetScancodeFromKey(SDLK_1);
io.KeyMap[ImGuiKey_2] = SDL_GetScancodeFromKey(SDLK_2);
io.KeyMap[ImGuiKey_3] = SDL_GetScancodeFromKey(SDLK_3);
io.KeyMap[ImGuiKey_4] = SDL_GetScancodeFromKey(SDLK_4);
io.KeyMap[ImGuiKey_5] = SDL_GetScancodeFromKey(SDLK_5);
io.KeyMap[ImGuiKey_6] = SDL_GetScancodeFromKey(SDLK_6);
io.KeyMap[ImGuiKey_7] = SDL_GetScancodeFromKey(SDLK_7);
io.KeyMap[ImGuiKey_8] = SDL_GetScancodeFromKey(SDLK_8);
io.KeyMap[ImGuiKey_9] = SDL_GetScancodeFromKey(SDLK_9);
io.KeyMap[ImGuiKey_0] = SDL_GetScancodeFromKey(SDLK_0);
io.KeyMap[ImGuiKey_A] = SDL_GetScancodeFromKey(SDLK_a);
io.KeyMap[ImGuiKey_B] = SDL_GetScancodeFromKey(SDLK_b);
io.KeyMap[ImGuiKey_C] = SDL_GetScancodeFromKey(SDLK_c);
io.KeyMap[ImGuiKey_D] = SDL_GetScancodeFromKey(SDLK_d);
io.KeyMap[ImGuiKey_E] = SDL_GetScancodeFromKey(SDLK_e);
io.KeyMap[ImGuiKey_F] = SDL_GetScancodeFromKey(SDLK_f);
io.KeyMap[ImGuiKey_G] = SDL_GetScancodeFromKey(SDLK_g);
io.KeyMap[ImGuiKey_H] = SDL_GetScancodeFromKey(SDLK_h);
io.KeyMap[ImGuiKey_I] = SDL_GetScancodeFromKey(SDLK_i);
io.KeyMap[ImGuiKey_J] = SDL_GetScancodeFromKey(SDLK_j);
io.KeyMap[ImGuiKey_K] = SDL_GetScancodeFromKey(SDLK_k);
io.KeyMap[ImGuiKey_L] = SDL_GetScancodeFromKey(SDLK_l);
io.KeyMap[ImGuiKey_M] = SDL_GetScancodeFromKey(SDLK_m);
io.KeyMap[ImGuiKey_N] = SDL_GetScancodeFromKey(SDLK_n);
io.KeyMap[ImGuiKey_O] = SDL_GetScancodeFromKey(SDLK_o);
io.KeyMap[ImGuiKey_P] = SDL_GetScancodeFromKey(SDLK_p);
io.KeyMap[ImGuiKey_Q] = SDL_GetScancodeFromKey(SDLK_q);
io.KeyMap[ImGuiKey_R] = SDL_GetScancodeFromKey(SDLK_r);
io.KeyMap[ImGuiKey_S] = SDL_GetScancodeFromKey(SDLK_s);
io.KeyMap[ImGuiKey_T] = SDL_GetScancodeFromKey(SDLK_t);
io.KeyMap[ImGuiKey_U] = SDL_GetScancodeFromKey(SDLK_u);
io.KeyMap[ImGuiKey_V] = SDL_GetScancodeFromKey(SDLK_v);
io.KeyMap[ImGuiKey_W] = SDL_GetScancodeFromKey(SDLK_w);
io.KeyMap[ImGuiKey_X] = SDL_GetScancodeFromKey(SDLK_x);
io.KeyMap[ImGuiKey_Y] = SDL_GetScancodeFromKey(SDLK_y);
io.KeyMap[ImGuiKey_Z] = SDL_GetScancodeFromKey(SDLK_z);
io.KeyMap[ImGuiKey_F1] = SDL_GetScancodeFromKey(SDLK_F1);
io.KeyMap[ImGuiKey_F2] = SDL_GetScancodeFromKey(SDLK_F2);
io.KeyMap[ImGuiKey_F3] = SDL_GetScancodeFromKey(SDLK_F3);
io.KeyMap[ImGuiKey_F4] = SDL_GetScancodeFromKey(SDLK_F4);
io.KeyMap[ImGuiKey_F5] = SDL_GetScancodeFromKey(SDLK_F5);
io.KeyMap[ImGuiKey_F6] = SDL_GetScancodeFromKey(SDLK_F6);
io.KeyMap[ImGuiKey_F7] = SDL_GetScancodeFromKey(SDLK_F7);
io.KeyMap[ImGuiKey_F8] = SDL_GetScancodeFromKey(SDLK_F8);
io.KeyMap[ImGuiKey_F9] = SDL_GetScancodeFromKey(SDLK_F9);
io.KeyMap[ImGuiKey_F10] = SDL_GetScancodeFromKey(SDLK_F10);
io.KeyMap[ImGuiKey_F11] = SDL_GetScancodeFromKey(SDLK_F11);
io.KeyMap[ImGuiKey_F12] = SDL_GetScancodeFromKey(SDLK_F12);
}
void ImGui_ImplSDL2_SetClipboardText(void *user_data, const char *text) {
SDL_SetClipboardText(text);
}
const char *ImGui_ImplSDL2_GetClipboardText(void *user_data) {
return SDL_GetClipboardText();
}
void InitializeClipboard() {
ImGuiIO &io = ImGui::GetIO();
io.SetClipboardTextFn = ImGui_ImplSDL2_SetClipboardText;
io.GetClipboardTextFn = ImGui_ImplSDL2_GetClipboardText;
io.ClipboardUserData = nullptr;
}
void HandleKeyDown(SDL_Event &event, editor::MasterEditor &editor) {
ImGuiIO &io = ImGui::GetIO();
io.KeysDown[event.key.keysym.scancode] = (event.type == SDL_KEYDOWN);
io.KeyShift = ((SDL_GetModState() & KMOD_SHIFT) != 0);
io.KeyCtrl = ((SDL_GetModState() & KMOD_CTRL) != 0);
io.KeyAlt = ((SDL_GetModState() & KMOD_ALT) != 0);
io.KeySuper = ((SDL_GetModState() & KMOD_GUI) != 0);
switch (event.key.keysym.sym) {
case SDLK_BACKSPACE:
case SDLK_LSHIFT:
case SDLK_LCTRL:
case SDLK_TAB:
io.KeysDown[event.key.keysym.scancode] = (event.type == SDL_KEYDOWN);
break;
case SDLK_z:
editor.emulator().snes().SetButtonState(1, 0, true);
break;
case SDLK_a:
editor.emulator().snes().SetButtonState(1, 1, true);
break;
case SDLK_RSHIFT:
editor.emulator().snes().SetButtonState(1, 2, true);
break;
case SDLK_RETURN:
editor.emulator().snes().SetButtonState(1, 3, true);
break;
case SDLK_UP:
editor.emulator().snes().SetButtonState(1, 4, true);
break;
case SDLK_DOWN:
editor.emulator().snes().SetButtonState(1, 5, true);
break;
case SDLK_LEFT:
editor.emulator().snes().SetButtonState(1, 6, true);
break;
case SDLK_RIGHT:
editor.emulator().snes().SetButtonState(1, 7, true);
break;
case SDLK_x:
editor.emulator().snes().SetButtonState(1, 8, true);
break;
case SDLK_s:
editor.emulator().snes().SetButtonState(1, 9, true);
break;
case SDLK_d:
editor.emulator().snes().SetButtonState(1, 10, true);
break;
case SDLK_c:
editor.emulator().snes().SetButtonState(1, 11, true);
break;
default:
break;
}
}
void HandleKeyUp(SDL_Event &event, editor::MasterEditor &editor) {
ImGuiIO &io = ImGui::GetIO();
int key = event.key.keysym.scancode;
IM_ASSERT(key >= 0 && key < IM_ARRAYSIZE(io.KeysDown));
io.KeysDown[key] = (event.type == SDL_KEYDOWN);
io.KeyShift = ((SDL_GetModState() & KMOD_SHIFT) != 0);
io.KeyCtrl = ((SDL_GetModState() & KMOD_CTRL) != 0);
io.KeyAlt = ((SDL_GetModState() & KMOD_ALT) != 0);
io.KeySuper = ((SDL_GetModState() & KMOD_GUI) != 0);
switch (event.key.keysym.sym) {
case SDLK_z:
editor.emulator().snes().SetButtonState(1, 0, false);
break;
case SDLK_a:
editor.emulator().snes().SetButtonState(1, 1, false);
break;
case SDLK_RSHIFT:
editor.emulator().snes().SetButtonState(1, 2, false);
break;
case SDLK_RETURN:
editor.emulator().snes().SetButtonState(1, 3, false);
break;
case SDLK_UP:
editor.emulator().snes().SetButtonState(1, 4, false);
break;
case SDLK_DOWN:
editor.emulator().snes().SetButtonState(1, 5, false);
break;
case SDLK_LEFT:
editor.emulator().snes().SetButtonState(1, 6, false);
break;
case SDLK_RIGHT:
editor.emulator().snes().SetButtonState(1, 7, false);
break;
case SDLK_x:
editor.emulator().snes().SetButtonState(1, 8, false);
break;
case SDLK_s:
editor.emulator().snes().SetButtonState(1, 9, false);
break;
case SDLK_d:
editor.emulator().snes().SetButtonState(1, 10, false);
break;
case SDLK_c:
editor.emulator().snes().SetButtonState(1, 11, false);
break;
default:
break;
}
}
void ChangeWindowSizeEvent(SDL_Event &event) {
ImGuiIO &io = ImGui::GetIO();
io.DisplaySize.x = static_cast<float>(event.window.data1);
io.DisplaySize.y = static_cast<float>(event.window.data2);
}
void HandleMouseMovement(int &wheel) {
ImGuiIO &io = ImGui::GetIO();
int mouseX;
int mouseY;
const int buttons = SDL_GetMouseState(&mouseX, &mouseY);
io.DeltaTime = 1.0f / 60.0f;
io.MousePos = ImVec2(static_cast<float>(mouseX), static_cast<float>(mouseY));
io.MouseDown[0] = buttons & SDL_BUTTON(SDL_BUTTON_LEFT);
io.MouseDown[1] = buttons & SDL_BUTTON(SDL_BUTTON_RIGHT);
io.MouseDown[2] = buttons & SDL_BUTTON(SDL_BUTTON_MIDDLE);
io.MouseWheel = static_cast<float>(wheel);
}
} // namespace
absl::Status Controller::OnEntry(std::string filename) { absl::Status Controller::OnEntry(std::string filename) {
#if defined(__APPLE__) && defined(__MACH__) RETURN_IF_ERROR(CreateWindow(window_, SDL_WINDOW_RESIZABLE));
#if TARGET_IPHONE_SIMULATOR == 1 editor_manager_.emulator().set_audio_buffer(window_.audio_buffer_.get());
/* iOS in Xcode simulator */ editor_manager_.emulator().set_audio_device_id(window_.audio_device_);
platform_ = Platform::kiOS; editor_manager_.Initialize(filename);
#elif TARGET_OS_IPHONE == 1
/* iOS */
platform_ = Platform::kiOS;
#elif TARGET_OS_MAC == 1
/* macOS */
platform_ = Platform::kMacOS;
#endif
#elif defined(_WIN32)
platform_ = Platform::kWindows;
#elif defined(__linux__)
platform_ = Platform::kLinux;
#else
platform_ = Platform::kUnknown;
#endif
RETURN_IF_ERROR(CreateSDL_Window())
RETURN_IF_ERROR(CreateRenderer())
RETURN_IF_ERROR(CreateGuiContext())
if (flags()->kLoadAudioDevice) {
RETURN_IF_ERROR(LoadAudioDevice())
master_editor_.emulator().set_audio_buffer(audio_buffer_);
master_editor_.emulator().set_audio_device_id(audio_device_);
}
InitializeKeymap();
master_editor_.SetupScreen(renderer_, filename);
active_ = true; active_ = true;
return absl::OkStatus(); return absl::OkStatus();
} }
void Controller::OnInput() { void Controller::OnInput() {
int wheel = 0; PRINT_IF_ERROR(HandleEvents(window_));
SDL_Event event;
ImGuiIO &io = ImGui::GetIO();
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_KEYDOWN:
HandleKeyDown(event, master_editor_);
break;
case SDL_KEYUP:
HandleKeyUp(event, master_editor_);
break;
case SDL_TEXTINPUT:
io.AddInputCharactersUTF8(event.text.text);
break;
case SDL_MOUSEWHEEL:
wheel = event.wheel.y;
break;
case SDL_WINDOWEVENT:
switch (event.window.event) {
case SDL_WINDOWEVENT_CLOSE:
CloseWindow();
break;
case SDL_WINDOWEVENT_SIZE_CHANGED:
ChangeWindowSizeEvent(event);
break;
default:
break;
}
break;
default:
break;
}
}
HandleMouseMovement(wheel);
} }
absl::Status Controller::OnLoad() { absl::Status Controller::OnLoad() {
if (master_editor_.quit()) { if (editor_manager_.quit() || !window_.active_) {
active_ = false; active_ = false;
return absl::OkStatus();
} }
NewMasterFrame();
RETURN_IF_ERROR(master_editor_.Update()); #if TARGET_OS_IPHONE != 1
ImGui_ImplSDLRenderer2_NewFrame();
ImGui_ImplSDL2_NewFrame();
ImGui::NewFrame();
const ImGuiViewport *viewport = ImGui::GetMainViewport();
ImGui::SetNextWindowPos(viewport->WorkPos);
ImGui::SetNextWindowSize(viewport->WorkSize);
ImGui::SetNextWindowViewport(viewport->ID);
ImGuiWindowFlags window_flags =
ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking;
window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse |
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove;
window_flags |=
ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
ImGui::Begin("DockSpaceWindow", nullptr, window_flags);
ImGui::PopStyleVar(3);
// Create DockSpace first
ImGuiID dockspace_id = ImGui::GetID("MyDockSpace");
gui::DockSpaceRenderer::BeginEnhancedDockSpace(dockspace_id, ImVec2(0.0f, 0.0f),
ImGuiDockNodeFlags_PassthruCentralNode);
editor_manager_.DrawMenuBar(); // Draw the fixed menu bar at the top
ImGui::End();
#endif
RETURN_IF_ERROR(editor_manager_.Update());
return absl::OkStatus(); return absl::OkStatus();
} }
void Controller::DoRender() const { void Controller::DoRender() const {
ImGui::Render(); ImGui::Render();
SDL_RenderClear(renderer_.get()); SDL_RenderClear(Renderer::Get().renderer());
ImGui_ImplSDLRenderer2_RenderDrawData(ImGui::GetDrawData(), renderer_.get()); ImGui_ImplSDLRenderer2_RenderDrawData(ImGui::GetDrawData(),
SDL_RenderPresent(renderer_.get()); Renderer::Get().renderer());
SDL_RenderPresent(Renderer::Get().renderer());
} }
void Controller::OnExit() { void Controller::OnExit() { PRINT_IF_ERROR(ShutdownWindow(window_)); }
ImGui::DestroyContext();
if (flags()->kLoadAudioDevice) {
SDL_PauseAudioDevice(audio_device_, 1);
SDL_CloseAudioDevice(audio_device_);
delete audio_buffer_;
}
switch (platform_) {
case Platform::kMacOS:
case Platform::kWindows:
case Platform::kLinux:
ImGui_ImplSDLRenderer2_Shutdown();
ImGui_ImplSDL2_Shutdown();
break;
case Platform::kiOS:
// Deferred
break;
default:
break;
}
ImGui::DestroyContext();
SDL_Quit();
}
absl::Status Controller::CreateSDL_Window() {
auto sdl_flags = SDL_INIT_VIDEO | SDL_INIT_TIMER;
if (flags()->kUseNewImGuiInput) {
sdl_flags |= SDL_INIT_GAMECONTROLLER;
}
if (flags()->kLoadAudioDevice) {
sdl_flags |= SDL_INIT_AUDIO;
}
if (SDL_Init(sdl_flags) != 0) {
return absl::InternalError(
absl::StrFormat("SDL_Init: %s\n", SDL_GetError()));
} else {
SDL_DisplayMode displayMode;
SDL_GetCurrentDisplayMode(0, &displayMode);
int screenWidth = displayMode.w * 0.8;
int screenHeight = displayMode.h * 0.8;
window_ = std::unique_ptr<SDL_Window, sdl_deleter>(
SDL_CreateWindow("Yet Another Zelda3 Editor", // window title
SDL_WINDOWPOS_UNDEFINED, // initial x position
SDL_WINDOWPOS_UNDEFINED, // initial y position
screenWidth, // width, in pixels
screenHeight, // height, in pixels
SDL_WINDOW_RESIZABLE),
sdl_deleter());
if (window_ == nullptr) {
return absl::InternalError(
absl::StrFormat("SDL_CreateWindow: %s\n", SDL_GetError()));
}
}
return absl::OkStatus();
}
absl::Status Controller::CreateRenderer() {
renderer_ = std::unique_ptr<SDL_Renderer, sdl_deleter>(
SDL_CreateRenderer(window_.get(), -1,
SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC),
sdl_deleter());
if (renderer_ == nullptr) {
return absl::InternalError(
absl::StrFormat("SDL_CreateRenderer: %s\n", SDL_GetError()));
} else {
SDL_SetRenderDrawBlendMode(renderer_.get(), SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawColor(renderer_.get(), 0x00, 0x00, 0x00, 0x00);
}
return absl::OkStatus();
}
absl::Status Controller::CreateGuiContext() {
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO &io = ImGui::GetIO();
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
if (flags()->kUseNewImGuiInput) {
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
}
// Initialize ImGui for SDL
ImGui_ImplSDL2_InitForSDLRenderer(window_.get(), renderer_.get());
ImGui_ImplSDLRenderer2_Init(renderer_.get());
if (flags()->kLoadSystemFonts) {
LoadSystemFonts();
} else {
RETURN_IF_ERROR(LoadFontFamilies());
}
// Set the default style
gui::ColorsYaze();
// Build a new ImGui frame
ImGui_ImplSDLRenderer2_NewFrame();
ImGui_ImplSDL2_NewFrame();
return absl::OkStatus();
}
absl::Status Controller::LoadFontFamilies() const {
ImGuiIO &io = ImGui::GetIO();
const char *font_path = "assets/font/";
static const char *KARLA_REGULAR = "Karla-Regular.ttf";
static const char *ROBOTO_MEDIUM = "Roboto-Medium.ttf";
static const char *COUSINE_REGULAR = "Cousine-Regular.ttf";
static const char *DROID_SANS = "DroidSans.ttf";
static const char *NOTO_SANS_JP = "NotoSansJP.ttf";
static const char *IBM_PLEX_JP = "IBMPlexSansJP-Bold.ttf";
static const float FONT_SIZE_DEFAULT = 14.0f;
static const float FONT_SIZE_DROID_SANS = 16.0f;
static const float ICON_FONT_SIZE = 18.0f;
// Icon configuration
static const ImWchar icons_ranges[] = {ICON_MIN_MD, 0xf900, 0};
ImFontConfig icons_config;
icons_config.MergeMode = true;
icons_config.GlyphOffset.y = 5.0f;
icons_config.GlyphMinAdvanceX = 13.0f;
icons_config.PixelSnapH = true;
// Japanese font configuration
ImFontConfig japanese_font_config;
japanese_font_config.MergeMode = true;
icons_config.GlyphOffset.y = 5.0f;
icons_config.GlyphMinAdvanceX = 13.0f;
icons_config.PixelSnapH = true;
// List of fonts to be loaded
std::vector<const char *> font_paths = {KARLA_REGULAR, ROBOTO_MEDIUM,
COUSINE_REGULAR, IBM_PLEX_JP};
// Load fonts with associated icon and Japanese merges
for (const auto &font_path : font_paths) {
float font_size =
(font_path == DROID_SANS) ? FONT_SIZE_DROID_SANS : FONT_SIZE_DEFAULT;
std::string actual_font_path;
#ifdef __APPLE__
#if TARGET_OS_IOS == 1
const std::string kBundlePath = GetBundleResourcePath();
actual_font_path = kBundlePath + font_path;
#else
actual_font_path = std::filesystem::absolute(font_path).string();
#endif
#else
actual_font_path = font_path;
#endif
if (!io.Fonts->AddFontFromFileTTF(actual_font_path.data(), font_size)) {
return absl::InternalError(
absl::StrFormat("Failed to load font from %s", actual_font_path));
}
// Merge icon set
std::string actual_icon_font_path = "";
const char *icon_font_path = FONT_ICON_FILE_NAME_MD;
#if defined(__APPLE__) && defined(__MACH__)
#if TARGET_OS_IOS == 1
const std::string kIconBundlePath = GetBundleResourcePath();
actual_icon_font_path = kIconBundlePath + "MaterialIcons-Regular.ttf";
#else
actual_icon_font_path = std::filesystem::absolute(icon_font_path).string();
#endif
#else
#endif
io.Fonts->AddFontFromFileTTF(actual_icon_font_path.data(), ICON_FONT_SIZE,
&icons_config, icons_ranges);
// Merge Japanese font
std::string actual_japanese_font_path = "";
const char *japanese_font_path = NOTO_SANS_JP;
#if defined(__APPLE__) && defined(__MACH__)
#if TARGET_OS_IOS == 1
const std::string kJapaneseBundlePath = GetBundleResourcePath();
actual_japanese_font_path = kJapaneseBundlePath + japanese_font_path;
#else
actual_japanese_font_path =
std::filesystem::absolute(japanese_font_path).string();
#endif
#else
#endif
io.Fonts->AddFontFromFileTTF(actual_japanese_font_path.data(), 18.0f,
&japanese_font_config,
io.Fonts->GetGlyphRangesJapanese());
}
return absl::OkStatus();
}
absl::Status Controller::LoadAudioDevice() {
SDL_AudioSpec want, have;
SDL_memset(&want, 0, sizeof(want));
want.freq = audio_frequency_;
want.format = AUDIO_S16;
want.channels = 2;
want.samples = 2048;
want.callback = NULL; // Uses the queue
audio_device_ = SDL_OpenAudioDevice(NULL, 0, &want, &have, 0);
if (audio_device_ == 0) {
return absl::InternalError(
absl::StrFormat("Failed to open audio: %s\n", SDL_GetError()));
}
audio_buffer_ = new int16_t[audio_frequency_ / 50 * 4];
master_editor_.emulator().set_audio_buffer(audio_buffer_);
SDL_PauseAudioDevice(audio_device_, 0);
return absl::OkStatus();
}
} // namespace core } // namespace core
} // namespace app
} // namespace yaze } // namespace yaze

View File

@@ -2,36 +2,25 @@
#define YAZE_APP_CORE_CONTROLLER_H #define YAZE_APP_CORE_CONTROLLER_H
#include <SDL.h> #include <SDL.h>
#include "imgui/backends/imgui_impl_sdl2.h"
#include "imgui/backends/imgui_impl_sdlrenderer2.h"
#include "imgui/imconfig.h"
#include "imgui/imgui.h"
#include "imgui/imgui_internal.h"
#include <memory> #include <memory>
#include "absl/status/status.h" #include "absl/status/status.h"
#include "app/core/common.h" #include "app/core/window.h"
#include "app/editor/master_editor.h" #include "app/editor/editor_manager.h"
#include "app/editor/utils/editor.h"
#include "app/gui/icons.h"
#include "app/gui/style.h"
int main(int argc, char **argv); int main(int argc, char **argv);
namespace yaze { namespace yaze {
namespace app {
namespace core { namespace core {
enum class Platform { kUnknown, kMacOS, kiOS, kWindows, kLinux };
/** /**
* @brief Main controller for the application. * @brief Main controller for the application.
* *
* This class is responsible for managing the main window and the * This class is responsible for managing the main window and the
* main editor. It is the main entry point for the application. * main editor. It is the main entry point for the application.
*/ */
class Controller : public ExperimentFlags { class Controller {
public: public:
bool IsActive() const { return active_; } bool IsActive() const { return active_; }
absl::Status OnEntry(std::string filename = ""); absl::Status OnEntry(std::string filename = "");
@@ -40,46 +29,19 @@ class Controller : public ExperimentFlags {
void DoRender() const; void DoRender() const;
void OnExit(); void OnExit();
absl::Status CreateSDL_Window(); auto window() -> SDL_Window * { return window_.window_.get(); }
absl::Status CreateRenderer(); void set_active(bool active) { active_ = active; }
absl::Status CreateGuiContext(); auto active() const { return active_; }
absl::Status LoadFontFamilies() const;
absl::Status LoadAudioDevice();
auto master_editor() -> editor::MasterEditor & { return master_editor_; }
private: private:
struct sdl_deleter {
void operator()(SDL_Window *p) const {
if (p) {
SDL_DestroyWindow(p);
}
}
void operator()(SDL_Renderer *p) const {
if (p) {
SDL_DestroyRenderer(p);
}
}
void operator()(SDL_Texture *p) const { SDL_DestroyTexture(p); }
};
void CloseWindow() { active_ = false; }
friend int ::main(int argc, char **argv); friend int ::main(int argc, char **argv);
bool active_; bool active_ = false;
Platform platform_; core::Window window_;
editor::MasterEditor master_editor_; editor::EditorManager editor_manager_;
int audio_frequency_ = 48000;
int16_t *audio_buffer_;
SDL_AudioDeviceID audio_device_;
std::shared_ptr<SDL_Window> window_;
std::shared_ptr<SDL_Renderer> renderer_;
}; };
} // namespace core } // namespace core
} // namespace app
} // namespace yaze } // namespace yaze
#endif // YAZE_APP_CORE_CONTROLLER_H #endif // YAZE_APP_CORE_CONTROLLER_H

33
src/app/core/core.cmake Normal file
View File

@@ -0,0 +1,33 @@
set(
YAZE_APP_CORE_SRC
app/core/controller.cc
app/emu/emulator.cc
app/core/project.cc
app/core/window.cc
app/core/asar_wrapper.cc
)
if (WIN32 OR MINGW OR UNIX AND NOT APPLE)
list(APPEND YAZE_APP_CORE_SRC
app/core/platform/font_loader.cc
app/core/platform/clipboard.cc
app/core/platform/file_dialog.cc
)
endif()
if(APPLE)
list(APPEND YAZE_APP_CORE_SRC
app/core/platform/file_dialog.cc
app/core/platform/file_dialog.mm
app/core/platform/app_delegate.mm
app/core/platform/font_loader.cc
app/core/platform/font_loader.mm
app/core/platform/clipboard.mm
)
find_library(COCOA_LIBRARY Cocoa)
if(NOT COCOA_LIBRARY)
message(FATAL_ERROR "Cocoa not found")
endif()
set(CMAKE_EXE_LINKER_FLAGS "-framework ServiceManagement -framework Foundation -framework Cocoa")
endif()

176
src/app/core/features.h Normal file
View File

@@ -0,0 +1,176 @@
#ifndef YAZE_APP_CORE_FEATURES_H
#define YAZE_APP_CORE_FEATURES_H
#include <string>
#include "imgui/imgui.h"
namespace yaze {
namespace core {
/**
* @class FeatureFlags
* @brief A class to manage experimental feature flags.
*/
class FeatureFlags {
public:
struct Flags {
// Log instructions to the GUI debugger.
bool kLogInstructions = true;
// Flag to enable the saving of all palettes to the Rom.
bool kSaveAllPalettes = false;
// Flag to enable the saving of gfx groups to the rom.
bool kSaveGfxGroups = false;
// Flag to enable the change queue, which could have any anonymous
// save routine for the Rom. In practice, just the overworld tilemap
// and tile32 save.
bool kSaveWithChangeQueue = false;
// Save dungeon map edits to the Rom.
bool kSaveDungeonMaps = false;
// Save graphics sheet to the Rom.
bool kSaveGraphicsSheet = false;
// Log to the console.
bool kLogToConsole = false;
// Use NFD (Native File Dialog) instead of bespoke file dialog implementation.
#if defined(YAZE_ENABLE_NFD) && YAZE_ENABLE_NFD
bool kUseNativeFileDialog = true;
#else
bool kUseNativeFileDialog = false;
#endif
// Overworld flags
struct Overworld {
// Load and render overworld sprites to the screen. Unstable.
bool kDrawOverworldSprites = false;
// Save overworld map edits to the Rom.
bool kSaveOverworldMaps = true;
// Save overworld entrances to the Rom.
bool kSaveOverworldEntrances = true;
// Save overworld exits to the Rom.
bool kSaveOverworldExits = true;
// Save overworld items to the Rom.
bool kSaveOverworldItems = true;
// Save overworld properties to the Rom.
bool kSaveOverworldProperties = true;
// Enable custom overworld features for vanilla ROMs or override detection.
// If ZSCustomOverworld ASM is already applied, features are auto-enabled.
bool kLoadCustomOverworld = false;
// Apply ZSCustomOverworld ASM patches when upgrading ROM versions.
bool kApplyZSCustomOverworldASM = false;
} overworld;
};
static Flags &get() {
static Flags instance;
return instance;
}
std::string Serialize() const {
std::string result;
result +=
"kLogInstructions: " + std::to_string(get().kLogInstructions) + "\n";
result +=
"kSaveAllPalettes: " + std::to_string(get().kSaveAllPalettes) + "\n";
result += "kSaveGfxGroups: " + std::to_string(get().kSaveGfxGroups) + "\n";
result +=
"kSaveWithChangeQueue: " + std::to_string(get().kSaveWithChangeQueue) +
"\n";
result +=
"kSaveDungeonMaps: " + std::to_string(get().kSaveDungeonMaps) + "\n";
result += "kLogToConsole: " + std::to_string(get().kLogToConsole) + "\n";
result += "kDrawOverworldSprites: " +
std::to_string(get().overworld.kDrawOverworldSprites) + "\n";
result += "kSaveOverworldMaps: " +
std::to_string(get().overworld.kSaveOverworldMaps) + "\n";
result += "kSaveOverworldEntrances: " +
std::to_string(get().overworld.kSaveOverworldEntrances) + "\n";
result += "kSaveOverworldExits: " +
std::to_string(get().overworld.kSaveOverworldExits) + "\n";
result += "kSaveOverworldItems: " +
std::to_string(get().overworld.kSaveOverworldItems) + "\n";
result += "kSaveOverworldProperties: " +
std::to_string(get().overworld.kSaveOverworldProperties) + "\n";
result += "kLoadCustomOverworld: " +
std::to_string(get().overworld.kLoadCustomOverworld) + "\n";
result += "kApplyZSCustomOverworldASM: " +
std::to_string(get().overworld.kApplyZSCustomOverworldASM) + "\n";
result += "kUseNativeFileDialog: " +
std::to_string(get().kUseNativeFileDialog) + "\n";
return result;
}
};
using ImGui::BeginMenu;
using ImGui::Checkbox;
using ImGui::EndMenu;
using ImGui::MenuItem;
using ImGui::Separator;
struct FlagsMenu {
void DrawOverworldFlags() {
Checkbox("Enable Overworld Sprites",
&FeatureFlags::get().overworld.kDrawOverworldSprites);
Separator();
Checkbox("Save Overworld Maps",
&FeatureFlags::get().overworld.kSaveOverworldMaps);
Checkbox("Save Overworld Entrances",
&FeatureFlags::get().overworld.kSaveOverworldEntrances);
Checkbox("Save Overworld Exits",
&FeatureFlags::get().overworld.kSaveOverworldExits);
Checkbox("Save Overworld Items",
&FeatureFlags::get().overworld.kSaveOverworldItems);
Checkbox("Save Overworld Properties",
&FeatureFlags::get().overworld.kSaveOverworldProperties);
Checkbox("Enable Custom Overworld Features",
&FeatureFlags::get().overworld.kLoadCustomOverworld);
ImGui::SameLine();
if (ImGui::Button("?")) {
ImGui::OpenPopup("CustomOverworldHelp");
}
if (ImGui::BeginPopup("CustomOverworldHelp")) {
ImGui::Text("This flag enables ZSCustomOverworld features.");
ImGui::Text("If ZSCustomOverworld ASM is already applied to the ROM,");
ImGui::Text("features are auto-enabled regardless of this flag.");
ImGui::Text("For vanilla ROMs, enable this to use custom features.");
ImGui::EndPopup();
}
Checkbox("Apply ZSCustomOverworld ASM",
&FeatureFlags::get().overworld.kApplyZSCustomOverworldASM);
}
void DrawDungeonFlags() {
Checkbox("Save Dungeon Maps", &FeatureFlags::get().kSaveDungeonMaps);
}
void DrawResourceFlags() {
Checkbox("Save All Palettes", &FeatureFlags::get().kSaveAllPalettes);
Checkbox("Save Gfx Groups", &FeatureFlags::get().kSaveGfxGroups);
Checkbox("Save Graphics Sheets", &FeatureFlags::get().kSaveGraphicsSheet);
}
void DrawSystemFlags() {
Checkbox("Enable Console Logging", &FeatureFlags::get().kLogToConsole);
Checkbox("Log Instructions to Emulator Debugger",
&FeatureFlags::get().kLogInstructions);
Checkbox("Use Native File Dialog (NFD)", &FeatureFlags::get().kUseNativeFileDialog);
}
};
} // namespace core
} // namespace yaze
#endif // YAZE_APP_CORE_FEATURES_H

View File

@@ -1,141 +0,0 @@
#include "app/core/labeling.h"
#include "imgui/imgui.h"
#include "imgui/misc/cpp/imgui_stdlib.h"
#include <cstdint>
#include <fstream>
#include <sstream>
#include <string>
#include <unordered_map>
#include <vector>
#include "app/core/common.h"
#include "app/core/constants.h"
#include "app/gui/icons.h"
namespace yaze {
namespace app {
namespace core {
bool ResourceLabelManager::LoadLabels(const std::string& filename) {
std::ifstream file(filename);
if (!file.is_open()) {
// Create the file if it does not exist
std::ofstream create_file(filename);
if (!create_file.is_open()) {
return false;
}
create_file.close();
file.open(filename);
if (!file.is_open()) {
return false;
}
}
filename_ = filename;
std::string line;
while (std::getline(file, line)) {
std::istringstream iss(line);
std::string type, key, value;
if (std::getline(iss, type, ',') && std::getline(iss, key, ',') &&
std::getline(iss, value)) {
labels_[type][key] = value;
}
}
labels_loaded_ = true;
return true;
}
bool ResourceLabelManager::SaveLabels() {
if (!labels_loaded_) {
return false;
}
std::ofstream file(filename_);
if (!file.is_open()) {
return false;
}
for (const auto& type_pair : labels_) {
for (const auto& label_pair : type_pair.second) {
file << type_pair.first << "," << label_pair.first << ","
<< label_pair.second << std::endl;
}
}
file.close();
return true;
}
void ResourceLabelManager::DisplayLabels(bool* p_open) {
if (!labels_loaded_) {
ImGui::Text("No labels loaded.");
return;
}
if (ImGui::Begin("Resource Labels", p_open)) {
for (const auto& type_pair : labels_) {
if (ImGui::TreeNode(type_pair.first.c_str())) {
for (const auto& label_pair : type_pair.second) {
std::string label_id = type_pair.first + "_" + label_pair.first;
ImGui::Text("%s: %s", label_pair.first.c_str(),
label_pair.second.c_str());
}
ImGui::TreePop();
}
}
if (ImGui::Button("Update Labels")) {
if (SaveLabels()) {
ImGui::Text("Labels updated successfully!");
} else {
ImGui::Text("Failed to update labels.");
}
}
}
ImGui::End();
}
void ResourceLabelManager::EditLabel(const std::string& type,
const std::string& key,
const std::string& newValue) {
labels_[type][key] = newValue;
}
void ResourceLabelManager::SelectableLabelWithNameEdit(
bool selected, const std::string& type, const std::string& key,
const std::string& defaultValue) {
std::string label = CreateOrGetLabel(type, key, defaultValue);
ImGui::Selectable(label.c_str(), selected,
ImGuiSelectableFlags_AllowDoubleClick);
std::string label_id = type + "_" + key;
if (ImGui::IsItemHovered() && ImGui::IsMouseClicked(ImGuiMouseButton_Right)) {
ImGui::OpenPopup(label_id.c_str());
}
if (ImGui::BeginPopupContextItem(label_id.c_str())) {
std::string* new_label = &labels_[type][key];
if (ImGui::InputText("##Label", new_label,
ImGuiInputTextFlags_EnterReturnsTrue)) {
labels_[type][key] = *new_label;
}
if (ImGui::Button(ICON_MD_CLOSE)) {
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
}
std::string ResourceLabelManager::CreateOrGetLabel(
const std::string& type, const std::string& key,
const std::string& defaultValue) {
if (labels_.find(type) == labels_.end()) {
labels_[type] = std::unordered_map<std::string, std::string>();
}
if (labels_[type].find(key) == labels_[type].end()) {
labels_[type][key] = defaultValue;
}
return labels_[type][key];
}
} // namespace core
} // namespace app
} // namespace yaze

View File

@@ -1,53 +0,0 @@
#ifndef YAZE_APP_CORE_LABELING_H_
#define YAZE_APP_CORE_LABELING_H_
#include <cstdint>
#include <fstream>
#include <sstream>
#include <string>
#include <unordered_map>
#include <vector>
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "app/core/common.h"
#include "app/core/constants.h"
namespace yaze {
namespace app {
namespace core {
// Default types
static constexpr absl::string_view kDefaultTypes[] = {
"Dungeon Names", "Dungeon Room Names", "Overworld Map Names"};
struct ResourceLabelManager {
bool LoadLabels(const std::string& filename);
bool SaveLabels();
void DisplayLabels(bool* p_open);
void EditLabel(const std::string& type, const std::string& key,
const std::string& newValue);
void SelectableLabelWithNameEdit(bool selected, const std::string& type,
const std::string& key,
const std::string& defaultValue);
std::string CreateOrGetLabel(const std::string& type, const std::string& key,
const std::string& defaultValue);
std::string CreateOrGetLabel(const std::string& type, const std::string& key,
const absl::string_view& defaultValue);
bool labels_loaded_ = false;
std::string filename_;
struct ResourceType {
std::string key_name;
std::string display_description;
};
std::unordered_map<std::string, std::unordered_map<std::string, std::string>>
labels_;
};
} // namespace core
} // namespace app
} // namespace yaze
#endif // YAZE_APP_CORE_LABELING_H_

View File

@@ -1,13 +1,57 @@
#ifndef YAZE_APP_CORE_PLATFORM_APP_DELEGATE_H #ifndef YAZE_APP_CORE_PLATFORM_APP_DELEGATE_H
#define YAZE_APP_CORE_PLATFORM_APP_DELEGATE_H #define YAZE_APP_CORE_PLATFORM_APP_DELEGATE_H
#ifdef TARGET_OS_MAC #if defined(__APPLE__) && defined(__MACH__)
/* Apple OSX and iOS (Darwin). */
#import <CoreText/CoreText.h>
#include <TargetConditionals.h>
#if TARGET_IPHONE_SIMULATOR == 1 || TARGET_OS_IPHONE == 1
/* iOS in Xcode simulator */
#import <PencilKit/PencilKit.h>
#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate,
UIDocumentPickerDelegate,
UITabBarControllerDelegate,
PKCanvasViewDelegate>
@property(strong, nonatomic) UIWindow *window;
@property UIDocumentPickerViewController *documentPicker;
@property(nonatomic, copy) void (^completionHandler)(NSString *selectedFile);
- (void)PresentDocumentPickerWithCompletionHandler:
(void (^)(NSString *selectedFile))completionHandler;
// TODO: Setup a tab bar controller for multiple yaze instances
@property(nonatomic) UITabBarController *tabBarController;
// TODO: Setup a font picker for the text editor and display settings
@property(nonatomic) UIFontPickerViewController *fontPicker;
// TODO: Setup the pencil kit for drawing
@property PKToolPicker *toolPicker;
@property PKCanvasView *canvasView;
// TODO: Setup the file manager for file operations
@property NSFileManager *fileManager;
@end
#elif TARGET_OS_MAC == 1
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
void InitializeCocoa(); /**
* @brief Initialize the Cocoa application.
*/
void yaze_initialize_cocoa();
/**
* @brief Run the Cocoa application delegate.
*/
int yaze_run_cocoa_app_delegate(const char *filename);
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"
@@ -15,4 +59,6 @@ void InitializeCocoa();
#endif // TARGET_OS_MAC #endif // TARGET_OS_MAC
#endif // defined(__APPLE__) && defined(__MACH__)
#endif // YAZE_APP_CORE_PLATFORM_APP_DELEGATE_H #endif // YAZE_APP_CORE_PLATFORM_APP_DELEGATE_H

Some files were not shown because too many files have changed in this diff Show More