Compare commits
42 Commits
dev/upgrad
...
dev/varian
| Author | SHA1 | Date |
|---|---|---|
|
|
2d59109994 | |
|
|
bae150305d | |
|
|
6300ef0e35 | |
|
|
a518a89798 | |
|
|
e69a8d13ec | |
|
|
ef91c4599b | |
|
|
9f9f40abd9 | |
|
|
81aaaa81b7 | |
|
|
c36cae7db9 | |
|
|
a06b0e6394 | |
|
|
17b3a4c23d | |
|
|
81132ac97b | |
|
|
97c8de24b9 | |
|
|
bb99e9025e | |
|
|
b4fa25106a | |
|
|
75a9ae1b39 | |
|
|
18b5537826 | |
|
|
b248573930 | |
|
|
3648615829 | |
|
|
8a30c78260 | |
|
|
cc00fb076e | |
|
|
ffc84ce44c | |
|
|
a727aedd97 | |
|
|
fb131ab6c4 | |
|
|
1572f96429 | |
|
|
5fbc11e1a1 | |
|
|
0fc379cbc3 | |
|
|
55e7c955c1 | |
|
|
35562ab6d7 | |
|
|
7aa70eb5d5 | |
|
|
2e2ab68178 | |
|
|
054b41da95 | |
|
|
60dfe0ae60 | |
|
|
180badad39 | |
|
|
08bad270e6 | |
|
|
c7cfa18ce9 | |
|
|
b5dad13bd7 | |
|
|
2e4f7d98e4 | |
|
|
6bf5b3516f | |
|
|
cf0f27cc92 | |
|
|
338954aa8a | |
|
|
efc11fcba9 |
|
|
@ -0,0 +1,169 @@
|
||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## Project Overview
|
||||||
|
|
||||||
|
Backlog is a game engine written in Zig (version 0.14) with a modular architecture. The engine supports cross-platform development with Windows, macOS, and Linux targets, and includes support for both static and dynamic module loading.
|
||||||
|
|
||||||
|
## Build System
|
||||||
|
|
||||||
|
The project uses Zig's build system with a custom `BuildSystem` wrapper:
|
||||||
|
|
||||||
|
### Key Build Commands
|
||||||
|
|
||||||
|
- `zig build` - Build the engine and default projects
|
||||||
|
- `zig build -Dcookshaders` - Build with shader compilation enabled
|
||||||
|
- `zig build -Dstatic_build` - Force static linking (required for Linux)
|
||||||
|
- `zig build tools` - Install development tools (gltf2ozz, spirv-reflect)
|
||||||
|
- `zig build gltf2ozz -- [args]` - Run GLTF animation converter
|
||||||
|
- `zig build spv-reflect -- [args]` - Run SPIRV reflection tool
|
||||||
|
- `python tools/scripts/cookShaders.py` - Compile shaders from HLSL to SPIR-V, MSL, and DXIL formats, must be run after editing shader files
|
||||||
|
|
||||||
|
### Project-Specific Commands
|
||||||
|
|
||||||
|
From the `projects/` directory:
|
||||||
|
- `zig build` - Build sample game and tools
|
||||||
|
- `zig build run-sampleGame` - Run the sample game
|
||||||
|
- `zig build run-newProject` - Run the project creation tool
|
||||||
|
|
||||||
|
### Testing
|
||||||
|
|
||||||
|
- `zig build test` - Run all tests (individual modules have their own test files in `tests/` subdirectories)
|
||||||
|
|
||||||
|
### Setup Commands
|
||||||
|
|
||||||
|
- `python tools/scripts/first-time-setup.py` - Initial setup script
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
### Engine Modules
|
||||||
|
|
||||||
|
The engine is organized into these core modules:
|
||||||
|
|
||||||
|
- **core** - Foundation systems (ECS, logging, memory tracking, jobs, scripting)
|
||||||
|
- **platform** - Cross-platform windowing and input handling
|
||||||
|
- **assets** - Asset loading and management system
|
||||||
|
- **rend** - 3D rendering system with mesh, camera, and material support
|
||||||
|
- **audio** - Sound engine integration
|
||||||
|
- **ui** - User interface rendering system
|
||||||
|
- **papyrus** - Text rendering and UI primitives
|
||||||
|
- **imgui** - Debug UI integration
|
||||||
|
- **physics** - Physics engine integration (Jolt)
|
||||||
|
- **sys** - System utilities and subprocess management
|
||||||
|
|
||||||
|
### Key Directories
|
||||||
|
|
||||||
|
- `engine/` - Core engine modules, each with their own `build.zig`
|
||||||
|
- `projects/` - Sample projects and games
|
||||||
|
- `lib/` - Third-party dependencies and wrappers
|
||||||
|
- `tools/` - Development utilities and scripts
|
||||||
|
- `content/` - Game assets and resources (located at `projects/content/`)
|
||||||
|
- `extras/` - Optional engine extensions
|
||||||
|
|
||||||
|
### Engine Initialization
|
||||||
|
|
||||||
|
The engine uses a spec-based initialization system where modules are conditionally enabled:
|
||||||
|
|
||||||
|
```zig
|
||||||
|
// Programs define which modules to enable
|
||||||
|
sampleGame.setModuleEnabled("imgui", true);
|
||||||
|
sampleGame.setModuleEnabled("physics", true);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Dynamic Modules
|
||||||
|
|
||||||
|
The engine supports dynamic module loading for game-specific code:
|
||||||
|
|
||||||
|
```zig
|
||||||
|
const externGame = sampleGame.addDynamicModule("externGame", b.path("sampleGame/externGame/externGame.zig"));
|
||||||
|
```
|
||||||
|
|
||||||
|
### Shader Pipeline
|
||||||
|
|
||||||
|
Shaders are written in HLSL and compiled to multiple targets:
|
||||||
|
- SPIR-V for Vulkan
|
||||||
|
- MSL for Metal (macOS)
|
||||||
|
- DXIL for DirectX
|
||||||
|
|
||||||
|
The shader compilation system automatically discovers `.hlsl` files in `engine/*/shaders/` directories.
|
||||||
|
|
||||||
|
## Development Notes
|
||||||
|
|
||||||
|
- All memory allocations go through a centralized `MemoryTracker` for leak detection
|
||||||
|
- The engine uses Tracy for profiling when enabled
|
||||||
|
- Lua scripting is integrated for game logic
|
||||||
|
- The build system generates API wrappers automatically for enabled modules
|
||||||
|
- Content directory location is determined by `content.txt` file pointing to `projects/content/`
|
||||||
|
|
||||||
|
## Common Development Tasks
|
||||||
|
|
||||||
|
- Adding new engine modules: Create in `engine/` with `build.zig` and add to `engineDepList`
|
||||||
|
- Creating new projects: Use the project template in `projects/minimal/`
|
||||||
|
- Shader development: Add HLSL files to module `shaders/` directories, run `cookShaders.py`
|
||||||
|
- Asset pipeline: Assets go in `projects/content/` and use `.cook` extensions for processed assets
|
||||||
|
|
||||||
|
## Issue Tracking with git-bug
|
||||||
|
|
||||||
|
This project uses git-bug for distributed issue tracking. Bug data is stored directly in the git repository. While named "git-bug", it can track all types of development work including bugs, features, tasks, and documentation.
|
||||||
|
|
||||||
|
### Common Commands
|
||||||
|
|
||||||
|
- `git bug bug` - List all issues
|
||||||
|
- `git bug bug new -t "title" -m "message"` - Create a new issue with title and message
|
||||||
|
- `git bug bug show <id>` - Display issue details
|
||||||
|
- `git bug bug comment <id>` - Add a comment to an issue
|
||||||
|
- `git bug bug status <id>` - Display issue status
|
||||||
|
- `git bug bug label new <id> <label>` - Add a label to an issue
|
||||||
|
- `git bug bug label rm <id> <label>` - Remove a label from an issue
|
||||||
|
- `git bug bug label <id>` - Display labels for an issue
|
||||||
|
- `git bug bug status:open` - List only open issues
|
||||||
|
- `git bug pull` - Pull issue updates from remote
|
||||||
|
- `git bug push` - Push issue updates to remote
|
||||||
|
|
||||||
|
### Workflow
|
||||||
|
|
||||||
|
- Issues are stored in the repository and sync with `git bug pull`/`git bug push`
|
||||||
|
- Issue IDs can be abbreviated to the first few characters
|
||||||
|
- Use labels to categorize issues by both type and component
|
||||||
|
- Use `--non-interactive` flag for scripting
|
||||||
|
- Keep issue descriptions factual and clear
|
||||||
|
|
||||||
|
### Standard Labels
|
||||||
|
|
||||||
|
Use these standard labels to categorize issues:
|
||||||
|
|
||||||
|
- **Component labels**: `core`, `rendering`, `physics`, `build-system`, `platform`, `assets`, `audio`, `ui`, `documentation`
|
||||||
|
- **Issue type labels**:
|
||||||
|
- `bug` - Defects, errors, or incorrect behavior
|
||||||
|
- `feature` - New functionality to implement
|
||||||
|
- `enhancement` - Improvements to existing features
|
||||||
|
- `task` - General development work items
|
||||||
|
- `documentation` - Documentation improvements or additions
|
||||||
|
- `question` - Design decisions or technical discussions
|
||||||
|
- `refactoring` - Code cleanup and restructuring
|
||||||
|
- **Problem type labels** (for bugs):
|
||||||
|
- `memory` - Memory allocation, leaks, or performance issues
|
||||||
|
- `threading` - Job system, parallelization, race conditions, or deadlocks
|
||||||
|
- `crash` - Application crashes or critical failures
|
||||||
|
- `build` - Build system or compilation issues
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create a feature request
|
||||||
|
git bug bug new -t "Add procedural terrain generation" -m "Implement heightmap-based terrain system"
|
||||||
|
git bug bug label new <id> feature rendering
|
||||||
|
|
||||||
|
# Create a task
|
||||||
|
git bug bug new -t "Update to Zig 0.15" -m "Migrate codebase to latest Zig version"
|
||||||
|
git bug bug label new <id> task build-system
|
||||||
|
|
||||||
|
# Create a documentation issue
|
||||||
|
git bug bug new -t "Document shader pipeline" -m "Add comprehensive guide for shader development workflow"
|
||||||
|
git bug bug label new <id> documentation rendering
|
||||||
|
|
||||||
|
# Create a bug report
|
||||||
|
git bug bug new -t "Memory leak in asset loader" -m "Assets not freed when unloading scenes"
|
||||||
|
git bug bug label new <id> bug assets memory
|
||||||
|
```
|
||||||
92
README.md
92
README.md
|
|
@ -1,18 +1,100 @@
|
||||||
# Backlog
|
# Backlog
|
||||||
|
|
||||||
|
|
||||||
zig version: 0.15.1
|
zig version: 0.15.1
|
||||||
|
|
||||||
Backlog Labs Game Engine.
|
Backlog Labs Game Engine.
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
run tools/scripts/first-time-setup.py
|
run tools/scripts/first-time-setup.py
|
||||||
|
|
||||||
ffmpeg -i INPUT.mp4 -c:v libtheora -q:v 7 -c:a libvorbis -q:a 4 OUTPUT.ogv
|
ffmpeg -i INPUT.mp4 -c:v libtheora -q:v 7 -c:a libvorbis -q:a 4 OUTPUT.ogv
|
||||||
|
|
||||||
|
## git-bug Cheat Sheet
|
||||||
|
|
||||||
/// --------------------------------------------------------
|
This project uses git-bug for distributed issue tracking. Issues are stored directly in the repository.
|
||||||
void* malloc(size_t size); // gives you a pointer to a memory buffer of size
|
|
||||||
void free(void* ptr); // releases a pointer to memory
|
### Common Commands
|
||||||
/// --------------------------------------------------------
|
|
||||||
|
**Listing Issues**
|
||||||
|
```bash
|
||||||
|
git bug bug # List all issues
|
||||||
|
git bug bug status:open # List only open issues
|
||||||
|
git bug bug status:closed # List only closed issues
|
||||||
|
```
|
||||||
|
|
||||||
|
**Creating Issues**
|
||||||
|
```bash
|
||||||
|
git bug bug new -t "title" -m "message" # Create new issue
|
||||||
|
git bug bug new -t "Add feature X" -m "Description" # Example
|
||||||
|
```
|
||||||
|
|
||||||
|
**Viewing & Managing Issues**
|
||||||
|
```bash
|
||||||
|
git bug bug show <id> # Show issue details
|
||||||
|
git bug bug comment <id> # Add a comment to an issue
|
||||||
|
git bug bug close <id> # Close an issue
|
||||||
|
git bug bug open <id> # Reopen an issue
|
||||||
|
git bug bug status <id> # Show issue status
|
||||||
|
```
|
||||||
|
|
||||||
|
**Labels**
|
||||||
|
```bash
|
||||||
|
git bug bug label <id> # Show labels for an issue
|
||||||
|
git bug bug label new <id> <label> # Add a label
|
||||||
|
git bug bug label rm <id> <label> # Remove a label
|
||||||
|
```
|
||||||
|
|
||||||
|
**Syncing**
|
||||||
|
```bash
|
||||||
|
git bug pull # Pull issue updates from remote
|
||||||
|
git bug push # Push issue updates to remote
|
||||||
|
```
|
||||||
|
|
||||||
|
### Standard Labels
|
||||||
|
|
||||||
|
**Component Labels**: `core`, `rendering`, `physics`, `build-system`, `platform`, `assets`, `audio`, `ui`, `documentation`
|
||||||
|
|
||||||
|
**Type Labels**:
|
||||||
|
- `bug` - Defects or incorrect behavior
|
||||||
|
- `feature` - New functionality
|
||||||
|
- `enhancement` - Improvements to existing features
|
||||||
|
- `task` - General development work
|
||||||
|
- `documentation` - Documentation improvements
|
||||||
|
- `question` - Design decisions or discussions
|
||||||
|
- `refactoring` - Code cleanup
|
||||||
|
|
||||||
|
**Problem Type Labels** (for bugs):
|
||||||
|
- `memory` - Memory issues
|
||||||
|
- `threading` - Concurrency issues
|
||||||
|
- `crash` - Application crashes
|
||||||
|
- `build` - Build system issues
|
||||||
|
|
||||||
|
### Quick Examples
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create a bug report
|
||||||
|
git bug bug new -t "Memory leak in asset loader" -m "Assets not freed when unloading scenes"
|
||||||
|
git bug bug label new <id> bug assets memory
|
||||||
|
|
||||||
|
# Create a feature request
|
||||||
|
git bug bug new -t "Add terrain generation" -m "Implement heightmap-based terrain"
|
||||||
|
git bug bug label new <id> feature rendering
|
||||||
|
|
||||||
|
# Create a task
|
||||||
|
git bug bug new -t "Update to Zig 0.15" -m "Migrate to latest Zig version"
|
||||||
|
git bug bug label new <id> task build-system
|
||||||
|
|
||||||
|
# View and comment on an issue
|
||||||
|
git bug bug show abc123
|
||||||
|
git bug bug comment abc123
|
||||||
|
```
|
||||||
|
|
||||||
|
### Tips
|
||||||
|
|
||||||
|
- Issue IDs can be abbreviated (first few characters)
|
||||||
|
- Use `--non-interactive` flag for scripting
|
||||||
|
- Issues sync with `git bug pull/push`
|
||||||
|
- Keep descriptions factual and clear
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,662 @@
|
||||||
|
// MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS=1 -- use this if you're getting that odd crash on mac
|
||||||
|
b: *std.Build,
|
||||||
|
nw_builder: *std.Build,
|
||||||
|
target: std.Build.ResolvedTarget,
|
||||||
|
optimize: std.builtin.OptimizeMode,
|
||||||
|
nw_mod: *std.Build.Module,
|
||||||
|
gltf2ozz: ozz.GltfToOzz,
|
||||||
|
options: *std.Build.Step.Options,
|
||||||
|
cookShaders: bool,
|
||||||
|
|
||||||
|
backlogRoot: []const u8,
|
||||||
|
// list of all shaders discovered under
|
||||||
|
// content/_shaders/def
|
||||||
|
reflectShaderPathList: [][]u8 = undefined,
|
||||||
|
|
||||||
|
staticBuild: bool = false,
|
||||||
|
|
||||||
|
nwdep: *std.Build.Dependency,
|
||||||
|
apigen: *std.Build.Step.Compile,
|
||||||
|
shaderEmbedGen: *std.Build.Step.Compile,
|
||||||
|
loadDynamicsGen: *std.Build.Step.Compile,
|
||||||
|
rcGen: *std.Build.Step.Compile,
|
||||||
|
generatedApis: std.StringHashMapUnmanaged(*std.Build.Module) = .{},
|
||||||
|
|
||||||
|
const engineDepList = [_][]const u8{
|
||||||
|
"assets",
|
||||||
|
"audio",
|
||||||
|
"core",
|
||||||
|
"net",
|
||||||
|
"papyrus",
|
||||||
|
"platform",
|
||||||
|
"rend",
|
||||||
|
"ui",
|
||||||
|
"imgui",
|
||||||
|
"physics",
|
||||||
|
"sys",
|
||||||
|
};
|
||||||
|
|
||||||
|
const BuildSystem = @This();
|
||||||
|
const std = @import("std");
|
||||||
|
const Build = std.Build;
|
||||||
|
const LazyPath = Build.LazyPath;
|
||||||
|
|
||||||
|
const ozz = @import("ozz");
|
||||||
|
|
||||||
|
pub const InitOptions = struct {
|
||||||
|
import_name: []const u8 = "Backlog",
|
||||||
|
backlogRoot: []const u8 = "./BacklogEngine",
|
||||||
|
staticBuild: bool = false,
|
||||||
|
target: Build.ResolvedTarget,
|
||||||
|
optimize: std.builtin.OptimizeMode,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn init(b: *std.Build, opts: InitOptions) BuildSystem {
|
||||||
|
var buildOpts = declareBuildOptions(b);
|
||||||
|
|
||||||
|
if (opts.target.result.os.tag == .linux) {
|
||||||
|
// using a static build for linux... object loading hell is not fun
|
||||||
|
std.debug.print("Important! only supporting static builds for linux", .{});
|
||||||
|
buildOpts.static_build = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const nwdep = b.dependency(opts.import_name, .{
|
||||||
|
.target = opts.target,
|
||||||
|
.optimize = opts.optimize,
|
||||||
|
.static_build = buildOpts.static_build,
|
||||||
|
});
|
||||||
|
|
||||||
|
var self = BuildSystem{
|
||||||
|
.b = b,
|
||||||
|
.nw_builder = nwdep.builder,
|
||||||
|
.target = opts.target,
|
||||||
|
.optimize = opts.optimize,
|
||||||
|
.nw_mod = nwdep.module("Backlog"),
|
||||||
|
.backlogRoot = opts.backlogRoot,
|
||||||
|
.options = createGameOptions(b, buildOpts),
|
||||||
|
.gltf2ozz = ozz.GltfToOzz.init(nwdep.builder, .{}),
|
||||||
|
.cookShaders = b.option(bool, "cookShaders", "generates shaders and updates .json files before running the build. (needs to be done whenever shaders are updated, this just runs tools/scripts/cook-shaders.py)") orelse false,
|
||||||
|
|
||||||
|
.staticBuild = buildOpts.static_build,
|
||||||
|
.nwdep = nwdep,
|
||||||
|
.apigen = nwdep.artifact("backlog-apigen"),
|
||||||
|
.loadDynamicsGen = nwdep.artifact("backlog-generate-loadDynamics"),
|
||||||
|
.rcGen = nwdep.artifact("backlog-generate-rc"),
|
||||||
|
.shaderEmbedGen = nwdep.artifact("backlog-shaderEmbedGen"),
|
||||||
|
};
|
||||||
|
|
||||||
|
const exeList = [1]*std.Build.Step.Compile{self.gltf2ozz.exe};
|
||||||
|
const install_tools = b.step("tools", "installs tools needed to generate outputs for the engine");
|
||||||
|
for (exeList) |exe| {
|
||||||
|
const toolsInstall = b.addInstallArtifact(exe, .{
|
||||||
|
.dest_dir = .{ .override = .{ .custom = "tools" } },
|
||||||
|
});
|
||||||
|
|
||||||
|
install_tools.dependOn(&toolsInstall.step);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const runArtifact = b.addRunArtifact(self.gltf2ozz.exe);
|
||||||
|
if (b.args) |args| {
|
||||||
|
runArtifact.addArgs(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
const run_exe = b.step("gltf2ozz", "runs the gltf animation converter.");
|
||||||
|
run_exe.dependOn(&runArtifact.step);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.addDependencyInstalls(self.b, .ReleaseFast);
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const AddProgramOptions = struct {
|
||||||
|
name: []const u8,
|
||||||
|
desc: []const u8,
|
||||||
|
root_source_file: LazyPath,
|
||||||
|
imports: []const Build.Module.Import = &.{},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn addProgram(self: *BuildSystem, opts: AddProgramOptions) *std.Build.Module {
|
||||||
|
const b = self.b;
|
||||||
|
|
||||||
|
const exe = self.nw_builder.addExecutable(.{
|
||||||
|
.name = opts.name,
|
||||||
|
.root_module = b.createModule(.{
|
||||||
|
.target = self.target,
|
||||||
|
.optimize = self.optimize,
|
||||||
|
.root_source_file = self.nw_builder.path("engine/main.zig"),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
b.installArtifact(exe);
|
||||||
|
const runArtifact = b.addRunArtifact(exe);
|
||||||
|
if (b.args) |args| {
|
||||||
|
runArtifact.addArgs(args);
|
||||||
|
}
|
||||||
|
const run_exe = b.step(self.b.fmt("run-{s}", .{opts.name}), opts.desc);
|
||||||
|
run_exe.dependOn(&runArtifact.step);
|
||||||
|
|
||||||
|
// main path = name/main.zig
|
||||||
|
const mod = b.addModule(opts.name, .{
|
||||||
|
.target = self.target,
|
||||||
|
.optimize = self.optimize,
|
||||||
|
.root_source_file = opts.root_source_file,
|
||||||
|
.imports = opts.imports,
|
||||||
|
});
|
||||||
|
|
||||||
|
exe.root_module.addImport("main", mod);
|
||||||
|
// todo.. remove this one and see what happens
|
||||||
|
exe.root_module.addImport("core", self.nwdep.module("core"));
|
||||||
|
// mod.addImport("Backlog", self.nw_mod);
|
||||||
|
exe.root_module.addOptions("BacklogOptions", self.options);
|
||||||
|
|
||||||
|
if (self.cookShaders) {
|
||||||
|
const cookShadersScript = b.fmt("{s}/tools/scripts/cookShaders.py", .{self.backlogRoot});
|
||||||
|
const cookShadersCommand = b.addSystemCommand(&[_][]const u8{"python"});
|
||||||
|
cookShadersCommand.addArg(cookShadersScript);
|
||||||
|
|
||||||
|
run_exe.dependOn(&cookShadersCommand.step);
|
||||||
|
}
|
||||||
|
|
||||||
|
b.getInstallStep().dependOn(self.nw_builder.getInstallStep());
|
||||||
|
|
||||||
|
// run_exe.dependOn(b.getInstallStep());
|
||||||
|
|
||||||
|
return mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const BuildOptions = struct {
|
||||||
|
mutex_job_queue: bool,
|
||||||
|
static_build: bool,
|
||||||
|
zero_logging: bool,
|
||||||
|
slow_logging: bool,
|
||||||
|
force_mailbox: bool,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn declareBuildOptions(b: *std.Build) BuildOptions {
|
||||||
|
return .{
|
||||||
|
.mutex_job_queue = b.option(bool, "mutex_job_queue", "temporary test, reverts to old mutex based queue behaviour in jobs.zig:JobManager") orelse false,
|
||||||
|
.static_build = b.option(bool, "static_build", "builds the entire game as a single executable") orelse false,
|
||||||
|
.zero_logging = b.option(bool, "zero_logging", "disables all logging, only intended for use on job dispatch testing") orelse false,
|
||||||
|
.slow_logging = b.option(bool, "slow_logging", "Disables buffered logging, takes a hit to performance but gain timing information on logging") orelse false,
|
||||||
|
.force_mailbox = b.option(bool, "force_mailbox", "forces mailbox mode for present mode. unlocks framerate to irresponsible levels") orelse false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn createGameOptions(b: *std.Build, options: BuildOptions) *std.Build.Step.Options {
|
||||||
|
const opts = b.addOptions();
|
||||||
|
|
||||||
|
inline for (@typeInfo(BuildOptions).@"struct".fields) |field| {
|
||||||
|
opts.addOption(bool, field.name, @field(options, field.name));
|
||||||
|
}
|
||||||
|
|
||||||
|
return opts;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn addExtraModule(self: *BuildSystem, mod: *std.Build.Module, moduleName: []const u8) void {
|
||||||
|
const dep = self.b.dependency(moduleName, .{ .target = self.target, .optimize = self.optimize, .static_build = self.staticBuild });
|
||||||
|
mod.addImport(moduleName, dep.module(moduleName));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn addDependencyInstalls(self: *BuildSystem, b: *std.Build, optimize: std.builtin.OptimizeMode) void {
|
||||||
|
//if (self.staticBuild) {
|
||||||
|
//return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
inline for (DynamicDepList) |d| {
|
||||||
|
b.installArtifact(b.dependency(
|
||||||
|
d.dep,
|
||||||
|
.{ .target = self.target, .optimize = optimize, .static_build = self.staticBuild },
|
||||||
|
).artifact(d.artifact));
|
||||||
|
}
|
||||||
|
|
||||||
|
// b.installArtifact(b.dependency(
|
||||||
|
// "sdl3",
|
||||||
|
// .{ .target = self.target, .optimize = optimize, .static_build = self.staticBuild },
|
||||||
|
// ).artifact("SDL3"));
|
||||||
|
}
|
||||||
|
|
||||||
|
const DynamicDepList: []const struct { dep: []const u8, artifact: []const u8 } = &.{
|
||||||
|
.{ .dep = "sdl3", .artifact = "SDL3" },
|
||||||
|
.{ .dep = "spng", .artifact = "spng_c" },
|
||||||
|
.{ .dep = "lua", .artifact = "luac" },
|
||||||
|
.{ .dep = "miniaudio", .artifact = "miniaudio_c" },
|
||||||
|
.{ .dep = "zphysics", .artifact = "joltc" },
|
||||||
|
// .{ .dep = "enet", .artifact = "enet_c" },
|
||||||
|
.{ .dep = "ozz", .artifact = "ozz_cpp" },
|
||||||
|
};
|
||||||
|
|
||||||
|
// all other modules are disabled by default
|
||||||
|
pub const defaultEnabledModules: []const []const u8 = &.{
|
||||||
|
"core",
|
||||||
|
"assets",
|
||||||
|
"platform",
|
||||||
|
"rend",
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const moduleOrder: []const []const u8 = &.{
|
||||||
|
"core",
|
||||||
|
"sys",
|
||||||
|
"assets",
|
||||||
|
"platform",
|
||||||
|
"net",
|
||||||
|
"physics",
|
||||||
|
"audio",
|
||||||
|
"rend",
|
||||||
|
"ui",
|
||||||
|
"imgui",
|
||||||
|
"papyrus",
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const DynamicModule = struct {
|
||||||
|
name: []const u8,
|
||||||
|
allocator: std.mem.Allocator,
|
||||||
|
buildSystem: *BuildSystem,
|
||||||
|
programName: []const u8,
|
||||||
|
opts: AddProgramOptions,
|
||||||
|
|
||||||
|
extras: std.ArrayListUnmanaged(GameModule) = .{},
|
||||||
|
gameModules: std.ArrayListUnmanaged(GameModule) = .{},
|
||||||
|
|
||||||
|
library: ?*std.Build.Step.Compile = null,
|
||||||
|
|
||||||
|
pub fn addExtraModule(self: *@This(), module: []const u8) void {
|
||||||
|
self.extras.append(self.allocator, .{ .name = module, .enabled = true }) catch @panic("out of memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init(name: []const u8, p: *Program) *@This() {
|
||||||
|
var self: *@This() = p.allocator.create(@This()) catch @panic("out of memory");
|
||||||
|
|
||||||
|
self.* = .{
|
||||||
|
.opts = p.opts,
|
||||||
|
.programName = p.opts.name,
|
||||||
|
.buildSystem = p.buildSystem,
|
||||||
|
.allocator = p.allocator,
|
||||||
|
.name = name,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (p.gameModules.items) |module| {
|
||||||
|
self.gameModules.append(self.allocator, module) catch @panic("out of memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (p.extras.items) |module| {
|
||||||
|
self.extras.append(self.allocator, module) catch @panic("out of memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compileInstall(self: *@This()) *std.Build.Step.Compile {
|
||||||
|
if (self.library) |lib| {
|
||||||
|
return lib;
|
||||||
|
}
|
||||||
|
|
||||||
|
const b = self.buildSystem.b;
|
||||||
|
const static = self.buildSystem.staticBuild;
|
||||||
|
const lib = b.addLibrary(.{
|
||||||
|
.name = self.name,
|
||||||
|
.linkage = if (static) .static else .dynamic,
|
||||||
|
.root_module = b.createModule(.{
|
||||||
|
.root_source_file = self.opts.root_source_file,
|
||||||
|
.link_libc = true,
|
||||||
|
.optimize = self.buildSystem.optimize,
|
||||||
|
.target = self.buildSystem.target,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const allocator = self.buildSystem.b.allocator;
|
||||||
|
|
||||||
|
var modlist = std.ArrayList([]const u8){};
|
||||||
|
|
||||||
|
for (self.gameModules.items) |mod| {
|
||||||
|
if (mod.enabled) {
|
||||||
|
modlist.append(allocator, mod.name) catch @panic("out of memory");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (self.extras.items) |extra| {
|
||||||
|
self.buildSystem.addExtraModule(lib.root_module, extra.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
lib.root_module.addImport("backlog", self.buildSystem.generateApi(self.name, modlist.items, null));
|
||||||
|
lib.root_module.addOptions("BacklogOptions", self.buildSystem.options);
|
||||||
|
|
||||||
|
if (static) {
|
||||||
|
// generateApi should create static callers for the main program
|
||||||
|
} else {
|
||||||
|
const installExtern = b.addInstallArtifact(lib, .{
|
||||||
|
.dest_dir = .{ .override = .{ .custom = "modules" } },
|
||||||
|
});
|
||||||
|
b.getInstallStep().dependOn(&installExtern.step);
|
||||||
|
}
|
||||||
|
|
||||||
|
return lib;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const GameModule = struct {
|
||||||
|
name: []const u8,
|
||||||
|
enabled: bool = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Program = struct {
|
||||||
|
allocator: std.mem.Allocator,
|
||||||
|
opts: AddProgramOptions,
|
||||||
|
gameModules: std.ArrayListUnmanaged(GameModule) = .{},
|
||||||
|
extras: std.ArrayListUnmanaged(GameModule) = .{},
|
||||||
|
dynamicModules: std.ArrayListUnmanaged(*DynamicModule) = .{},
|
||||||
|
buildSystem: *BuildSystem,
|
||||||
|
|
||||||
|
iconPath: ?std.Build.LazyPath = null,
|
||||||
|
|
||||||
|
pub fn setIconPath(self: *@This(), path: []const u8) void {
|
||||||
|
if (self.iconPath != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.iconPath = self.buildSystem.generateRc(self.opts.name, path) catch return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setModuleEnabled(self: *@This(), module: []const u8, enable: bool) void {
|
||||||
|
for (self.gameModules.items) |*m| {
|
||||||
|
if (std.mem.eql(u8, m.name, module)) {
|
||||||
|
m.enabled = enable;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// module not found, add it here.
|
||||||
|
self.gameModules.append(self.allocator, .{ .name = module, .enabled = enable }) catch @panic("out of memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn addExtraModule(self: *@This(), module: []const u8) void {
|
||||||
|
self.extras.append(self.allocator, .{ .name = module, .enabled = true }) catch @panic("out of memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn addDynamicModule(self: *@This(), module: []const u8, root_source_file: std.Build.LazyPath) *DynamicModule {
|
||||||
|
const dynamicModule = DynamicModule.init(module, self);
|
||||||
|
dynamicModule.opts.root_source_file = root_source_file;
|
||||||
|
self.dynamicModules.append(self.allocator, dynamicModule) catch @panic("out of memory");
|
||||||
|
|
||||||
|
return dynamicModule;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compileInstall(self: *@This()) *std.Build.Module {
|
||||||
|
const exe = self.buildSystem.addProgram(self.opts);
|
||||||
|
const allocator = self.buildSystem.b.allocator;
|
||||||
|
|
||||||
|
var modlist = std.ArrayList([]const u8){};
|
||||||
|
|
||||||
|
for (self.gameModules.items) |mod| {
|
||||||
|
if (mod.enabled) {
|
||||||
|
modlist.append(allocator, mod.name) catch @panic("out of memory");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (self.extras.items) |extra| {
|
||||||
|
self.buildSystem.addExtraModule(exe, extra.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
exe.addImport("backlog", self.buildSystem.generateApi(self.opts.name, modlist.items, self.dynamicModules.items));
|
||||||
|
|
||||||
|
if (self.buildSystem.target.result.os.tag == .windows) {
|
||||||
|
if (self.iconPath) |ip| {
|
||||||
|
exe.addWin32ResourceFile(.{
|
||||||
|
.file = ip,
|
||||||
|
.flags = &.{},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return exe;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn program(self: *BuildSystem, opts: AddProgramOptions) *Program {
|
||||||
|
const prog = self.b.allocator.create(Program) catch unreachable;
|
||||||
|
|
||||||
|
prog.* = .{
|
||||||
|
.allocator = self.b.allocator,
|
||||||
|
.opts = opts,
|
||||||
|
.buildSystem = self,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (moduleOrder) |module| {
|
||||||
|
prog.setModuleEnabled(module, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (defaultEnabledModules) |module| {
|
||||||
|
prog.setModuleEnabled(module, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return prog;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========= standalone build instance =======
|
||||||
|
// maybe the default should be like an engine launcher/project launcher or something
|
||||||
|
pub fn build(b: *std.Build) void {
|
||||||
|
const target = b.standardTargetOptions(.{});
|
||||||
|
const optimize = b.standardOptimizeOption(.{});
|
||||||
|
const static_build = b.option(bool, "static_build", "builds backlog dependencies for static linking") orelse false;
|
||||||
|
|
||||||
|
const fwdGeneratorExe = b.addExecutable(.{
|
||||||
|
.name = "backlog-generate-fwd",
|
||||||
|
.root_module = b.createModule(.{
|
||||||
|
.target = b.graph.host,
|
||||||
|
.optimize = .Debug,
|
||||||
|
.root_source_file = b.path("build/generateFwd.zig"),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const generateExe = b.addExecutable(.{
|
||||||
|
.name = "backlog-apigen",
|
||||||
|
.root_module = b.createModule(.{
|
||||||
|
.target = b.graph.host,
|
||||||
|
.optimize = .Debug,
|
||||||
|
.root_source_file = b.path("build/generateApi.zig"),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const generateShaders = b.addExecutable(.{
|
||||||
|
.name = "backlog-shaderEmbedGen",
|
||||||
|
.root_module = b.createModule(.{
|
||||||
|
.target = b.graph.host,
|
||||||
|
.optimize = .Debug,
|
||||||
|
.root_source_file = b.path("build/generateEmbeddedShaders.zig"),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const generateRcExe = b.addExecutable(.{
|
||||||
|
.name = "backlog-generate-rc",
|
||||||
|
.root_module = b.createModule(.{
|
||||||
|
.target = b.graph.host,
|
||||||
|
.optimize = .Debug,
|
||||||
|
.root_source_file = b.path("build/generateRc.zig"),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const generateLoadDynamicsExe = b.addExecutable(.{
|
||||||
|
.name = "backlog-generate-loadDynamics",
|
||||||
|
.root_module = b.createModule(.{
|
||||||
|
.target = b.graph.host,
|
||||||
|
.optimize = .Debug,
|
||||||
|
.root_source_file = b.path("build/generateLoadDynamics.zig"),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
b.installArtifact(generateLoadDynamicsExe);
|
||||||
|
b.installArtifact(generateExe);
|
||||||
|
b.installArtifact(generateShaders);
|
||||||
|
b.installArtifact(generateRcExe);
|
||||||
|
|
||||||
|
{
|
||||||
|
const loadDynamicsStub = b.addModule("loadDynamicsStub", .{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
.root_source_file = b.path("engine/loadDynamicsStub.zig"),
|
||||||
|
});
|
||||||
|
|
||||||
|
_ = loadDynamicsStub;
|
||||||
|
|
||||||
|
const mod = b.addModule("Backlog", .{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
.root_source_file = b.path("engine/backlog.zig"),
|
||||||
|
});
|
||||||
|
|
||||||
|
for (engineDepList) |depName| {
|
||||||
|
const dep = b.dependency(
|
||||||
|
depName,
|
||||||
|
.{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
.static_build = static_build,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const run = b.addRunArtifact(fwdGeneratorExe);
|
||||||
|
const output = run.addOutputFileArg(b.fmt("{s}_fwd.zig", .{depName}));
|
||||||
|
|
||||||
|
const modFwd = b.addModule(depName, .{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
.root_source_file = output,
|
||||||
|
});
|
||||||
|
|
||||||
|
mod.addImport(b.fmt("{s}", .{depName}), modFwd);
|
||||||
|
modFwd.addImport("module", dep.module(depName));
|
||||||
|
|
||||||
|
// mod.addImport(depName, dep.module(depName));
|
||||||
|
}
|
||||||
|
|
||||||
|
// link in large platform support functions... special case.
|
||||||
|
{
|
||||||
|
const dep = b.dependency("sdl3", .{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
.static_build = static_build,
|
||||||
|
});
|
||||||
|
const lib = dep.module("SDL3");
|
||||||
|
|
||||||
|
mod.addImport("sdl3_fwd", lib);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generateApi(self: *@This(), programName: []const u8, moduleList: []const []const u8, dynamicModules: ?[]const *DynamicModule) *std.Build.Module {
|
||||||
|
// std.debug.print("GENERATE API:: {s}\n", .{programName});
|
||||||
|
|
||||||
|
for (moduleList) |mod| {
|
||||||
|
_ = mod;
|
||||||
|
// std.debug.print("{s}\n", .{mod});
|
||||||
|
}
|
||||||
|
//
|
||||||
|
if (self.generatedApis.get(programName)) |m| {
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
const run = self.b.addRunArtifact(self.apigen);
|
||||||
|
const pfile = self.b.fmt("{s}Api.zig", .{programName});
|
||||||
|
const output = run.addOutputFileArg(pfile);
|
||||||
|
for (moduleList) |modName| {
|
||||||
|
run.addArg(modName);
|
||||||
|
}
|
||||||
|
|
||||||
|
const mod = self.b.addModule(pfile, .{
|
||||||
|
.target = self.target,
|
||||||
|
.optimize = self.optimize,
|
||||||
|
.root_source_file = output,
|
||||||
|
});
|
||||||
|
for (moduleList) |modName| {
|
||||||
|
mod.addImport(modName, self.nwdep.module(modName));
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadStatics = self.generateInstallStaticResources(programName, "content/_shaders") catch unreachable;
|
||||||
|
mod.addImport("staticShaderLoader", loadStatics);
|
||||||
|
|
||||||
|
// deal with dynamics
|
||||||
|
if (dynamicModules) |dynamics| {
|
||||||
|
const loadDynamics = self.generateLoadDynamics(programName, dynamics) catch @panic("unknown");
|
||||||
|
mod.addImport("loadDynamics", loadDynamics);
|
||||||
|
} else {
|
||||||
|
mod.addImport("loadDynamics", self.nwdep.module("loadDynamicsStub"));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.generatedApis.put(self.b.allocator, programName, mod) catch @panic("out of memory");
|
||||||
|
|
||||||
|
return mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generateRc(self: *@This(), programName: []const u8, iconPath: []const u8) !std.Build.LazyPath {
|
||||||
|
const run = self.b.addRunArtifact(self.rcGen);
|
||||||
|
const pfile = self.b.fmt("{s}.rc", .{programName});
|
||||||
|
const output = run.addOutputFileArg(pfile);
|
||||||
|
run.addArg(iconPath);
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generateLoadDynamics(self: *@This(), programName: []const u8, dynamics: []const *DynamicModule) !*std.Build.Module {
|
||||||
|
const run = self.b.addRunArtifact(self.loadDynamicsGen);
|
||||||
|
const pfile = self.b.fmt("{s}LoadDynamics.zig", .{programName});
|
||||||
|
const output = run.addOutputFileArg(pfile);
|
||||||
|
if (self.staticBuild) {
|
||||||
|
run.addArg("static");
|
||||||
|
} else {
|
||||||
|
run.addArg("dynamic");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (dynamics) |dyn| {
|
||||||
|
run.addArg(dyn.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
const mod = self.b.addModule(pfile, .{
|
||||||
|
.target = self.target,
|
||||||
|
.optimize = self.optimize,
|
||||||
|
.root_source_file = output,
|
||||||
|
});
|
||||||
|
|
||||||
|
mod.addImport("core", self.nwdep.module("core"));
|
||||||
|
for (dynamics) |dyn| {
|
||||||
|
const dynmod = dyn.compileInstall();
|
||||||
|
mod.addImport(dyn.name, dynmod.root_module);
|
||||||
|
}
|
||||||
|
|
||||||
|
return mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generateInstallStaticResources(self: *@This(), programName: []const u8, shadersPath: []const u8) !*std.Build.Module {
|
||||||
|
const run = self.b.addRunArtifact(self.shaderEmbedGen);
|
||||||
|
const pfile = self.b.fmt("{s}ShaderGen.zig", .{programName});
|
||||||
|
const output = run.addOutputFileArg(pfile);
|
||||||
|
run.addArg(shadersPath);
|
||||||
|
|
||||||
|
const b = self.b;
|
||||||
|
const mod = self.b.addModule(pfile, .{
|
||||||
|
.target = self.target,
|
||||||
|
.optimize = self.optimize,
|
||||||
|
.root_source_file = output,
|
||||||
|
});
|
||||||
|
mod.addImport("core", self.nwdep.module("core"));
|
||||||
|
|
||||||
|
var dir = try std.fs.cwd().openDir("content/_shaders", .{ .iterate = true });
|
||||||
|
defer dir.close();
|
||||||
|
|
||||||
|
var walker = dir.iterate();
|
||||||
|
while (try walker.next()) |shaderType| {
|
||||||
|
if (shaderType.kind == .directory) {
|
||||||
|
var d2 = try dir.openDir(shaderType.name, .{ .iterate = true });
|
||||||
|
defer d2.close();
|
||||||
|
var w2 = d2.iterate();
|
||||||
|
while (try w2.next()) |shaderName| {
|
||||||
|
const shaderPath = b.fmt("content/_shaders/{s}/{s}", .{ shaderType.name, shaderName.name });
|
||||||
|
mod.addAnonymousImport(shaderName.name, .{
|
||||||
|
.root_source_file = b.path(shaderPath),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mod;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,696 @@
|
||||||
|
// MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS=1 -- use this if you're getting that odd crash on mac
|
||||||
|
b: *std.Build,
|
||||||
|
nw_builder: *std.Build,
|
||||||
|
target: std.Build.ResolvedTarget,
|
||||||
|
optimize: std.builtin.Mode,
|
||||||
|
nw_mod: *std.Build.Module,
|
||||||
|
spirvReflect: SpirvReflect.SpirvGenerator2,
|
||||||
|
gltf2ozz: ozz.GltfToOzz,
|
||||||
|
options: *std.Build.Step.Options,
|
||||||
|
cookShaders: bool,
|
||||||
|
|
||||||
|
backlogRoot: []const u8,
|
||||||
|
// list of all shaders discovered under
|
||||||
|
// content/_shaders/def
|
||||||
|
reflectShaderPathList: [][]u8 = undefined,
|
||||||
|
|
||||||
|
staticBuild: bool = false,
|
||||||
|
|
||||||
|
nwdep: *std.Build.Dependency,
|
||||||
|
apigen: *std.Build.Step.Compile,
|
||||||
|
shaderEmbedGen: *std.Build.Step.Compile,
|
||||||
|
loadDynamicsGen: *std.Build.Step.Compile,
|
||||||
|
rcGen: *std.Build.Step.Compile,
|
||||||
|
generatedApis: std.StringHashMapUnmanaged(*std.Build.Module) = .{},
|
||||||
|
|
||||||
|
const engineDepList = [_][]const u8{
|
||||||
|
"assets",
|
||||||
|
"audio",
|
||||||
|
"core",
|
||||||
|
"net",
|
||||||
|
"papyrus",
|
||||||
|
"platform",
|
||||||
|
"rend",
|
||||||
|
"ui",
|
||||||
|
"imgui",
|
||||||
|
"physics",
|
||||||
|
"sys",
|
||||||
|
};
|
||||||
|
|
||||||
|
const BuildSystem = @This();
|
||||||
|
const std = @import("std");
|
||||||
|
const Build = std.Build;
|
||||||
|
const LazyPath = Build.LazyPath;
|
||||||
|
|
||||||
|
const SpirvReflect = @import("SpirvReflect");
|
||||||
|
const ozz = @import("ozz");
|
||||||
|
|
||||||
|
pub const InitOptions = struct {
|
||||||
|
import_name: []const u8 = "Backlog",
|
||||||
|
backlogRoot: []const u8 = "./BacklogEngine",
|
||||||
|
staticBuild: bool = false,
|
||||||
|
target: Build.ResolvedTarget,
|
||||||
|
optimize: std.builtin.OptimizeMode,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn init(b: *std.Build, opts: InitOptions) BuildSystem {
|
||||||
|
var buildOpts = declareBuildOptions(b);
|
||||||
|
|
||||||
|
if (opts.target.result.os.tag == .linux) {
|
||||||
|
// using a static build for linux... object loading hell is not fun
|
||||||
|
std.debug.print("Important! only supporting static builds for linux", .{});
|
||||||
|
buildOpts.static_build = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const nwdep = b.dependency(opts.import_name, .{
|
||||||
|
.target = opts.target,
|
||||||
|
.optimize = opts.optimize,
|
||||||
|
.static_build = buildOpts.static_build,
|
||||||
|
});
|
||||||
|
|
||||||
|
var self = BuildSystem{
|
||||||
|
.b = b,
|
||||||
|
.nw_builder = nwdep.builder,
|
||||||
|
.target = opts.target,
|
||||||
|
.optimize = opts.optimize,
|
||||||
|
.nw_mod = nwdep.module("Backlog"),
|
||||||
|
.backlogRoot = opts.backlogRoot,
|
||||||
|
.spirvReflect = SpirvReflect.SpirvGenerator2.init(nwdep.builder, .{}),
|
||||||
|
.options = createGameOptions(b, buildOpts),
|
||||||
|
.gltf2ozz = ozz.GltfToOzz.init(nwdep.builder, .{}),
|
||||||
|
.cookShaders = b.option(bool, "cookShaders", "generates shaders and updates .json files before running the build. (needs to be done whenever shaders are updated, this just runs tools/scripts/cook-shaders.py)") orelse false,
|
||||||
|
|
||||||
|
.staticBuild = buildOpts.static_build,
|
||||||
|
.nwdep = nwdep,
|
||||||
|
.apigen = nwdep.artifact("backlog-apigen"),
|
||||||
|
.loadDynamicsGen = nwdep.artifact("backlog-generate-loadDynamics"),
|
||||||
|
.rcGen = nwdep.artifact("backlog-generate-rc"),
|
||||||
|
.shaderEmbedGen = nwdep.artifact("backlog-shaderEmbedGen"),
|
||||||
|
};
|
||||||
|
|
||||||
|
const exeList = [2]*std.Build.Step.Compile{ self.gltf2ozz.exe, self.spirvReflect.reflect };
|
||||||
|
const install_tools = b.step("tools", "installs tools needed to generate outputs for the engine");
|
||||||
|
for (exeList) |exe| {
|
||||||
|
const toolsInstall = b.addInstallArtifact(exe, .{
|
||||||
|
.dest_dir = .{ .override = .{ .custom = "tools" } },
|
||||||
|
});
|
||||||
|
|
||||||
|
install_tools.dependOn(&toolsInstall.step);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const runArtifact = b.addRunArtifact(self.gltf2ozz.exe);
|
||||||
|
if (b.args) |args| {
|
||||||
|
runArtifact.addArgs(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
const run_exe = b.step("gltf2ozz", "runs the gltf animation converter.");
|
||||||
|
run_exe.dependOn(&runArtifact.step);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const runArtifact = b.addRunArtifact(self.spirvReflect.reflect);
|
||||||
|
if (b.args) |args| {
|
||||||
|
runArtifact.addArgs(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
const run_exe = b.step("spv-reflect", "runs the gltf animation converter.");
|
||||||
|
run_exe.dependOn(&runArtifact.step);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.addDependencyInstalls(self.b, .ReleaseFast);
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const AddProgramOptions = struct {
|
||||||
|
name: []const u8,
|
||||||
|
desc: []const u8,
|
||||||
|
root_source_file: LazyPath,
|
||||||
|
imports: []const Build.Module.Import = &.{},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn addProgram(self: *BuildSystem, opts: AddProgramOptions) *std.Build.Module {
|
||||||
|
const b = self.b;
|
||||||
|
|
||||||
|
const exe = self.nw_builder.addExecutable(.{
|
||||||
|
.name = opts.name,
|
||||||
|
.target = self.target,
|
||||||
|
.optimize = self.optimize,
|
||||||
|
.root_source_file = self.nw_builder.path("engine/main.zig"),
|
||||||
|
});
|
||||||
|
|
||||||
|
b.installArtifact(exe);
|
||||||
|
const runArtifact = b.addRunArtifact(exe);
|
||||||
|
if (b.args) |args| {
|
||||||
|
runArtifact.addArgs(args);
|
||||||
|
}
|
||||||
|
const run_exe = b.step(self.b.fmt("run-{s}", .{opts.name}), opts.desc);
|
||||||
|
run_exe.dependOn(&runArtifact.step);
|
||||||
|
|
||||||
|
// main path = name/main.zig
|
||||||
|
const mod = b.addModule(opts.name, .{
|
||||||
|
.target = self.target,
|
||||||
|
.optimize = self.optimize,
|
||||||
|
.root_source_file = opts.root_source_file,
|
||||||
|
.imports = opts.imports,
|
||||||
|
});
|
||||||
|
|
||||||
|
exe.root_module.addImport("main", mod);
|
||||||
|
// todo.. remove this one and see what happens
|
||||||
|
exe.root_module.addImport("core", self.nwdep.module("core"));
|
||||||
|
// mod.addImport("Backlog", self.nw_mod);
|
||||||
|
exe.root_module.addOptions("BacklogOptions", self.options);
|
||||||
|
|
||||||
|
if (self.cookShaders) {
|
||||||
|
const cookShadersScript = b.fmt("{s}/tools/scripts/cookShaders.py", .{self.backlogRoot});
|
||||||
|
const cookShadersCommand = b.addSystemCommand(&[_][]const u8{"python"});
|
||||||
|
cookShadersCommand.addArg(cookShadersScript);
|
||||||
|
|
||||||
|
run_exe.dependOn(&cookShadersCommand.step);
|
||||||
|
}
|
||||||
|
|
||||||
|
b.getInstallStep().dependOn(self.nw_builder.getInstallStep());
|
||||||
|
|
||||||
|
// run_exe.dependOn(b.getInstallStep());
|
||||||
|
|
||||||
|
return mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const BuildOptions = struct {
|
||||||
|
mutex_job_queue: bool,
|
||||||
|
static_build: bool,
|
||||||
|
zero_logging: bool,
|
||||||
|
slow_logging: bool,
|
||||||
|
force_mailbox: bool,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn declareBuildOptions(b: *std.Build) BuildOptions {
|
||||||
|
return .{
|
||||||
|
.mutex_job_queue = b.option(bool, "mutex_job_queue", "temporary test, reverts to old mutex based queue behaviour in jobs.zig:JobManager") orelse false,
|
||||||
|
.static_build = b.option(bool, "static_build", "builds the entire game as a single executable") orelse false,
|
||||||
|
.zero_logging = b.option(bool, "zero_logging", "disables all logging, only intended for use on job dispatch testing") orelse false,
|
||||||
|
.slow_logging = b.option(bool, "slow_logging", "Disables buffered logging, takes a hit to performance but gain timing information on logging") orelse false,
|
||||||
|
.force_mailbox = b.option(bool, "force_mailbox", "forces mailbox mode for present mode. unlocks framerate to irresponsible levels") orelse false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn createGameOptions(b: *std.Build, options: BuildOptions) *std.Build.Step.Options {
|
||||||
|
const opts = b.addOptions();
|
||||||
|
|
||||||
|
inline for (@typeInfo(BuildOptions).@"struct".fields) |field| {
|
||||||
|
opts.addOption(bool, field.name, @field(options, field.name));
|
||||||
|
}
|
||||||
|
|
||||||
|
// build options for core.zig
|
||||||
|
// opts.addOption(
|
||||||
|
// bool,
|
||||||
|
// "mutex_job_queue",
|
||||||
|
// );
|
||||||
|
|
||||||
|
// opts.addOption(
|
||||||
|
// bool,
|
||||||
|
// "static_build",
|
||||||
|
// );
|
||||||
|
|
||||||
|
// opts.addOption(
|
||||||
|
// bool,
|
||||||
|
// "zero_logging",
|
||||||
|
// );
|
||||||
|
// opts.addOption(
|
||||||
|
// bool,
|
||||||
|
// "slow_logging",
|
||||||
|
// );
|
||||||
|
// opts.addOption(
|
||||||
|
// bool,
|
||||||
|
// "force_mailbox",
|
||||||
|
// );
|
||||||
|
|
||||||
|
return opts;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn addExtraModule(self: *BuildSystem, mod: *std.Build.Module, moduleName: []const u8) void {
|
||||||
|
const dep = self.b.dependency(moduleName, .{ .target = self.target, .optimize = self.optimize, .static_build = self.staticBuild });
|
||||||
|
mod.addImport(moduleName, dep.module(moduleName));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn addDependencyInstalls(self: *BuildSystem, b: *std.Build, optimize: std.builtin.OptimizeMode) void {
|
||||||
|
//if (self.staticBuild) {
|
||||||
|
//return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
inline for (DynamicDepList) |d| {
|
||||||
|
b.installArtifact(b.dependency(
|
||||||
|
d.dep,
|
||||||
|
.{ .target = self.target, .optimize = optimize, .static_build = self.staticBuild },
|
||||||
|
).artifact(d.artifact));
|
||||||
|
}
|
||||||
|
|
||||||
|
// b.installArtifact(b.dependency(
|
||||||
|
// "sdl3",
|
||||||
|
// .{ .target = self.target, .optimize = optimize, .static_build = self.staticBuild },
|
||||||
|
// ).artifact("SDL3"));
|
||||||
|
}
|
||||||
|
|
||||||
|
const DynamicDepList: []const struct { dep: []const u8, artifact: []const u8 } = &.{
|
||||||
|
.{ .dep = "sdl3", .artifact = "SDL3" },
|
||||||
|
.{ .dep = "spng", .artifact = "spng_c" },
|
||||||
|
.{ .dep = "lua", .artifact = "luac" },
|
||||||
|
// .{ .dep = "miniaudio", .artifact = "miniaudio_c" },
|
||||||
|
.{ .dep = "zphysics", .artifact = "joltc" },
|
||||||
|
// .{ .dep = "enet", .artifact = "enet_c" },
|
||||||
|
.{ .dep = "ozz", .artifact = "ozz_cpp" },
|
||||||
|
};
|
||||||
|
|
||||||
|
// all other modules are disabled by default
|
||||||
|
pub const defaultEnabledModules: []const []const u8 = &.{
|
||||||
|
"core",
|
||||||
|
"assets",
|
||||||
|
"platform",
|
||||||
|
"rend",
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const moduleOrder: []const []const u8 = &.{
|
||||||
|
"core",
|
||||||
|
"sys",
|
||||||
|
"assets",
|
||||||
|
"platform",
|
||||||
|
"net",
|
||||||
|
"physics",
|
||||||
|
"audio",
|
||||||
|
"rend",
|
||||||
|
"ui",
|
||||||
|
"imgui",
|
||||||
|
"papyrus",
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const DynamicModule = struct {
|
||||||
|
name: []const u8,
|
||||||
|
allocator: std.mem.Allocator,
|
||||||
|
buildSystem: *BuildSystem,
|
||||||
|
programName: []const u8,
|
||||||
|
opts: AddProgramOptions,
|
||||||
|
|
||||||
|
extras: std.ArrayListUnmanaged(GameModule) = .{},
|
||||||
|
gameModules: std.ArrayListUnmanaged(GameModule) = .{},
|
||||||
|
|
||||||
|
library: ?*std.Build.Step.Compile = null,
|
||||||
|
|
||||||
|
pub fn addExtraModule(self: *@This(), module: []const u8) void {
|
||||||
|
self.extras.append(self.allocator, .{ .name = module, .enabled = true }) catch @panic("out of memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init(name: []const u8, p: *Program) *@This() {
|
||||||
|
var self: *@This() = p.allocator.create(@This()) catch @panic("out of memory");
|
||||||
|
|
||||||
|
self.* = .{
|
||||||
|
.opts = p.opts,
|
||||||
|
.programName = p.opts.name,
|
||||||
|
.buildSystem = p.buildSystem,
|
||||||
|
.allocator = p.allocator,
|
||||||
|
.name = name,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (p.gameModules.items) |module| {
|
||||||
|
self.gameModules.append(self.allocator, module) catch @panic("out of memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (p.extras.items) |module| {
|
||||||
|
self.extras.append(self.allocator, module) catch @panic("out of memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compileInstall(self: *@This()) *std.Build.Step.Compile {
|
||||||
|
if (self.library) |lib| {
|
||||||
|
return lib;
|
||||||
|
}
|
||||||
|
|
||||||
|
const b = self.buildSystem.b;
|
||||||
|
const static = self.buildSystem.staticBuild;
|
||||||
|
const lib = if (static)
|
||||||
|
b.addStaticLibrary(.{
|
||||||
|
.root_source_file = self.opts.root_source_file,
|
||||||
|
.link_libc = true,
|
||||||
|
.optimize = self.buildSystem.optimize,
|
||||||
|
.target = self.buildSystem.target,
|
||||||
|
.name = self.name,
|
||||||
|
})
|
||||||
|
else
|
||||||
|
b.addSharedLibrary(.{
|
||||||
|
.root_source_file = self.opts.root_source_file,
|
||||||
|
.link_libc = true,
|
||||||
|
.optimize = self.buildSystem.optimize,
|
||||||
|
.target = self.buildSystem.target,
|
||||||
|
.name = self.name,
|
||||||
|
});
|
||||||
|
|
||||||
|
var modlist = std.ArrayList([]const u8).init(self.buildSystem.b.allocator);
|
||||||
|
|
||||||
|
for (self.gameModules.items) |mod| {
|
||||||
|
if (mod.enabled) {
|
||||||
|
modlist.append(mod.name) catch @panic("out of memory");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (self.extras.items) |extra| {
|
||||||
|
self.buildSystem.addExtraModule(lib.root_module, extra.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
lib.root_module.addImport("backlog", self.buildSystem.generateApi(self.name, modlist.items, null));
|
||||||
|
lib.root_module.addOptions("BacklogOptions", self.buildSystem.options);
|
||||||
|
|
||||||
|
if (static) {
|
||||||
|
// generateApi should create static callers for the main program
|
||||||
|
} else {
|
||||||
|
const installExtern = b.addInstallArtifact(lib, .{
|
||||||
|
.dest_dir = .{ .override = .{ .custom = "modules" } },
|
||||||
|
});
|
||||||
|
b.getInstallStep().dependOn(&installExtern.step);
|
||||||
|
}
|
||||||
|
|
||||||
|
return lib;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const GameModule = struct {
|
||||||
|
name: []const u8,
|
||||||
|
enabled: bool = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Program = struct {
|
||||||
|
allocator: std.mem.Allocator,
|
||||||
|
opts: AddProgramOptions,
|
||||||
|
gameModules: std.ArrayListUnmanaged(GameModule) = .{},
|
||||||
|
extras: std.ArrayListUnmanaged(GameModule) = .{},
|
||||||
|
dynamicModules: std.ArrayListUnmanaged(*DynamicModule) = .{},
|
||||||
|
buildSystem: *BuildSystem,
|
||||||
|
|
||||||
|
iconPath: ?std.Build.LazyPath = null,
|
||||||
|
|
||||||
|
pub fn setIconPath(self: *@This(), path: []const u8) void {
|
||||||
|
if (self.iconPath != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.iconPath = self.buildSystem.generateRc(self.opts.name, path) catch return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setModuleEnabled(self: *@This(), module: []const u8, enable: bool) void {
|
||||||
|
for (self.gameModules.items) |*m| {
|
||||||
|
if (std.mem.eql(u8, m.name, module)) {
|
||||||
|
m.enabled = enable;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// module not found, add it here.
|
||||||
|
self.gameModules.append(self.allocator, .{ .name = module, .enabled = enable }) catch @panic("out of memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn addExtraModule(self: *@This(), module: []const u8) void {
|
||||||
|
self.extras.append(self.allocator, .{ .name = module, .enabled = true }) catch @panic("out of memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn addDynamicModule(self: *@This(), module: []const u8, root_source_file: std.Build.LazyPath) *DynamicModule {
|
||||||
|
const dynamicModule = DynamicModule.init(module, self);
|
||||||
|
dynamicModule.opts.root_source_file = root_source_file;
|
||||||
|
self.dynamicModules.append(self.allocator, dynamicModule) catch @panic("out of memory");
|
||||||
|
|
||||||
|
return dynamicModule;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compileInstall(self: *@This()) *std.Build.Module {
|
||||||
|
const exe = self.buildSystem.addProgram(self.opts);
|
||||||
|
var modlist = std.ArrayList([]const u8).init(self.buildSystem.b.allocator);
|
||||||
|
|
||||||
|
for (self.gameModules.items) |mod| {
|
||||||
|
if (mod.enabled) {
|
||||||
|
modlist.append(mod.name) catch @panic("out of memory");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (self.extras.items) |extra| {
|
||||||
|
self.buildSystem.addExtraModule(exe, extra.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
exe.addImport("backlog", self.buildSystem.generateApi(self.opts.name, modlist.items, self.dynamicModules.items));
|
||||||
|
|
||||||
|
if (self.buildSystem.target.result.os.tag == .windows) {
|
||||||
|
if (self.iconPath) |ip| {
|
||||||
|
exe.addWin32ResourceFile(.{
|
||||||
|
.file = ip,
|
||||||
|
.flags = &.{},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return exe;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn program(self: *BuildSystem, opts: AddProgramOptions) *Program {
|
||||||
|
const prog = self.b.allocator.create(Program) catch unreachable;
|
||||||
|
|
||||||
|
prog.* = .{
|
||||||
|
.allocator = self.b.allocator,
|
||||||
|
.opts = opts,
|
||||||
|
.buildSystem = self,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (moduleOrder) |module| {
|
||||||
|
prog.setModuleEnabled(module, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (defaultEnabledModules) |module| {
|
||||||
|
prog.setModuleEnabled(module, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return prog;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========= standalone build instance =======
|
||||||
|
// maybe the default should be like an engine launcher/project launcher or something
|
||||||
|
pub fn build(b: *std.Build) void {
|
||||||
|
const target = b.standardTargetOptions(.{});
|
||||||
|
const optimize = b.standardOptimizeOption(.{});
|
||||||
|
const static_build = b.option(bool, "static_build", "builds backlog dependencies for static linking") orelse false;
|
||||||
|
|
||||||
|
const spirvDep = b.dependency("SpirvReflect", .{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
.static_build = static_build,
|
||||||
|
});
|
||||||
|
_ = spirvDep;
|
||||||
|
|
||||||
|
const fwdGeneratorExe = b.addExecutable(.{
|
||||||
|
.name = "backlog-generate-fwd",
|
||||||
|
.target = b.graph.host,
|
||||||
|
.optimize = .Debug,
|
||||||
|
.root_source_file = b.path("build/generateFwd.zig"),
|
||||||
|
});
|
||||||
|
|
||||||
|
const generateExe = b.addExecutable(.{
|
||||||
|
.name = "backlog-apigen",
|
||||||
|
.target = b.graph.host,
|
||||||
|
.optimize = .Debug,
|
||||||
|
.root_source_file = b.path("build/generateApi.zig"),
|
||||||
|
});
|
||||||
|
|
||||||
|
const generateShaders = b.addExecutable(.{
|
||||||
|
.name = "backlog-shaderEmbedGen",
|
||||||
|
.target = b.graph.host,
|
||||||
|
.optimize = .Debug,
|
||||||
|
.root_source_file = b.path("build/generateEmbeddedShaders.zig"),
|
||||||
|
});
|
||||||
|
|
||||||
|
const generateRcExe = b.addExecutable(.{
|
||||||
|
.name = "backlog-generate-rc",
|
||||||
|
.target = b.graph.host,
|
||||||
|
.optimize = .Debug,
|
||||||
|
.root_source_file = b.path("build/generateRc.zig"),
|
||||||
|
});
|
||||||
|
|
||||||
|
const generateLoadDynamicsExe = b.addExecutable(.{
|
||||||
|
.name = "backlog-generate-loadDynamics",
|
||||||
|
.target = b.graph.host,
|
||||||
|
.optimize = .Debug,
|
||||||
|
.root_source_file = b.path("build/generateLoadDynamics.zig"),
|
||||||
|
});
|
||||||
|
|
||||||
|
b.installArtifact(generateLoadDynamicsExe);
|
||||||
|
b.installArtifact(generateExe);
|
||||||
|
b.installArtifact(generateShaders);
|
||||||
|
b.installArtifact(generateRcExe);
|
||||||
|
|
||||||
|
{
|
||||||
|
const loadDynamicsStub = b.addModule("loadDynamicsStub", .{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
.root_source_file = b.path("engine/loadDynamicsStub.zig"),
|
||||||
|
});
|
||||||
|
|
||||||
|
_ = loadDynamicsStub;
|
||||||
|
|
||||||
|
const mod = b.addModule("Backlog", .{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
.root_source_file = b.path("engine/backlog.zig"),
|
||||||
|
});
|
||||||
|
|
||||||
|
for (engineDepList) |depName| {
|
||||||
|
const dep = b.dependency(
|
||||||
|
depName,
|
||||||
|
.{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
.static_build = static_build,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const run = b.addRunArtifact(fwdGeneratorExe);
|
||||||
|
const output = run.addOutputFileArg(b.fmt("{s}_fwd.zig", .{depName}));
|
||||||
|
|
||||||
|
const modFwd = b.addModule(depName, .{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
.root_source_file = output,
|
||||||
|
});
|
||||||
|
|
||||||
|
mod.addImport(b.fmt("{s}", .{depName}), modFwd);
|
||||||
|
modFwd.addImport("module", dep.module(depName));
|
||||||
|
|
||||||
|
// mod.addImport(depName, dep.module(depName));
|
||||||
|
}
|
||||||
|
|
||||||
|
// link in large platform support functions... special case.
|
||||||
|
{
|
||||||
|
const dep = b.dependency("sdl3", .{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
.static_build = static_build,
|
||||||
|
});
|
||||||
|
const lib = dep.module("SDL3");
|
||||||
|
|
||||||
|
mod.addImport("sdl3_fwd", lib);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generateApi(self: *@This(), programName: []const u8, moduleList: []const []const u8, dynamicModules: ?[]const *DynamicModule) *std.Build.Module {
|
||||||
|
// std.debug.print("GENERATE API:: {s}\n", .{programName});
|
||||||
|
|
||||||
|
for (moduleList) |mod| {
|
||||||
|
_ = mod;
|
||||||
|
// std.debug.print("{s}\n", .{mod});
|
||||||
|
}
|
||||||
|
//
|
||||||
|
if (self.generatedApis.get(programName)) |m| {
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
const run = self.b.addRunArtifact(self.apigen);
|
||||||
|
const pfile = self.b.fmt("{s}Api.zig", .{programName});
|
||||||
|
const output = run.addOutputFileArg(pfile);
|
||||||
|
for (moduleList) |modName| {
|
||||||
|
run.addArg(modName);
|
||||||
|
}
|
||||||
|
|
||||||
|
const mod = self.b.addModule(pfile, .{
|
||||||
|
.target = self.target,
|
||||||
|
.optimize = self.optimize,
|
||||||
|
.root_source_file = output,
|
||||||
|
});
|
||||||
|
for (moduleList) |modName| {
|
||||||
|
mod.addImport(modName, self.nwdep.module(modName));
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadStatics = self.generateInstallStaticResources(programName, "content/_shaders") catch unreachable;
|
||||||
|
mod.addImport("staticShaderLoader", loadStatics);
|
||||||
|
|
||||||
|
// deal with dynamics
|
||||||
|
if (dynamicModules) |dynamics| {
|
||||||
|
const loadDynamics = self.generateLoadDynamics(programName, dynamics) catch @panic("unknown");
|
||||||
|
mod.addImport("loadDynamics", loadDynamics);
|
||||||
|
} else {
|
||||||
|
mod.addImport("loadDynamics", self.nwdep.module("loadDynamicsStub"));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.generatedApis.put(self.b.allocator, programName, mod) catch @panic("out of memory");
|
||||||
|
|
||||||
|
return mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generateRc(self: *@This(), programName: []const u8, iconPath: []const u8) !std.Build.LazyPath {
|
||||||
|
const run = self.b.addRunArtifact(self.rcGen);
|
||||||
|
const pfile = self.b.fmt("{s}.rc", .{programName});
|
||||||
|
const output = run.addOutputFileArg(pfile);
|
||||||
|
run.addArg(iconPath);
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generateLoadDynamics(self: *@This(), programName: []const u8, dynamics: []const *DynamicModule) !*std.Build.Module {
|
||||||
|
const run = self.b.addRunArtifact(self.loadDynamicsGen);
|
||||||
|
const pfile = self.b.fmt("{s}LoadDynamics.zig", .{programName});
|
||||||
|
const output = run.addOutputFileArg(pfile);
|
||||||
|
if (self.staticBuild) {
|
||||||
|
run.addArg("static");
|
||||||
|
} else {
|
||||||
|
run.addArg("dynamic");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (dynamics) |dyn| {
|
||||||
|
run.addArg(dyn.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
const mod = self.b.addModule(pfile, .{
|
||||||
|
.target = self.target,
|
||||||
|
.optimize = self.optimize,
|
||||||
|
.root_source_file = output,
|
||||||
|
});
|
||||||
|
|
||||||
|
mod.addImport("core", self.nwdep.module("core"));
|
||||||
|
for (dynamics) |dyn| {
|
||||||
|
const dynmod = dyn.compileInstall();
|
||||||
|
mod.addImport(dyn.name, dynmod.root_module);
|
||||||
|
}
|
||||||
|
|
||||||
|
return mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generateInstallStaticResources(self: *@This(), programName: []const u8, shadersPath: []const u8) !*std.Build.Module {
|
||||||
|
const run = self.b.addRunArtifact(self.shaderEmbedGen);
|
||||||
|
const pfile = self.b.fmt("{s}ShaderGen.zig", .{programName});
|
||||||
|
const output = run.addOutputFileArg(pfile);
|
||||||
|
run.addArg(shadersPath);
|
||||||
|
|
||||||
|
const b = self.b;
|
||||||
|
const mod = self.b.addModule(pfile, .{
|
||||||
|
.target = self.target,
|
||||||
|
.optimize = self.optimize,
|
||||||
|
.root_source_file = output,
|
||||||
|
});
|
||||||
|
mod.addImport("core", self.nwdep.module("core"));
|
||||||
|
|
||||||
|
var dir = try std.fs.cwd().openDir("content/_shaders", .{ .iterate = true });
|
||||||
|
defer dir.close();
|
||||||
|
|
||||||
|
var walker = dir.iterate();
|
||||||
|
while (try walker.next()) |shaderType| {
|
||||||
|
if (shaderType.kind == .directory) {
|
||||||
|
var d2 = try dir.openDir(shaderType.name, .{ .iterate = true });
|
||||||
|
defer d2.close();
|
||||||
|
var w2 = d2.iterate();
|
||||||
|
while (try w2.next()) |shaderName| {
|
||||||
|
const shaderPath = b.fmt("content/_shaders/{s}/{s}", .{ shaderType.name, shaderName.name });
|
||||||
|
mod.addAnonymousImport(shaderName.name, .{
|
||||||
|
.root_source_file = b.path(shaderPath),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mod;
|
||||||
|
}
|
||||||
584
build.zig
584
build.zig
|
|
@ -1,42 +1,27 @@
|
||||||
// MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS=1 -- use this if you're getting that odd crash on mac
|
// MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS=1 -- use this if you're getting that odd crash on mac
|
||||||
b: *std.Build,
|
b: *std.Build,
|
||||||
nw_builder: *std.Build,
|
bEngine: *std.Build, // used to resolve executable paths from within the engine's root directory
|
||||||
target: std.Build.ResolvedTarget,
|
opts: bh.Options,
|
||||||
optimize: std.builtin.OptimizeMode,
|
|
||||||
nw_mod: *std.Build.Module,
|
nw_mod: *std.Build.Module,
|
||||||
gltf2ozz: ozz.GltfToOzz,
|
gltf2ozz: ozz.GltfToOzz,
|
||||||
options: *std.Build.Step.Options,
|
options: *std.Build.Step.Options,
|
||||||
cookShaders: bool,
|
cookShaders: bool,
|
||||||
|
|
||||||
backlogRoot: []const u8,
|
backlogRoot: []const u8,
|
||||||
|
|
||||||
// list of all shaders discovered under
|
// list of all shaders discovered under
|
||||||
// content/_shaders/def
|
// content/_shaders/def
|
||||||
reflectShaderPathList: [][]u8 = undefined,
|
reflectShaderPathList: [][]u8 = undefined,
|
||||||
|
|
||||||
staticBuild: bool = false,
|
|
||||||
|
|
||||||
nwdep: *std.Build.Dependency,
|
nwdep: *std.Build.Dependency,
|
||||||
apigen: *std.Build.Step.Compile,
|
// apigen: *std.Build.Step.Compile,
|
||||||
shaderEmbedGen: *std.Build.Step.Compile,
|
shaderEmbedGen: *std.Build.Step.Compile,
|
||||||
loadDynamicsGen: *std.Build.Step.Compile,
|
loadDynamicsGen: *std.Build.Step.Compile,
|
||||||
rcGen: *std.Build.Step.Compile,
|
rcGen: *std.Build.Step.Compile,
|
||||||
|
specGen: *std.Build.Step.Compile,
|
||||||
generatedApis: std.StringHashMapUnmanaged(*std.Build.Module) = .{},
|
generatedApis: std.StringHashMapUnmanaged(*std.Build.Module) = .{},
|
||||||
|
|
||||||
const engineDepList = [_][]const u8{
|
pub const BuildSystem = @This();
|
||||||
"assets",
|
|
||||||
"audio",
|
|
||||||
"core",
|
|
||||||
"net",
|
|
||||||
"papyrus",
|
|
||||||
"platform",
|
|
||||||
"rend",
|
|
||||||
"ui",
|
|
||||||
"imgui",
|
|
||||||
"physics",
|
|
||||||
"sys",
|
|
||||||
};
|
|
||||||
|
|
||||||
const BuildSystem = @This();
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const Build = std.Build;
|
const Build = std.Build;
|
||||||
const LazyPath = Build.LazyPath;
|
const LazyPath = Build.LazyPath;
|
||||||
|
|
@ -46,41 +31,47 @@ const ozz = @import("ozz");
|
||||||
pub const InitOptions = struct {
|
pub const InitOptions = struct {
|
||||||
import_name: []const u8 = "Backlog",
|
import_name: []const u8 = "Backlog",
|
||||||
backlogRoot: []const u8 = "./BacklogEngine",
|
backlogRoot: []const u8 = "./BacklogEngine",
|
||||||
staticBuild: bool = false,
|
target: std.Build.ResolvedTarget,
|
||||||
target: Build.ResolvedTarget,
|
|
||||||
optimize: std.builtin.OptimizeMode,
|
optimize: std.builtin.OptimizeMode,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn init(b: *std.Build, opts: InitOptions) BuildSystem {
|
pub fn init(b: *std.Build, initOptions: InitOptions) BuildSystem {
|
||||||
var buildOpts = declareBuildOptions(b);
|
const buildOpts = declareBuildOptions(b);
|
||||||
|
|
||||||
|
const opts = bh.Options{
|
||||||
|
.target = initOptions.target,
|
||||||
|
.optimize = initOptions.optimize,
|
||||||
|
.static_build = b.option(bool, "static_build", "builds backlog dependencies for static linking") orelse false,
|
||||||
|
.tracy = b.option(bool, "tracy", "builds with tracy support") orelse false,
|
||||||
|
};
|
||||||
|
|
||||||
if (opts.target.result.os.tag == .linux) {
|
if (opts.target.result.os.tag == .linux) {
|
||||||
// using a static build for linux... object loading hell is not fun
|
// using a static build for linux... object loading hell is not fun...
|
||||||
std.debug.print("Important! only supporting static builds for linux", .{});
|
// i have skill issues in that realm right now
|
||||||
buildOpts.static_build = true;
|
// std.debug.print("Important! only supporting static builds for linux", .{});
|
||||||
|
// opts.static_build = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const nwdep = b.dependency(opts.import_name, .{
|
const nwdep = b.dependency(initOptions.import_name, .{
|
||||||
.target = opts.target,
|
.target = opts.target,
|
||||||
.optimize = opts.optimize,
|
.optimize = opts.optimize,
|
||||||
.static_build = buildOpts.static_build,
|
.static_build = opts.static_build,
|
||||||
});
|
});
|
||||||
|
|
||||||
var self = BuildSystem{
|
var self = BuildSystem{
|
||||||
.b = b,
|
.b = b,
|
||||||
.nw_builder = nwdep.builder,
|
.bEngine = nwdep.builder,
|
||||||
.target = opts.target,
|
.opts = opts,
|
||||||
.optimize = opts.optimize,
|
|
||||||
.nw_mod = nwdep.module("Backlog"),
|
.nw_mod = nwdep.module("Backlog"),
|
||||||
.backlogRoot = opts.backlogRoot,
|
.backlogRoot = initOptions.backlogRoot,
|
||||||
.options = createGameOptions(b, buildOpts),
|
.options = createGameOptions(b, buildOpts, opts),
|
||||||
.gltf2ozz = ozz.GltfToOzz.init(nwdep.builder, .{}),
|
.gltf2ozz = ozz.GltfToOzz.init(nwdep.builder, .{}),
|
||||||
.cookShaders = b.option(bool, "cookShaders", "generates shaders and updates .json files before running the build. (needs to be done whenever shaders are updated, this just runs tools/scripts/cook-shaders.py)") orelse false,
|
.cookShaders = b.option(bool, "cookShaders", "generates shaders and updates .json files before running the build. (needs to be done whenever shaders are updated, this just runs tools/scripts/cook-shaders.py)") orelse false,
|
||||||
|
|
||||||
.staticBuild = buildOpts.static_build,
|
|
||||||
.nwdep = nwdep,
|
.nwdep = nwdep,
|
||||||
.apigen = nwdep.artifact("backlog-apigen"),
|
// .apigen = nwdep.artifact("backlog-apigen"),
|
||||||
.loadDynamicsGen = nwdep.artifact("backlog-generate-loadDynamics"),
|
.loadDynamicsGen = nwdep.artifact("backlog-generate-loadDynamics"),
|
||||||
|
.specGen = nwdep.artifact("backlog-generate-spec"),
|
||||||
.rcGen = nwdep.artifact("backlog-generate-rc"),
|
.rcGen = nwdep.artifact("backlog-generate-rc"),
|
||||||
.shaderEmbedGen = nwdep.artifact("backlog-shaderEmbedGen"),
|
.shaderEmbedGen = nwdep.artifact("backlog-shaderEmbedGen"),
|
||||||
};
|
};
|
||||||
|
|
@ -110,135 +101,55 @@ pub fn init(b: *std.Build, opts: InitOptions) BuildSystem {
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const AddProgramOptions = struct {
|
// Build Options for the engine,
|
||||||
name: []const u8,
|
// should generally be written as false = default
|
||||||
desc: []const u8,
|
// true = enabling something
|
||||||
root_source_file: LazyPath,
|
const BuildOptions = struct {
|
||||||
imports: []const Build.Module.Import = &.{},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn addProgram(self: *BuildSystem, opts: AddProgramOptions) *std.Build.Module {
|
|
||||||
const b = self.b;
|
|
||||||
|
|
||||||
const exe = self.nw_builder.addExecutable(.{
|
|
||||||
.name = opts.name,
|
|
||||||
.root_module = b.createModule(.{
|
|
||||||
.target = self.target,
|
|
||||||
.optimize = self.optimize,
|
|
||||||
.root_source_file = self.nw_builder.path("engine/main.zig"),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
b.installArtifact(exe);
|
|
||||||
const runArtifact = b.addRunArtifact(exe);
|
|
||||||
if (b.args) |args| {
|
|
||||||
runArtifact.addArgs(args);
|
|
||||||
}
|
|
||||||
const run_exe = b.step(self.b.fmt("run-{s}", .{opts.name}), opts.desc);
|
|
||||||
run_exe.dependOn(&runArtifact.step);
|
|
||||||
|
|
||||||
// main path = name/main.zig
|
|
||||||
const mod = b.addModule(opts.name, .{
|
|
||||||
.target = self.target,
|
|
||||||
.optimize = self.optimize,
|
|
||||||
.root_source_file = opts.root_source_file,
|
|
||||||
.imports = opts.imports,
|
|
||||||
});
|
|
||||||
|
|
||||||
exe.root_module.addImport("main", mod);
|
|
||||||
// todo.. remove this one and see what happens
|
|
||||||
exe.root_module.addImport("core", self.nwdep.module("core"));
|
|
||||||
// mod.addImport("Backlog", self.nw_mod);
|
|
||||||
exe.root_module.addOptions("BacklogOptions", self.options);
|
|
||||||
|
|
||||||
if (self.cookShaders) {
|
|
||||||
const cookShadersScript = b.fmt("{s}/tools/scripts/cookShaders.py", .{self.backlogRoot});
|
|
||||||
const cookShadersCommand = b.addSystemCommand(&[_][]const u8{"python"});
|
|
||||||
cookShadersCommand.addArg(cookShadersScript);
|
|
||||||
|
|
||||||
run_exe.dependOn(&cookShadersCommand.step);
|
|
||||||
}
|
|
||||||
|
|
||||||
b.getInstallStep().dependOn(self.nw_builder.getInstallStep());
|
|
||||||
|
|
||||||
// run_exe.dependOn(b.getInstallStep());
|
|
||||||
|
|
||||||
return mod;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const BuildOptions = struct {
|
|
||||||
mutex_job_queue: bool,
|
mutex_job_queue: bool,
|
||||||
static_build: bool,
|
|
||||||
zero_logging: bool,
|
zero_logging: bool,
|
||||||
slow_logging: bool,
|
slow_logging: bool,
|
||||||
force_mailbox: bool,
|
force_mailbox: bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn declareBuildOptions(b: *std.Build) BuildOptions {
|
fn declareBuildOptions(b: *std.Build) BuildOptions {
|
||||||
return .{
|
return .{
|
||||||
.mutex_job_queue = b.option(bool, "mutex_job_queue", "temporary test, reverts to old mutex based queue behaviour in jobs.zig:JobManager") orelse false,
|
.mutex_job_queue = b.option(bool, "mutex_job_queue", "temporary test, reverts to old mutex based queue behaviour in jobs.zig:JobManager") orelse false,
|
||||||
.static_build = b.option(bool, "static_build", "builds the entire game as a single executable") orelse false,
|
|
||||||
.zero_logging = b.option(bool, "zero_logging", "disables all logging, only intended for use on job dispatch testing") orelse false,
|
.zero_logging = b.option(bool, "zero_logging", "disables all logging, only intended for use on job dispatch testing") orelse false,
|
||||||
.slow_logging = b.option(bool, "slow_logging", "Disables buffered logging, takes a hit to performance but gain timing information on logging") orelse false,
|
.slow_logging = b.option(bool, "slow_logging", "Disables buffered logging, takes a hit to performance but gain timing information on logging") orelse false,
|
||||||
.force_mailbox = b.option(bool, "force_mailbox", "forces mailbox mode for present mode. unlocks framerate to irresponsible levels") orelse false,
|
.force_mailbox = b.option(bool, "force_mailbox", "forces mailbox mode for present mode. unlocks framerate to irresponsible levels") orelse false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn createGameOptions(b: *std.Build, options: BuildOptions) *std.Build.Step.Options {
|
fn createGameOptions(b: *std.Build, options: BuildOptions, bhopts: bh.Options) *std.Build.Step.Options {
|
||||||
const opts = b.addOptions();
|
const opts = b.addOptions();
|
||||||
|
|
||||||
inline for (@typeInfo(BuildOptions).@"struct".fields) |field| {
|
inline for (@typeInfo(BuildOptions).@"struct".fields) |field| {
|
||||||
opts.addOption(bool, field.name, @field(options, field.name));
|
opts.addOption(bool, field.name, @field(options, field.name));
|
||||||
}
|
}
|
||||||
|
|
||||||
// build options for core.zig
|
// forward the options to the build options
|
||||||
// opts.addOption(
|
opts.addOption(bool, "tracy", bhopts.tracy);
|
||||||
// bool,
|
opts.addOption(bool, "static_build", bhopts.static_build);
|
||||||
// "mutex_job_queue",
|
|
||||||
// );
|
|
||||||
|
|
||||||
// opts.addOption(
|
|
||||||
// bool,
|
|
||||||
// "static_build",
|
|
||||||
// );
|
|
||||||
|
|
||||||
// opts.addOption(
|
|
||||||
// bool,
|
|
||||||
// "zero_logging",
|
|
||||||
// );
|
|
||||||
// opts.addOption(
|
|
||||||
// bool,
|
|
||||||
// "slow_logging",
|
|
||||||
// );
|
|
||||||
// opts.addOption(
|
|
||||||
// bool,
|
|
||||||
// "force_mailbox",
|
|
||||||
// );
|
|
||||||
|
|
||||||
return opts;
|
return opts;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn addExtraModule(self: *BuildSystem, mod: *std.Build.Module, moduleName: []const u8) void {
|
pub fn addExtraModule(self: *BuildSystem, mod: *std.Build.Module, moduleName: []const u8) void {
|
||||||
const dep = self.b.dependency(moduleName, .{ .target = self.target, .optimize = self.optimize, .static_build = self.staticBuild });
|
const dep = self.b.dependency(moduleName, .{ .target = self.opts.target, .optimize = self.opts.optimize, .static_build = self.opts.static_build });
|
||||||
mod.addImport(moduleName, dep.module(moduleName));
|
mod.addImport(moduleName, dep.module(moduleName));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn addDependencyInstalls(self: *BuildSystem, b: *std.Build, optimize: std.builtin.OptimizeMode) void {
|
fn addDependencyInstalls(self: *BuildSystem, b: *std.Build, optimize: std.builtin.OptimizeMode) void {
|
||||||
//if (self.staticBuild) {
|
if (self.opts.static_build) {
|
||||||
//return;
|
return;
|
||||||
// }
|
}
|
||||||
|
|
||||||
inline for (DynamicDepList) |d| {
|
inline for (DynamicDepList) |d| {
|
||||||
b.installArtifact(b.dependency(
|
b.installArtifact(b.dependency(
|
||||||
d.dep,
|
d.dep,
|
||||||
.{ .target = self.target, .optimize = optimize, .static_build = self.staticBuild },
|
.{ .target = self.opts.target, .optimize = optimize, .static_build = self.opts.static_build },
|
||||||
).artifact(d.artifact));
|
).artifact(d.artifact));
|
||||||
}
|
}
|
||||||
|
|
||||||
// b.installArtifact(b.dependency(
|
|
||||||
// "sdl3",
|
|
||||||
// .{ .target = self.target, .optimize = optimize, .static_build = self.staticBuild },
|
|
||||||
// ).artifact("SDL3"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const DynamicDepList: []const struct { dep: []const u8, artifact: []const u8 } = &.{
|
const DynamicDepList: []const struct { dep: []const u8, artifact: []const u8 } = &.{
|
||||||
|
|
@ -251,365 +162,19 @@ const DynamicDepList: []const struct { dep: []const u8, artifact: []const u8 } =
|
||||||
.{ .dep = "ozz", .artifact = "ozz_cpp" },
|
.{ .dep = "ozz", .artifact = "ozz_cpp" },
|
||||||
};
|
};
|
||||||
|
|
||||||
// all other modules are disabled by default
|
pub fn addProgram(
|
||||||
pub const defaultEnabledModules: []const []const u8 = &.{
|
self: *@This(),
|
||||||
"core",
|
|
||||||
"assets",
|
|
||||||
"platform",
|
|
||||||
"rend",
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const moduleOrder: []const []const u8 = &.{
|
|
||||||
"core",
|
|
||||||
"sys",
|
|
||||||
"assets",
|
|
||||||
"platform",
|
|
||||||
"net",
|
|
||||||
"physics",
|
|
||||||
"audio",
|
|
||||||
"rend",
|
|
||||||
"ui",
|
|
||||||
"imgui",
|
|
||||||
"papyrus",
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const DynamicModule = struct {
|
|
||||||
name: []const u8,
|
name: []const u8,
|
||||||
allocator: std.mem.Allocator,
|
) *Program {
|
||||||
buildSystem: *BuildSystem,
|
const p = self.b.allocator.create(Program) catch unreachable;
|
||||||
programName: []const u8,
|
p.* = .{
|
||||||
opts: AddProgramOptions,
|
.name = name,
|
||||||
|
.opts = self.opts,
|
||||||
extras: std.ArrayListUnmanaged(GameModule) = .{},
|
|
||||||
gameModules: std.ArrayListUnmanaged(GameModule) = .{},
|
|
||||||
|
|
||||||
library: ?*std.Build.Step.Compile = null,
|
|
||||||
|
|
||||||
pub fn addExtraModule(self: *@This(), module: []const u8) void {
|
|
||||||
self.extras.append(self.allocator, .{ .name = module, .enabled = true }) catch @panic("out of memory");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn init(name: []const u8, p: *Program) *@This() {
|
|
||||||
var self: *@This() = p.allocator.create(@This()) catch @panic("out of memory");
|
|
||||||
|
|
||||||
self.* = .{
|
|
||||||
.opts = p.opts,
|
|
||||||
.programName = p.opts.name,
|
|
||||||
.buildSystem = p.buildSystem,
|
|
||||||
.allocator = p.allocator,
|
|
||||||
.name = name,
|
|
||||||
};
|
|
||||||
|
|
||||||
for (p.gameModules.items) |module| {
|
|
||||||
self.gameModules.append(self.allocator, module) catch @panic("out of memory");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (p.extras.items) |module| {
|
|
||||||
self.extras.append(self.allocator, module) catch @panic("out of memory");
|
|
||||||
}
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compileInstall(self: *@This()) *std.Build.Step.Compile {
|
|
||||||
if (self.library) |lib| {
|
|
||||||
return lib;
|
|
||||||
}
|
|
||||||
|
|
||||||
const b = self.buildSystem.b;
|
|
||||||
const static = self.buildSystem.staticBuild;
|
|
||||||
const lib = b.addLibrary(.{
|
|
||||||
.name = self.name,
|
|
||||||
.linkage = if (static) .static else .dynamic,
|
|
||||||
.root_module = b.createModule(.{
|
|
||||||
.root_source_file = self.opts.root_source_file,
|
|
||||||
.link_libc = true,
|
|
||||||
.optimize = self.buildSystem.optimize,
|
|
||||||
.target = self.buildSystem.target,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
const allocator = self.buildSystem.b.allocator;
|
|
||||||
|
|
||||||
var modlist = std.ArrayList([]const u8){};
|
|
||||||
|
|
||||||
for (self.gameModules.items) |mod| {
|
|
||||||
if (mod.enabled) {
|
|
||||||
modlist.append(allocator, mod.name) catch @panic("out of memory");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (self.extras.items) |extra| {
|
|
||||||
self.buildSystem.addExtraModule(lib.root_module, extra.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
lib.root_module.addImport("backlog", self.buildSystem.generateApi(self.name, modlist.items, null));
|
|
||||||
lib.root_module.addOptions("BacklogOptions", self.buildSystem.options);
|
|
||||||
|
|
||||||
if (static) {
|
|
||||||
// generateApi should create static callers for the main program
|
|
||||||
} else {
|
|
||||||
const installExtern = b.addInstallArtifact(lib, .{
|
|
||||||
.dest_dir = .{ .override = .{ .custom = "modules" } },
|
|
||||||
});
|
|
||||||
b.getInstallStep().dependOn(&installExtern.step);
|
|
||||||
}
|
|
||||||
|
|
||||||
return lib;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const GameModule = struct {
|
|
||||||
name: []const u8,
|
|
||||||
enabled: bool = true,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const Program = struct {
|
|
||||||
allocator: std.mem.Allocator,
|
|
||||||
opts: AddProgramOptions,
|
|
||||||
gameModules: std.ArrayListUnmanaged(GameModule) = .{},
|
|
||||||
extras: std.ArrayListUnmanaged(GameModule) = .{},
|
|
||||||
dynamicModules: std.ArrayListUnmanaged(*DynamicModule) = .{},
|
|
||||||
buildSystem: *BuildSystem,
|
|
||||||
|
|
||||||
iconPath: ?std.Build.LazyPath = null,
|
|
||||||
|
|
||||||
pub fn setIconPath(self: *@This(), path: []const u8) void {
|
|
||||||
if (self.iconPath != null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.iconPath = self.buildSystem.generateRc(self.opts.name, path) catch return;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn setModuleEnabled(self: *@This(), module: []const u8, enable: bool) void {
|
|
||||||
for (self.gameModules.items) |*m| {
|
|
||||||
if (std.mem.eql(u8, m.name, module)) {
|
|
||||||
m.enabled = enable;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// module not found, add it here.
|
|
||||||
self.gameModules.append(self.allocator, .{ .name = module, .enabled = enable }) catch @panic("out of memory");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn addExtraModule(self: *@This(), module: []const u8) void {
|
|
||||||
self.extras.append(self.allocator, .{ .name = module, .enabled = true }) catch @panic("out of memory");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn addDynamicModule(self: *@This(), module: []const u8, root_source_file: std.Build.LazyPath) *DynamicModule {
|
|
||||||
const dynamicModule = DynamicModule.init(module, self);
|
|
||||||
dynamicModule.opts.root_source_file = root_source_file;
|
|
||||||
self.dynamicModules.append(self.allocator, dynamicModule) catch @panic("out of memory");
|
|
||||||
|
|
||||||
return dynamicModule;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compileInstall(self: *@This()) *std.Build.Module {
|
|
||||||
const exe = self.buildSystem.addProgram(self.opts);
|
|
||||||
const allocator = self.buildSystem.b.allocator;
|
|
||||||
|
|
||||||
var modlist = std.ArrayList([]const u8){};
|
|
||||||
|
|
||||||
for (self.gameModules.items) |mod| {
|
|
||||||
if (mod.enabled) {
|
|
||||||
modlist.append(allocator, mod.name) catch @panic("out of memory");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (self.extras.items) |extra| {
|
|
||||||
self.buildSystem.addExtraModule(exe, extra.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
exe.addImport("backlog", self.buildSystem.generateApi(self.opts.name, modlist.items, self.dynamicModules.items));
|
|
||||||
|
|
||||||
if (self.buildSystem.target.result.os.tag == .windows) {
|
|
||||||
if (self.iconPath) |ip| {
|
|
||||||
exe.addWin32ResourceFile(.{
|
|
||||||
.file = ip,
|
|
||||||
.flags = &.{},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return exe;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn program(self: *BuildSystem, opts: AddProgramOptions) *Program {
|
|
||||||
const prog = self.b.allocator.create(Program) catch unreachable;
|
|
||||||
|
|
||||||
prog.* = .{
|
|
||||||
.allocator = self.b.allocator,
|
|
||||||
.opts = opts,
|
|
||||||
.buildSystem = self,
|
.buildSystem = self,
|
||||||
|
.allocator = self.b.allocator,
|
||||||
};
|
};
|
||||||
|
|
||||||
for (moduleOrder) |module| {
|
return p;
|
||||||
prog.setModuleEnabled(module, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (defaultEnabledModules) |module| {
|
|
||||||
prog.setModuleEnabled(module, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return prog;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ========= standalone build instance =======
|
|
||||||
// maybe the default should be like an engine launcher/project launcher or something
|
|
||||||
pub fn build(b: *std.Build) void {
|
|
||||||
const target = b.standardTargetOptions(.{});
|
|
||||||
const optimize = b.standardOptimizeOption(.{});
|
|
||||||
const static_build = b.option(bool, "static_build", "builds backlog dependencies for static linking") orelse false;
|
|
||||||
|
|
||||||
const fwdGeneratorExe = b.addExecutable(.{
|
|
||||||
.name = "backlog-generate-fwd",
|
|
||||||
.root_module = b.createModule(.{
|
|
||||||
.target = b.graph.host,
|
|
||||||
.optimize = .Debug,
|
|
||||||
.root_source_file = b.path("build/generateFwd.zig"),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
const generateExe = b.addExecutable(.{
|
|
||||||
.name = "backlog-apigen",
|
|
||||||
.root_module = b.createModule(.{
|
|
||||||
.target = b.graph.host,
|
|
||||||
.optimize = .Debug,
|
|
||||||
.root_source_file = b.path("build/generateApi.zig"),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
const generateShaders = b.addExecutable(.{
|
|
||||||
.name = "backlog-shaderEmbedGen",
|
|
||||||
.root_module = b.createModule(.{
|
|
||||||
.target = b.graph.host,
|
|
||||||
.optimize = .Debug,
|
|
||||||
.root_source_file = b.path("build/generateEmbeddedShaders.zig"),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
const generateRcExe = b.addExecutable(.{
|
|
||||||
.name = "backlog-generate-rc",
|
|
||||||
.root_module = b.createModule(.{
|
|
||||||
.target = b.graph.host,
|
|
||||||
.optimize = .Debug,
|
|
||||||
.root_source_file = b.path("build/generateRc.zig"),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
const generateLoadDynamicsExe = b.addExecutable(.{
|
|
||||||
.name = "backlog-generate-loadDynamics",
|
|
||||||
.root_module = b.createModule(.{
|
|
||||||
.target = b.graph.host,
|
|
||||||
.optimize = .Debug,
|
|
||||||
.root_source_file = b.path("build/generateLoadDynamics.zig"),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
b.installArtifact(generateLoadDynamicsExe);
|
|
||||||
b.installArtifact(generateExe);
|
|
||||||
b.installArtifact(generateShaders);
|
|
||||||
b.installArtifact(generateRcExe);
|
|
||||||
|
|
||||||
{
|
|
||||||
const loadDynamicsStub = b.addModule("loadDynamicsStub", .{
|
|
||||||
.target = target,
|
|
||||||
.optimize = optimize,
|
|
||||||
.root_source_file = b.path("engine/loadDynamicsStub.zig"),
|
|
||||||
});
|
|
||||||
|
|
||||||
_ = loadDynamicsStub;
|
|
||||||
|
|
||||||
const mod = b.addModule("Backlog", .{
|
|
||||||
.target = target,
|
|
||||||
.optimize = optimize,
|
|
||||||
.root_source_file = b.path("engine/backlog.zig"),
|
|
||||||
});
|
|
||||||
|
|
||||||
for (engineDepList) |depName| {
|
|
||||||
const dep = b.dependency(
|
|
||||||
depName,
|
|
||||||
.{
|
|
||||||
.target = target,
|
|
||||||
.optimize = optimize,
|
|
||||||
.static_build = static_build,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
const run = b.addRunArtifact(fwdGeneratorExe);
|
|
||||||
const output = run.addOutputFileArg(b.fmt("{s}_fwd.zig", .{depName}));
|
|
||||||
|
|
||||||
const modFwd = b.addModule(depName, .{
|
|
||||||
.target = target,
|
|
||||||
.optimize = optimize,
|
|
||||||
.root_source_file = output,
|
|
||||||
});
|
|
||||||
|
|
||||||
mod.addImport(b.fmt("{s}", .{depName}), modFwd);
|
|
||||||
modFwd.addImport("module", dep.module(depName));
|
|
||||||
|
|
||||||
// mod.addImport(depName, dep.module(depName));
|
|
||||||
}
|
|
||||||
|
|
||||||
// link in large platform support functions... special case.
|
|
||||||
{
|
|
||||||
const dep = b.dependency("sdl3", .{
|
|
||||||
.target = target,
|
|
||||||
.optimize = optimize,
|
|
||||||
.static_build = static_build,
|
|
||||||
});
|
|
||||||
const lib = dep.module("SDL3");
|
|
||||||
|
|
||||||
mod.addImport("sdl3_fwd", lib);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn generateApi(self: *@This(), programName: []const u8, moduleList: []const []const u8, dynamicModules: ?[]const *DynamicModule) *std.Build.Module {
|
|
||||||
// std.debug.print("GENERATE API:: {s}\n", .{programName});
|
|
||||||
|
|
||||||
for (moduleList) |mod| {
|
|
||||||
_ = mod;
|
|
||||||
// std.debug.print("{s}\n", .{mod});
|
|
||||||
}
|
|
||||||
//
|
|
||||||
if (self.generatedApis.get(programName)) |m| {
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
const run = self.b.addRunArtifact(self.apigen);
|
|
||||||
const pfile = self.b.fmt("{s}Api.zig", .{programName});
|
|
||||||
const output = run.addOutputFileArg(pfile);
|
|
||||||
for (moduleList) |modName| {
|
|
||||||
run.addArg(modName);
|
|
||||||
}
|
|
||||||
|
|
||||||
const mod = self.b.addModule(pfile, .{
|
|
||||||
.target = self.target,
|
|
||||||
.optimize = self.optimize,
|
|
||||||
.root_source_file = output,
|
|
||||||
});
|
|
||||||
for (moduleList) |modName| {
|
|
||||||
mod.addImport(modName, self.nwdep.module(modName));
|
|
||||||
}
|
|
||||||
|
|
||||||
const loadStatics = self.generateInstallStaticResources(programName, "content/_shaders") catch unreachable;
|
|
||||||
mod.addImport("staticShaderLoader", loadStatics);
|
|
||||||
|
|
||||||
// deal with dynamics
|
|
||||||
if (dynamicModules) |dynamics| {
|
|
||||||
const loadDynamics = self.generateLoadDynamics(programName, dynamics) catch @panic("unknown");
|
|
||||||
mod.addImport("loadDynamics", loadDynamics);
|
|
||||||
} else {
|
|
||||||
mod.addImport("loadDynamics", self.nwdep.module("loadDynamicsStub"));
|
|
||||||
}
|
|
||||||
|
|
||||||
self.generatedApis.put(self.b.allocator, programName, mod) catch @panic("out of memory");
|
|
||||||
|
|
||||||
return mod;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generateRc(self: *@This(), programName: []const u8, iconPath: []const u8) !std.Build.LazyPath {
|
pub fn generateRc(self: *@This(), programName: []const u8, iconPath: []const u8) !std.Build.LazyPath {
|
||||||
|
|
@ -621,35 +186,6 @@ pub fn generateRc(self: *@This(), programName: []const u8, iconPath: []const u8)
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generateLoadDynamics(self: *@This(), programName: []const u8, dynamics: []const *DynamicModule) !*std.Build.Module {
|
|
||||||
const run = self.b.addRunArtifact(self.loadDynamicsGen);
|
|
||||||
const pfile = self.b.fmt("{s}LoadDynamics.zig", .{programName});
|
|
||||||
const output = run.addOutputFileArg(pfile);
|
|
||||||
if (self.staticBuild) {
|
|
||||||
run.addArg("static");
|
|
||||||
} else {
|
|
||||||
run.addArg("dynamic");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (dynamics) |dyn| {
|
|
||||||
run.addArg(dyn.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
const mod = self.b.addModule(pfile, .{
|
|
||||||
.target = self.target,
|
|
||||||
.optimize = self.optimize,
|
|
||||||
.root_source_file = output,
|
|
||||||
});
|
|
||||||
|
|
||||||
mod.addImport("core", self.nwdep.module("core"));
|
|
||||||
for (dynamics) |dyn| {
|
|
||||||
const dynmod = dyn.compileInstall();
|
|
||||||
mod.addImport(dyn.name, dynmod.root_module);
|
|
||||||
}
|
|
||||||
|
|
||||||
return mod;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn generateInstallStaticResources(self: *@This(), programName: []const u8, shadersPath: []const u8) !*std.Build.Module {
|
pub fn generateInstallStaticResources(self: *@This(), programName: []const u8, shadersPath: []const u8) !*std.Build.Module {
|
||||||
const run = self.b.addRunArtifact(self.shaderEmbedGen);
|
const run = self.b.addRunArtifact(self.shaderEmbedGen);
|
||||||
const pfile = self.b.fmt("{s}ShaderGen.zig", .{programName});
|
const pfile = self.b.fmt("{s}ShaderGen.zig", .{programName});
|
||||||
|
|
@ -658,8 +194,8 @@ pub fn generateInstallStaticResources(self: *@This(), programName: []const u8, s
|
||||||
|
|
||||||
const b = self.b;
|
const b = self.b;
|
||||||
const mod = self.b.addModule(pfile, .{
|
const mod = self.b.addModule(pfile, .{
|
||||||
.target = self.target,
|
.target = self.opts.target,
|
||||||
.optimize = self.optimize,
|
.optimize = self.opts.optimize,
|
||||||
.root_source_file = output,
|
.root_source_file = output,
|
||||||
});
|
});
|
||||||
mod.addImport("core", self.nwdep.module("core"));
|
mod.addImport("core", self.nwdep.module("core"));
|
||||||
|
|
@ -684,3 +220,15 @@ pub fn generateInstallStaticResources(self: *@This(), programName: []const u8, s
|
||||||
|
|
||||||
return mod;
|
return mod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ========= standalone build instance =======
|
||||||
|
// maybe the default should be like an engine launcher/project launcher or something
|
||||||
|
pub fn build(b: *std.Build) void {
|
||||||
|
const opts = bh.declareOptions(b);
|
||||||
|
engineDeps.buildGenerators(b, opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
const bh = @import("bh");
|
||||||
|
const engineDeps = @import("build/engineDeps.zig");
|
||||||
|
const program = @import("build/program.zig");
|
||||||
|
const Program = program.Program;
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,23 @@
|
||||||
.{
|
.{ .name = .Backlog, .version = "0.0.0", .dependencies = .{
|
||||||
.name = .Backlog,
|
.assets = .{ .path = "engine/assets" },
|
||||||
.version = "0.0.0",
|
.audio = .{ .path = "engine/audio" },
|
||||||
.dependencies = .{
|
.core = .{ .path = "engine/core" },
|
||||||
.assets = .{ .path = "engine/assets" },
|
.net = .{ .path = "engine/net" },
|
||||||
.audio = .{ .path = "engine/audio" },
|
.papyrus = .{ .path = "engine/papyrus" },
|
||||||
.core = .{ .path = "engine/core" },
|
.physics = .{ .path = "engine/physics" },
|
||||||
.net = .{ .path = "engine/net" },
|
.platform = .{ .path = "engine/platform" },
|
||||||
.papyrus = .{ .path = "engine/papyrus" },
|
.imgui = .{ .path = "engine/imgui" },
|
||||||
.physics = .{ .path = "engine/physics" },
|
.ui = .{ .path = "engine/ui" },
|
||||||
.platform = .{ .path = "engine/platform" },
|
.sys = .{ .path = "engine/sys" },
|
||||||
.imgui = .{ .path = "engine/imgui" },
|
.rend = .{ .path = "engine/rend" },
|
||||||
.ui = .{ .path = "engine/ui" },
|
|
||||||
.sys = .{ .path = "engine/sys" },
|
|
||||||
.rend = .{.path = "engine/rend" },
|
|
||||||
|
|
||||||
.ozz = .{ .path = "lib/ozz" },
|
.ozz = .{ .path = "lib/ozz" },
|
||||||
.spng = .{ .path = "lib/spng" },
|
.spng = .{ .path = "lib/spng" },
|
||||||
.zphysics = .{ .path = "lib/zphysics" },
|
.zphysics = .{ .path = "lib/zphysics" },
|
||||||
|
|
||||||
.sdl3 = .{ .path = "lib/sdl3" },
|
.sdl3 = .{ .path = "lib/sdl3" },
|
||||||
.enet = .{ .path = "lib/enet" },
|
.enet = .{ .path = "lib/enet" },
|
||||||
},
|
.bh = .{ .path = "lib/bh" },
|
||||||
.paths = .{
|
}, .paths = .{
|
||||||
"",
|
"",
|
||||||
},
|
}, .fingerprint = 0xcf9bab998abe37e3 }
|
||||||
.fingerprint = 0xcf9bab998abe37e3
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
pub const AddProgramOptions = struct {
|
||||||
|
name: []const u8,
|
||||||
|
desc: []const u8,
|
||||||
|
root_source_file: LazyPath,
|
||||||
|
imports: []const Build.Module.Import = &.{},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Program = struct {
|
||||||
|
allocator: std.mem.Allocator,
|
||||||
|
opts: AddProgramOptions,
|
||||||
|
gameModules: std.ArrayListUnmanaged(GameModule) = .{},
|
||||||
|
extras: std.ArrayListUnmanaged(GameModule) = .{},
|
||||||
|
dynamicModules: std.ArrayListUnmanaged(*DynamicModule) = .{},
|
||||||
|
buildSystem: *BuildSystem,
|
||||||
|
|
||||||
|
iconPath: ?std.Build.LazyPath = null,
|
||||||
|
|
||||||
|
pub fn setIconPath(self: *@This(), path: []const u8) void {
|
||||||
|
if (self.iconPath != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.iconPath = self.buildSystem.generateRc(self.opts.name, path) catch return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setModuleEnabled(self: *@This(), module: []const u8, enable: bool) void {
|
||||||
|
for (self.gameModules.items) |*m| {
|
||||||
|
if (std.mem.eql(u8, m.name, module)) {
|
||||||
|
m.enabled = enable;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// module not found, add it here.
|
||||||
|
self.gameModules.append(self.allocator, .{ .name = module, .enabled = enable }) catch @panic("out of memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn addExtraModule(self: *@This(), module: []const u8) void {
|
||||||
|
self.extras.append(self.allocator, .{ .name = module, .enabled = true }) catch @panic("out of memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn addDynamicModule(self: *@This(), module: []const u8, root_source_file: std.Build.LazyPath) *DynamicModule {
|
||||||
|
const dynamicModule = DynamicModule.init(module, self);
|
||||||
|
dynamicModule.opts.root_source_file = root_source_file;
|
||||||
|
self.dynamicModules.append(self.allocator, dynamicModule) catch @panic("out of memory");
|
||||||
|
|
||||||
|
return dynamicModule;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compileInstall(self: *@This()) *std.Build.Module {
|
||||||
|
const exe = self.buildSystem.addProgram(self.opts);
|
||||||
|
const allocator = self.buildSystem.b.allocator;
|
||||||
|
|
||||||
|
var modlist = std.ArrayList([]const u8){};
|
||||||
|
|
||||||
|
for (self.gameModules.items) |mod| {
|
||||||
|
if (mod.enabled) {
|
||||||
|
modlist.append(allocator, mod.name) catch @panic("out of memory");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (self.extras.items) |extra| {
|
||||||
|
self.buildSystem.addExtraModule(exe, extra.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
exe.addImport("backlog", self.buildSystem.generateApi(self.opts.name, modlist.items, self.dynamicModules.items));
|
||||||
|
|
||||||
|
if (self.buildSystem.target.result.os.tag == .windows) {
|
||||||
|
if (self.iconPath) |ip| {
|
||||||
|
exe.addWin32ResourceFile(.{
|
||||||
|
.file = ip,
|
||||||
|
.flags = &.{},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return exe;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const Build = std.Build;
|
||||||
|
const LazyPath = Build.LazyPath;
|
||||||
|
|
||||||
|
|
@ -0,0 +1,138 @@
|
||||||
|
const engineDepList = [_][]const u8{
|
||||||
|
"assets",
|
||||||
|
"audio",
|
||||||
|
"core",
|
||||||
|
"net",
|
||||||
|
"papyrus",
|
||||||
|
"platform",
|
||||||
|
"rend",
|
||||||
|
"ui",
|
||||||
|
"imgui",
|
||||||
|
"physics",
|
||||||
|
"sys",
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn depList() []const []const u8 {
|
||||||
|
return &engineDepList;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn buildGenerators(b: *std.Build, opts: bh.Options) void {
|
||||||
|
const target = opts.target;
|
||||||
|
const optimize = opts.optimize;
|
||||||
|
const static_build = opts.static_build;
|
||||||
|
|
||||||
|
const fwdGeneratorExe = b.addExecutable(.{
|
||||||
|
.name = "backlog-generate-fwd",
|
||||||
|
.root_module = b.createModule(.{
|
||||||
|
.target = b.graph.host,
|
||||||
|
.optimize = .Debug,
|
||||||
|
.root_source_file = b.path("buildgen/generateFwd.zig"),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const generateModApiExe = b.addExecutable(.{
|
||||||
|
.name = "backlog-generate-modapi",
|
||||||
|
.root_module = b.createModule(.{
|
||||||
|
.target = b.graph.host,
|
||||||
|
.optimize = .Debug,
|
||||||
|
.root_source_file = b.path("buildgen/generateModApi.zig"),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const generateProgramSpecExe = b.addExecutable(.{
|
||||||
|
.name = "backlog-generate-spec",
|
||||||
|
.root_module = b.createModule(.{
|
||||||
|
.target = b.graph.host,
|
||||||
|
.optimize = .Debug,
|
||||||
|
.root_source_file = b.path("buildgen/generateProgramSpec.zig"),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const generateShaders = b.addExecutable(.{
|
||||||
|
.name = "backlog-shaderEmbedGen",
|
||||||
|
.root_module = b.createModule(.{
|
||||||
|
.target = b.graph.host,
|
||||||
|
.optimize = .Debug,
|
||||||
|
.root_source_file = b.path("buildgen/generateEmbeddedShaders.zig"),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const generateRcExe = b.addExecutable(.{
|
||||||
|
.name = "backlog-generate-rc",
|
||||||
|
.root_module = b.createModule(.{
|
||||||
|
.target = b.graph.host,
|
||||||
|
.optimize = .Debug,
|
||||||
|
.root_source_file = b.path("buildgen/generateRc.zig"),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const generateLoadDynamicsExe = b.addExecutable(.{
|
||||||
|
.name = "backlog-generate-loadDynamics",
|
||||||
|
.root_module = b.createModule(.{
|
||||||
|
.target = b.graph.host,
|
||||||
|
.optimize = .Debug,
|
||||||
|
.root_source_file = b.path("buildgen/generateLoadDynamics.zig"),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
b.installArtifact(fwdGeneratorExe);
|
||||||
|
b.installArtifact(generateLoadDynamicsExe);
|
||||||
|
b.installArtifact(generateProgramSpecExe);
|
||||||
|
b.installArtifact(generateShaders);
|
||||||
|
b.installArtifact(generateRcExe);
|
||||||
|
b.installArtifact(generateModApiExe);
|
||||||
|
|
||||||
|
{
|
||||||
|
const loadDynamicsStub = b.addModule("loadDynamicsStub", .{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
.root_source_file = b.path("engine/loadDynamicsStub.zig"),
|
||||||
|
});
|
||||||
|
|
||||||
|
_ = loadDynamicsStub;
|
||||||
|
|
||||||
|
const mod = b.addModule("Backlog", .{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
.root_source_file = b.path("engine/backlog.zig"),
|
||||||
|
});
|
||||||
|
|
||||||
|
for (depList()) |depName| {
|
||||||
|
const dep = b.dependency(
|
||||||
|
depName,
|
||||||
|
.{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
.static_build = static_build,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const run = b.addRunArtifact(fwdGeneratorExe);
|
||||||
|
const output = run.addOutputFileArg(b.fmt("{s}_fwd.zig", .{depName}));
|
||||||
|
|
||||||
|
const modFwd = b.addModule(depName, .{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
.root_source_file = output,
|
||||||
|
});
|
||||||
|
|
||||||
|
mod.addImport(b.fmt("{s}", .{depName}), modFwd);
|
||||||
|
modFwd.addImport("module", dep.module(depName));
|
||||||
|
}
|
||||||
|
|
||||||
|
// link in large platform support functions... special case.
|
||||||
|
{
|
||||||
|
const dep = b.dependency("sdl3", .{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
.static_build = static_build,
|
||||||
|
});
|
||||||
|
const lib = dep.module("SDL3");
|
||||||
|
|
||||||
|
mod.addImport("sdl3_fwd", lib);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const bh = @import("bh");
|
||||||
|
|
@ -0,0 +1,182 @@
|
||||||
|
// legacy code, kept here as reference
|
||||||
|
pub const GameModule = struct {
|
||||||
|
name: []const u8,
|
||||||
|
enabled: bool = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn program(self: *BuildSystem, opts: AddProgramOptions) *Program {
|
||||||
|
const prog = self.b.allocator.create(Program) catch unreachable;
|
||||||
|
|
||||||
|
prog.* = .{
|
||||||
|
.allocator = self.b.allocator,
|
||||||
|
.opts = opts,
|
||||||
|
.buildSystem = self,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (moduleOrder) |module| {
|
||||||
|
prog.setModuleEnabled(module, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (defaultEnabledModules) |module| {
|
||||||
|
prog.setModuleEnabled(module, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return prog;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const DynamicModule = struct {
|
||||||
|
name: []const u8,
|
||||||
|
allocator: std.mem.Allocator,
|
||||||
|
buildSystem: *BuildSystem,
|
||||||
|
programName: []const u8,
|
||||||
|
opts: Program.AddProgramOptions,
|
||||||
|
|
||||||
|
extras: std.ArrayListUnmanaged(Program.GameModule) = .{},
|
||||||
|
gameModules: std.ArrayListUnmanaged(Program.GameModule) = .{},
|
||||||
|
|
||||||
|
library: ?*std.Build.Step.Compile = null,
|
||||||
|
|
||||||
|
pub fn addExtraModule(self: *@This(), module: []const u8) void {
|
||||||
|
self.extras.append(self.allocator, .{ .name = module, .enabled = true }) catch @panic("out of memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init(name: []const u8, p: *Program) *@This() {
|
||||||
|
var self: *@This() = p.allocator.create(@This()) catch @panic("out of memory");
|
||||||
|
|
||||||
|
self.* = .{
|
||||||
|
.opts = p.opts,
|
||||||
|
.programName = p.opts.name,
|
||||||
|
.buildSystem = p.buildSystem,
|
||||||
|
.allocator = p.allocator,
|
||||||
|
.name = name,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (p.gameModules.items) |module| {
|
||||||
|
self.gameModules.append(self.allocator, module) catch @panic("out of memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (p.extras.items) |module| {
|
||||||
|
self.extras.append(self.allocator, module) catch @panic("out of memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compileInstall(self: *@This()) *std.Build.Step.Compile {
|
||||||
|
if (self.library) |lib| {
|
||||||
|
return lib;
|
||||||
|
}
|
||||||
|
|
||||||
|
const b = self.buildSystem.b;
|
||||||
|
const static = self.buildSystem.staticBuild;
|
||||||
|
const lib = b.addLibrary(.{
|
||||||
|
.name = self.name,
|
||||||
|
.linkage = if (static) .static else .dynamic,
|
||||||
|
.root_module = b.createModule(.{
|
||||||
|
.root_source_file = self.opts.root_source_file,
|
||||||
|
.link_libc = true,
|
||||||
|
.optimize = self.buildSystem.optimize,
|
||||||
|
.target = self.buildSystem.target,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const allocator = self.buildSystem.b.allocator;
|
||||||
|
|
||||||
|
var modlist = std.ArrayList([]const u8){};
|
||||||
|
|
||||||
|
for (self.gameModules.items) |mod| {
|
||||||
|
if (mod.enabled) {
|
||||||
|
modlist.append(allocator, mod.name) catch @panic("out of memory");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (self.extras.items) |extra| {
|
||||||
|
self.buildSystem.addExtraModule(lib.root_module, extra.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
lib.root_module.addImport("backlog", self.buildSystem.generateApi(self.name, modlist.items, null));
|
||||||
|
lib.root_module.addOptions("BacklogOptions", self.buildSystem.options);
|
||||||
|
|
||||||
|
if (!static) {
|
||||||
|
const installExtern = b.addInstallArtifact(lib, .{
|
||||||
|
.dest_dir = .{ .override = .{ .custom = "modules" } },
|
||||||
|
});
|
||||||
|
b.getInstallStep().dependOn(&installExtern.step);
|
||||||
|
}
|
||||||
|
|
||||||
|
return lib;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn generateApi(self: *@This(), programName: []const u8, moduleList: []const []const u8, dynamicModules: ?[]const *DynamicModule,) *std.Build.Module {
|
||||||
|
// std.debug.print("GENERATE API:: {s}\n", .{programName});
|
||||||
|
|
||||||
|
for (moduleList) |mod| {
|
||||||
|
_ = mod;
|
||||||
|
// std.debug.print("{s}\n", .{mod});
|
||||||
|
}
|
||||||
|
//
|
||||||
|
if (self.generatedApis.get(programName)) |m| {
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
const run = self.b.addRunArtifact(self.apigen);
|
||||||
|
const pfile = self.b.fmt("{s}Api.zig", .{programName});
|
||||||
|
const output = run.addOutputFileArg(pfile);
|
||||||
|
for (moduleList) |modName| {
|
||||||
|
run.addArg(modName);
|
||||||
|
}
|
||||||
|
|
||||||
|
const mod = self.b.addModule(pfile, .{
|
||||||
|
.target = self.target,
|
||||||
|
.optimize = self.optimize,
|
||||||
|
.root_source_file = output,
|
||||||
|
});
|
||||||
|
for (moduleList) |modName| {
|
||||||
|
mod.addImport(modName, self.nwdep.module(modName));
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadStatics = self.generateInstallStaticResources(programName, "content/_shaders") catch unreachable;
|
||||||
|
mod.addImport("staticShaderLoader", loadStatics);
|
||||||
|
|
||||||
|
// deal with dynamics
|
||||||
|
if (dynamicModules) |dynamics| {
|
||||||
|
const loadDynamics = self.generateLoadDynamics(programName, dynamics) catch @panic("unknown");
|
||||||
|
mod.addImport("loadDynamics", loadDynamics);
|
||||||
|
} else {
|
||||||
|
mod.addImport("loadDynamics", self.nwdep.module("loadDynamicsStub"));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.generatedApis.put(self.b.allocator, programName, mod) catch @panic("out of memory");
|
||||||
|
|
||||||
|
return mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generateLoadDynamics(self: *@This(), programName: []const u8, dynamics: []const *DynamicModule) !*std.Build.Module {
|
||||||
|
const run = self.b.addRunArtifact(self.loadDynamicsGen);
|
||||||
|
const pfile = self.b.fmt("{s}LoadDynamics.zig", .{programName});
|
||||||
|
const output = run.addOutputFileArg(pfile);
|
||||||
|
if (self.staticBuild) {
|
||||||
|
run.addArg("static");
|
||||||
|
} else {
|
||||||
|
run.addArg("dynamic");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (dynamics) |dyn| {
|
||||||
|
run.addArg(dyn.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
const mod = self.b.addModule(pfile, .{
|
||||||
|
.target = self.target,
|
||||||
|
.optimize = self.optimize,
|
||||||
|
.root_source_file = output,
|
||||||
|
});
|
||||||
|
|
||||||
|
mod.addImport("core", self.nwdep.module("core"));
|
||||||
|
for (dynamics) |dyn| {
|
||||||
|
const dynmod = dyn.compileInstall();
|
||||||
|
mod.addImport(dyn.name, dynmod.root_module);
|
||||||
|
}
|
||||||
|
|
||||||
|
return mod;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,227 @@
|
||||||
|
pub const AddProgramOptions = struct {
|
||||||
|
name: []const u8,
|
||||||
|
opt: bh.Options,
|
||||||
|
root_source_file: std.Build.LazyPath,
|
||||||
|
};
|
||||||
|
|
||||||
|
// all other modules are disabled by default
|
||||||
|
pub const defaultEnabledModules: []const []const u8 = &.{
|
||||||
|
"core",
|
||||||
|
"assets",
|
||||||
|
"platform",
|
||||||
|
"rend",
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const moduleOrder: []const []const u8 = &.{
|
||||||
|
"core",
|
||||||
|
"sys",
|
||||||
|
"assets",
|
||||||
|
"platform",
|
||||||
|
"net",
|
||||||
|
"physics",
|
||||||
|
"audio",
|
||||||
|
"rend",
|
||||||
|
"ui",
|
||||||
|
"imgui",
|
||||||
|
"papyrus",
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const GameModule = struct {
|
||||||
|
name: []const u8,
|
||||||
|
enabled: bool = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Program = struct {
|
||||||
|
name: []const u8,
|
||||||
|
opts: bh.Options,
|
||||||
|
|
||||||
|
// root_path: not used yet, we will create a second module that dynamically loads in to that root_path
|
||||||
|
|
||||||
|
gameModules: std.ArrayListUnmanaged(GameModule) = .{},
|
||||||
|
gameModulesMap: std.StringHashMapUnmanaged(bool) = .{},
|
||||||
|
buildSystem: *backlog.BuildSystem,
|
||||||
|
iconPath: ?std.Build.LazyPath = null,
|
||||||
|
allocator: std.mem.Allocator, // just set this to the build allocator
|
||||||
|
|
||||||
|
pub fn setModuleEnabled(self: *@This(), name: []const u8, enabled: bool) void {
|
||||||
|
const r = self.gameModulesMap.getOrPut(self.allocator, name) catch unreachable;
|
||||||
|
r.value_ptr.* = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finalizeModules(self: *@This()) void {
|
||||||
|
self.gameModules.clearRetainingCapacity();
|
||||||
|
|
||||||
|
for (moduleOrder) |mod| {
|
||||||
|
var enabled: bool = false;
|
||||||
|
for (defaultEnabledModules) |default| {
|
||||||
|
if (std.mem.eql(u8, default, mod)) {
|
||||||
|
enabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.gameModulesMap.get(mod)) |value| {
|
||||||
|
enabled = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enabled) {
|
||||||
|
self.gameModules.append(self.allocator, .{ .name = mod, .enabled = enabled }) catch unreachable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setIconPath(self: *@This(), path: []const u8) void {
|
||||||
|
if (self.iconPath != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.iconPath = self.buildSystem.generateRc(self.name, path) catch return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn makeSpec(self: *@This()) *std.Build.Module {
|
||||||
|
const b = self.buildSystem.b;
|
||||||
|
const run = b.addRunArtifact(self.buildSystem.specGen);
|
||||||
|
const pfile = run.addOutputFileArg(b.fmt("{s}-spec.zig", .{self.name}));
|
||||||
|
run.addArg(self.name);
|
||||||
|
for (self.gameModules.items) |mod| {
|
||||||
|
if (mod.enabled)
|
||||||
|
run.addArg(mod.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
const mod = b.createModule(.{
|
||||||
|
.target = self.opts.target,
|
||||||
|
.optimize = self.opts.optimize,
|
||||||
|
.root_source_file = pfile,
|
||||||
|
});
|
||||||
|
|
||||||
|
const core = self.buildSystem.nwdep.module("core");
|
||||||
|
mod.addImport("core", core);
|
||||||
|
|
||||||
|
return mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn makeGameApi(self: *@This()) *std.Build.Module {
|
||||||
|
const b = self.buildSystem.b;
|
||||||
|
const apigen = self.buildSystem.nwdep.artifact("backlog-generate-modapi");
|
||||||
|
const run = b.addRunArtifact(apigen);
|
||||||
|
const pfile = run.addOutputFileArg(b.fmt("{s}-api.zig", .{self.name}));
|
||||||
|
|
||||||
|
run.addArg(self.name);
|
||||||
|
|
||||||
|
for (self.gameModules.items) |mod| {
|
||||||
|
if (mod.enabled) {
|
||||||
|
run.addArg(mod.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const api = b.createModule(.{
|
||||||
|
.target = self.opts.target,
|
||||||
|
.optimize = self.opts.optimize,
|
||||||
|
.root_source_file = pfile,
|
||||||
|
});
|
||||||
|
|
||||||
|
for (self.gameModules.items) |mod| {
|
||||||
|
if (mod.enabled) {
|
||||||
|
api.addImport(mod.name, self.buildSystem.nwdep.module(mod.name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return api;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn makeGameModule(self: *@This()) *std.Build.Step.Compile {
|
||||||
|
const b = self.buildSystem.b;
|
||||||
|
const bEngine = self.buildSystem.bEngine;
|
||||||
|
|
||||||
|
const opts = self.opts;
|
||||||
|
|
||||||
|
// 1. generate the main launch codeset.
|
||||||
|
const lib = b.addLibrary(.{
|
||||||
|
.name = b.fmt("{s}-mod", .{self.name}),
|
||||||
|
.linkage = if (opts.static_build) .static else .dynamic,
|
||||||
|
.root_module = b.createModule(.{
|
||||||
|
.target = opts.target,
|
||||||
|
.optimize = opts.optimize,
|
||||||
|
.root_source_file = bEngine.path("engine/modulelaunch.zig"),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (opts.static_build) {
|
||||||
|
// b.installArtifact(lib);
|
||||||
|
} else {
|
||||||
|
const installExtern = b.addInstallArtifact(lib, .{
|
||||||
|
.dest_dir = .{ .override = .{ .custom = "modules" } },
|
||||||
|
});
|
||||||
|
b.getInstallStep().dependOn(&installExtern.step);
|
||||||
|
}
|
||||||
|
|
||||||
|
return lib;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generateStaticShaders(self: *@This()) *std.Build.Module {
|
||||||
|
const loadStatics = self.buildSystem.generateInstallStaticResources(self.name, "content/_shaders") catch unreachable;
|
||||||
|
return loadStatics;
|
||||||
|
}
|
||||||
|
|
||||||
|
// spec is linked in both the base trampoline
|
||||||
|
pub fn compileInstall(self: *@This()) *std.Build.Step.Compile {
|
||||||
|
const bEngine = self.buildSystem.bEngine;
|
||||||
|
const b = self.buildSystem.b;
|
||||||
|
const core = self.buildSystem.nwdep.module("core");
|
||||||
|
self.finalizeModules();
|
||||||
|
|
||||||
|
// 1. create the loader
|
||||||
|
const exe = bEngine.addExecutable(.{
|
||||||
|
.name = self.name,
|
||||||
|
.root_module = bEngine.createModule(.{
|
||||||
|
.target = self.opts.target,
|
||||||
|
.optimize = self.opts.optimize,
|
||||||
|
.root_source_file = bEngine.path("engine/main2.zig"),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
// link core
|
||||||
|
const spec = self.makeSpec();
|
||||||
|
exe.root_module.addImport("gamespec", spec);
|
||||||
|
exe.root_module.addImport("core", core);
|
||||||
|
exe.root_module.addOptions("BacklogOptions", self.buildSystem.options);
|
||||||
|
|
||||||
|
if (!self.opts.static_build) {
|
||||||
|
const platform = self.buildSystem.nwdep.module("platform");
|
||||||
|
exe.root_module.addImport("platform", platform);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.opts.static_build) {
|
||||||
|
exe.root_module.addImport("staticShaderLoader", self.generateStaticShaders());
|
||||||
|
}
|
||||||
|
|
||||||
|
const gameModule = self.makeGameModule();
|
||||||
|
const gameApi = self.makeGameApi();
|
||||||
|
gameModule.root_module.addImport("backlog", gameApi);
|
||||||
|
gameModule.root_module.addImport("gamespec", spec);
|
||||||
|
|
||||||
|
if (self.opts.static_build) {
|
||||||
|
exe.root_module.addImport("backlog", gameApi);
|
||||||
|
}
|
||||||
|
|
||||||
|
// self.buildSystem.b.installArtifact(exe);
|
||||||
|
const installed = self.buildSystem.b.addInstallArtifact(exe, .{});
|
||||||
|
|
||||||
|
{
|
||||||
|
const run = b.addSystemCommand(&.{b.fmt("zig-out/bin/{s}", .{self.name})});
|
||||||
|
run.step.dependOn(&installed.step);
|
||||||
|
|
||||||
|
if (b.args) |args| {
|
||||||
|
run.addArgs(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
const run_exe = b.step(b.fmt("run-{s}", .{self.name}), "runs the program");
|
||||||
|
run_exe.dependOn(&run.step);
|
||||||
|
}
|
||||||
|
|
||||||
|
return exe;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const bh = @import("bh");
|
||||||
|
const backlog = @import("../build.zig");
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const Build = std.Build;
|
||||||
|
const LazyPath = Build.LazyPath;
|
||||||
125
build/utils.zig
125
build/utils.zig
|
|
@ -1,19 +1,114 @@
|
||||||
pub fn loadFileAlloc(filename: []const u8, comptime alignment: usize, allocator: std.mem.Allocator) ![]u8 {
|
|
||||||
var file = try std.fs.cwd().openFile(filename, .{});
|
pub fn buildGenerators(b: *std.Build, opts: bh.Options) void {
|
||||||
defer file.close();
|
const target = opts.target;
|
||||||
const filesize = (try file.stat()).size + 1; // add null byte
|
const optimize = opts.optimize;
|
||||||
const buffer: []align(alignment) u8 = try allocator.alignedAlloc(u8, alignment, filesize);
|
const static_build = opts.static_build;
|
||||||
errdefer allocator.free(buffer);
|
|
||||||
try file.reader().readNoEof(buffer[0 .. buffer.len - 1]);
|
const fwdGeneratorExe = b.addExecutable(.{
|
||||||
buffer[buffer.len - 1] = 0;
|
.name = "backlog-generate-fwd",
|
||||||
return buffer;
|
.root_module = b.createModule(.{
|
||||||
|
.target = b.graph.host,
|
||||||
|
.optimize = .Debug,
|
||||||
|
.root_source_file = b.path("buildgen/generateFwd.zig"),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const generateExe = b.addExecutable(.{
|
||||||
|
.name = "backlog-apigen",
|
||||||
|
.root_module = b.createModule(.{
|
||||||
|
.target = b.graph.host,
|
||||||
|
.optimize = .Debug,
|
||||||
|
.root_source_file = b.path("buildgen/generateApi.zig"),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const generateShaders = b.addExecutable(.{
|
||||||
|
.name = "backlog-shaderEmbedGen",
|
||||||
|
.root_module = b.createModule(.{
|
||||||
|
.target = b.graph.host,
|
||||||
|
.optimize = .Debug,
|
||||||
|
.root_source_file = b.path("buildgen/generateEmbeddedShaders.zig"),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const generateRcExe = b.addExecutable(.{
|
||||||
|
.name = "backlog-generate-rc",
|
||||||
|
.root_module = b.createModule(.{
|
||||||
|
.target = b.graph.host,
|
||||||
|
.optimize = .Debug,
|
||||||
|
.root_source_file = b.path("buildgen/generateRc.zig"),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const generateLoadDynamicsExe = b.addExecutable(.{
|
||||||
|
.name = "backlog-generate-loadDynamics",
|
||||||
|
.root_module = b.createModule(.{
|
||||||
|
.target = b.graph.host,
|
||||||
|
.optimize = .Debug,
|
||||||
|
.root_source_file = b.path("buildgen/generateLoadDynamics.zig"),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
b.installArtifact(fwdGeneratorExe);
|
||||||
|
b.installArtifact(generateLoadDynamicsExe);
|
||||||
|
b.installArtifact(generateExe);
|
||||||
|
b.installArtifact(generateShaders);
|
||||||
|
b.installArtifact(generateRcExe);
|
||||||
|
|
||||||
|
{
|
||||||
|
const loadDynamicsStub = b.addModule("loadDynamicsStub", .{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
.root_source_file = b.path("engine/loadDynamicsStub.zig"),
|
||||||
|
});
|
||||||
|
|
||||||
|
_ = loadDynamicsStub;
|
||||||
|
|
||||||
|
const mod = b.addModule("Backlog", .{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
.root_source_file = b.path("engine/backlog.zig"),
|
||||||
|
});
|
||||||
|
|
||||||
|
for (depList()) |depName| {
|
||||||
|
const dep = b.dependency(
|
||||||
|
depName,
|
||||||
|
.{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
.static_build = static_build,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const run = b.addRunArtifact(fwdGeneratorExe);
|
||||||
|
const output = run.addOutputFileArg(b.fmt("{s}_fwd.zig", .{depName}));
|
||||||
|
|
||||||
|
const modFwd = b.addModule(depName, .{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
.root_source_file = output,
|
||||||
|
});
|
||||||
|
|
||||||
|
mod.addImport(b.fmt("{s}", .{depName}), modFwd);
|
||||||
|
modFwd.addImport("module", dep.module(depName));
|
||||||
|
|
||||||
|
// mod.addImport(depName, dep.module(depName));
|
||||||
|
}
|
||||||
|
|
||||||
|
// link in large platform support functions... special case.
|
||||||
|
{
|
||||||
|
const dep = b.dependency("sdl3", .{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
.static_build = static_build,
|
||||||
|
});
|
||||||
|
const lib = dep.module("SDL3");
|
||||||
|
|
||||||
|
mod.addImport("sdl3_fwd", lib);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn checkAndFormatAst(allocator: std.mem.Allocator, input: []const u8) ![]u8 {
|
|
||||||
var ast = try std.zig.Ast.parse(allocator, @as([:0]const u8, @ptrCast(input)), .zig);
|
|
||||||
const out = try ast.render(allocator);
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
const bh = @import("bh");
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ pub fn main() !void {
|
||||||
\\ pub fn startEngine(vtable: *core.EngineObjectVTable, spec: *core.SpecVariantMap) bool {
|
\\ pub fn startEngine(vtable: *core.EngineObjectVTable, spec: *core.SpecVariantMap) bool {
|
||||||
\\ const args = getArgs() catch return false;
|
\\ const args = getArgs() catch return false;
|
||||||
\\
|
\\
|
||||||
\\ var backingAllocator: std.mem.Allocator = std.heap.c_allocator;
|
\\ var backingAllocator: std.mem.Allocator = std.heap.smp_allocator;
|
||||||
\\ var gpa: std.heap.GeneralPurposeAllocator(.{
|
\\ var gpa: std.heap.GeneralPurposeAllocator(.{
|
||||||
\\ .stack_trace_frames = 20,
|
\\ .stack_trace_frames = 20,
|
||||||
\\ }) = .{};
|
\\ }) = .{};
|
||||||
|
|
@ -162,7 +162,7 @@ pub fn main() !void {
|
||||||
try writer.print(allocator, ".{s} = true,\n", .{mod});
|
try writer.print(allocator, ".{s} = true,\n", .{mod});
|
||||||
}
|
}
|
||||||
|
|
||||||
try writer.print(allocator, "}}, std.heap.c_allocator); }}\n", .{});
|
try writer.print(allocator, "}}, std.heap.smp_allocator); }}\n", .{});
|
||||||
|
|
||||||
try writer.print(allocator, "const std = @import(\"std\");\n\n", .{});
|
try writer.print(allocator, "const std = @import(\"std\");\n\n", .{});
|
||||||
|
|
||||||
|
|
@ -73,10 +73,10 @@ pub fn main() !void {
|
||||||
|
|
||||||
var ast = try std.zig.Ast.parse(allocator, @as([:0]const u8, @ptrCast(writer.items[0 .. writer.items.len - 1])), .zig);
|
var ast = try std.zig.Ast.parse(allocator, @as([:0]const u8, @ptrCast(writer.items[0 .. writer.items.len - 1])), .zig);
|
||||||
|
|
||||||
// std.debug.print("output=\n{s}", .{content.items[0 .. content.items.len - 1]});
|
|
||||||
defer ast.deinit(allocator);
|
defer ast.deinit(allocator);
|
||||||
const out = try ast.renderAlloc(allocator);
|
const out = try ast.renderAlloc(allocator);
|
||||||
|
|
||||||
|
std.debug.print("output=\n{s}", .{out});
|
||||||
// Write the content to the file
|
// Write the content to the file
|
||||||
try file.writeAll(out);
|
try file.writeAll(out);
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub fn usage() void {
|
||||||
|
std.debug.print("generates a loader module which calls the start_modules for all the modules that the game module depends on.\ngenerate-mod-api <output file name> <module_name> <module list>\n", .{});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() !void {
|
||||||
|
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||||
|
defer arena.deinit();
|
||||||
|
const allocator = arena.allocator();
|
||||||
|
|
||||||
|
// Get output filename from build system
|
||||||
|
const args = try std.process.argsAlloc(allocator);
|
||||||
|
if (args.len < 3) {
|
||||||
|
usage();
|
||||||
|
@panic("Missing output filename\n");
|
||||||
|
}
|
||||||
|
const out_path = args[1];
|
||||||
|
const module_name = args[2];
|
||||||
|
const module_list = args[3..];
|
||||||
|
|
||||||
|
var writer = std.ArrayList(u8){};
|
||||||
|
|
||||||
|
try writer.print(allocator, "pub const moduleName:[]const u8 = \"{s}\";\n", .{module_name});
|
||||||
|
|
||||||
|
try writer.print(allocator, "pub const moduleList:[]const []const u8 = &.{{\n", .{});
|
||||||
|
for (module_list) |mod| {
|
||||||
|
try writer.print(allocator, "\"{s}\",\n", .{mod});
|
||||||
|
}
|
||||||
|
try writer.print(allocator, "}};\n", .{});
|
||||||
|
|
||||||
|
for (module_list) |mod| {
|
||||||
|
try writer.print(allocator, "pub const {s} = @import(\"{s}\").module;\n", .{ mod, mod });
|
||||||
|
}
|
||||||
|
|
||||||
|
try writer.append(allocator, 0);
|
||||||
|
|
||||||
|
const file = try std.fs.cwd().createFile(out_path, .{});
|
||||||
|
defer file.close();
|
||||||
|
|
||||||
|
var ast = try std.zig.Ast.parse(allocator, @as([:0]const u8, @ptrCast(writer.items[0 .. writer.items.len - 1])), .zig);
|
||||||
|
|
||||||
|
// std.debug.print("output=\n{s}", .{writer.items[0 .. writer.items.len - 1]});
|
||||||
|
defer ast.deinit(allocator);
|
||||||
|
const out = try ast.renderAlloc(allocator);
|
||||||
|
|
||||||
|
// Write the content to the file
|
||||||
|
try file.writeAll(out);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub fn usage() void {
|
||||||
|
std.debug.print("generate-program-spec <output file name> <spec_name> <module list>\n", .{});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() !void {
|
||||||
|
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||||
|
defer arena.deinit();
|
||||||
|
const allocator = arena.allocator();
|
||||||
|
|
||||||
|
// Get output filename from build system
|
||||||
|
const args = try std.process.argsAlloc(allocator);
|
||||||
|
if (args.len < 3) {
|
||||||
|
usage();
|
||||||
|
@panic("Missing output filename\n");
|
||||||
|
}
|
||||||
|
const out_path = args[1];
|
||||||
|
|
||||||
|
const programName = args[2];
|
||||||
|
const modules = args[3..];
|
||||||
|
|
||||||
|
// Generate Zig code content
|
||||||
|
var writer = std.ArrayList(u8){};
|
||||||
|
_ = try writer.appendSlice(allocator,
|
||||||
|
\\const core = @import("core").module;
|
||||||
|
\\
|
||||||
|
\\ const std = @import("std");
|
||||||
|
\\ pub fn getSpec() !*core.SpecVariantMap {
|
||||||
|
\\ const spec = try std.heap.smp_allocator.create(core.SpecVariantMap);
|
||||||
|
\\ spec.* = try core.createSpecVariant(.{
|
||||||
|
\\ .useGPA = true,
|
||||||
|
);
|
||||||
|
|
||||||
|
try writer.print(allocator, ".name = \"{s}\",\n", .{programName});
|
||||||
|
try writer.print(allocator, ".moduleName = \"{s}-mod\",\n", .{programName});
|
||||||
|
|
||||||
|
for (modules) |mod| {
|
||||||
|
try writer.print(allocator, ".{s} = true,\n", .{mod});
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = try writer.appendSlice(allocator,
|
||||||
|
\\ }, std.heap.smp_allocator);
|
||||||
|
\\
|
||||||
|
\\ return spec;
|
||||||
|
\\ }
|
||||||
|
\\
|
||||||
|
);
|
||||||
|
|
||||||
|
_ = try writer.print(allocator, "pub const programName = \"{s}\";", .{programName});
|
||||||
|
|
||||||
|
try writer.append(allocator, 0);
|
||||||
|
|
||||||
|
// Write to specified output file
|
||||||
|
// Open or create the file for writing (overwrites if it exists)
|
||||||
|
const file = try std.fs.cwd().createFile(out_path, .{});
|
||||||
|
defer file.close();
|
||||||
|
|
||||||
|
var ast = try std.zig.Ast.parse(allocator, @as([:0]const u8, @ptrCast(writer.items[0 .. writer.items.len - 1])), .zig);
|
||||||
|
|
||||||
|
// std.debug.print("output=\n{s}", .{content.items[0 .. content.items.len - 1]});
|
||||||
|
defer ast.deinit(allocator);
|
||||||
|
const out = try ast.renderAlloc(allocator);
|
||||||
|
|
||||||
|
// Write the content to the file
|
||||||
|
try file.writeAll(out);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
// templated file
|
||||||
|
//
|
||||||
|
// should still be a formattable zig file
|
||||||
|
// even if it is not compile-able
|
||||||
|
//
|
||||||
|
// definitions marked with // TEMPLATE_DEFINITION
|
||||||
|
// are removed during the templating step
|
||||||
|
|
||||||
|
const programName = "__program_name"; // TEMPLATE_DEFINITION
|
||||||
|
|
||||||
|
export fn loadModule() void {}
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
// templated file
|
||||||
|
//
|
||||||
|
// should still be a formattable zig file
|
||||||
|
// even if it is not compile-able
|
||||||
|
//
|
||||||
|
// definitions marked with // TEMPLATE_DEFINITION
|
||||||
|
// are removed during the templating step
|
||||||
|
|
||||||
|
const core = @import("core");
|
||||||
|
|
||||||
|
const programName = "__program_name"; // TEMPLATE_DEFINITION
|
||||||
|
|
||||||
|
pub export fn startup_module(p_allocator: *anyopaque, p_a: ?*anyopaque) bool {
|
||||||
|
const allocator = core.modulePreamble(p_allocator, p_a) catch return false;
|
||||||
|
_ = allocator;
|
||||||
|
// imgui.setupFromModule();
|
||||||
|
// platform.setupFromModule();
|
||||||
|
// sys.setupFromModule();
|
||||||
|
// rend.setupFromModule();
|
||||||
|
// backlog.physics.setupFromModule();
|
||||||
|
|
||||||
|
core.engine_logs("creating externgame");
|
||||||
|
// start_module(core.startup_getArgs(p_a.?)) catch return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
pub export fn startup_module(p_allocator: *anyopaque, p_a: ?*anyopaque) bool {
|
||||||
|
const allocator = core.modulePreamble(p_allocator, p_a) catch return false;
|
||||||
|
_ = allocator;
|
||||||
|
core.engine_logs("module started");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub export fn shutdown_module() void {}
|
||||||
|
|
||||||
|
// const backlog = @import("backlog");
|
||||||
|
// const core = backlog.core;
|
||||||
|
|
||||||
|
const core = @import("core").module;
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
pub fn loadFileAlloc(filename: []const u8, comptime alignment: usize, allocator: std.mem.Allocator) ![]u8 {
|
||||||
|
var file = try std.fs.cwd().openFile(filename, .{});
|
||||||
|
defer file.close();
|
||||||
|
const filesize = (try file.stat()).size + 1; // add null byte
|
||||||
|
const buffer: []align(alignment) u8 = try allocator.alignedAlloc(u8, alignment, filesize);
|
||||||
|
errdefer allocator.free(buffer);
|
||||||
|
try file.reader().readNoEof(buffer[0 .. buffer.len - 1]);
|
||||||
|
buffer[buffer.len - 1] = 0;
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn checkAndFormatAst(allocator: std.mem.Allocator, input: []const u8) ![]u8 {
|
||||||
|
var ast = try std.zig.Ast.parse(allocator, @as([:0]const u8, @ptrCast(input)), .zig);
|
||||||
|
const out = try ast.render(allocator);
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
.fontcache/
|
||||||
|
Saved/
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const Backlog = @import("Backlog");
|
||||||
|
|
||||||
|
pub fn build(b: *std.Build) void {
|
||||||
|
const target = b.standardTargetOptions(.{});
|
||||||
|
const optimize = b.standardOptimizeOption(.{});
|
||||||
|
|
||||||
|
var blbuild = Backlog.init(b, .{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
.backlogRoot = "../",
|
||||||
|
});
|
||||||
|
|
||||||
|
// blbuild.addDependencyInstalls(b, .ReleaseFast); //.ReleaseFast);
|
||||||
|
const zuck = blbuild.program(.{
|
||||||
|
.name = "zuck",
|
||||||
|
.desc = "A tiny shooter made with this engine.",
|
||||||
|
.root_source_file = b.path("zuck/main.zig"),
|
||||||
|
});
|
||||||
|
|
||||||
|
zuck.setModuleEnabled("imgui", true);
|
||||||
|
zuck.setModuleEnabled("audio", true);
|
||||||
|
zuck.setModuleEnabled("physics", true);
|
||||||
|
zuck.setModuleEnabled("ui", true);
|
||||||
|
zuck.setModuleEnabled("sys", true);
|
||||||
|
zuck.setModuleEnabled("net", true);
|
||||||
|
zuck.addExtraModule("gameExtras");
|
||||||
|
|
||||||
|
{
|
||||||
|
const zuckGame = zuck.addDynamicModule("zuckGame", b.path("zuck/game.zig"));
|
||||||
|
_ = zuckGame.compileInstall();
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = zuck.compileInstall();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
.{
|
||||||
|
.name = .MyProjects,
|
||||||
|
.version = "0.0.0",
|
||||||
|
.dependencies = .{
|
||||||
|
// Neonwood's /lib folder contains
|
||||||
|
// third party libraries.
|
||||||
|
//
|
||||||
|
// They can be directly accessed
|
||||||
|
//
|
||||||
|
// as well as any of the engine/ libraries
|
||||||
|
//
|
||||||
|
// in the general case though,
|
||||||
|
|
||||||
|
// engine libraries
|
||||||
|
.Backlog = .{ .path = "../" },
|
||||||
|
|
||||||
|
|
||||||
|
.SpirvReflect = .{ .path = "../lib/spirv-reflect-zig" },
|
||||||
|
|
||||||
|
.gameExtras = .{.path = "../extras/gameExtras"},
|
||||||
|
|
||||||
|
.zphysics = .{.path = "../lib/zphysics"},
|
||||||
|
.spng = .{ .path = "../lib/spng" },
|
||||||
|
.ozz = .{ .path = "../lib/ozz" },
|
||||||
|
.sdl3 = .{ .path = "../lib/sdl3" },
|
||||||
|
.miniaudio = .{ .path = "../lib/miniaudio" },
|
||||||
|
.lua = .{ .path = "../lib/lua" },
|
||||||
|
|
||||||
|
.enet = .{ .path = "../lib/enet" },
|
||||||
|
},
|
||||||
|
.paths = .{
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
.fingerprint = 0x14099f73bcfb78d8,
|
||||||
|
}
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,198 @@
|
||||||
|
#include <metal_stdlib>
|
||||||
|
#include <simd/simd.h>
|
||||||
|
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
struct type_Uniforms
|
||||||
|
{
|
||||||
|
float4 viewPos;
|
||||||
|
float4 lightPosition;
|
||||||
|
float4 directionalLight;
|
||||||
|
float4 directionalLightColor;
|
||||||
|
float2 screenSize;
|
||||||
|
float lightPower;
|
||||||
|
float time;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Scene
|
||||||
|
{
|
||||||
|
float4x4 Model;
|
||||||
|
uint textureMode;
|
||||||
|
int animation;
|
||||||
|
uint flags;
|
||||||
|
float float0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct type_StructuredBuffer_Scene
|
||||||
|
{
|
||||||
|
Scene _m0[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
constant float4 _92 = {};
|
||||||
|
constant float3 _94 = {};
|
||||||
|
|
||||||
|
struct main0_out
|
||||||
|
{
|
||||||
|
float4 out_var_SV_Target0 [[color(0)]];
|
||||||
|
float4 out_var_SV_Target1 [[color(1)]];
|
||||||
|
float4 out_var_SV_Target2 [[color(2)]];
|
||||||
|
float4 out_var_SV_Target3 [[color(3)]];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct main0_in
|
||||||
|
{
|
||||||
|
float2 in_var_TEXCOORD0 [[user(locn0)]];
|
||||||
|
float3 in_var_TEXCOORD1 [[user(locn1)]];
|
||||||
|
float3 in_var_TEXCOORD2 [[user(locn2)]];
|
||||||
|
float4 in_var_TEXCOORD3 [[user(locn3)]];
|
||||||
|
uint in_var_TEXCOORD4 [[user(locn4)]];
|
||||||
|
float3 in_var_TEXCOORD5 [[user(locn5)]];
|
||||||
|
};
|
||||||
|
|
||||||
|
fragment main0_out main0(main0_in in [[stage_in]], constant type_Uniforms& Uniforms [[buffer(0)]], const device type_StructuredBuffer_Scene& scene [[buffer(1)]], texture2d<float> Texture0 [[texture(0)]], texture2d<float> Texture1 [[texture(1)]], texture2d<float> Texture2 [[texture(2)]], texture2d<float> DirectionalShadowDepthMap [[texture(3)]], sampler Sampler0 [[sampler(0)]], sampler Sampler1 [[sampler(1)]], sampler Sampler2 [[sampler(2)]], sampler DirectionalShadowSampler [[sampler(3)]])
|
||||||
|
{
|
||||||
|
main0_out out = {};
|
||||||
|
int _104 = int(scene._m0[in.in_var_TEXCOORD4].textureMode);
|
||||||
|
int _105 = _104 & 240;
|
||||||
|
float4 _139;
|
||||||
|
if (_105 == 16)
|
||||||
|
{
|
||||||
|
float3 _126 = float3(Texture0.sample(Sampler0, in.in_var_TEXCOORD0).x, Texture1.sample(Sampler1, in.in_var_TEXCOORD0).x, Texture2.sample(Sampler2, in.in_var_TEXCOORD0).x) + float3(-0.0625, -0.5, -0.5);
|
||||||
|
_139 = float4(dot(_126, float3(1.164000034332275390625, 0.0, 1.7929999828338623046875)), dot(_126, float3(1.164000034332275390625, -0.212999999523162841796875, -0.53299999237060546875)), dot(_126, float3(1.164000034332275390625, 2.111999988555908203125, 0.0)), 1.0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float4 _138;
|
||||||
|
if (_105 == 0)
|
||||||
|
{
|
||||||
|
_138 = Texture0.sample(Sampler0, in.in_var_TEXCOORD0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_138 = _92;
|
||||||
|
}
|
||||||
|
_139 = _138;
|
||||||
|
}
|
||||||
|
float4 _145;
|
||||||
|
if ((_104 & 1) == 1)
|
||||||
|
{
|
||||||
|
_145 = powr(_139, float4(2.2000000476837158203125));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_145 = _139;
|
||||||
|
}
|
||||||
|
if (_145.w < 0.00999999977648258209228515625)
|
||||||
|
{
|
||||||
|
discard_fragment();
|
||||||
|
}
|
||||||
|
float3 _155 = float3(0.800000011920928955078125, 0.800000011920928955078125, 0.5) * Uniforms.lightPower;
|
||||||
|
float3 _202;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
float3 _159 = Uniforms.lightPosition.xyz - in.in_var_TEXCOORD1;
|
||||||
|
float _160 = length(_159);
|
||||||
|
float _161 = _160 * _160;
|
||||||
|
float _167;
|
||||||
|
if (_160 > 2.0)
|
||||||
|
{
|
||||||
|
_167 = 0.5 / _161;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_167 = 1.0 / _161;
|
||||||
|
}
|
||||||
|
float _172;
|
||||||
|
if (_160 > 4.0)
|
||||||
|
{
|
||||||
|
_172 = _167 * 0.5;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_172 = _167;
|
||||||
|
}
|
||||||
|
float _174 = (_160 > 15.0) ? 0.0 : _172;
|
||||||
|
float _176 = (_174 > 1.0) ? 1.0 : _174;
|
||||||
|
if (length(in.in_var_TEXCOORD2) < 0.100000001490116119384765625)
|
||||||
|
{
|
||||||
|
_202 = (in.in_var_TEXCOORD1 * _155) * _176;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
float3 _183 = fast::normalize(_159);
|
||||||
|
_202 = ((_155 * precise::max(dot(_183, in.in_var_TEXCOORD2), 0.0)) * _176) + (((_155 * powr(precise::max(dot(in.in_var_TEXCOORD2, fast::normalize(_183 + fast::normalize(in.in_var_TEXCOORD1 - Uniforms.viewPos.xyz))), 0.0), 30.0)) * 2.0) * _176);
|
||||||
|
break;
|
||||||
|
} while(false);
|
||||||
|
float3 _219 = ((in.in_var_TEXCOORD3.xyz / float3(in.in_var_TEXCOORD3.w)) * 0.5) + float3(0.5);
|
||||||
|
float3 _221;
|
||||||
|
_221.x = _219.x;
|
||||||
|
float2 _222 = _221.xy;
|
||||||
|
_222.y = -_219.y;
|
||||||
|
float _229;
|
||||||
|
int _232;
|
||||||
|
int _234;
|
||||||
|
_229 = 0.0;
|
||||||
|
_232 = 0;
|
||||||
|
_234 = -2;
|
||||||
|
float _230;
|
||||||
|
int _233;
|
||||||
|
for (; _234 <= 2; _229 = _230, _232 = _233, _234++)
|
||||||
|
{
|
||||||
|
_233 = _232;
|
||||||
|
_230 = _229;
|
||||||
|
for (int _243 = -2; _243 <= 2; )
|
||||||
|
{
|
||||||
|
_233++;
|
||||||
|
_230 += float((in.in_var_TEXCOORD3.z - 0.0030000000260770320892333984375) > DirectionalShadowDepthMap.sample(DirectionalShadowSampler, (_222 + float2(float(_243) * 0.000244140625, float(_234) * 0.000244140625))).x);
|
||||||
|
_243++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
float3 _272;
|
||||||
|
if ((_104 & 2) > 0)
|
||||||
|
{
|
||||||
|
_272 = powr(_145.xyz, float3(0.4545454680919647216796875));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_272 = _145.xyz * ((float3(0.100000001490116119384765625) + _202) + ((Uniforms.directionalLightColor.xyz * precise::max(dot(Uniforms.directionalLight.xyz, in.in_var_TEXCOORD2), 0.0)) * (1.0 - (_229 / float(_232)))));
|
||||||
|
}
|
||||||
|
float4 _289;
|
||||||
|
if (_272.x > 1.0)
|
||||||
|
{
|
||||||
|
float4 _288 = float4(0.0);
|
||||||
|
_288.x = _272.x;
|
||||||
|
_289 = _288;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_289 = float4(0.0);
|
||||||
|
}
|
||||||
|
float4 _294;
|
||||||
|
if (_272.y > 1.0)
|
||||||
|
{
|
||||||
|
float4 _293 = _289;
|
||||||
|
_293.y = _272.y;
|
||||||
|
_294 = _293;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_294 = _289;
|
||||||
|
}
|
||||||
|
float4 _299;
|
||||||
|
if (_272.z > 1.0)
|
||||||
|
{
|
||||||
|
float4 _298 = _294;
|
||||||
|
_298.z = _272.z;
|
||||||
|
_299 = _298;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_299 = _294;
|
||||||
|
}
|
||||||
|
out.out_var_SV_Target0 = float4(_272, _145.w);
|
||||||
|
out.out_var_SV_Target1 = _299;
|
||||||
|
out.out_var_SV_Target2 = float4(in.in_var_TEXCOORD1, 1.0);
|
||||||
|
out.out_var_SV_Target3 = float4(in.in_var_TEXCOORD5, 1.0);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,119 @@
|
||||||
|
#include <metal_stdlib>
|
||||||
|
#include <simd/simd.h>
|
||||||
|
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
struct Scene
|
||||||
|
{
|
||||||
|
float4x4 Model;
|
||||||
|
uint textureMode;
|
||||||
|
int animation;
|
||||||
|
uint flags;
|
||||||
|
float float0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct type_StructuredBuffer_Scene
|
||||||
|
{
|
||||||
|
Scene _m0[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BoneTransform
|
||||||
|
{
|
||||||
|
float4x4 final;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct type_StructuredBuffer_BoneTransform
|
||||||
|
{
|
||||||
|
BoneTransform _m0[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct type_Uniforms
|
||||||
|
{
|
||||||
|
float4x4 ViewProjection;
|
||||||
|
float4x4 NoTranslateView;
|
||||||
|
float4x4 ViewTransform;
|
||||||
|
float4x4 ShadowMapProjection;
|
||||||
|
float4 cameraPosition;
|
||||||
|
float time;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct main0_out
|
||||||
|
{
|
||||||
|
float2 out_var_TEXCOORD0 [[user(locn0)]];
|
||||||
|
float3 out_var_TEXCOORD1 [[user(locn1)]];
|
||||||
|
float3 out_var_TEXCOORD2 [[user(locn2)]];
|
||||||
|
float4 out_var_TEXCOORD3 [[user(locn3)]];
|
||||||
|
uint out_var_TEXCOORD4 [[user(locn4)]];
|
||||||
|
float3 out_var_TEXCOORD5 [[user(locn5)]];
|
||||||
|
float4 gl_Position [[position]];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct main0_in
|
||||||
|
{
|
||||||
|
float3 in_var_TEXCOORD0 [[attribute(0)]];
|
||||||
|
float3 in_var_TEXCOORD1 [[attribute(1)]];
|
||||||
|
float2 in_var_TEXCOORD3 [[attribute(3)]];
|
||||||
|
uint in_var_TEXCOORD4 [[attribute(4)]];
|
||||||
|
uint in_var_TEXCOORD5 [[attribute(5)]];
|
||||||
|
};
|
||||||
|
|
||||||
|
vertex main0_out main0(main0_in in [[stage_in]], constant type_Uniforms& Uniforms [[buffer(0)]], const device type_StructuredBuffer_Scene& scene [[buffer(1)]], const device type_StructuredBuffer_BoneTransform& animationBuffer [[buffer(2)]], uint gl_InstanceIndex [[instance_id]])
|
||||||
|
{
|
||||||
|
main0_out out = {};
|
||||||
|
float3 _111;
|
||||||
|
if (scene._m0[gl_InstanceIndex].animation != (-1))
|
||||||
|
{
|
||||||
|
float3 _83;
|
||||||
|
_83 = float3(0.0);
|
||||||
|
for (int _86 = 0; _86 < 4; )
|
||||||
|
{
|
||||||
|
uint _92 = (8u * uint(_86)) & 31u;
|
||||||
|
_83 += ((animationBuffer._m0[uint(scene._m0[gl_InstanceIndex].animation) + ((in.in_var_TEXCOORD4 >> _92) & 255u)].final * float4(in.in_var_TEXCOORD0, 1.0)).xyz * (float((in.in_var_TEXCOORD5 >> _92) & 255u) * 0.0039215688593685626983642578125));
|
||||||
|
_86++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
_111 = _83;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_111 = in.in_var_TEXCOORD0;
|
||||||
|
}
|
||||||
|
float4 _115 = float4(_111, 1.0);
|
||||||
|
float3 _207;
|
||||||
|
float3 _208;
|
||||||
|
float3 _209;
|
||||||
|
float4 _210;
|
||||||
|
float4 _211;
|
||||||
|
if (int(scene._m0[gl_InstanceIndex].flags & 4u) > 0)
|
||||||
|
{
|
||||||
|
float3 _127 = (scene._m0[gl_InstanceIndex].Model * float4(0.0, 0.0, 0.0, 1.0)).xyz;
|
||||||
|
float3 _132 = fast::normalize(Uniforms.cameraPosition.xyz - _127);
|
||||||
|
float3 _134 = fast::normalize(cross(float3(0.0, 1.0, 0.0), _132));
|
||||||
|
float4 _152 = float4((_127 + ((_134 * (-in.in_var_TEXCOORD0.x)) * scene._m0[gl_InstanceIndex].float0)) + ((cross(_132, _134) * in.in_var_TEXCOORD0.y) * scene._m0[gl_InstanceIndex].float0), 1.0);
|
||||||
|
_207 = _152.xyz;
|
||||||
|
_208 = _132;
|
||||||
|
_209 = float3(0.0, 0.0, 1.0);
|
||||||
|
_210 = Uniforms.ViewProjection * _152;
|
||||||
|
_211 = _152;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float4 _159 = scene._m0[gl_InstanceIndex].Model * _115;
|
||||||
|
float4x4 _194 = float4x4(float4(fast::normalize(float3(scene._m0[gl_InstanceIndex].Model[0][0], scene._m0[gl_InstanceIndex].Model[1][0], scene._m0[gl_InstanceIndex].Model[2][0])), 0.0), float4(fast::normalize(float3(scene._m0[gl_InstanceIndex].Model[0][1], scene._m0[gl_InstanceIndex].Model[1][1], scene._m0[gl_InstanceIndex].Model[2][1])), 0.0), float4(fast::normalize(float3(scene._m0[gl_InstanceIndex].Model[0][2], scene._m0[gl_InstanceIndex].Model[1][2], scene._m0[gl_InstanceIndex].Model[2][2])), 0.0), float4(0.0, 0.0, 0.0, 1.0));
|
||||||
|
float4 _198 = float4(in.in_var_TEXCOORD1, 1.0);
|
||||||
|
_207 = _159.xyz;
|
||||||
|
_208 = fast::normalize(_198 * _194).xyz;
|
||||||
|
_209 = (_198 * (_194 * transpose(Uniforms.NoTranslateView))).xyz;
|
||||||
|
_210 = Uniforms.ViewProjection * (scene._m0[gl_InstanceIndex].Model * _115);
|
||||||
|
_211 = _159;
|
||||||
|
}
|
||||||
|
out.out_var_TEXCOORD0 = in.in_var_TEXCOORD3;
|
||||||
|
out.out_var_TEXCOORD1 = _207;
|
||||||
|
out.out_var_TEXCOORD2 = _208;
|
||||||
|
out.out_var_TEXCOORD3 = Uniforms.ShadowMapProjection * _211;
|
||||||
|
out.out_var_TEXCOORD4 = gl_InstanceIndex;
|
||||||
|
out.out_var_TEXCOORD5 = _209;
|
||||||
|
out.gl_Position = _210;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,259 @@
|
||||||
|
#include <metal_stdlib>
|
||||||
|
#include <simd/simd.h>
|
||||||
|
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
struct Scene
|
||||||
|
{
|
||||||
|
float2 imagePosition;
|
||||||
|
float2 _imageSize;
|
||||||
|
float2 anchorPoint;
|
||||||
|
float2 scale;
|
||||||
|
float alpha;
|
||||||
|
float borderWidth;
|
||||||
|
uint flags;
|
||||||
|
float4 baseColor;
|
||||||
|
float4 rounding;
|
||||||
|
float4 edgeColor;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct type_StructuredBuffer_Scene
|
||||||
|
{
|
||||||
|
Scene _m0[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct main0_out
|
||||||
|
{
|
||||||
|
float4 out_var_SV_Target0 [[color(0)]];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct main0_in
|
||||||
|
{
|
||||||
|
float4 in_var_TEXCOORD0 [[user(locn0)]];
|
||||||
|
float2 in_var_TEXCOORD1 [[user(locn1)]];
|
||||||
|
float2 in_var_TEXCOORD2 [[user(locn2)]];
|
||||||
|
uint in_var_TEXCOORD3 [[user(locn3)]];
|
||||||
|
};
|
||||||
|
|
||||||
|
fragment main0_out main0(main0_in in [[stage_in]], const device type_StructuredBuffer_Scene& scene [[buffer(0)]], texture2d<float> Texture0 [[texture(0)]], sampler Sampler0 [[sampler(0)]])
|
||||||
|
{
|
||||||
|
main0_out out = {};
|
||||||
|
bool _71 = in.in_var_TEXCOORD2.x < scene._m0[in.in_var_TEXCOORD3].rounding.x;
|
||||||
|
bool _78;
|
||||||
|
if (_71)
|
||||||
|
{
|
||||||
|
_78 = in.in_var_TEXCOORD2.y < scene._m0[in.in_var_TEXCOORD3].rounding.y;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_78 = false;
|
||||||
|
}
|
||||||
|
float _95;
|
||||||
|
float3 _96;
|
||||||
|
if (_78)
|
||||||
|
{
|
||||||
|
float _82 = distance(in.in_var_TEXCOORD2, float2(scene._m0[in.in_var_TEXCOORD3].rounding.x));
|
||||||
|
float _93;
|
||||||
|
float3 _94;
|
||||||
|
if (_82 > scene._m0[in.in_var_TEXCOORD3].rounding.x)
|
||||||
|
{
|
||||||
|
discard_fragment();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (abs(_82 - scene._m0[in.in_var_TEXCOORD3].rounding.x) < 1.0)
|
||||||
|
{
|
||||||
|
_93 = scene._m0[in.in_var_TEXCOORD3].edgeColor.w;
|
||||||
|
_94 = scene._m0[in.in_var_TEXCOORD3].edgeColor.xyz;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_93 = scene._m0[in.in_var_TEXCOORD3].alpha;
|
||||||
|
_94 = in.in_var_TEXCOORD0.xyz;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_95 = _93;
|
||||||
|
_96 = _94;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_95 = scene._m0[in.in_var_TEXCOORD3].alpha;
|
||||||
|
_96 = in.in_var_TEXCOORD0.xyz;
|
||||||
|
}
|
||||||
|
float _99 = scene._m0[in.in_var_TEXCOORD3]._imageSize.x - scene._m0[in.in_var_TEXCOORD3].rounding.y;
|
||||||
|
bool _106;
|
||||||
|
if (in.in_var_TEXCOORD2.x > _99)
|
||||||
|
{
|
||||||
|
_106 = in.in_var_TEXCOORD2.y < scene._m0[in.in_var_TEXCOORD3].rounding.y;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_106 = false;
|
||||||
|
}
|
||||||
|
float _123;
|
||||||
|
float3 _124;
|
||||||
|
if (_106)
|
||||||
|
{
|
||||||
|
float _110 = distance(in.in_var_TEXCOORD2, float2(_99, scene._m0[in.in_var_TEXCOORD3].rounding.y));
|
||||||
|
float _121;
|
||||||
|
float3 _122;
|
||||||
|
if (_110 > scene._m0[in.in_var_TEXCOORD3].rounding.y)
|
||||||
|
{
|
||||||
|
discard_fragment();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (abs(_110 - scene._m0[in.in_var_TEXCOORD3].rounding.y) < 1.0)
|
||||||
|
{
|
||||||
|
_121 = scene._m0[in.in_var_TEXCOORD3].edgeColor.w;
|
||||||
|
_122 = scene._m0[in.in_var_TEXCOORD3].edgeColor.xyz;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_121 = _95;
|
||||||
|
_122 = _96;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_123 = _121;
|
||||||
|
_124 = _122;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_123 = _95;
|
||||||
|
_124 = _96;
|
||||||
|
}
|
||||||
|
bool _132;
|
||||||
|
if (_71)
|
||||||
|
{
|
||||||
|
_132 = in.in_var_TEXCOORD2.y > (scene._m0[in.in_var_TEXCOORD3]._imageSize.y - scene._m0[in.in_var_TEXCOORD3].rounding.y);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_132 = false;
|
||||||
|
}
|
||||||
|
float _151;
|
||||||
|
float3 _152;
|
||||||
|
if (_132)
|
||||||
|
{
|
||||||
|
float _138 = distance(in.in_var_TEXCOORD2, float2(scene._m0[in.in_var_TEXCOORD3].rounding.x, scene._m0[in.in_var_TEXCOORD3]._imageSize.y - scene._m0[in.in_var_TEXCOORD3].rounding.y));
|
||||||
|
float _149;
|
||||||
|
float3 _150;
|
||||||
|
if (_138 > scene._m0[in.in_var_TEXCOORD3].rounding.y)
|
||||||
|
{
|
||||||
|
discard_fragment();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (abs(_138 - scene._m0[in.in_var_TEXCOORD3].rounding.y) < 1.0)
|
||||||
|
{
|
||||||
|
_149 = scene._m0[in.in_var_TEXCOORD3].edgeColor.w;
|
||||||
|
_150 = scene._m0[in.in_var_TEXCOORD3].edgeColor.xyz;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_149 = _123;
|
||||||
|
_150 = _124;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_151 = _149;
|
||||||
|
_152 = _150;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_151 = _123;
|
||||||
|
_152 = _124;
|
||||||
|
}
|
||||||
|
bool _163;
|
||||||
|
if (in.in_var_TEXCOORD2.x > (scene._m0[in.in_var_TEXCOORD3]._imageSize.x - scene._m0[in.in_var_TEXCOORD3].rounding.w))
|
||||||
|
{
|
||||||
|
_163 = (scene._m0[in.in_var_TEXCOORD3]._imageSize.y - in.in_var_TEXCOORD2.y) < scene._m0[in.in_var_TEXCOORD3].rounding.w;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_163 = false;
|
||||||
|
}
|
||||||
|
float _183;
|
||||||
|
float3 _184;
|
||||||
|
if (_163)
|
||||||
|
{
|
||||||
|
float _170 = distance(in.in_var_TEXCOORD2, float2(scene._m0[in.in_var_TEXCOORD3]._imageSize.x - scene._m0[in.in_var_TEXCOORD3].rounding.x, scene._m0[in.in_var_TEXCOORD3]._imageSize.y - scene._m0[in.in_var_TEXCOORD3].rounding.y));
|
||||||
|
float _181;
|
||||||
|
float3 _182;
|
||||||
|
if (_170 > scene._m0[in.in_var_TEXCOORD3].rounding.y)
|
||||||
|
{
|
||||||
|
discard_fragment();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (abs(_170 - scene._m0[in.in_var_TEXCOORD3].rounding.y) < 1.0)
|
||||||
|
{
|
||||||
|
_181 = scene._m0[in.in_var_TEXCOORD3].edgeColor.w;
|
||||||
|
_182 = scene._m0[in.in_var_TEXCOORD3].edgeColor.xyz;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_181 = _151;
|
||||||
|
_182 = _152;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_183 = _181;
|
||||||
|
_184 = _182;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_183 = _151;
|
||||||
|
_184 = _152;
|
||||||
|
}
|
||||||
|
bool _191;
|
||||||
|
if (!(in.in_var_TEXCOORD2.x < scene._m0[in.in_var_TEXCOORD3].borderWidth))
|
||||||
|
{
|
||||||
|
_191 = in.in_var_TEXCOORD2.x > (scene._m0[in.in_var_TEXCOORD3]._imageSize.x - scene._m0[in.in_var_TEXCOORD3].borderWidth);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_191 = true;
|
||||||
|
}
|
||||||
|
bool _198;
|
||||||
|
if (!_191)
|
||||||
|
{
|
||||||
|
_198 = in.in_var_TEXCOORD2.y < scene._m0[in.in_var_TEXCOORD3].borderWidth;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_198 = true;
|
||||||
|
}
|
||||||
|
bool _207;
|
||||||
|
if (!_198)
|
||||||
|
{
|
||||||
|
_207 = in.in_var_TEXCOORD2.y > (scene._m0[in.in_var_TEXCOORD3]._imageSize.y - scene._m0[in.in_var_TEXCOORD3].borderWidth);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_207 = true;
|
||||||
|
}
|
||||||
|
float _212;
|
||||||
|
float3 _213;
|
||||||
|
if (_207)
|
||||||
|
{
|
||||||
|
_212 = scene._m0[in.in_var_TEXCOORD3].edgeColor.w;
|
||||||
|
_213 = scene._m0[in.in_var_TEXCOORD3].edgeColor.xyz;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_212 = _183;
|
||||||
|
_213 = _184;
|
||||||
|
}
|
||||||
|
float4 _238;
|
||||||
|
if ((scene._m0[in.in_var_TEXCOORD3].flags & 1u) > 0u)
|
||||||
|
{
|
||||||
|
float4 _227 = Texture0.sample(Sampler0, float2(in.in_var_TEXCOORD1.x, 1.0 - in.in_var_TEXCOORD1.y));
|
||||||
|
_238 = float4(_227.xyz, _227.w * _212);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_238 = float4(_213, _212);
|
||||||
|
}
|
||||||
|
out.out_var_SV_Target0 = _238;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
#include <metal_stdlib>
|
||||||
|
#include <simd/simd.h>
|
||||||
|
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
struct Scene
|
||||||
|
{
|
||||||
|
float2 imagePosition;
|
||||||
|
float2 _imageSize;
|
||||||
|
float2 anchorPoint;
|
||||||
|
float2 scale;
|
||||||
|
float alpha;
|
||||||
|
float borderWidth;
|
||||||
|
uint flags;
|
||||||
|
float4 baseColor;
|
||||||
|
float4 rounding;
|
||||||
|
float4 edgeColor;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct type_StructuredBuffer_Scene
|
||||||
|
{
|
||||||
|
Scene _m0[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct type_Uniforms
|
||||||
|
{
|
||||||
|
float2 Extents;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct main0_out
|
||||||
|
{
|
||||||
|
float4 out_var_TEXCOORD0 [[user(locn0)]];
|
||||||
|
float2 out_var_TEXCOORD1 [[user(locn1)]];
|
||||||
|
float2 out_var_TEXCOORD2 [[user(locn2)]];
|
||||||
|
uint out_var_TEXCOORD3 [[user(locn3)]];
|
||||||
|
float4 gl_Position [[position]];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct main0_in
|
||||||
|
{
|
||||||
|
float3 in_var_TEXCOORD0 [[attribute(0)]];
|
||||||
|
float2 in_var_TEXCOORD3 [[attribute(3)]];
|
||||||
|
};
|
||||||
|
|
||||||
|
vertex main0_out main0(main0_in in [[stage_in]], constant type_Uniforms& Uniforms [[buffer(0)]], const device type_StructuredBuffer_Scene& scene [[buffer(1)]], uint gl_InstanceIndex [[instance_id]])
|
||||||
|
{
|
||||||
|
main0_out out = {};
|
||||||
|
float2 _63 = scene._m0[gl_InstanceIndex]._imageSize / Uniforms.Extents;
|
||||||
|
float2 _69 = (((scene._m0[gl_InstanceIndex].imagePosition / Uniforms.Extents) * 2.0) - float2(1.0)) - ((scene._m0[gl_InstanceIndex].anchorPoint * _63) * scene._m0[gl_InstanceIndex].scale);
|
||||||
|
float _85 = _69.y + ((in.in_var_TEXCOORD0.y * _63.y) * scene._m0[gl_InstanceIndex].scale.y);
|
||||||
|
float4 _88 = float4(_69.x + ((in.in_var_TEXCOORD0.x * _63.x) * scene._m0[gl_InstanceIndex].scale.x), _85, in.in_var_TEXCOORD0.z, 1.0);
|
||||||
|
_88.y = -_85;
|
||||||
|
float2 _100 = ((in.in_var_TEXCOORD0.xy - scene._m0[gl_InstanceIndex].anchorPoint) * float2(0.5)) * scene._m0[gl_InstanceIndex]._imageSize;
|
||||||
|
_100.y = scene._m0[gl_InstanceIndex]._imageSize.y - _100.y;
|
||||||
|
out.out_var_TEXCOORD0 = scene._m0[gl_InstanceIndex].baseColor;
|
||||||
|
out.out_var_TEXCOORD1 = float2(1.0 - in.in_var_TEXCOORD3.x, in.in_var_TEXCOORD3.y);
|
||||||
|
out.out_var_TEXCOORD2 = _100;
|
||||||
|
out.out_var_TEXCOORD3 = gl_InstanceIndex;
|
||||||
|
out.gl_Position = _88;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,102 @@
|
||||||
|
#include <metal_stdlib>
|
||||||
|
#include <simd/simd.h>
|
||||||
|
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
struct FontInfo
|
||||||
|
{
|
||||||
|
float2 position;
|
||||||
|
float2 size;
|
||||||
|
uint isSdf;
|
||||||
|
uint pad0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct type_StructuredBuffer_FontInfo
|
||||||
|
{
|
||||||
|
FontInfo _m0[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct main0_out
|
||||||
|
{
|
||||||
|
float4 out_var_SV_Target0 [[color(0)]];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct main0_in
|
||||||
|
{
|
||||||
|
uint in_var_TEXCOORD0 [[user(locn0)]];
|
||||||
|
float2 in_var_TEXCOORD1 [[user(locn1)]];
|
||||||
|
float2 in_var_TEXCOORD2 [[user(locn2)]];
|
||||||
|
uint in_var_TEXCOORD3 [[user(locn3)]];
|
||||||
|
};
|
||||||
|
|
||||||
|
fragment main0_out main0(main0_in in [[stage_in]], const device type_StructuredBuffer_FontInfo& fontBuffer [[buffer(0)]], texture2d<float> Texture0 [[texture(0)]], sampler Sampler0 [[sampler(0)]])
|
||||||
|
{
|
||||||
|
main0_out out = {};
|
||||||
|
float4 _67 = Texture0.sample(Sampler0, in.in_var_TEXCOORD1);
|
||||||
|
bool _104;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
bool _85;
|
||||||
|
if (in.in_var_TEXCOORD2.x >= fontBuffer._m0[in.in_var_TEXCOORD3].position.x)
|
||||||
|
{
|
||||||
|
_85 = in.in_var_TEXCOORD2.x <= (fontBuffer._m0[in.in_var_TEXCOORD3].position.x + fontBuffer._m0[in.in_var_TEXCOORD3].size.x);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_85 = false;
|
||||||
|
}
|
||||||
|
bool _92;
|
||||||
|
if (_85)
|
||||||
|
{
|
||||||
|
_92 = in.in_var_TEXCOORD2.y >= fontBuffer._m0[in.in_var_TEXCOORD3].position.y;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_92 = false;
|
||||||
|
}
|
||||||
|
bool _101;
|
||||||
|
if (_92)
|
||||||
|
{
|
||||||
|
_101 = in.in_var_TEXCOORD2.y <= (fontBuffer._m0[in.in_var_TEXCOORD3].position.y + fontBuffer._m0[in.in_var_TEXCOORD3].size.y);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_101 = false;
|
||||||
|
}
|
||||||
|
if (_101)
|
||||||
|
{
|
||||||
|
_104 = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_104 = false;
|
||||||
|
break;
|
||||||
|
} while(false);
|
||||||
|
if (!_104)
|
||||||
|
{
|
||||||
|
discard_fragment();
|
||||||
|
}
|
||||||
|
float _110 = float(in.in_var_TEXCOORD0 & 255u) * 0.0039215688593685626983642578125;
|
||||||
|
float _114 = float((in.in_var_TEXCOORD0 >> 8u) & 255u) * 0.0039215688593685626983642578125;
|
||||||
|
float _118 = float((in.in_var_TEXCOORD0 >> 16u) & 255u) * 0.0039215688593685626983642578125;
|
||||||
|
float _122 = float((in.in_var_TEXCOORD0 >> 24u) & 255u) * 0.0039215688593685626983642578125;
|
||||||
|
float4 _187;
|
||||||
|
if (fontBuffer._m0[in.in_var_TEXCOORD3].isSdf == 1u)
|
||||||
|
{
|
||||||
|
float _128 = _67.x;
|
||||||
|
float _129 = fwidth(_128);
|
||||||
|
float _130 = 0.529411792755126953125 - _129;
|
||||||
|
float _131 = 0.529411792755126953125 + _129;
|
||||||
|
float2 _137 = (dfdx(in.in_var_TEXCOORD1) + dfdy(in.in_var_TEXCOORD1)) * 0.3540000021457672119140625;
|
||||||
|
float4 _144 = float4(in.in_var_TEXCOORD1 - _137, in.in_var_TEXCOORD1 + _137);
|
||||||
|
float4 _176 = float4(_110, _114, _118, ((fast::clamp(smoothstep(_130, _131, _128), 0.0, 1.0) + (0.5 * (((fast::clamp(smoothstep(_130, _131, Texture0.sample(Sampler0, _144.xy).x), 0.0, 1.0) + fast::clamp(smoothstep(_130, _131, Texture0.sample(Sampler0, _144.zw).x), 0.0, 1.0)) + fast::clamp(smoothstep(_130, _131, Texture0.sample(Sampler0, _144.xw).x), 0.0, 1.0)) + fast::clamp(smoothstep(_130, _131, Texture0.sample(Sampler0, _144.zy).x), 0.0, 1.0)))) * 0.3333333432674407958984375) * _122);
|
||||||
|
float3 _178 = powr(_176.xyz, float3(2.2000000476837158203125));
|
||||||
|
_187 = float4(_178.x, _178.y, _178.z, _176.w);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_187 = float4(_110, _114, _118, powr(_67.x / dot(float4(_110, _114, _118, _122).xyz, float3(0.2125999927520751953125, 0.715200006961822509765625, 0.072200000286102294921875)), 0.4545454680919647216796875) * _122);
|
||||||
|
}
|
||||||
|
out.out_var_SV_Target0 = _187;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
#include <metal_stdlib>
|
||||||
|
#include <simd/simd.h>
|
||||||
|
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
struct FontInfo
|
||||||
|
{
|
||||||
|
float2 position;
|
||||||
|
float2 size;
|
||||||
|
uint isSdf;
|
||||||
|
uint pad0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct type_StructuredBuffer_FontInfo
|
||||||
|
{
|
||||||
|
FontInfo _m0[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct type_Uniforms
|
||||||
|
{
|
||||||
|
float2 Extents;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct main0_out
|
||||||
|
{
|
||||||
|
uint out_var_TEXCOORD0 [[user(locn0)]];
|
||||||
|
float2 out_var_TEXCOORD1 [[user(locn1)]];
|
||||||
|
float2 out_var_TEXCOORD2 [[user(locn2)]];
|
||||||
|
uint out_var_TEXCOORD3 [[user(locn3)]];
|
||||||
|
float4 gl_Position [[position]];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct main0_in
|
||||||
|
{
|
||||||
|
float2 in_var_TEXCOORD0 [[attribute(0)]];
|
||||||
|
float2 in_var_TEXCOORD1 [[attribute(1)]];
|
||||||
|
uint in_var_TEXCOORD2 [[attribute(2)]];
|
||||||
|
};
|
||||||
|
|
||||||
|
vertex main0_out main0(main0_in in [[stage_in]], constant type_Uniforms& Uniforms [[buffer(0)]], const device type_StructuredBuffer_FontInfo& fontBuffer [[buffer(1)]], uint gl_InstanceIndex [[instance_id]])
|
||||||
|
{
|
||||||
|
main0_out out = {};
|
||||||
|
float2 _46 = in.in_var_TEXCOORD0 + fontBuffer._m0[gl_InstanceIndex].position;
|
||||||
|
float2 _51 = ((_46 / Uniforms.Extents) * 2.0) + float2(-1.0);
|
||||||
|
float4 _54 = float4(_51, 0.0, 1.0);
|
||||||
|
_54.y = -_51.y;
|
||||||
|
out.out_var_TEXCOORD0 = in.in_var_TEXCOORD2;
|
||||||
|
out.out_var_TEXCOORD1 = in.in_var_TEXCOORD1;
|
||||||
|
out.out_var_TEXCOORD2 = _46;
|
||||||
|
out.out_var_TEXCOORD3 = gl_InstanceIndex;
|
||||||
|
out.gl_Position = _54;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,3 @@
|
||||||
|
# studio games depot
|
||||||
|
|
||||||
|
!! not for open source.
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
pub const BoxObject = struct {
|
||||||
|
playing: bool = false,
|
||||||
|
|
||||||
|
pub fn create(allocator: std.mem.Allocator, entity: core.Entity, params: core.SpawnParameters) !*@This() {
|
||||||
|
const position = params.posRot.position;
|
||||||
|
|
||||||
|
const box2 = entity;
|
||||||
|
const scene = box2.addComponent(core.Scene).?;
|
||||||
|
|
||||||
|
const mesh = box2.addComponent(rend.MeshComponent).?;
|
||||||
|
mesh.setMesh("m_crate");
|
||||||
|
mesh.setTexture("t_crate");
|
||||||
|
|
||||||
|
scene.setPosition(position);
|
||||||
|
scene.setScaleV(params.posRot.scale);
|
||||||
|
scene.setMobility(.moveable);
|
||||||
|
|
||||||
|
const collider = box2.addComponent(physics.PhysicsCollider).?;
|
||||||
|
try collider.setupByShapeName(core.MakeName("ph_small_box"), .{
|
||||||
|
.motion_type = .dynamic,
|
||||||
|
.object_layer = physics.ObjectLayers.moving,
|
||||||
|
.friction = 0.8,
|
||||||
|
.mass_properties_override = .{ .mass = 12 },
|
||||||
|
.override_mass_properties = .calc_inertia,
|
||||||
|
});
|
||||||
|
|
||||||
|
return try allocator.create(@This());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn createSmoky(allocator: std.mem.Allocator, entity: core.Entity, params: core.SpawnParameters) !*@This() {
|
||||||
|
const rv = try create(allocator, entity, params);
|
||||||
|
|
||||||
|
const particle = entity.addComponent(rend.ParticleEmitter).?;
|
||||||
|
particle.start();
|
||||||
|
particle.gravity = .{ .y = 1.0 };
|
||||||
|
particle.particleVelocity = .{ .min = 0.6, .max = 1.2 };
|
||||||
|
particle.particleLife = .{ .min = 5, .max = 6 };
|
||||||
|
var name = core.MakeName("t_pixelSmoke");
|
||||||
|
particle.texture = rend.getTexture(&name).?;
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroy(self: *@This(), alloc: std.mem.Allocator) void {
|
||||||
|
alloc.destroy(self);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const Backlog = @import("Backlog");
|
||||||
|
const core = Backlog.core;
|
||||||
|
const rend = Backlog.rend;
|
||||||
|
const physics = Backlog.physics;
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
const backlog = @import("backlog");
|
||||||
|
const core = backlog.core;
|
||||||
|
const imgui = backlog.imgui;
|
||||||
|
const physics = backlog.physics;
|
||||||
|
const rend = backlog.rend;
|
||||||
|
const ig = imgui.api;
|
||||||
|
const sys = backlog.sys;
|
||||||
|
const ui = backlog.ui;
|
||||||
|
const net = backlog.net;
|
||||||
|
const audio = backlog.audio;
|
||||||
|
const platform = backlog.platform;
|
||||||
|
|
||||||
|
pub export fn shutdown_module() void {}
|
||||||
|
pub export fn startup_module(p_allocator: *anyopaque, p_a: ?*anyopaque) bool {
|
||||||
|
const allocator = core.modulePreamble(p_allocator, p_a) catch return false;
|
||||||
|
_ = allocator;
|
||||||
|
imgui.setupFromModule();
|
||||||
|
platform.setupFromModule();
|
||||||
|
sys.setupFromModule();
|
||||||
|
rend.setupFromModule();
|
||||||
|
backlog.physics.setupFromModule();
|
||||||
|
|
||||||
|
start_module(core.startup_getArgs(p_a.?)) catch return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start_module(args: core.ModuleLoaderArgs) !void {
|
||||||
|
_ = args;
|
||||||
|
core.PatchOrCreateObject(ZuckGame, .{});
|
||||||
|
// core.PatchOrCreateObject(ZuckEditor, .{});
|
||||||
|
}
|
||||||
|
|
||||||
|
const ZuckGame = @import("games/ZuckGame.zig");
|
||||||
|
const ZuckEditor = @import("games/ZuckEditor.zig");
|
||||||
|
|
||||||
|
const ZuckPlayer = @import("actors/ZuckPlayer.zig");
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
pub var NeonObjectTable = core.EngineObjectVTable.from(@This(), "zuck.game.Editor");
|
||||||
|
|
||||||
|
allocator: std.mem.Allocator = undefined,
|
||||||
|
|
||||||
|
pub const Slack = core.SlackStruct(@This(), 8192);
|
||||||
|
|
||||||
|
pub fn create(allocator: std.mem.Allocator) !*@This() {
|
||||||
|
const self = try Slack.create(allocator);
|
||||||
|
self.* = .{
|
||||||
|
.allocator = allocator,
|
||||||
|
};
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tick(self: *@This(), dt: f64) void {
|
||||||
|
_ = self;
|
||||||
|
_ = dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroy(self: *@This()) void {
|
||||||
|
self.allocator.destroy(Slack.fromPtr(self));
|
||||||
|
}
|
||||||
|
|
||||||
|
const backlog = @import("backlog");
|
||||||
|
const std = @import("std");
|
||||||
|
const extras = @import("gameExtras");
|
||||||
|
|
||||||
|
const core = backlog.core;
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
pub var NeonObjectTable = core.EngineObjectVTable.from(@This(), "zuck.game.Root");
|
||||||
|
|
||||||
|
allocator: std.mem.Allocator = undefined,
|
||||||
|
|
||||||
|
pub const Slack = core.SlackStruct(@This(), 1024);
|
||||||
|
|
||||||
|
pub fn create(allocator: std.mem.Allocator) !*@This() {
|
||||||
|
const self = try Slack.create(allocator);
|
||||||
|
self.* = .{
|
||||||
|
.allocator = allocator,
|
||||||
|
};
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tick(self: *@This(), dt: f64) void {
|
||||||
|
_ = self;
|
||||||
|
_ = dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroy(self: *@This()) void {
|
||||||
|
self.allocator.destroy(Slack.fromPtr(self));
|
||||||
|
}
|
||||||
|
|
||||||
|
const backlog = @import("backlog");
|
||||||
|
const std = @import("std");
|
||||||
|
const extras = @import("gameExtras");
|
||||||
|
|
||||||
|
const core = backlog.core;
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
pub var NeonObjectTable = core.EngineObjectVTable.from(@This(), "main");
|
||||||
|
|
||||||
|
allocator: std.mem.Allocator,
|
||||||
|
|
||||||
|
pub fn init(allocator: std.mem.Allocator) !*@This() {
|
||||||
|
const self = try allocator.create(@This());
|
||||||
|
self.* = .{
|
||||||
|
.allocator = allocator,
|
||||||
|
};
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn prepare(self: *@This()) !void {
|
||||||
|
_ = self;
|
||||||
|
try api.loadDynamicModules();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tick(self: *@This(), dt: f64) void {
|
||||||
|
_ = self;
|
||||||
|
_ = dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *@This()) void {
|
||||||
|
// Engine handles memory deallocation
|
||||||
|
_ = self;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() anyerror!void {
|
||||||
|
var spec = try api.getSpec("minimal");
|
||||||
|
_ = api.startEngine(&NeonObjectTable, &spec);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const api = @import("backlog");
|
||||||
|
const core = api.core;
|
||||||
|
|
@ -0,0 +1,199 @@
|
||||||
|
# Backlog Engine Build Options
|
||||||
|
|
||||||
|
This document provides comprehensive documentation for all `core.BuildOption` flags available in the Backlog game engine.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Build options in Backlog are boolean flags that control various compilation behaviors and engine features. They are accessed at compile-time using `core.BuildOption("option_name")` and can be set via Zig's build system command line arguments.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Build options are set when building the project:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
zig build -Doption_name
|
||||||
|
# or
|
||||||
|
zig build -Doption_name=true
|
||||||
|
```
|
||||||
|
|
||||||
|
To disable an option explicitly:
|
||||||
|
```bash
|
||||||
|
zig build -Doption_name=false
|
||||||
|
```
|
||||||
|
|
||||||
|
## Core Engine Build Options
|
||||||
|
|
||||||
|
### Performance & Development Options
|
||||||
|
|
||||||
|
#### `mutex_job_queue`
|
||||||
|
- **Type**: `bool`
|
||||||
|
- **Default**: `false`
|
||||||
|
- **Description**: Temporary test option that reverts to old mutex-based queue behavior in `jobs.zig:JobManager`
|
||||||
|
- **Usage**: `zig build -Dmutex_job_queue`
|
||||||
|
- **Impact**: Changes job system threading behavior for debugging/testing purposes
|
||||||
|
- **Files**: `engine/core/src/jobs.zig:8`
|
||||||
|
|
||||||
|
#### `force_mailbox`
|
||||||
|
- **Type**: `bool`
|
||||||
|
- **Default**: `false`
|
||||||
|
- **Description**: Forces mailbox mode for present mode, unlocking framerate to very high levels
|
||||||
|
- **Usage**: `zig build -Dforce_mailbox`
|
||||||
|
- **Impact**: Disables VSync and allows unlimited framerate rendering
|
||||||
|
- **Warning**: Can cause excessive GPU usage and heat generation
|
||||||
|
|
||||||
|
### Logging Options
|
||||||
|
|
||||||
|
#### `zero_logging`
|
||||||
|
- **Type**: `bool`
|
||||||
|
- **Default**: `false`
|
||||||
|
- **Description**: Disables all logging completely, intended primarily for job dispatch performance testing
|
||||||
|
- **Usage**: `zig build -Dzero_logging`
|
||||||
|
- **Impact**: Removes all log output, improving performance but eliminating debug information
|
||||||
|
- **Files**: `engine/core/src/logging.zig:7`
|
||||||
|
|
||||||
|
#### `slow_logging`
|
||||||
|
- **Type**: `bool`
|
||||||
|
- **Default**: `false`
|
||||||
|
- **Description**: Disables buffered logging, taking a performance hit but providing accurate timing information
|
||||||
|
- **Usage**: `zig build -Dslow_logging`
|
||||||
|
- **Impact**: Each log call is immediately flushed, providing precise timing but reducing performance
|
||||||
|
- **Files**: `engine/core/src/logging.zig:6`
|
||||||
|
|
||||||
|
### Build & Deployment Options
|
||||||
|
|
||||||
|
#### `static_build`
|
||||||
|
- **Type**: `bool`
|
||||||
|
- **Default**: `false`
|
||||||
|
- **Description**: Builds the entire game as a single executable with static linking
|
||||||
|
- **Usage**: `zig build -Dstatic_build`
|
||||||
|
- **Impact**:
|
||||||
|
- Required for Linux builds
|
||||||
|
- Disables dynamic module loading
|
||||||
|
- Creates self-contained executable
|
||||||
|
- **Files**:
|
||||||
|
- `build.zig:190`
|
||||||
|
- `engine/core/src/extern/externModule.zig:139`
|
||||||
|
- `build/generateApi.zig:118`
|
||||||
|
- `engine/rend/src/sgpu/renderer.zig:1126`
|
||||||
|
|
||||||
|
#### `RootDeploymentOnly`
|
||||||
|
- **Type**: `bool`
|
||||||
|
- **Default**: Not explicitly set (appears to default to `false`)
|
||||||
|
- **Description**: Controls whether only root deployment operations are performed
|
||||||
|
- **Usage**: `zig build -DRootDeploymentOnly`
|
||||||
|
- **Impact**: Appears to limit engine initialization to root-level deployment only
|
||||||
|
- **Files**: `engine/main.zig:28`
|
||||||
|
|
||||||
|
### Development & Shader Options
|
||||||
|
|
||||||
|
#### `cookShaders`
|
||||||
|
- **Type**: `bool`
|
||||||
|
- **Default**: `false`
|
||||||
|
- **Description**: Generates shaders and updates `.json` files before running the build
|
||||||
|
- **Usage**: `zig build -DcookShaders`
|
||||||
|
- **Impact**:
|
||||||
|
- Automatically runs `tools/scripts/cookShaders.py`
|
||||||
|
- Compiles HLSL shaders to SPIR-V, MSL, and DXIL formats
|
||||||
|
- Must be run whenever shader files are modified
|
||||||
|
- **Files**: `build.zig:80`
|
||||||
|
|
||||||
|
### Third-Party Integration Options
|
||||||
|
|
||||||
|
#### `tracy` (Tracy Profiler)
|
||||||
|
- **Type**: `bool`
|
||||||
|
- **Default**: `false`
|
||||||
|
- **Description**: Enables Tracy profiler integration for performance analysis
|
||||||
|
- **Usage**: `zig build -Dtracy`
|
||||||
|
- **Impact**:
|
||||||
|
- Adds Tracy profiling instrumentation
|
||||||
|
- Enables real-time performance monitoring
|
||||||
|
- Increases binary size and may affect performance
|
||||||
|
- **Files**: `lib/tracy/build_tracy.zig:37`
|
||||||
|
|
||||||
|
## Build Option Categories
|
||||||
|
|
||||||
|
### By Purpose
|
||||||
|
|
||||||
|
**Performance Testing**:
|
||||||
|
- `mutex_job_queue` - Job system behavior testing
|
||||||
|
- `zero_logging` - Maximum performance logging
|
||||||
|
- `force_mailbox` - Unlimited framerate testing
|
||||||
|
|
||||||
|
**Development & Debugging**:
|
||||||
|
- `slow_logging` - Precise timing information
|
||||||
|
- `tracy` - Performance profiling
|
||||||
|
- `cookShaders` - Shader development workflow
|
||||||
|
|
||||||
|
**Deployment & Distribution**:
|
||||||
|
- `static_build` - Self-contained executable creation
|
||||||
|
- `RootDeploymentOnly` - Deployment scope control
|
||||||
|
|
||||||
|
### By Impact Level
|
||||||
|
|
||||||
|
**High Impact** (affects core engine behavior):
|
||||||
|
- `static_build`
|
||||||
|
- `zero_logging`
|
||||||
|
- `mutex_job_queue`
|
||||||
|
|
||||||
|
**Medium Impact** (affects specific subsystems):
|
||||||
|
- `slow_logging`
|
||||||
|
- `force_mailbox`
|
||||||
|
- `cookShaders`
|
||||||
|
|
||||||
|
**Low Impact** (development/profiling tools):
|
||||||
|
- `tracy`
|
||||||
|
- `RootDeploymentOnly`
|
||||||
|
|
||||||
|
## Common Build Configurations
|
||||||
|
|
||||||
|
### Development Build
|
||||||
|
```bash
|
||||||
|
zig build -Dslow_logging -Dtracy -DcookShaders
|
||||||
|
```
|
||||||
|
|
||||||
|
### Performance Testing Build
|
||||||
|
```bash
|
||||||
|
zig build -Dzero_logging -Dforce_mailbox -Dmutex_job_queue
|
||||||
|
```
|
||||||
|
|
||||||
|
### Production/Release Build
|
||||||
|
```bash
|
||||||
|
zig build -Dstatic_build
|
||||||
|
```
|
||||||
|
|
||||||
|
### Linux Build (Required)
|
||||||
|
```bash
|
||||||
|
zig build -Dstatic_build
|
||||||
|
```
|
||||||
|
|
||||||
|
## Implementation Details
|
||||||
|
|
||||||
|
Build options are implemented through Zig's compile-time options system:
|
||||||
|
|
||||||
|
1. **Definition**: Options are defined in `build.zig` in the `BuildOptions` struct
|
||||||
|
2. **Access**: Runtime code accesses options via `core.BuildOption("option_name")`
|
||||||
|
3. **Compilation**: The `core.BuildOption()` function checks for the option at compile-time
|
||||||
|
4. **Fallback**: If an option is not defined, it defaults to `false`
|
||||||
|
|
||||||
|
The `core.BuildOption()` function implementation:
|
||||||
|
```zig
|
||||||
|
pub fn BuildOption(comptime option: []const u8) bool {
|
||||||
|
if (@hasDecl(@import("root"), "options")) {
|
||||||
|
const r = @import("root").options;
|
||||||
|
if (@hasDecl(r, option)) {
|
||||||
|
return @field(r, option);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- All build options are boolean flags
|
||||||
|
- Options not explicitly set default to `false`
|
||||||
|
- Some combinations may be incompatible (e.g., `zero_logging` + `slow_logging`)
|
||||||
|
- Linux builds require `static_build=true`
|
||||||
|
- Shader compilation via `cookShaders` should be run after modifying any `.hlsl` files
|
||||||
|
|
@ -0,0 +1,152 @@
|
||||||
|
# Backlog Game Engine Overview
|
||||||
|
|
||||||
|
The Backlog Game Engine is a modern, modular game engine built with Zig, designed for cross-platform game development. It provides a comprehensive set of tools and systems for creating interactive 3D applications and games.
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
- **Zig 0.14** or later
|
||||||
|
- **Python 3** for build scripts
|
||||||
|
|
||||||
|
## Running Examples
|
||||||
|
|
||||||
|
The engine comes with several examples to demonstrate its capabilities:
|
||||||
|
|
||||||
|
### Sample Game
|
||||||
|
|
||||||
|
The main example showcasing most engine features including:
|
||||||
|
- 3D rendering with meshes and textures
|
||||||
|
- Physics simulation
|
||||||
|
- ImGui debug interface
|
||||||
|
- Input handling
|
||||||
|
- Dynamic module loading
|
||||||
|
|
||||||
|
**To run the sample game:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd projects
|
||||||
|
zig build run-sampleGame
|
||||||
|
```
|
||||||
|
|
||||||
|
To compile and target linux with cross compiling,
|
||||||
|
|
||||||
|
```
|
||||||
|
zig build -Dtarget=x86_64-linux-gnu
|
||||||
|
```
|
||||||
|
|
||||||
|
The linux build is always compiled as a static executable.
|
||||||
|
|
||||||
|
**Sample Game Controls:**
|
||||||
|
- `WASD` - Move camera
|
||||||
|
- `Mouse` - Look around (toggle menu with `T`)
|
||||||
|
- `E/Q` - Move up/down
|
||||||
|
- `R` - Reload shaders
|
||||||
|
- `Escape` - Exit
|
||||||
|
|
||||||
|
### Minimal Example
|
||||||
|
|
||||||
|
A basic template demonstrating the minimal setup required for a Backlog application:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd projects/minimal
|
||||||
|
zig build
|
||||||
|
zig build run-minimal
|
||||||
|
```
|
||||||
|
|
||||||
|
This example shows:
|
||||||
|
- Basic engine initialization
|
||||||
|
- ImGui integration
|
||||||
|
- Simple game loop structure
|
||||||
|
|
||||||
|
## Creating New Projects
|
||||||
|
|
||||||
|
The engine includes a project creation tool to help you get started with new projects quickly.
|
||||||
|
|
||||||
|
### Using the New Project Tool
|
||||||
|
|
||||||
|
1. Navigate to the projects directory:
|
||||||
|
```bash
|
||||||
|
cd projects
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Run the project creator:
|
||||||
|
```bash
|
||||||
|
zig build run-newProject
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Click "Create Project" to generate your new project structure
|
||||||
|
|
||||||
|
### Manual Project Creation
|
||||||
|
|
||||||
|
Alternatively, you can create projects manually by copying the minimal template:
|
||||||
|
|
||||||
|
1. Copy the `projects/minimal` directory:
|
||||||
|
```bash
|
||||||
|
cp -r projects/minimal projects/my-new-project
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Edit `projects/my-new-project/build.zig` and update:
|
||||||
|
- Project name
|
||||||
|
- Root source file path
|
||||||
|
- Enabled modules as needed
|
||||||
|
|
||||||
|
3. Modify `src/main.zig` to implement your game logic
|
||||||
|
|
||||||
|
### Project Structure
|
||||||
|
|
||||||
|
A typical Backlog project includes:
|
||||||
|
|
||||||
|
```
|
||||||
|
my-project/
|
||||||
|
├── build.zig # Build configuration
|
||||||
|
├── build.zig.zon # Dependencies
|
||||||
|
├── src/
|
||||||
|
│ └── main.zig # Main game code
|
||||||
|
├── content/ # Game assets (optional)
|
||||||
|
└── Saved/ # Runtime generated files
|
||||||
|
```
|
||||||
|
|
||||||
|
## Engine Modules
|
||||||
|
|
||||||
|
When creating projects, you can enable these modules:
|
||||||
|
|
||||||
|
- **core** - Essential engine systems (always enabled)
|
||||||
|
- **platform** - Windowing and input (always enabled)
|
||||||
|
- **assets** - Asset loading and management (always enabled)
|
||||||
|
- **rend** - 3D rendering system (always enabled)
|
||||||
|
- **imgui** - Debug UI and developer tools
|
||||||
|
- **audio** - Sound and music playback
|
||||||
|
- **physics** - Physics simulation (Jolt Physics)
|
||||||
|
- **ui** - User interface rendering
|
||||||
|
- **papyrus** - Text rendering and UI primitives
|
||||||
|
- **sys** - System utilities
|
||||||
|
|
||||||
|
## Asset Pipeline
|
||||||
|
|
||||||
|
Assets are placed in the `content/` directory within your project:
|
||||||
|
|
||||||
|
all shaders are cooked to the target system's native format. DXIL for dx12, msl for metal and spv for vulkan.
|
||||||
|
|
||||||
|
These cooked format shaders are placed under content/_shaders
|
||||||
|
|
||||||
|
## Building and Development
|
||||||
|
|
||||||
|
### Building Projects
|
||||||
|
|
||||||
|
From your project directory:
|
||||||
|
```bash
|
||||||
|
zig build # Build project
|
||||||
|
zig build run-[projectname] # Build and run
|
||||||
|
```
|
||||||
|
|
||||||
|
### Testing
|
||||||
|
|
||||||
|
Run tests for the entire engine:
|
||||||
|
```bash
|
||||||
|
zig build test
|
||||||
|
```
|
||||||
|
|
||||||
|
Or test individual modules:
|
||||||
|
```bash
|
||||||
|
cd engine/core
|
||||||
|
zig build test
|
||||||
|
```
|
||||||
|
|
@ -120,11 +120,6 @@ pub const AssetLoaderInterface = struct {
|
||||||
unreachable;
|
unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!@hasDecl(TargetType, "destroy")) {
|
|
||||||
@compileLog("Tried to generate AssetLoaderInterface for type ", TargetType, "but it's missing func destroy.");
|
|
||||||
unreachable;
|
|
||||||
}
|
|
||||||
|
|
||||||
const self = @This(){
|
const self = @This(){
|
||||||
.typeName = @typeName(TargetType),
|
.typeName = @typeName(TargetType),
|
||||||
.typeSize = @sizeOf(TargetType),
|
.typeSize = @sizeOf(TargetType),
|
||||||
|
|
@ -159,15 +154,15 @@ pub const AssetReferenceSys = struct {
|
||||||
|
|
||||||
pub var NeonObjectTable = core.EngineObjectVTable.from(@This(), "AssetReference");
|
pub var NeonObjectTable = core.EngineObjectVTable.from(@This(), "AssetReference");
|
||||||
|
|
||||||
pub fn init(allocator: std.mem.Allocator) !*@This() {
|
pub fn init(self: *@This(), allocator: std.mem.Allocator, first: bool) !void {
|
||||||
const self = try allocator.create(@This());
|
if (!first)
|
||||||
|
return;
|
||||||
|
|
||||||
self.* = @This(){
|
self.* = @This(){
|
||||||
.loaders = .{},
|
.loaders = .{},
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.outstandingAssetJobs = std.atomic.Value(i32).init(0),
|
.outstandingAssetJobs = std.atomic.Value(i32).init(0),
|
||||||
};
|
};
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn registerLoader(self: *@This(), loader: anytype) !void {
|
pub fn registerLoader(self: *@This(), loader: anytype) !void {
|
||||||
|
|
@ -210,6 +205,5 @@ pub const AssetReferenceSys = struct {
|
||||||
// i.destroy(self.allocator);
|
// i.destroy(self.allocator);
|
||||||
// }
|
// }
|
||||||
self.loaders.deinit(self.allocator);
|
self.loaders.deinit(self.allocator);
|
||||||
self.allocator.destroy(self);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -73,8 +73,10 @@ pub const SoundEngine = struct {
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
volume: f32 = 1.0,
|
volume: f32 = 1.0,
|
||||||
|
|
||||||
pub fn init(allocator: std.mem.Allocator) !*@This() {
|
pub fn init(self: *@This(), allocator: std.mem.Allocator, first: bool) !void {
|
||||||
const self = try allocator.create(@This());
|
if (!first)
|
||||||
|
return;
|
||||||
|
|
||||||
self.* = @This(){
|
self.* = @This(){
|
||||||
.engine = allocator.create(ma.ma_engine) catch unreachable,
|
.engine = allocator.create(ma.ma_engine) catch unreachable,
|
||||||
.sounds = .{},
|
.sounds = .{},
|
||||||
|
|
@ -83,8 +85,6 @@ pub const SoundEngine = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
_ = ma.ma_engine_init(null, self.engine);
|
_ = ma.ma_engine_init(null, self.engine);
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn shutdown(self: *@This()) void {
|
pub fn shutdown(self: *@This()) void {
|
||||||
|
|
|
||||||
|
|
@ -156,7 +156,7 @@ pub const createSpecVariant = core.createSpecVariant;
|
||||||
pub export fn initAndRun(vtable: *core.EngineObjectVTable, spec: *core.SpecVariantMap) bool {
|
pub export fn initAndRun(vtable: *core.EngineObjectVTable, spec: *core.SpecVariantMap) bool {
|
||||||
const args = getArgs() catch return false;
|
const args = getArgs() catch return false;
|
||||||
|
|
||||||
var backingAllocator: std.mem.Allocator = std.heap.c_allocator;
|
var backingAllocator: std.mem.Allocator = std.heap.smp_allocator;
|
||||||
var gpa: std.heap.GeneralPurposeAllocator(.{
|
var gpa: std.heap.GeneralPurposeAllocator(.{
|
||||||
.stack_trace_frames = 20,
|
.stack_trace_frames = 20,
|
||||||
}) = .{};
|
}) = .{};
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
pub const std = @import("std");
|
||||||
|
const core = @import("core");
|
||||||
|
const impl = core;
|
||||||
|
|
||||||
|
pub const inputs = struct {
|
||||||
|
pub const getInputStack = inputs.getInputStack;
|
||||||
|
};
|
||||||
|
|
@ -2,14 +2,9 @@ const std = @import("std");
|
||||||
|
|
||||||
const dependencyList = [_][]const u8{
|
const dependencyList = [_][]const u8{
|
||||||
"p2",
|
"p2",
|
||||||
"tracy",
|
"tracy", // usually doesnt have C deps... unless we're compiled with it on, in which case we only support static builds
|
||||||
"zmath",
|
"zmath",
|
||||||
"packer", // packer might need to be split into another setup that doesn't have C deps.
|
"packer", // packer no longer has C deps.
|
||||||
|
|
||||||
// these ones use c deps, but if i move them out to platform... then core will have zero c dependencies.
|
|
||||||
"lua",
|
|
||||||
"spng",
|
|
||||||
// "nfd",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn build(b: *std.Build) void {
|
pub fn build(b: *std.Build) void {
|
||||||
|
|
@ -33,8 +28,10 @@ pub fn build(b: *std.Build) void {
|
||||||
.root_module = b.createModule(.{
|
.root_module = b.createModule(.{
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
|
.link_libc = true,
|
||||||
.root_source_file = b.path("tests/tests.zig"),
|
.root_source_file = b.path("tests/tests.zig"),
|
||||||
}),
|
}),
|
||||||
|
.use_llvm = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const sampleGameExtern = b.addLibrary(.{
|
const sampleGameExtern = b.addLibrary(.{
|
||||||
|
|
@ -45,8 +42,10 @@ pub fn build(b: *std.Build) void {
|
||||||
.target = target,
|
.target = target,
|
||||||
}),
|
}),
|
||||||
.linkage = .dynamic,
|
.linkage = .dynamic,
|
||||||
|
.use_llvm = true,
|
||||||
.name = "external",
|
.name = "external",
|
||||||
});
|
});
|
||||||
|
sampleGameExtern.root_module.addImport("core", mod);
|
||||||
|
|
||||||
const installExtern = b.addInstallArtifact(sampleGameExtern, .{
|
const installExtern = b.addInstallArtifact(sampleGameExtern, .{
|
||||||
.dest_dir = .{ .override = .{ .custom = "modules" } },
|
.dest_dir = .{ .override = .{ .custom = "modules" } },
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
.name = .core,
|
.name = .core,
|
||||||
.version = "0.0.0",
|
.version = "0.0.0",
|
||||||
.dependencies = .{
|
.dependencies = .{
|
||||||
.spng = .{ .path = "../../lib/spng" },
|
// .spng = .{ .path = "../../lib/spng" },
|
||||||
// .nfd = .{ .path = "../../lib/nfd" },
|
// .nfd = .{ .path = "../../lib/nfd" },
|
||||||
|
|
||||||
// with -Dtracy = false, this one pulls in no C dependencies
|
// with -Dtracy = false, this one pulls in no C dependencies
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
.zmath = .{ .path = "../../lib/zmath" },
|
.zmath = .{ .path = "../../lib/zmath" },
|
||||||
.packer = .{ .path = "../../lib/packer" },
|
.packer = .{ .path = "../../lib/packer" },
|
||||||
.p2 = .{ .path = "../../lib/p2" },
|
.p2 = .{ .path = "../../lib/p2" },
|
||||||
.lua = .{ .path = "../../lib/lua" },
|
// .lua = .{ .path = "../../lib/lua" },
|
||||||
// .zgltf = .{ .path = "../../lib/zgltf" },
|
// .zgltf = .{ .path = "../../lib/zgltf" },
|
||||||
},
|
},
|
||||||
.paths = .{
|
.paths = .{
|
||||||
|
|
|
||||||
|
|
@ -169,12 +169,12 @@ pub fn init(backingAllocator: std.mem.Allocator, settings: SetupSettings) @This(
|
||||||
core.engine_logs("[dmt] Enabling Detailed Memory Tracking");
|
core.engine_logs("[dmt] Enabling Detailed Memory Tracking");
|
||||||
}
|
}
|
||||||
|
|
||||||
const stackCompactor = if (EnableMemoryTimeline) core.StackCompactor.create(std.heap.c_allocator) catch null else null;
|
const stackCompactor = if (EnableMemoryTimeline) core.StackCompactor.create(std.heap.smp_allocator) catch null else null;
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.backingAllocator = backingAllocator,
|
.backingAllocator = backingAllocator,
|
||||||
.stackCompactor = stackCompactor,
|
.stackCompactor = stackCompactor,
|
||||||
.timeline = if (EnableMemoryTimeline) EventTimeline.init(std.heap.c_allocator) catch null else null,
|
.timeline = if (EnableMemoryTimeline) EventTimeline.init(std.heap.smp_allocator) catch null else null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ const std = @import("std");
|
||||||
|
|
||||||
pub fn ParseArgs(comptime T: type) !T {
|
pub fn ParseArgs(comptime T: type) !T {
|
||||||
// I think i am actually totally cool with leaking this one and leaving it around... just dont spam call this function
|
// I think i am actually totally cool with leaking this one and leaving it around... just dont spam call this function
|
||||||
var iter = try std.process.argsWithAllocator(std.heap.c_allocator);
|
var iter = try std.process.argsWithAllocator(std.heap.smp_allocator);
|
||||||
var args: T = .{};
|
var args: T = .{};
|
||||||
|
|
||||||
const shortBuf: [32]u8 = undefined;
|
const shortBuf: [32]u8 = undefined;
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,16 @@
|
||||||
pub const ConfigRegistry = struct {
|
pub const ConfigRegistry = struct {
|
||||||
pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This(), "core.ConfigRegistry");
|
pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This(), "core.ConfigRegistry");
|
||||||
|
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator = undefined,
|
||||||
configMap: ?ConfigMap = null,
|
configMap: ?ConfigMap = null,
|
||||||
|
|
||||||
pub fn create(allocator: std.mem.Allocator) !*@This() {
|
pub fn init(self: *@This(), allocator: std.mem.Allocator, first: bool) !void {
|
||||||
const self = try allocator.create(@This());
|
if (!first)
|
||||||
|
return;
|
||||||
|
|
||||||
self.* = .{
|
self.* = .{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
};
|
};
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// by convention this should be in the root
|
// by convention this should be in the root
|
||||||
|
|
@ -38,11 +37,10 @@ pub const ConfigRegistry = struct {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn destroy(self: *@This()) void {
|
pub fn deinit(self: *@This()) void {
|
||||||
if (self.configMap) |*map| {
|
if (self.configMap) |*map| {
|
||||||
map.deinit();
|
map.deinit();
|
||||||
}
|
}
|
||||||
self.allocator.destroy(self);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,21 +8,22 @@ pub const ConsoleCommand = struct {
|
||||||
pub const Console = struct {
|
pub const Console = struct {
|
||||||
pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This(), "core.Console");
|
pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This(), "core.Console");
|
||||||
|
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator = undefined,
|
||||||
arena: std.heap.ArenaAllocator,
|
arena: std.heap.ArenaAllocator = undefined,
|
||||||
|
|
||||||
commandMap: std.StringHashMapUnmanaged(ConsoleCommand) = .{},
|
commandMap: std.StringHashMapUnmanaged(ConsoleCommand) = .{},
|
||||||
|
|
||||||
pub fn create(allocator: std.mem.Allocator) !*@This() {
|
pub fn init(self: *@This(), allocator: std.mem.Allocator, first: bool) !void {
|
||||||
const self = try allocator.create(@This());
|
if (!first) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
self.* = .{
|
self.* = .{
|
||||||
.arena = std.heap.ArenaAllocator.init(allocator),
|
.arena = std.heap.ArenaAllocator.init(allocator),
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
};
|
};
|
||||||
|
|
||||||
core.engine_logs("console system created");
|
core.engine_logs("console system created");
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn addConsoleCommand(self: *@This(), funcName: []const u8, func: ConsoleFunc) !void {
|
pub fn addConsoleCommand(self: *@This(), funcName: []const u8, func: ConsoleFunc) !void {
|
||||||
|
|
@ -56,10 +57,9 @@ pub const Console = struct {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn destroy(self: *@This()) void {
|
pub fn deinit(self: *@This()) void {
|
||||||
self.arena.deinit();
|
self.arena.deinit();
|
||||||
self.commandMap.deinit(self.allocator);
|
self.commandMap.deinit(self.allocator);
|
||||||
self.allocator.destroy(self);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
// main public facing root file for core
|
// main public facing root file for core
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub const machinery = @import("machinery/machinery.zig");
|
||||||
|
|
||||||
pub const gameObjectList = @import("utils/gameObjectList.zig");
|
pub const gameObjectList = @import("utils/gameObjectList.zig");
|
||||||
pub const GameObjectList = gameObjectList.GameObjectList;
|
pub const GameObjectList = gameObjectList.GameObjectList;
|
||||||
pub const GameObjectInterface = gameObjectList.GameObjectInterface;
|
pub const GameObjectInterface = gameObjectList.GameObjectInterface;
|
||||||
|
|
@ -25,9 +27,10 @@ pub const debugBox = debug_draw.debugBox;
|
||||||
pub const debugLine = debug_draw.debugLine;
|
pub const debugLine = debug_draw.debugLine;
|
||||||
// pub const script_bindings = script.script_bindings;
|
// pub const script_bindings = script.script_bindings;
|
||||||
|
|
||||||
pub const misc = @import("misc.zig");
|
|
||||||
pub const engineTime = @import("engineTime.zig");
|
pub const engineTime = @import("engineTime.zig");
|
||||||
pub const engineObject = @import("engineObject.zig");
|
pub const engineObject = @import("engineObject.zig");
|
||||||
|
pub const EngineObjectOpts = engineObject.EngineObjectOpts;
|
||||||
|
pub const ObjectOpts = engineObject.EngineObjectOpts;
|
||||||
pub const EngineObjectVTable = engineObject.EngineObjectVTable;
|
pub const EngineObjectVTable = engineObject.EngineObjectVTable;
|
||||||
pub const MakeTypeName = engineObject.MakeTypeName;
|
pub const MakeTypeName = engineObject.MakeTypeName;
|
||||||
pub const PatchStruct = engineObject.PatchStruct;
|
pub const PatchStruct = engineObject.PatchStruct;
|
||||||
|
|
@ -38,16 +41,13 @@ pub const EngineObjectDelegate = engineObject.EngineObjectDelegate;
|
||||||
pub const FieldInfo = engineObject.FieldInfo;
|
pub const FieldInfo = engineObject.FieldInfo;
|
||||||
|
|
||||||
pub const jobs = @import("jobs.zig");
|
pub const jobs = @import("jobs.zig");
|
||||||
pub const JobContext = jobs.JobContext;
|
pub const JobContext = jobs.ThreadContext;
|
||||||
|
pub const ThreadContext = jobs.ThreadContext;
|
||||||
pub const JobManager = jobs.JobManager;
|
pub const JobManager = jobs.JobManager;
|
||||||
pub const JobWorker = jobs.JobWorker;
|
pub const JobWorker = jobs.JobWorker;
|
||||||
|
|
||||||
pub const file_utils = @import("file_utils.zig");
|
|
||||||
pub const string_utils = @import("string_utils.zig");
|
|
||||||
pub const type_utils = @import("type_utils.zig");
|
|
||||||
pub const engine = @import("engine.zig");
|
pub const engine = @import("engine.zig");
|
||||||
pub const tracy = @import("tracy").t;
|
pub const tracy = @import("tracy").t;
|
||||||
pub const png = @import("png.zig");
|
|
||||||
|
|
||||||
pub const colors = @import("colors.zig");
|
pub const colors = @import("colors.zig");
|
||||||
|
|
||||||
|
|
@ -140,8 +140,6 @@ pub const SceneSystem = scene.SceneSystem;
|
||||||
|
|
||||||
pub const Engine = engine.Engine;
|
pub const Engine = engine.Engine;
|
||||||
|
|
||||||
pub const spng = @import("spng");
|
|
||||||
|
|
||||||
pub const MemoryTracker = @import("MemoryTracker.zig");
|
pub const MemoryTracker = @import("MemoryTracker.zig");
|
||||||
|
|
||||||
pub const DefaultSavePath = "Saved";
|
pub const DefaultSavePath = "Saved";
|
||||||
|
|
@ -172,14 +170,16 @@ pub const defaultHighlight = logging.defaultHighlight;
|
||||||
|
|
||||||
pub const packer = @import("packer");
|
pub const packer = @import("packer");
|
||||||
|
|
||||||
pub const FileSystem = packer.PackerFS;
|
|
||||||
pub const PackerFS = packer.PackerFS;
|
|
||||||
|
|
||||||
pub const StackCompactor = stacks.StackCompactor;
|
pub const StackCompactor = stacks.StackCompactor;
|
||||||
|
|
||||||
var staticsInitialized = false;
|
pub var staticsInitialized = false;
|
||||||
var gEngine: *Engine = undefined;
|
var gEngine: *Engine = undefined;
|
||||||
|
pub const PackerFS = packer.PackerFS;
|
||||||
var gPackerFS: *PackerFS = undefined;
|
var gPackerFS: *PackerFS = undefined;
|
||||||
|
|
||||||
|
pub fn fs() *PackerFS {
|
||||||
|
return gPackerFS;
|
||||||
|
}
|
||||||
var fsInitialized: bool = false;
|
var fsInitialized: bool = false;
|
||||||
|
|
||||||
pub fn EngineObject(comptime T: type) type {
|
pub fn EngineObject(comptime T: type) type {
|
||||||
|
|
@ -216,8 +216,6 @@ pub const undefineComponentList = ecs.undefineComponentList;
|
||||||
pub const Entity = ecs.Entity;
|
pub const Entity = ecs.Entity;
|
||||||
pub const createEntity = ecs.createEntity;
|
pub const createEntity = ecs.createEntity;
|
||||||
|
|
||||||
pub const script = @import("script.zig");
|
|
||||||
|
|
||||||
pub const stacks = @import("stacks.zig");
|
pub const stacks = @import("stacks.zig");
|
||||||
pub const walkAndPrintStack = stacks.walkAndPrintStack;
|
pub const walkAndPrintStack = stacks.walkAndPrintStack;
|
||||||
|
|
||||||
|
|
@ -236,10 +234,6 @@ pub fn registerObjectAdvanced(comptime T: type, name: []const u8, comptime funcN
|
||||||
try get(GameObjectSystem).registerObjectAdvanced(name, T, funcName);
|
try get(GameObjectSystem).registerObjectAdvanced(name, T, funcName);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fs() *PackerFS {
|
|
||||||
return gPackerFS;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const Module = ModuleDescription{
|
pub const Module = ModuleDescription{
|
||||||
.name = "core",
|
.name = "core",
|
||||||
.enabledByDefault = true,
|
.enabledByDefault = true,
|
||||||
|
|
@ -280,8 +274,6 @@ pub fn maybeInitPackerFs(allocator: std.mem.Allocator) !void {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start_module_(map: *SpecVariantMap, args: anytype, allocator: std.mem.Allocator) !void {
|
pub fn start_module_(map: *SpecVariantMap, args: anytype, allocator: std.mem.Allocator) !void {
|
||||||
staticsInitialized = true;
|
|
||||||
|
|
||||||
if (map.get("utility")) |x| {
|
if (map.get("utility")) |x| {
|
||||||
if (x.boolean == true) {
|
if (x.boolean == true) {
|
||||||
engine_logs("utility mode - no gui");
|
engine_logs("utility mode - no gui");
|
||||||
|
|
@ -294,15 +286,9 @@ pub fn start_module_(map: *SpecVariantMap, args: anytype, allocator: std.mem.All
|
||||||
fatDump = true;
|
fatDump = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
script.lua.setupMiniDump(fatDump);
|
|
||||||
_ = try algorithm.createNameRegistry(allocator);
|
_ = try algorithm.createNameRegistry(allocator);
|
||||||
// LUA BEGIN -- what if i want to make the scripting integration optional?
|
|
||||||
// try script.start_lua(allocator);
|
|
||||||
// LUA END
|
|
||||||
try maybeInitPackerFs(allocator);
|
try maybeInitPackerFs(allocator);
|
||||||
|
|
||||||
// load configs.
|
|
||||||
//const name = if (@hasField(@TypeOf(programSpec), "configName")) programSpec.configName else programSpec.name;
|
|
||||||
var name = map.get("name").?.string;
|
var name = map.get("name").?.string;
|
||||||
|
|
||||||
if (map.get("configName")) |x| {
|
if (map.get("configName")) |x| {
|
||||||
|
|
@ -311,8 +297,7 @@ pub fn start_module_(map: *SpecVariantMap, args: anytype, allocator: std.mem.All
|
||||||
|
|
||||||
gEngine = try allocator.create(Engine);
|
gEngine = try allocator.create(Engine);
|
||||||
gEngine.* = try Engine.init(allocator);
|
gEngine.* = try Engine.init(allocator);
|
||||||
_ = try createObject(ModuleLoader, .{});
|
staticsInitialized = true;
|
||||||
try console.start();
|
|
||||||
|
|
||||||
const engineName = try std.fmt.allocPrint(allocator, "{s}Engine.ini", .{name});
|
const engineName = try std.fmt.allocPrint(allocator, "{s}Engine.ini", .{name});
|
||||||
defer allocator.free(engineName);
|
defer allocator.free(engineName);
|
||||||
|
|
@ -323,16 +308,15 @@ pub fn start_module_(map: *SpecVariantMap, args: anytype, allocator: std.mem.All
|
||||||
try logging.setupLogging(gEngine);
|
try logging.setupLogging(gEngine);
|
||||||
}
|
}
|
||||||
|
|
||||||
try ecs.setup(allocator);
|
|
||||||
|
|
||||||
_ = try gEngine.createObject(scene.SceneSystem, .{ .can_tick = true });
|
|
||||||
|
|
||||||
try algorithm.string_pool.setup(allocator);
|
try algorithm.string_pool.setup(allocator);
|
||||||
|
gEngine.stringContext = algorithm.string_pool.gStringContext;
|
||||||
|
|
||||||
// _ = try gEngine.createObject(script_bindings.ScriptTicks, .{ .can_tick = true });
|
_ = try createObject(ModuleLoader, .{});
|
||||||
|
_ = try createObject(ecs.EcsRegistry, .{ .can_tick = true, .isCore = true });
|
||||||
|
_ = try createObject(scene.SceneSystem, .{ .can_tick = true });
|
||||||
_ = try createObject(GameObjectSystem, .{ .can_tick = true });
|
_ = try createObject(GameObjectSystem, .{ .can_tick = true });
|
||||||
_ = try inputs.initInputStack();
|
_ = try createObject(inputs.InputStack, .{});
|
||||||
|
_ = try createObject(console.Console, .{});
|
||||||
|
|
||||||
// components define
|
// components define
|
||||||
try ecs.defineComponentList(ComponentList, allocator);
|
try ecs.defineComponentList(ComponentList, allocator);
|
||||||
|
|
@ -343,8 +327,8 @@ pub fn start_module_(map: *SpecVariantMap, args: anytype, allocator: std.mem.All
|
||||||
pub fn setupFromModule(__args: ModuleLoaderArgs) !void {
|
pub fn setupFromModule(__args: ModuleLoaderArgs) !void {
|
||||||
gEngine = __args.engine;
|
gEngine = __args.engine;
|
||||||
gPackerFS = __args.packerFS;
|
gPackerFS = __args.packerFS;
|
||||||
// script.setupLuaFromModule(__args.luaState, __args.luaAllocator);
|
|
||||||
algorithm.names.gRegistry = __args.nameRegistry;
|
algorithm.names.gRegistry = __args.nameRegistry;
|
||||||
|
algorithm.string_pool.gStringContext = gEngine.stringContext;
|
||||||
logging.setupLoggingFromModule();
|
logging.setupLoggingFromModule();
|
||||||
staticsInitialized = true;
|
staticsInitialized = true;
|
||||||
|
|
||||||
|
|
@ -366,18 +350,36 @@ pub fn shutdown_module(_: std.mem.Allocator) void {
|
||||||
|
|
||||||
ecs.shutdown();
|
ecs.shutdown();
|
||||||
algorithm.destroyNameRegistry();
|
algorithm.destroyNameRegistry();
|
||||||
gEngine.deinit();
|
|
||||||
gPackerFS.destroy();
|
gPackerFS.destroy();
|
||||||
// LUA BEGIN
|
|
||||||
// script.shutdown_lua();
|
|
||||||
// LUA END
|
|
||||||
console.shutdown();
|
console.shutdown();
|
||||||
algorithm.string_pool.shutdown();
|
algorithm.string_pool.shutdown();
|
||||||
|
|
||||||
|
gEngine.deinit();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn parallelJob(capture: anytype, async: bool, maxWorkerCount: ?u32) !void {
|
||||||
|
const z = tracy.ZoneNC(@src(), "parallel Job", 0xCF8774);
|
||||||
|
defer z.End();
|
||||||
|
|
||||||
|
const jobManager = getEngine().jobManager;
|
||||||
|
const requestedWorkers = if (maxWorkerCount) |m| m else jobManager.numWorkers;
|
||||||
|
const baseWorkerCount = @min(requestedWorkers, @max(getEngine().jobManager.numWorkers - 2, 1));
|
||||||
|
|
||||||
|
const workerStart: u32 = if (async) 0 else 1;
|
||||||
|
|
||||||
|
for (workerStart..baseWorkerCount) |workerId| {
|
||||||
|
try jobManager.newJob(capture, .{ .threadId = @intCast(workerId), .threadCount = baseWorkerCount });
|
||||||
|
}
|
||||||
|
|
||||||
|
// start working on the job locally
|
||||||
|
if (!async) {
|
||||||
|
try jobManager.runLocally(capture, .{ .threadId = 0, .threadCount = baseWorkerCount });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn dispatchJob(capture: anytype) !void {
|
pub fn dispatchJob(capture: anytype) !void {
|
||||||
try gEngine.jobManager.newJob(capture);
|
try gEngine.jobManager.newJob(capture, .{ .threadId = 0, .threadCount = 1 }); //0, 1, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn createObject(comptime T: type, params: engine.NeonObjectParams) !*T {
|
pub fn createObject(comptime T: type, params: engine.NeonObjectParams) !*T {
|
||||||
|
|
@ -524,7 +526,11 @@ pub fn startup_getArgs(p_allocator: *anyopaque) ModuleLoaderArgs {
|
||||||
pub fn modulePreamble(p_allocator: *anyopaque, p_a: ?*anyopaque) !std.mem.Allocator {
|
pub fn modulePreamble(p_allocator: *anyopaque, p_a: ?*anyopaque) !std.mem.Allocator {
|
||||||
const args = startup_getArgs(p_a.?);
|
const args = startup_getArgs(p_a.?);
|
||||||
const allocator = startup_getAllocator(p_allocator);
|
const allocator = startup_getAllocator(p_allocator);
|
||||||
try setupFromModule(args);
|
|
||||||
|
if (comptime !BuildOption("static_build")) {
|
||||||
|
try setupFromModule(args);
|
||||||
|
}
|
||||||
|
|
||||||
return allocator;
|
return allocator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -608,3 +614,7 @@ pub fn itof32(i: anytype) f32 {
|
||||||
pub fn itof64(i: anytype) f32 {
|
pub fn itof64(i: anytype) f32 {
|
||||||
return @as(f32, @floatFromInt(i));
|
return @as(f32, @floatFromInt(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn setShutdownModule(shutdownFunction: *const fn () callconv(.c) void) void {
|
||||||
|
getEngine().shutdownModuleFunction = shutdownFunction;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -111,7 +111,7 @@
|
||||||
|
|
||||||
pub fn createEntity() !Entity {
|
pub fn createEntity() !Entity {
|
||||||
const rv = Entity{ .handle = try getRegistry().baseSet.createObject(.{}) };
|
const rv = Entity{ .handle = try getRegistry().baseSet.createObject(.{}) };
|
||||||
core.engine_log("entity created: {d}", .{rv.handle.index});
|
// core.engine_log("entity created: {d}", .{rv.handle.index});
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -132,7 +132,7 @@ pub fn destroyAllEntities() void {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn destroyEntity(e: Entity) void {
|
pub fn destroyEntity(e: Entity) void {
|
||||||
core.engine_log("entity destroyed: {d}", .{e.handle.index});
|
// core.engine_log("entity destroyed: {d}", .{e.handle.index});
|
||||||
const registry = getRegistry();
|
const registry = getRegistry();
|
||||||
if (registry.baseSet.get(e.handle)) |entityEntry| {
|
if (registry.baseSet.get(e.handle)) |entityEntry| {
|
||||||
for (entityEntry.containers.items) |ref| {
|
for (entityEntry.containers.items) |ref| {
|
||||||
|
|
@ -210,15 +210,15 @@ pub const EcsRegistry = struct {
|
||||||
|
|
||||||
pub var NeonObjectTable = core.EngineObjectVTable.from(@This(), "core.EcsRegistry");
|
pub var NeonObjectTable = core.EngineObjectVTable.from(@This(), "core.EcsRegistry");
|
||||||
|
|
||||||
pub fn init(allocator: std.mem.Allocator) !*@This() {
|
pub fn init(self: *@This(), allocator: std.mem.Allocator, first: bool) !void {
|
||||||
const self = try allocator.create(@This());
|
if (!first) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
self.* = .{
|
self.* = .{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.baseSet = BaseSet.init(allocator),
|
.baseSet = BaseSet.init(allocator),
|
||||||
};
|
};
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn registerContainer(self: *@This(), ref: EcsContainerRef, _containerName: core.Name) !void {
|
pub fn registerContainer(self: *@This(), ref: EcsContainerRef, _containerName: core.Name) !void {
|
||||||
|
|
@ -279,13 +279,11 @@ pub const EcsRegistry = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *@This()) void {
|
pub fn deinit(self: *@This()) void {
|
||||||
self.destroy();
|
// this should never work... wtf?
|
||||||
}
|
// for (self.containers.items) |ref| {
|
||||||
|
// ref.vtable.evictFromRegistry(ref.ptr);
|
||||||
|
// }
|
||||||
|
|
||||||
pub fn destroy(self: *@This()) void {
|
|
||||||
for (self.containers.items) |ref| {
|
|
||||||
ref.vtable.evictFromRegistry(ref.ptr);
|
|
||||||
}
|
|
||||||
for (self.systems.items) |ref| {
|
for (self.systems.items) |ref| {
|
||||||
ref.vtable.destroy(ref.ptr);
|
ref.vtable.destroy(ref.ptr);
|
||||||
}
|
}
|
||||||
|
|
@ -300,7 +298,6 @@ pub const EcsRegistry = struct {
|
||||||
self.containers.deinit(self.allocator);
|
self.containers.deinit(self.allocator);
|
||||||
self.containerNames.deinit(self.allocator);
|
self.containerNames.deinit(self.allocator);
|
||||||
self.containersByName.deinit(self.allocator);
|
self.containersByName.deinit(self.allocator);
|
||||||
self.allocator.destroy(self);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -377,7 +374,7 @@ pub const Entity = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn addComponent(self: @This(), comptime Component: type) ?*Component {
|
pub fn addComponent(self: @This(), comptime Component: type) ?*Component {
|
||||||
core.engine_log("adding component: {d} {s}", .{ self.handle.index, @typeName(Component) });
|
// core.engine_log("adding component: {d} {s}", .{ self.handle.index, @typeName(Component) });
|
||||||
const rv = Component.BaseContainer.createWithHandleECS(self.handle);
|
const rv = Component.BaseContainer.createWithHandleECS(self.handle);
|
||||||
|
|
||||||
const list = &getRegistry().baseSet.get(self.handle).?.containers;
|
const list = &getRegistry().baseSet.get(self.handle).?.containers;
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ const time = @import("engineTime.zig");
|
||||||
const core = @import("core.zig");
|
const core = @import("core.zig");
|
||||||
const jobs = @import("jobs.zig");
|
const jobs = @import("jobs.zig");
|
||||||
const math = @import("math.zig");
|
const math = @import("math.zig");
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
const pscopes = core.algorithm.pscopes;
|
||||||
|
|
||||||
const tracy = @import("tracy").t;
|
const tracy = @import("tracy").t;
|
||||||
const p2 = @import("p2");
|
const p2 = @import("p2");
|
||||||
|
|
@ -84,8 +86,15 @@ pub const Engine = struct {
|
||||||
|
|
||||||
delegates: EngineDelegates,
|
delegates: EngineDelegates,
|
||||||
|
|
||||||
|
rootTimer: std.time.Timer,
|
||||||
|
scopesContext: *pscopes.ScopesContext,
|
||||||
|
timeTilCalibration: f64 = 1.0, // in seconds
|
||||||
|
calibrationPeriod: f64 = 1.0, // in seconds
|
||||||
first: bool = true,
|
first: bool = true,
|
||||||
|
|
||||||
|
shutdownModuleFunction: ?*const fn () callconv(.c) void = null,
|
||||||
|
stringContext: *core.algorithm.string_pool.StringContext = undefined,
|
||||||
|
|
||||||
pub fn init(allocator: std.mem.Allocator) !@This() {
|
pub fn init(allocator: std.mem.Allocator) !@This() {
|
||||||
const rv = Engine{
|
const rv = Engine{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
|
|
@ -96,8 +105,10 @@ pub const Engine = struct {
|
||||||
.lastEngineTime = 0.0,
|
.lastEngineTime = 0.0,
|
||||||
.jobManager = try JobManager.create(allocator),
|
.jobManager = try JobManager.create(allocator),
|
||||||
.eventors = .{},
|
.eventors = .{},
|
||||||
|
.rootTimer = try std.time.Timer.start(),
|
||||||
.frameNumber = 1,
|
.frameNumber = 1,
|
||||||
.exitListeners = .{},
|
.exitListeners = .{},
|
||||||
|
.scopesContext = try pscopes.ScopesContext.create(allocator),
|
||||||
// .nfdRuntime = try nfd.NFDRuntime.create(allocator, .{}),
|
// .nfdRuntime = try nfd.NFDRuntime.create(allocator, .{}),
|
||||||
.delegates = EngineDelegates.init(allocator),
|
.delegates = EngineDelegates.init(allocator),
|
||||||
};
|
};
|
||||||
|
|
@ -113,14 +124,13 @@ pub const Engine = struct {
|
||||||
self.jobManager.destroy();
|
self.jobManager.destroy();
|
||||||
|
|
||||||
self.engineObjectsByName.deinit(self.allocator);
|
self.engineObjectsByName.deinit(self.allocator);
|
||||||
|
self.scopesContext.destroy();
|
||||||
|
|
||||||
if (self.destroyListCore.items.len > 0) {
|
if (self.destroyListCore.items.len > 0) {
|
||||||
var i: i32 = @intCast(self.destroyListCore.items.len - 1);
|
var i: i32 = @intCast(self.destroyListCore.items.len - 1);
|
||||||
while (i >= 0) : (i -= 1) {
|
while (i >= 0) : (i -= 1) {
|
||||||
const item = self.destroyListCore.items[@as(usize, @intCast(i))];
|
const item = self.destroyListCore.items[@as(usize, @intCast(i))];
|
||||||
if (item.vtable.deinit_func) |deinitFn| {
|
self.destroyObject(item);
|
||||||
deinitFn(item.ptr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.destroyListCore.deinit(self.allocator);
|
self.destroyListCore.deinit(self.allocator);
|
||||||
|
|
@ -151,6 +161,10 @@ pub const Engine = struct {
|
||||||
return @ptrCast(@alignCast(rv));
|
return @ptrCast(@alignCast(rv));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DebugSlack = struct {
|
||||||
|
slack: [1024 * 64]u8 align(16) = undefined,
|
||||||
|
};
|
||||||
|
|
||||||
// creates an engine object using the engine's allocator.
|
// creates an engine object using the engine's allocator.
|
||||||
pub fn createObjectVTable(self: *@This(), vtable: *core.EngineObjectVTable, params: NeonObjectParams) !*anyopaque {
|
pub fn createObjectVTable(self: *@This(), vtable: *core.EngineObjectVTable, params: NeonObjectParams) !*anyopaque {
|
||||||
if (self.createObjectLock) {
|
if (self.createObjectLock) {
|
||||||
|
|
@ -162,7 +176,17 @@ pub const Engine = struct {
|
||||||
self.createObjectLock = true;
|
self.createObjectLock = true;
|
||||||
defer self.createObjectLock = false;
|
defer self.createObjectLock = false;
|
||||||
const newIndex = self.engineObjects.items.len;
|
const newIndex = self.engineObjects.items.len;
|
||||||
const newObjectPtr = try vtable.init_func(self.allocator); // call this thing with the special allocator that adds vtable. slackSize to it.
|
var newObjectPtr: *anyopaque = undefined; //self.allocator.create(DebugSlack);
|
||||||
|
|
||||||
|
if (comptime core.BuildOption("static_build")) {
|
||||||
|
newObjectPtr = @ptrCast(@alignCast((try self.allocator.alignedAlloc(u8, .@"16", vtable.typeSize))));
|
||||||
|
} else {
|
||||||
|
newObjectPtr = @ptrCast(@alignCast((try self.allocator.create(DebugSlack))));
|
||||||
|
}
|
||||||
|
|
||||||
|
try vtable.init_func(newObjectPtr, self.allocator, true);
|
||||||
|
|
||||||
|
// try vtable.init_func(self.allocator); // call this thing with the special allocator that adds vtable. slackSize to it.
|
||||||
|
|
||||||
const newObjectRef = EngineObjectRef{
|
const newObjectRef = EngineObjectRef{
|
||||||
.ptr = @as(*anyopaque, @ptrCast(newObjectPtr)),
|
.ptr = @as(*anyopaque, @ptrCast(newObjectPtr)),
|
||||||
|
|
@ -230,6 +254,7 @@ pub const Engine = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tick(self: *@This()) !void {
|
pub fn tick(self: *@This()) !void {
|
||||||
|
// ------------ frame updates ---------
|
||||||
tracy.FrameMark();
|
tracy.FrameMark();
|
||||||
tracy.FrameMarkStart("frame");
|
tracy.FrameMarkStart("frame");
|
||||||
defer tracy.FrameMarkEnd("frame");
|
defer tracy.FrameMarkEnd("frame");
|
||||||
|
|
@ -238,14 +263,18 @@ pub const Engine = struct {
|
||||||
|
|
||||||
var z1 = tracy.ZoneN(@src(), "time updates");
|
var z1 = tracy.ZoneN(@src(), "time updates");
|
||||||
|
|
||||||
|
var shouldCalibrate: bool = false;
|
||||||
|
|
||||||
if (self.first) {
|
if (self.first) {
|
||||||
self.first = false;
|
self.first = false;
|
||||||
self.engineStartTime = newTime;
|
self.engineStartTime = newTime;
|
||||||
self.lastEngineTime = newTime;
|
self.lastEngineTime = newTime;
|
||||||
self.sessionStamp = std.time.microTimestamp();
|
self.sessionStamp = std.time.microTimestamp();
|
||||||
|
shouldCalibrate = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newTime < self.lastEngineTime) {
|
if (newTime < self.lastEngineTime) {
|
||||||
|
try core.assertf(false, "negative deltaTime this should not be possible", .{});
|
||||||
std.debug.print("Warning! negative deltaTime? clamping to 0.0 newTime: {d} lastEngineTime:{d}", .{
|
std.debug.print("Warning! negative deltaTime? clamping to 0.0 newTime: {d} lastEngineTime:{d}", .{
|
||||||
newTime,
|
newTime,
|
||||||
self.lastEngineTime,
|
self.lastEngineTime,
|
||||||
|
|
@ -253,6 +282,16 @@ pub const Engine = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.deltaTime = @max(newTime - self.lastEngineTime, 0.0);
|
self.deltaTime = @max(newTime - self.lastEngineTime, 0.0);
|
||||||
|
|
||||||
|
self.timeTilCalibration -= self.deltaTime;
|
||||||
|
|
||||||
|
if (self.timeTilCalibration < 0 or shouldCalibrate) {
|
||||||
|
const zcalibrate = core.tracy.ZoneN(@src(), "calibrate timing scopeContext");
|
||||||
|
self.scopesContext.calibrate();
|
||||||
|
zcalibrate.End();
|
||||||
|
self.timeTilCalibration = self.calibrationPeriod;
|
||||||
|
}
|
||||||
|
|
||||||
math.rollingAverage(&self.averageFrameTime, self.deltaTime, @floatFromInt(self.averageFrameSampleWindow));
|
math.rollingAverage(&self.averageFrameTime, self.deltaTime, @floatFromInt(self.averageFrameSampleWindow));
|
||||||
z1.End();
|
z1.End();
|
||||||
|
|
||||||
|
|
@ -263,7 +302,9 @@ pub const Engine = struct {
|
||||||
z2.End();
|
z2.End();
|
||||||
|
|
||||||
self.frameNumber += 1;
|
self.frameNumber += 1;
|
||||||
|
// -------------------------------------------
|
||||||
|
|
||||||
|
// sync
|
||||||
var z3 = tracy.ZoneN(@src(), "platform event updates");
|
var z3 = tracy.ZoneN(@src(), "platform event updates");
|
||||||
if (self.platformProcEventsFunc) |procEventsFn| {
|
if (self.platformProcEventsFunc) |procEventsFn| {
|
||||||
try procEventsFn(self.platformCtx, self.frameNumber);
|
try procEventsFn(self.platformCtx, self.frameNumber);
|
||||||
|
|
@ -274,12 +315,14 @@ pub const Engine = struct {
|
||||||
objectRef.vtable.processEvents.?(objectRef.ptr, self.frameNumber) catch @panic("process event error");
|
objectRef.vtable.processEvents.?(objectRef.ptr, self.frameNumber) catch @panic("process event error");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pretick
|
||||||
var z4 = tracy.ZoneN(@src(), "pretick event updates");
|
var z4 = tracy.ZoneN(@src(), "pretick event updates");
|
||||||
for (self.preTickables.items) |*objectRef| {
|
for (self.preTickables.items) |*objectRef| {
|
||||||
objectRef.vtable.preTick_func.?(objectRef.ptr, self.deltaTime) catch @panic("pretick event error");
|
objectRef.vtable.preTick_func.?(objectRef.ptr, self.deltaTime) catch @panic("pretick event error");
|
||||||
}
|
}
|
||||||
z4.End();
|
z4.End();
|
||||||
|
|
||||||
|
// tick
|
||||||
var z5 = tracy.ZoneN(@src(), "system object ticks");
|
var z5 = tracy.ZoneN(@src(), "system object ticks");
|
||||||
var index: isize = @as(isize, @intCast(self.tickables.items.len)) - 1;
|
var index: isize = @as(isize, @intCast(self.tickables.items.len)) - 1;
|
||||||
while (index >= 0) : (index -= 1) {
|
while (index >= 0) : (index -= 1) {
|
||||||
|
|
@ -293,6 +336,7 @@ pub const Engine = struct {
|
||||||
|
|
||||||
const systemsThreadTime: f64 = time.getEngineTime() - newTime;
|
const systemsThreadTime: f64 = time.getEngineTime() - newTime;
|
||||||
|
|
||||||
|
// renderer
|
||||||
for (self.renderers.items) |*renderer| {
|
for (self.renderers.items) |*renderer| {
|
||||||
var z = tracy.Zone(@src());
|
var z = tracy.Zone(@src());
|
||||||
z.Name(renderer.vtable.typeName);
|
z.Name(renderer.vtable.typeName);
|
||||||
|
|
@ -328,14 +372,29 @@ pub const Engine = struct {
|
||||||
self.destroyDependents();
|
self.destroyDependents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn destroyObject(self: *@This(), item: EngineObjectRef) void {
|
||||||
|
core.engine_log("destroying object {s}", .{item.vtable.typeName});
|
||||||
|
if (item.vtable.deinit_func) |deinitFn| {
|
||||||
|
deinitFn(item.ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (comptime core.BuildOption("static_build")) {
|
||||||
|
var slice: []u8 = undefined;
|
||||||
|
slice.ptr = @ptrCast(@alignCast(item.ptr));
|
||||||
|
slice.len = item.vtable.typeSize;
|
||||||
|
self.allocator.rawFree(slice, .@"16", @returnAddress());
|
||||||
|
} else {
|
||||||
|
const asStruct: *DebugSlack = @ptrCast(@alignCast(item.ptr));
|
||||||
|
self.allocator.destroy(asStruct);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn destroyDependents(self: *@This()) void {
|
fn destroyDependents(self: *@This()) void {
|
||||||
if (self.destroyListSimple.items.len > 0) {
|
if (self.destroyListSimple.items.len > 0) {
|
||||||
var i: i32 = @intCast(self.destroyListSimple.items.len - 1);
|
var i: i32 = @intCast(self.destroyListSimple.items.len - 1);
|
||||||
while (i >= 0) : (i -= 1) {
|
while (i >= 0) : (i -= 1) {
|
||||||
const item = self.destroyListSimple.items[@as(usize, @intCast(i))];
|
const item = self.destroyListSimple.items[@as(usize, @intCast(i))];
|
||||||
if (item.vtable.deinit_func) |deinitFn| {
|
self.destroyObject(item);
|
||||||
deinitFn(item.ptr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.dependentsDestroyed.store(true, .seq_cst);
|
self.dependentsDestroyed.store(true, .seq_cst);
|
||||||
|
|
|
||||||
|
|
@ -68,10 +68,6 @@ pub fn updateEngineVTable(comptime T: type) void {
|
||||||
|
|
||||||
vtable.* = T.NeonObjectTable;
|
vtable.* = T.NeonObjectTable;
|
||||||
vtable.version = version + 1;
|
vtable.version = version + 1;
|
||||||
|
|
||||||
if (@hasDecl(T, "objectReload")) {
|
|
||||||
core.get(T).objectReload();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn PatchStruct(comptime T: type, p: *T, old: []const FieldInfo) void {
|
pub fn PatchStruct(comptime T: type, p: *T, old: []const FieldInfo) void {
|
||||||
|
|
@ -167,7 +163,8 @@ pub const EngineObjectVTable = struct {
|
||||||
|
|
||||||
singletonName: ?[]const u8 = null,
|
singletonName: ?[]const u8 = null,
|
||||||
|
|
||||||
init_func: *const fn (std.mem.Allocator) EngineDataEventError!*anyopaque,
|
// new init_function passes in an already created object
|
||||||
|
init_func: *const fn (*anyopaque, std.mem.Allocator, bool) EngineDataEventError!void,
|
||||||
tick_func: ?*const fn (*anyopaque, f64) void = null,
|
tick_func: ?*const fn (*anyopaque, f64) void = null,
|
||||||
engineDraw_func: ?*const fn (*anyopaque, f64) void = null,
|
engineDraw_func: ?*const fn (*anyopaque, f64) void = null,
|
||||||
preTick_func: ?*const fn (*anyopaque, f64) EngineDataEventError!void = null,
|
preTick_func: ?*const fn (*anyopaque, f64) EngineDataEventError!void = null,
|
||||||
|
|
@ -271,11 +268,10 @@ pub const EngineObjectVTable = struct {
|
||||||
|
|
||||||
if (@hasDecl(TargetType, "init")) {
|
if (@hasDecl(TargetType, "init")) {
|
||||||
const wrappedInit = struct {
|
const wrappedInit = struct {
|
||||||
const funcFind: @TypeOf(@field(TargetType, "init")) = @field(TargetType, "init");
|
pub fn func(p: *anyopaque, allocator: std.mem.Allocator, first: bool) EngineDataEventError!void {
|
||||||
|
const newObject: *TargetType = @ptrCast(@alignCast(p)); // funcFind(allocator) catch return error.BadInit;
|
||||||
pub fn func(allocator: std.mem.Allocator) EngineDataEventError!*anyopaque {
|
newObject.init(allocator, first) catch return error.BadInit;
|
||||||
const newObject = funcFind(allocator) catch return error.BadInit;
|
// return @as(*anyopaque, @ptrCast(newObject));
|
||||||
return @as(*anyopaque, @ptrCast(newObject));
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -284,11 +280,10 @@ pub const EngineObjectVTable = struct {
|
||||||
|
|
||||||
if (@hasDecl(TargetType, "create")) {
|
if (@hasDecl(TargetType, "create")) {
|
||||||
const wrappedInit = struct {
|
const wrappedInit = struct {
|
||||||
const funcFind: @TypeOf(@field(TargetType, "create")) = @field(TargetType, "create");
|
pub fn func(p: *anyopaque, allocator: std.mem.Allocator, first: bool) EngineDataEventError!void {
|
||||||
|
const newObject: *TargetType = @ptrCast(@alignCast(p)); // funcFind(allocator) catch return error.BadInit;
|
||||||
pub fn func(allocator: std.mem.Allocator) EngineDataEventError!*anyopaque {
|
newObject.create(allocator, first) catch return error.BadInit;
|
||||||
const newObject = funcFind(allocator) catch return error.BadInit;
|
// return @as(*anyopaque, @ptrCast(newObject));
|
||||||
return @as(*anyopaque, @ptrCast(newObject));
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue