Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,28 +69,28 @@ jobs:
if-no-files-found: error

windows:
name: Windows MSVC
name: Windows MinGW (MSVC also tested by native package job)
runs-on: windows-latest
steps:
- name: Check out source
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Configure and build
run: |
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++
cmake --build build --parallel 2
- name: Run tests and benchmark
run: |
ctest --test-dir build --output-on-failure
New-Item -ItemType Directory -Force docs/reports/generated | Out-Null
./build/forge2d_benchmark.exe | Tee-Object docs/reports/generated/benchmark-msvc.json
./build/forge2d_benchmark.exe | Tee-Object docs/reports/generated/benchmark-mingw.json
./build/forge2d_arena.exe assets/arena.scene out/ci
- name: Upload Windows evidence
if: always()
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: windows-msvc-evidence
name: windows-mingw-evidence
path: |
docs/reports/generated/benchmark-msvc.json
docs/reports/generated/benchmark-mingw.json
out/ci
if-no-files-found: error

Expand All @@ -111,9 +111,9 @@ jobs:
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON
- name: Analyze authored targets
run: >-
clang-tidy -p build src/collision.cpp src/pathfinding.cpp src/replay.cpp src/scene.cpp
clang-tidy -p build src/editor.cpp src/collision.cpp src/pathfinding.cpp src/replay.cpp src/scene.cpp
src/software_renderer.cpp src/world.cpp apps/forge2d_arena.cpp tests/test_main.cpp
benchmarks/benchmark.cpp
tests/test_editor.cpp benchmarks/benchmark.cpp

coverage:
name: Coverage gate
Expand Down
21 changes: 21 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,24 @@ jobs:
cmake --build build --parallel 2
- name: Analyze
uses: github/codeql-action/analyze@24c54180a607b1449ed407dd24f251e4e9147c8d # v4.38.3; coordinated version

analyze-windows:
name: Analyze native Windows C and C++
runs-on: windows-latest
timeout-minutes: 20
steps:
- name: Check out source
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Initialize CodeQL
uses: github/codeql-action/init@24c54180a607b1449ed407dd24f251e4e9147c8d # v4.38.3; coordinated version
with:
languages: c-cpp
build-mode: manual
- name: Build actual native and core targets
run: |
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug
cmake --build build --parallel 2
- name: Analyze native Windows source
uses: github/codeql-action/analyze@24c54180a607b1449ed407dd24f251e4e9147c8d # v4.38.3; coordinated version
63 changes: 63 additions & 0 deletions .github/workflows/native-app.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# File: native-app.yml
# Purpose: Build and extract-test the actual Windows editor; retain bounded proof, not routine full packages.
name: Native application
on:
push:
branches: [main]
pull_request:
workflow_dispatch:
inputs:
retain_package:
description: Retain the unsigned portable candidate for reviewed main-source distribution
type: boolean
required: false
default: false
permissions:
contents: read
concurrency:
group: native-${{ github.ref }}
cancel-in-progress: true
jobs:
windows:
name: Actual Windows editor and extracted portable package
runs-on: windows-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.14.10"
check-latest: true
- name: Build static-runtime executable and actual core/file tests
shell: pwsh
run: |
$vs = & "${env:ProgramFiles(x86)}/Microsoft Visual Studio/Installer/vswhere.exe" -latest -products '*' -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath
if (-not $vs -or -not (Test-Path -LiteralPath "$vs/Common7/Tools/VsDevCmd.bat")) { throw 'Reviewed MSVC toolchain unavailable.' }
$command = '"' + $vs + '/Common7/Tools/VsDevCmd.bat" -arch=x64 -host_arch=x64 && pwsh -NoProfile -File scripts/build-native.ps1 -Output release/windows'
& cmd.exe /d /s /c $command
if ($LASTEXITCODE -ne 0) { throw 'Native build/tests failed.' }
- name: Extract package and exercise native play, restart and corrupt-profile recovery
run: python scripts/smoke-native.py release/windows/Forge2DEditor-1.1.0-windows-x64.zip artifacts/native/hosted
- name: Retain bounded synthetic receipts and own-window screenshots
if: always()
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: forge2d-native-proof
path: |
artifacts/native/hosted/*.json
artifacts/native/hosted/*.png
artifacts/native/hosted/*failure.txt
if-no-files-found: warn
retention-days: 1
- name: Retain full unsigned package only on explicit trusted-main request
if: github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main' && inputs.retain_package
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: forge2d-reviewed-portable-candidate
path: |
release/windows/*.zip
release/windows/*.sha256
if-no-files-found: error
retention-days: 1
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# File: .gitignore
# Purpose: Exclude build products, editor state, generated reports, and local runtime output.
.cache/
.runtime/
artifacts/
release/
.idea/
.vs/
.vscode/
Expand Down
48 changes: 47 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# Purpose: Configure the portable engine core, tests, benchmark, sample, and optional SDL3 frontend.
cmake_minimum_required(VERSION 3.25)

project(forge2d_engine VERSION 1.0.0 LANGUAGES C CXX)
project(forge2d_engine VERSION 1.1.0 LANGUAGES C CXX)

include(CTest)
include(GNUInstallDirs)
Expand Down Expand Up @@ -64,6 +64,7 @@ forge2d_enable_sanitizers(forge2d_platform_c)
forge2d_enable_coverage(forge2d_platform_c)

add_library(forge2d_core STATIC
src/editor.cpp
src/collision.cpp
src/pathfinding.cpp
src/replay.cpp
Expand All @@ -87,6 +88,38 @@ forge2d_set_warnings(forge2d_arena)
forge2d_enable_sanitizers(forge2d_arena)
forge2d_enable_coverage(forge2d_arena)

if(WIN32)
enable_language(RC)
set(FORGE2D_NATIVE_SOURCE "unavailable")
set(FORGE2D_NATIVE_DIRTY "true")
find_package(Git QUIET)
if(GIT_FOUND)
execute_process(COMMAND ${GIT_EXECUTABLE} -c safe.directory=${CMAKE_CURRENT_SOURCE_DIR}
rev-parse HEAD WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_VARIABLE native_source OUTPUT_STRIP_TRAILING_WHITESPACE RESULT_VARIABLE native_git_result)
if(native_git_result EQUAL 0 AND native_source MATCHES "^[0-9a-f]+$")
set(FORGE2D_NATIVE_SOURCE "${native_source}")
execute_process(COMMAND ${GIT_EXECUTABLE} -c safe.directory=${CMAKE_CURRENT_SOURCE_DIR}
status --porcelain WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_VARIABLE native_status OUTPUT_STRIP_TRAILING_WHITESPACE)
if(native_status STREQUAL "")
set(FORGE2D_NATIVE_DIRTY "false")
endif()
endif()
endif()
add_executable(Forge2DEditor WIN32 apps/forge2d_editor.cpp apps/editor_files.cpp apps/editor.rc)
target_link_libraries(Forge2DEditor PRIVATE Forge2D::Core comdlg32 gdiplus bcrypt shell32 ole32)
target_compile_definitions(Forge2DEditor PRIVATE UNICODE _UNICODE
FORGE2D_NATIVE_SOURCE="${FORGE2D_NATIVE_SOURCE}" FORGE2D_NATIVE_DIRTY=${FORGE2D_NATIVE_DIRTY})
if(MINGW)
target_link_options(Forge2DEditor PRIVATE -municode)
endif()
forge2d_set_warnings(Forge2DEditor)
add_custom_command(TARGET Forge2DEditor POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_CURRENT_SOURCE_DIR}/assets $<TARGET_FILE_DIR:Forge2DEditor>/assets)
endif()

if(FORGE2D_BUILD_SDL)
include(FetchContent)
set(SDL_SHARED OFF CACHE BOOL "" FORCE)
Expand All @@ -113,6 +146,19 @@ if(FORGE2D_BUILD_TESTS)
forge2d_enable_sanitizers(forge2d_tests)
forge2d_enable_coverage(forge2d_tests)
add_test(NAME forge2d_tests COMMAND forge2d_tests)
add_executable(forge2d_editor_tests tests/test_editor.cpp)
target_link_libraries(forge2d_editor_tests PRIVATE Forge2D::Core)
forge2d_set_warnings(forge2d_editor_tests)
forge2d_enable_sanitizers(forge2d_editor_tests)
forge2d_enable_coverage(forge2d_editor_tests)
add_test(NAME forge2d_editor_tests COMMAND forge2d_editor_tests)
if(WIN32)
add_executable(forge2d_editor_files_tests tests/test_editor_files.cpp apps/editor_files.cpp)
target_link_libraries(forge2d_editor_files_tests PRIVATE Forge2D::Core bcrypt shell32 ole32)
target_compile_definitions(forge2d_editor_files_tests PRIVATE UNICODE _UNICODE)
forge2d_set_warnings(forge2d_editor_files_tests)
add_test(NAME forge2d_editor_files_tests COMMAND forge2d_editor_files_tests)
endif()
endif()

if(FORGE2D_BUILD_BENCHMARKS)
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ RUN apt-get update \
WORKDIR /source
COPY . .
RUN cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release \
&& cmake --build build --target forge2d_arena forge2d_tests forge2d_benchmark --parallel \
&& cmake --build build --target forge2d_arena forge2d_tests forge2d_editor_tests forge2d_benchmark --parallel \
&& ctest --test-dir build --output-on-failure \
&& ./build/forge2d_benchmark

Expand Down
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,23 @@ generation-safe entities, sparse-set components, fixed-timestep simulation, spat
A* pathfinding, versioned scenes and replays, bounded allocation, software screenshot evidence, an
optional SDL3 frontend, and regression budgets.

The **Windows native Forge2D Editor** adds an actual scene-edit/play workflow over that same C++
engine. Open `Forge2DEditor.exe` from an extracted portable candidate: edit all strict scene fields,
Apply with validation, move the player with focused-canvas keys, Play/Pause/Step, inspect overlap
counts, save an authored project, import recorded inputs and export matching scene/replay/image/
snapshot evidence. Prepared arena and collision-layer files are normal inputs inside the full app.
The application needs no IDE, compiler, Python, Node or network at runtime.

Project saves live under the current OS account's local `Forge2DEditor` profile, outside the program
folder. Restart restores the authored scene **paused at tick zero**. Invalid Apply preserves the
previous world; closing warns about unapplied/unsaved edits; a second profile owner is refused.
This is a small, purpose-built editor, not a complete commercial game engine: masks detect AABB
overlaps without physical response, and imported replay files need their matching scene.
See [native usage, fields, limits and build](docs/native-editor.md),
[observed validation](docs/reports/native-editor-2026-11-10.md) and the
[native workflow](.github/workflows/native-app.yml). Created by **Jason Stys**;
[source/contact](https://github.com/JasonStys).

The project is intentionally smaller than a commercial engine. Its goal is to demonstrate memory
ownership, data layout, deterministic behavior, parser safety, algorithmic trade-offs, portable
build engineering, and honest performance evidence in a codebase a reviewer can understand.
Expand Down Expand Up @@ -37,6 +54,7 @@ application responsibilities.
- Four-neighbor A* with stable tie-breaking and explicit O((V+E) log V) analysis.
- Versioned, bounded, strict scene/replay parsers plus a libFuzzer target.
- Headless software rendering to portable PPM evidence and an optional SDL3 accelerated frontend.
- C++/Win32 native source editor, fixed-tick play/replay, durable local project and evidence exports.
- MSVC, GCC, and Clang builds; warnings-as-errors; ASan/UBSan; fuzz smoke; CodeQL; coverage;
packaging; and a non-root headless container.

Expand Down
31 changes: 31 additions & 0 deletions apps/editor.rc
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// File: editor.rc
// Purpose: Embed truthful Windows product/author metadata for the portable native editor.
#include <winver.h>
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,1,0,0
PRODUCTVERSION 1,1,0,0
FILEFLAGSMASK 0x3fL
FILEFLAGS 0x0L
FILEOS 0x40004L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "Jason Stys\0"
VALUE "FileDescription", "Forge2D Editor\0"
VALUE "FileVersion", "1.1.0\0"
VALUE "InternalName", "Forge2DEditor\0"
VALUE "LegalCopyright", "Copyright Jason Stys. MIT license.\0"
VALUE "OriginalFilename", "Forge2DEditor.exe\0"
VALUE "ProductName", "Forge2D Editor\0"
VALUE "ProductVersion", "1.1.0\0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
Loading
Loading