
DirectZ namespace dz is a rewrite of Zeungine and aims to improve upon its core logic while adding GPU driven rendering.
DirectZ uses spirv_reflect to reflect developer written .glsl shaders. Because of this, DirectZ allows developers to simply write shader code and have their render resources created automagically for you.
Memory is mapped from the GPU to CPU, and, using compute shaders, most of the apps logic can be offloaded to the GPU to achieve highly parallel gameloops.
DirectZ provides:
- Easy API for creating windows
- Quick access to a fully reflected Shader pipeline
- GPU driven rendering
Build Status

Documentation
DirectZ has a GitHub pages site, a static build of the Doxygen documentaion.
It is available at https://ZeunO8.github.io/DirectZ/
Getting hands on DirectZ
You can download a Release installer from the releases page or, if building from source, I recommend a clone and install
git clone https://github.com/Zeucor/DirectZ.git --recurse-submodules
cd DirectZ
cmake -G Ninja -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
cmake --build build
# Unix
sudo cmake --install build
# Windows (as admin)
cmake --install build
Building apps with DirectZ
To get setup with a cross platform compatible render context, create the following files.
(note: this example is available in full at /tests/x-platform)
CMakeLists.txt
cmake_minimum_required(VERSION 3.2.1...4.8.8) # use a version range
project(dz-x-platform VERSION 1.0.0)
set(LIB_NAME x-platform)
add_library(${LIB_NAME} SHARED src/app-lib.cpp)
target_compile_features(${LIB_NAME} PRIVATE cxx_std_20)
find_package(DirectZ REQUIRED)
message(STATUS "DirectZ_LIBRARIES: ${DirectZ_LIBRARIES}")
message(STATUS "DirectZ_INCLUDE_DIRS: ${DirectZ_INCLUDE_DIRS}")
target_include_directories(${LIB_NAME} PRIVATE ${DirectZ_INCLUDE_DIRS})
target_link_libraries(${LIB_NAME} PRIVATE ${DirectZ_LIBRARIES})
if((WIN32 OR UNIX) AND NOT IOS AND NOT ANDROID)
add_executable(${PROJECT_NAME} src/runtime.cpp)
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_20)
target_include_directories(${PROJECT_NAME} PRIVATE ${DirectZ_INCLUDE_DIRS})
target_link_libraries(${PROJECT_NAME} PRIVATE ${LIB_NAME})
elseif(ANDROID OR IOS)
# we can link ${LIB_NAME} in an app loader and call native code
endif()
src/app-lib.cpp
WINDOW* cached_window = 0;
DZ_EXPORT EventInterface*
init(
const WindowCreateInfo& window_info)
{
cached_window = window_create(window_info);
Shader* compute_shader = shader_create();
Shader* raster_shader = shader_create();
return window_get_event_interface(cached_window);
}
{
return window_poll_events(cached_window);
}
{
}
{
}
Includes the headers required to get started with a DirectZ instance, developers should include this ...
DZ_EXPORT EventInterface * init(const WindowCreateInfo &window_info)
Initializes the runtime environment.
#define DZ_EXPORT
Definition DirectZ.hpp:34
DZ_EXPORT bool poll_events()
Polls for runtime events.
DZ_EXPORT void render()
Renders the current frame.
DZ_EXPORT void update()
Performs per-frame logic before rendering.
void window_render(WINDOW *, bool multi_window_render=false)
Renders the specified window based on its context configuration.
src/runtime.cpp
int main()
{
EventInterface* ei = 0;
.title = "Example Window",
.x = 128,
.y = 128,
.width = 640,
.height = 480
})))
return 1;
{
}
return 0;
}
Buffer Groups
Before we get into Shaders, we must touch on Buffer Groups.
As we are now GPU driven, the core location of data for logic and rendering exists on the GPU.
Buffer Groups allow us to group a set of buffers (known as SSBOs in glsl) and images such that their data can be shared between Shaders.
Before creating any shaders in init add:
auto main_buffer_group = buffer_group_create("main_buffer_group");
If using multiple buffer groups (you would when sharing specific portions of data with specific shaders) you should resetrict to specific keys in the shader.
auto main_buffer_group = buffer_group_create("main_buffer_group");
auto windows_buffer_group = buffer_group_create("windows_buffer_group");
buffer_group_restrict_to_keys(main_buffer_group, {"Quads"});
buffer_group_restrict_to_keys(windows_buffer_group, {"WindowStates"});
Shaders
Shaders drive DirectZ. You write your shader using .glsl, DirectZ uses spirv_reflect to reflect the inputs/outputs, SSBOs, images back to DirectZ such that you can interface with the Shader as if it were mapped to your program.
Writing a raster pipeline
For our raster_shader we need two modules, Vertex and Fragment. Below is an implementation of a raster_shader that declares a Quad struct and the "Quads" Buffer
shader_add_module(raster_shader, ShaderModuleType::Vertex,
DZ_GLSL_VERSION + R"(
struct Quad {
vec4 viewport;
};
layout(std430, binding = 0) buffer QuadsBuffer {
Quad quads[];
} Quads;
vec3 get_quad_position()
{
vec3 pos;
switch (gl_VertexIndex)
{
case 0: pos = vec3(1.0, 1.0, 0); break;
case 1: pos = vec3(-1.0, 1.0, 0); break;
case 2: pos = vec3(-1.0, -1.0, 0); break;
case 3: pos = vec3(-1.0, -1.0, 0); break;
case 4: pos = vec3(1.0, -1.0, 0); break;
case 5: pos = vec3(1.0, 1.0, 0); break;
}
// vec4 viewport = Quads.quads[gl_InstanceIndex].viewport;
return pos;
}
vec2 get_quad_uv()
{
switch (gl_VertexIndex)
{
case 0: return vec2(1, 1);
case 1: return vec2(0, 1);
case 2: return vec2(0, 0);
case 3: return vec2(0, 0);
case 4: return vec2(1, 0);
case 5: return vec2(1, 1);
}
return vec2(0);
}
void main() {
gl_Position = vec4(get_quad_position(), 1);
}
)");
shader_add_module(raster_shader, ShaderModuleType::Fragment,
DZ_GLSL_VERSION + R"(
layout(location = 0) out vec4 outColor;
void main() {
outColor = vec4(1, 0, 0, 1);
}
)");
License
Almost all of the code in this repository is licensed under the MIT license.
Dependencies and fonts may have their own license