Tailored for Experimentation & Academy
Documentation | Features | Building
🚀 Latest Update: Mesh Shading support added to
AxionGFX.




Top: Raster / Center: Real-Time Path-Tracing / Bottom: Custom Assets
Axion is designed with strict modularity in mind. You are not forced to use the entire engine stack; you can pick and choose modules based on your prototyping needs.
AxionCommon: Shared utilities, math libraries, and base types.AxionGFX: High-level, API-agnostic rendering framework (RHI + RenderGraph). Can be used standalone.AxionCore: Scene management, Asset Loading, and high-level logic.AxionEditor: The sandbox environment and tooling.
- Pure Graphics: Use
AxionGFXalone for low-level graphics experiments (Compute Shaders, Raytracing) without the overhead of a game engine scene graph. - Interop (Fast Prototyping): Use
AxionCoresolely as a resource loader (AssetManager) to feed data intoAxionGFX, bypassing the ECS/Scene systems entirely. - Render Engine (WIP): Use
AxionCorefor creating fast and efficient graphic applications tailored for any need. - Designer (WIP): Use
AxionEditorfor loading entire designed scenes and rendering them with beautiful graphics. Add interactivity making use of the SceneGraph components.
- Advanced RenderGraph: Automatic barrier insertion and transient resource management.
- Declarative API: Fluent Builder pattern for defining pipelines and resources easily.
- Multi-Pipeline Support: Robust support for Compute, Graphics, Ray Tracing and Mesh Pipelines.
- Shader System:
- Hot-Reloading support.+
- Automatic Reflection using SLANG.
- Agnostic compilation to DXIL and SPIR-V.
- GPU-Driven Rendering: Indirect Rendering, Mesh Shading, true instancing and GPU Culling.
- Modern Architecture: PIMPL idioms, ECS integration, and strict RAII resource management.
- Tooling: Integrated Logger, Windowing, and Event systems.
This project is a work in progress.
- OS: Windows 10/11.
- SDKs: Vulkan SDK 1.4.*.
- Tools: CMake (3.20+), Ninja 🥷 (Optional, recommended for speed).´
- Git LFS: Required to download binary assets (textures, meshes).
(If you clone the repo and assets appear as 1KB text files, run
git lfs pull).
Heavy dependencies that need to be built (GLFW, fmt, etc) will be fetch recursively. Slang and other necessary binaries will be automatically downloaded using Cmake's fetch content
Clone the repository:
git clone --recursive [https://github.com/AEspinosaDev/AxionEngine.git](https://github.com/AEspinosaDev/AxionEngine.git) cd AxionEngineBuild with CMake:
mkdir build cd build cmake ..Note: The CMake configuration automatically locates and links system dependencies (except Vulkan SDK). It is designed to work out-of-the-box with VS Code or Visual Studio.
Options: To disable building tests, examples or specific engine modules:
cmake -DAXION_BUILD_EDITOR=OFF .. cmake -DAXION_BUILD_CORE=OFF .. cmake -DAXION_BUILD_GFX=OFF .. cmake -DAXION_BUILD_TESTS=OFF .. cmake -DAXION_BUILD_SAMPLES=OFF ..
#pragma once
#include"Axion/Common/Logging.h"
#include"Axion/Core/Assets/AssetManager.h"
#include"Axion/Core/Assets/Materials/StandardPBRMaterial.h"
#include"Axion/Core/Platform/Window.h"
#include"Axion/Core/Render/Rasterizer.h"
#include"Axion/Core/Scene/Entity.h"
#include"Axion/Core/Scene/Scene.h"
#include<vector>USING_AXION_NAMESPACEintmain( /*int argc, char* argv[]*/ ) {
try
{
#ifdef AXION_DEBUG
Logger::init( Logger::Level::Info, "CoreInitializationTest.log" );
#endif
Core::Platform::Window wnd( { .platformType = Graphics::PlatformType::Win32,
.name = "Axion PBR Showcase" } );
Core::Assets::AssetManager assets;
Core::Scene::Scene scene( "TestScene", &assets );
Core::Render::RasterizerSettings rastDesc {};
rastDesc.common.name = "MyRasterizer";
rastDesc.useGPUCulling = true;
rastDesc.common.selectedDeviceID = 0;
auto rasterizer = Core::Render::createRasterizer( &wnd, rastDesc );
rasterizer->compileShaders();
// =================================================================================// 1. ASSET LOADING (GEOMETRY & Textures)// =================================================================================auto cubeHandle = assets.mesh( "Cube" ).createCube();
auto sphereHandle = assets.mesh( "Sphere" ).createSphere();
auto dragonHandle = assets.mesh( "Dragon" ).import( AXION_MESH_DIR"/dragon.obj" );
auto ajaxHandle = assets.mesh( "Ajax" ).import( AXION_MESH_DIR"/ajax.obj" );
auto albedoTexHandle = assets.texture( "AxionTexture" ).import( AXION_TEXTURE_DIR"/Axion.png" );
auto albedoTexHandle2 = assets.texture( "PlanetTexture" ).import( AXION_TEXTURE_DIR"/Jupiter.jpg", Core::Assets::TextureImportAsGamma | Core::Assets::TextureImportForce4Channels | Core::Assets::TextureImportFlipVertically );
// =================================================================================// 2. PBR MATERIAL CREATION (PHYSICAL VARIETY)// =================================================================================// Material 1: Gold (For the Dragon) - Metallic and smoothauto matGoldH = assets.material( "Gold" ).create<Core::Assets::StandardPBRMaterial>();
auto matGold = assets.getMaterial<Core::Assets::StandardPBRMaterial>( matGoldH );
matGold->setAlbedo( { 1.0f, 0.76f, 0.33f } ); // Characteristic Gold Color
matGold->setMetallic( 1.0f );
matGold->setRoughness( 0.2f ); // Polished// Material 2: Shiny Red Plastic (For the Sphere) - Dielectricauto matRedPlasticH = assets.material( "Jupiter" ).create<Core::Assets::StandardPBRMaterial>();
auto matRed = assets.getMaterial<Core::Assets::StandardPBRMaterial>( matRedPlasticH );
matRed->setAlbedoTexture( albedoTexHandle2 );
matRed->setMetallic( 0.0f ); // Plastic/Dielectric
matRed->setRoughness( 0.8f ); // Very glossy (Sharp reflections)auto matChromeH = assets.material( "ChromeBlue" ).create<Core::Assets::StandardPBRMaterial>();
auto matChrome = assets.getMaterial<Core::Assets::StandardPBRMaterial>( matChromeH );
matChrome->setAlbedo( { 0.3f, 0.5f, 1.0f } ); // Light Blue Tint
matChrome->setMetallic( 0.0f );
matChrome->setRoughness( 0.3f ); // Almost mirror// Material 4: Grey Rubber/Matte (For the Cube) - Roughauto matRubberH = assets.material( "Rubber" ).create<Core::Assets::StandardPBRMaterial>();
auto matRubber = assets.getMaterial<Core::Assets::StandardPBRMaterial>( matRubberH );
matRubber->setAlbedoTexture( albedoTexHandle );
matRubber->setMetallic( 0.0f );
matRubber->setRoughness( 0.8f ); // Very matte, scatters light// =================================================================================// 3. SCENE SETUP (OBJECTS)// =================================================================================auto cameraEntity = scene.createEntity( "MainCamera" );
cameraEntity.addComponent<Core::Scene::CameraComponent>();
cameraEntity.getComponent<Core::Scene::TransformComponent>().position( { 0.0f, 0.0f, 5.0f } );
cameraEntity.getComponent<Core::Scene::TransformComponent>().lookAt( { 0.0f, 0.0f, 0.0f } );
cameraEntity.getComponent<Core::Scene::CameraComponent>().exposureCompensation = 5.0f;
// Dragon (Top Left) -> GOLDauto dragonEntity = scene.createEntity( "Dragon" );
dragonEntity.addComponent<Core::Scene::MeshComponent>( dragonHandle, matGoldH );
dragonEntity.getComponent<Core::Scene::TransformComponent>().translation = { -1.5f, 1.5f, 0.0f };
dragonEntity.getComponent<Core::Scene::TransformComponent>().scale = { 2.0f, 2.0f, 2.0f };
// Sphere (Top Right) -> RED PLASTICauto sphereEntity = scene.createEntity( "Sphere" );
sphereEntity.addComponent<Core::Scene::MeshComponent>( sphereHandle, matRedPlasticH );
sphereEntity.getComponent<Core::Scene::TransformComponent>().translation = { 1.5f, 1.5f, 0.0f };
sphereEntity.getComponent<Core::Scene::TransformComponent>().scale = { 0.8f, 0.8f, 0.8f };
// Ajax (Bottom Right) -> BLUE CHROMEauto ajaxEntity = scene.createEntity( "Ajax" );
ajaxEntity.addComponent<Core::Scene::MeshComponent>( ajaxHandle, matChromeH );
ajaxEntity.getComponent<Core::Scene::TransformComponent>().translation = { 1.5f, -1.5f, 0.0f };
ajaxEntity.getComponent<Core::Scene::TransformComponent>().scale = { 2.0f, 2.0f, 2.0f };
// Cube (Bottom Left) -> GREY RUBBERauto cubeEntity = scene.createEntity( "Cube" );
cubeEntity.addComponent<Core::Scene::MeshComponent>( cubeHandle, matRubberH );
cubeEntity.getComponent<Core::Scene::TransformComponent>().translation = { -1.5f, -1.5f, 0.0f };
cubeEntity.getComponent<Core::Scene::TransformComponent>().scale = { 1.25f, 1.25f, 1.25f };
// =================================================================================// 4. LIGHTING SETUP (ATMOSPHERE + LIGHTS)// =================================================================================// A. Global Constant Ambientauto envEntity = scene.createEntity( "GlobalEnvironment" );
envEntity.addComponent<Core::Scene::EnvironmentComponent>();
auto& env = envEntity.getComponent<Core::Scene::EnvironmentComponent>();
env.active = true;
env.type = Core::Scene::EnvironmentComponent::Type::Global;
env.skyType = Core::Scene::EnvironmentComponent::SkyType::Constant;
env.skyColor = { 0.1f, 0.1f, 0.5f };
env.groundColor = { 0.2f, 0.2f, 0.2f };
env.intensity = 1.0f;
// B. Directional Light (Moon / Key Light)auto sunEntity = scene.createEntity( "MoonLight" );
sunEntity.addComponent<Core::Scene::LightComponent>();
auto& sun = sunEntity.getComponent<Core::Scene::LightComponent>();
sun.type = Core::Scene::LightComponent::Type::Directional;
sun.intensity = 50.0f; // Lux (adjusted to avoid burnout without tonemapping)
sun.color = { 0.8f, 0.9f, 1.0f }; // Cold Blueish White
sun.useTemperature = true;
sun.temperature = 8000.0f;
sunEntity.getComponent<Core::Scene::TransformComponent>().lookAt( { 1.0f, -1.0f, -0.5f } ); // Coming from top-left// Main Loopstaticauto startTime = std::chrono::high_resolution_clock::now();
while ( !wnd.shouldClose() )
{
staticuint64_t frameCounter = 0;
staticdouble elapsedSeconds = 0.0;
static std::chrono::high_resolution_clock clock;
staticauto t0 = clock.now();
frameCounter++;
auto t1 = clock.now();
auto deltaTime = t1 - t0;
t0 = t1;
// Delta time in seconds (critical for frame-rate independent rotation)float dt = deltaTime.count() * 1e-9f;
elapsedSeconds += dt;
if ( elapsedSeconds > 1.0 )
{
wchar_t buffer[100];
double fps = frameCounter / elapsedSeconds;
swprintf_s( buffer, 100, L"Axion Engine | FPS: %.2f\n", fps );
OutputDebugStringW( buffer );
frameCounter = 0;
elapsedSeconds = 0.0;
}
float rotSpeed = 0.5f; // Radians per secondfloat step = rotSpeed * dt;
dragonEntity.getComponent<Core::Scene::TransformComponent>().rotate( { 0.0f, step, 0.0f } );
ajaxEntity.getComponent<Core::Scene::TransformComponent>().rotate( { 0.0f, -step, 0.0f } );
sphereEntity.getComponent<Core::Scene::TransformComponent>().rotate( { 0.0f, -step, 0.0f } );
wnd.update();
rasterizer->render( scene, cameraEntity );
}
} catch ( const std::exception& e )
{
returnEXIT_FAILURE;
}
#ifdef AXION_DEBUG
Axion::Logger::shutdown();
#endifreturnEXIT_SUCCESS;
}This example demonstrates how to set up a complete Raster Pipeline that generates the typical triangle.
Notice how Resource Barriers, Descriptor Sets, and Layouts are handled implicitly by the engine's RenderGraph and Reflection systems.
In less than 200 lines of code you have a complete rasterization framework built on top of DX12/Vulkan, Uniform Buffers and Geometry running.
#pragma once
#include"Axion/Common/Defines.h"
#include"Axion/Graphics/Platforms/Win32.h"
#include"Axion/Graphics/Renderer.h"USING_AXION_NAMESPACEstructCamera {
Math::Vec3 camPos = { 0.0f, 0.0f, -1.5f };
float fov = 60.0f;
structPayload {
Math::Mat4 viewProj;
};
};
structTrianglePass {
Graphics::PipelineHandle pipeline;
Graphics::BufferHandle vbo;
Graphics::BufferHandle ibo;
Graphics::RGResourceHandle output; // Backbuffer
Graphics::BufferHandle cameraBuffer; // Camera Uniform BufferstructData {
Graphics::RGResourceHandle target;
};
voidsetup( Graphics::RenderPassBuilder& pb, Data& data ) {
data.target = pb.write( output, Graphics::RHI::ResourceState::RenderTarget );
}
voidexecute( const Data& data, Graphics::RenderPassContext& ctx ) {
auto* pso = ctx.pipelines.getGraphicPipeline( pipeline );
auto* targetTex = ctx.getTexture( data.target );
auto* vb = ctx.resources.getBuffer( vbo );
auto* ib = ctx.resources.getBuffer( ibo );
auto* ubo = ctx.resources.getBuffer( cameraBuffer );
Graphics::RHI::RenderingDesc info;
info.renderArea = targetTex->getDescription().size.to2D();
info.colorAttachments.push_back( { .texture = targetTex } );
ctx.cmd->beginRendering( info );
ctx.cmd->bindGraphicPipeline( pso );
auto* set0 = ctx.allocateSet( pso->getDescription().layout, 0 );
set0->attach( 0, ubo, Graphics::RHI::ResourceState::ConstantBuffer );
ctx.cmd->bindDescriptorSet( 0, set0 );
ctx.cmd->bindVertexBuffer( 0, vb );
ctx.cmd->bindIndexBuffer( ib );
ctx.cmd->drawIndexed( 3 );
ctx.cmd->endRendering();
ctx.cmd->barrier( targetTex, Graphics::RHI::ResourceState::Present );
}
};
intmain( /*int argc, char* argv[]*/ ) {
try
{
#ifdef AXION_DEBUG
Axion::Logger::init( Logger::Level::Info, "Engine.log" );
#endifauto wnd = Axion::Graphics::createWindowForWin32( GetModuleHandle( nullptr ), { .name = "GFX RASTER TEST" } );
auto bufferingType = Graphics::BufferingType::Double;
const uint FRAMES_IN_FLIGHT = (size_t)bufferingType + 1;
auto rnd = Axion::Graphics::createRenderer( wnd,
{ .gfxApi = Graphics::API::DirectX12,
.bufferingType = bufferingType,
.presentMode = Graphics::PresentMode::Immediate,
.autoSync = true } );
//-------------------------------------// Dedclaring Shaders & Pipelines//-------------------------------------
rnd->shaders().shader( "DrawShader" ).asDXIL().path( AXION_SHADER_DIR"/Slang/Testing/Raster.slang" ).vs( "vsMain" ).ps( "psMain" ).load();
rnd->shaders().compileAllShaders();
TrianglePass rpass;
rpass.pipeline = rnd->pipelines()
.graphic( "RasterPipeline" )
.shader( "DrawShader" )
.addRenderTarget( rnd->getSettings().backbufferFormat )
.cullNone()
.disableDepth()
.create();
//-------------------------------------// Declaring Static Resources//-------------------------------------// GEOMETRYstructVertex {
float x, y, z;
float r, g, b;
};
std::vector<Vertex> vertices = {
{ 0.0f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f },
{ 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f },
{ -0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f } };
std::vector<uint> indices = { 0, 1, 2 };
rpass.vbo = rnd->resources()
.buffer( "VertexBuffer" )
.asVBO()
.withData( vertices.data() )
.stride( sizeof( Vertex ) )
.size( vertices.size() * sizeof( Vertex ) )
.create();
rpass.ibo = rnd->resources().buffer( "IndexBuffer" ).asIBO().withData( indices.data() ).size( indices.size() * sizeof( uint ) ).create();
//-------------------------------------// UNIFORM CONSTANT BUFFER//-------------------------------------
std::vector<Graphics::BufferHandle> camBuffers( FRAMES_IN_FLIGHT );
for ( int i = 0; i < FRAMES_IN_FLIGHT; ++i )
{
camBuffers[i] = rnd->resources().buffer( "CamUniformBuffer_" + std::to_string( i ) ).size( sizeof( Camera::Payload ) ).asCBO().onCPU().create();
}
//-------------------------------------// CAMERA AND INPUT//-------------------------------------
Camera cam {};
auto evnt = wnd->onKey().subscribe( [&cam]( const Event::KeyEvent& e ) {
if ( e.keyCode == Event::KeyCode::W && e.pressed )
cam.camPos.z += 0.01f;
if ( e.keyCode == Event::KeyCode::S && e.pressed )
cam.camPos.z -= 0.01f;
if ( e.keyCode == Event::KeyCode::D && e.pressed )
cam.camPos.x += 0.01f;
if ( e.keyCode == Event::KeyCode::A && e.pressed )
cam.camPos.x -= 0.01f;
if ( e.keyCode == Event::KeyCode::Q && e.pressed )
cam.camPos.y += 0.01f;
if ( e.keyCode == Event::KeyCode::E && e.pressed )
cam.camPos.y -= 0.01f;
} );
//-------------------------------------// Main Loop//-------------------------------------staticauto startTime = std::chrono::high_resolution_clock::now();
while ( !wnd->shouldClose() )
{
wnd->processMessages();
// Process Uniformsfloat aspect = (float)wnd->getSettings().size.width / (float)wnd->getSettings().size.height;
auto proj = Axion::Math::perspective( Math::radians( cam.fov ), aspect, 0.01f, 10.0f );
auto view = Axion::Math::lookAt( cam.camPos, { 0, 0, 0 }, { 0, 1, 0 } );
Camera::Payload camData;
camData.viewProj = proj * view;
camData.viewProj = Axion::Math::transpose( camData.viewProj );
auto frameIndex = rnd->getCurrentFrameIndex();
auto* cbRaw = rnd->resources().getBuffer( camBuffers[frameIndex] );
cbRaw->copyData( camData );
// Call render func and feed it with a lambda building the RenderGraph
rnd->render( [&]( Axion::Graphics::RenderGraphBuilder& builder ) {
rpass.output = builder.import( "Backbuffer", rnd->getCurrentBackbufferHandle() );
rpass.cameraBuffer = camBuffers[frameIndex];
builder.addPass<TrianglePass>( "TrianglePass", rpass );
} );
};
} catch ( const std::exception& e )
{
returnEXIT_FAILURE;
}
#ifdef AXION_DEBUG
Axion::Logger::shutdown();
#endifreturnEXIT_SUCCESS;
}
This example demonstrates how to set up a complete Compute Pipeline that generates an HDR image, applies Tone Mapping, and blits the result to the Backbuffer.
Notice how Resource Barriers, Descriptor Sets, and Layouts are handled implicitly by the engine's RenderGraph and Reflection systems.
#include"Axion/Graphics/Renderer.h"
#include"Axion/Graphics/Platforms/Win32.h"USING_AXION_NAMESPACE// 1. Define your PassesstructGenerationPass {
Graphics::PipelineHandle pipelineHandle;
Graphics::RGResourceHandle outputHandle;
structPushConstantData {
float time;
float speed = 1.0;
};
PushConstantData pushData;
structData {
Graphics::RGResourceHandle outputHDR;
};
voidsetup( Graphics::RenderPassBuilder& builder, Data& data ) {
data.outputHDR = builder.write( outputHandle );
}
voidexecute( const Data& data, Graphics::RenderPassContext& ctx ) {
auto* pso = ctx.pipelines.getComputePipeline( pipelineHandle );
auto* texOut = ctx.getTexture( data.outputHDR );
auto* set0 = ctx.allocateSet( pso->getDescription().layout, 0 );
set0->bind( 0, texOut, Graphics::RHI::ResourceState::UnorderedAccess );
ctx.cmd->bindComputePipeline( pso );
ctx.cmd->bindDescriptorSet( 0, set0 );
ctx.cmd->pushConstants( 1, pushData );
ctx.cmd->dispatch( texOut->getDescription().size );
}
};
structToneMappingPass {
Graphics::PipelineHandle pipelineHandle;
Graphics::RGResourceHandle inputHandle;
Graphics::RGResourceHandle outputHandle;
structData {
Graphics::RGResourceHandle inputHDR;
Graphics::RGResourceHandle outputLDR;
};
voidsetup( Graphics::RenderPassBuilder& builder, Data& data ) {
data.inputHDR = builder.read( inputHandle );
data.outputLDR = builder.write( outputHandle );
}
voidexecute( const Data& data, Graphics::RenderPassContext& ctx ) {
auto* pso = ctx.pipelines.getComputePipeline( pipelineHandle );
auto* texIn = ctx.getTexture( data.inputHDR );
auto* texOut = ctx.getTexture( data.outputLDR );
auto* set0 = ctx.allocateSet( pso->getDescription().layout, 0 );
auto* set1 = ctx.allocateSet( pso->getDescription().layout, 1 );
set0->bind( 0, texIn, Graphics::RHI::ResourceState::ShaderResource );
set1->bind( 0, texOut, Graphics::RHI::ResourceState::UnorderedAccess );
ctx.cmd->bindComputePipeline( pso );
ctx.cmd->bindDescriptorSet( 0, set0 );
ctx.cmd->bindDescriptorSet( 1, set1 );
ctx.cmd->dispatch( texIn->getDescription().size );
}
};
structCopyPass {
Graphics::RGResourceHandle inputHandle;
Graphics::RGResourceHandle outputHandle;
structData {
Graphics::RGResourceHandle inputLDR;
Graphics::RGResourceHandle outputLDR;
};
voidsetup( Graphics::RenderPassBuilder& builder, Data& data ) {
data.inputLDR = builder.read( inputHandle, Graphics::RHI::ResourceState::CopySource );
data.outputLDR = builder.write( outputHandle, Graphics::RHI::ResourceState::CopyDest );
}
voidexecute( const Data& data, Graphics::RenderPassContext& ctx ) {
auto* srcTex = ctx.getTexture( data.inputLDR );
auto* dstTex = ctx.getTexture( data.outputLDR );
ctx.cmd->copyTexture( dstTex, srcTex );
ctx.cmd->barrier( dstTex, Graphics::RHI::ResourceState::Present );
}
};
intmain() {
try {
// Init Subsystemsauto wnd = Axion::Graphics::createWindowForWin32(GetModuleHandle(nullptr), { .name = "AXION DEMO" });
auto rnd = Axion::Graphics::createRenderer(wnd, { .gfxApi = Graphics::API::DirectX12, .presentMode = Graphics::PresentMode::Vsync });
// Load Shaders (Hot-Reloadable)
rnd->shaders().shader("GenShader").asDXIL().path("Shaders/Gen.slang").cs("computeMain").load();
rnd->shaders().shader("ToneMapShader").asDXIL().path("Shaders/ToneMap.slang").cs("computeMain").load();
rnd->shaders().compileAllShaders();
// Create Pipelines
GenerationPass gpass;
gpass.pipelineHandle = rnd->pipelines().compute( "GenerationPipeline" ).shader( "GenerationShader" ).create();
ToneMappingPass tpass;
tpass.pipelineHandle = rnd->pipelines().compute( "TonemappingPipeline" ).shader( "TonemappingShader" ).create();
CopyPass cpypass;
auto evnt = wnd->onKey().subscribe( [&gpass]( const Event::KeyEvent& e ) { if ( e.keyCode == 38 && e.pressed ){
gpass.pushData.speed += 0.1;
}
if ( e.keyCode == 40 && e.pressed ){
gpass.pushData.speed -= 0.1;
} } );
staticauto startTime = std::chrono::high_resolution_clock::now();
while ( !wnd->shouldClose() )
{
staticuint64_t frameCounter = 0;
staticdouble elapsedSeconds = 0.0;
static std::chrono::high_resolution_clock clock;
staticauto t0 = clock.now();
frameCounter++;
auto t1 = clock.now();
auto deltaTime = t1 - t0;
t0 = t1;
elapsedSeconds += deltaTime.count() * 1e-9;
if ( elapsedSeconds > 1.0 )
{
wchar_t buffer[100];
double fps = frameCounter / elapsedSeconds;
swprintf_s( buffer, 100, L"FPS: %.2f\n", fps ); OutputDebugStringW( buffer ); frameCounter = 0;
elapsedSeconds = 0.0;
}
wnd->processMessages();
rnd->render( [&]( Axion::Graphics::RenderGraphBuilder& builder ) {
usingnamespaceAxion::Graphics;auto wndExtent = wnd->getSettings().size;
gpass.pushData.time = std::chrono::duration<float>( t1 - startTime ).count();
gpass.outputHandle = builder.texture( "HDRIntermidiate" ).format( Format::RGBA16_FLOAT ).extent( wndExtent.width, wndExtent.height, 1 ).asStorage().create();
builder.addPass<GenerationPass>( "GenerationPass", gpass );
tpass.outputHandle = builder.texture( "LDRIntermidiate" ).format( Format::RGBA8_UNORM ).extent( wndExtent.width, wndExtent.height, 1 ).asStorage().create();
tpass.inputHandle = gpass.outputHandle;
builder.addPass<ToneMappingPass>( "TonemappingPass", tpass );
cpypass.inputHandle = tpass.outputHandle;
cpypass.outputHandle = builder.import( "Backbuffer", rnd->getCurrentBackbufferHandle() );
builder.addPass<CopyPass>( "CopyPass", cpypass );
} );
};
} catch ( const std::exception& e )
{
returnEXIT_FAILURE;
}
#ifdef AXION_DEBUG
Axion::Logger::shutdown();
#endifreturnEXIT_SUCCESS;
}


