mirror of
https://github.com/ZDoom/ZDRay.git
synced 2024-11-23 20:32:19 +00:00
Add a level mesh viewer (--viewer cmdline arg) for better debugging
This commit is contained in:
parent
6f779c0351
commit
e28879187c
12 changed files with 973 additions and 16 deletions
|
@ -81,13 +81,17 @@ set(ZDRAY_SOURCES
|
||||||
src/lightmapper/gpuraytracer.h
|
src/lightmapper/gpuraytracer.h
|
||||||
src/lightmapper/stacktrace.cpp
|
src/lightmapper/stacktrace.cpp
|
||||||
src/lightmapper/stacktrace.h
|
src/lightmapper/stacktrace.h
|
||||||
|
src/lightmapper/levelmeshviewer.cpp
|
||||||
|
src/lightmapper/levelmeshviewer.h
|
||||||
src/lightmapper/glsl/binding_lightmapper.glsl.h
|
src/lightmapper/glsl/binding_lightmapper.glsl.h
|
||||||
src/lightmapper/glsl/binding_raytrace.glsl.h
|
src/lightmapper/glsl/binding_raytrace.glsl.h
|
||||||
src/lightmapper/glsl/binding_textures.glsl.h
|
src/lightmapper/glsl/binding_textures.glsl.h
|
||||||
|
src/lightmapper/glsl/binding_viewer.glsl.h
|
||||||
src/lightmapper/glsl/frag_blur.glsl.h
|
src/lightmapper/glsl/frag_blur.glsl.h
|
||||||
src/lightmapper/glsl/frag_copy.glsl.h
|
src/lightmapper/glsl/frag_copy.glsl.h
|
||||||
src/lightmapper/glsl/frag_raytrace.glsl.h
|
src/lightmapper/glsl/frag_raytrace.glsl.h
|
||||||
src/lightmapper/glsl/frag_resolve.glsl.h
|
src/lightmapper/glsl/frag_resolve.glsl.h
|
||||||
|
src/lightmapper/glsl/frag_viewer.glsl.h
|
||||||
src/lightmapper/glsl/montecarlo.glsl.h
|
src/lightmapper/glsl/montecarlo.glsl.h
|
||||||
src/lightmapper/glsl/polyfill_rayquery.glsl.h
|
src/lightmapper/glsl/polyfill_rayquery.glsl.h
|
||||||
src/lightmapper/glsl/trace_ambient_occlusion.glsl.h
|
src/lightmapper/glsl/trace_ambient_occlusion.glsl.h
|
||||||
|
@ -98,6 +102,7 @@ set(ZDRAY_SOURCES
|
||||||
src/lightmapper/glsl/vert_copy.glsl.h
|
src/lightmapper/glsl/vert_copy.glsl.h
|
||||||
src/lightmapper/glsl/vert_raytrace.glsl.h
|
src/lightmapper/glsl/vert_raytrace.glsl.h
|
||||||
src/lightmapper/glsl/vert_screenquad.glsl.h
|
src/lightmapper/glsl/vert_screenquad.glsl.h
|
||||||
|
src/lightmapper/glsl/vert_viewer.glsl.h
|
||||||
src/models/model.cpp
|
src/models/model.cpp
|
||||||
src/models/model.h
|
src/models/model.h
|
||||||
src/models/model_md2.h
|
src/models/model_md2.h
|
||||||
|
|
97
src/lightmapper/glsl/binding_viewer.glsl.h
Normal file
97
src/lightmapper/glsl/binding_viewer.glsl.h
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
static const char* binding_viewer_glsl = R"glsl(
|
||||||
|
|
||||||
|
struct SurfaceInfo
|
||||||
|
{
|
||||||
|
vec3 Normal;
|
||||||
|
float Sky;
|
||||||
|
uint PortalIndex;
|
||||||
|
int TextureIndex;
|
||||||
|
float Alpha;
|
||||||
|
float Padding0;
|
||||||
|
uint LightStart;
|
||||||
|
uint LightEnd;
|
||||||
|
uint Padding1;
|
||||||
|
uint Padding2;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PortalInfo
|
||||||
|
{
|
||||||
|
mat4 Transformation;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LightInfo
|
||||||
|
{
|
||||||
|
vec3 Origin;
|
||||||
|
float Padding0;
|
||||||
|
vec3 RelativeOrigin;
|
||||||
|
float Padding1;
|
||||||
|
float Radius;
|
||||||
|
float Intensity;
|
||||||
|
float InnerAngleCos;
|
||||||
|
float OuterAngleCos;
|
||||||
|
vec3 SpotDir;
|
||||||
|
float SourceRadius;
|
||||||
|
vec3 Color;
|
||||||
|
float Padding3;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(set = 0, binding = 0, std430) buffer SurfaceIndexBuffer { uint surfaceIndices[]; };
|
||||||
|
layout(set = 0, binding = 1, std430) buffer SurfaceBuffer { SurfaceInfo surfaces[]; };
|
||||||
|
layout(set = 0, binding = 2, std430) buffer LightBuffer { LightInfo lights[]; };
|
||||||
|
layout(set = 0, binding = 3, std430) buffer LightIndexBuffer { int lightIndexes[]; };
|
||||||
|
layout(set = 0, binding = 4, std430) buffer PortalBuffer { PortalInfo portals[]; };
|
||||||
|
|
||||||
|
#if defined(USE_RAYQUERY)
|
||||||
|
|
||||||
|
layout(set = 0, binding = 5) uniform accelerationStructureEXT acc;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
struct CollisionNode
|
||||||
|
{
|
||||||
|
vec3 center;
|
||||||
|
float padding1;
|
||||||
|
vec3 extents;
|
||||||
|
float padding2;
|
||||||
|
int left;
|
||||||
|
int right;
|
||||||
|
int element_index;
|
||||||
|
int padding3;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(set = 0, binding = 5, std430) buffer NodeBuffer
|
||||||
|
{
|
||||||
|
int nodesRoot;
|
||||||
|
int nodebufferPadding1;
|
||||||
|
int nodebufferPadding2;
|
||||||
|
int nodebufferPadding3;
|
||||||
|
CollisionNode nodes[];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct SurfaceVertex // Note: this must always match the FFlatVertex struct
|
||||||
|
{
|
||||||
|
vec3 pos;
|
||||||
|
float lindex;
|
||||||
|
vec2 uv;
|
||||||
|
vec2 luv;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(set = 0, binding = 6, std430) buffer VertexBuffer { SurfaceVertex vertices[]; };
|
||||||
|
layout(set = 0, binding = 7, std430) buffer ElementBuffer { int elements[]; };
|
||||||
|
|
||||||
|
layout(set = 1, binding = 0) uniform sampler2D textures[];
|
||||||
|
|
||||||
|
layout(push_constant) uniform PushConstants
|
||||||
|
{
|
||||||
|
mat4 ViewToWorld;
|
||||||
|
vec3 CameraPos;
|
||||||
|
float ProjX;
|
||||||
|
vec3 SunDir;
|
||||||
|
float ProjY;
|
||||||
|
vec3 SunColor;
|
||||||
|
float SunIntensity;
|
||||||
|
};
|
||||||
|
|
||||||
|
)glsl";
|
51
src/lightmapper/glsl/frag_viewer.glsl.h
Normal file
51
src/lightmapper/glsl/frag_viewer.glsl.h
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
static const char* frag_viewer_glsl = R"glsl(
|
||||||
|
|
||||||
|
#include <shaders/lightmap/binding_viewer.glsl>
|
||||||
|
#include <shaders/lightmap/polyfill_rayquery.glsl>
|
||||||
|
#include <shaders/lightmap/trace_levelmesh.glsl>
|
||||||
|
#include <shaders/lightmap/trace_sunlight.glsl>
|
||||||
|
#include <shaders/lightmap/trace_light.glsl>
|
||||||
|
#include <shaders/lightmap/trace_ambient_occlusion.glsl>
|
||||||
|
|
||||||
|
layout(location = 0) in vec3 FragRay;
|
||||||
|
layout(location = 0) out vec4 fragcolor;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec3 incoming = vec3(0.1);
|
||||||
|
|
||||||
|
vec3 origin = CameraPos;
|
||||||
|
vec3 L = normalize(FragRay);
|
||||||
|
TraceResult result = TraceFirstHit(origin, 0.0, L, 10000.0);
|
||||||
|
if (result.primitiveIndex != -1)
|
||||||
|
{
|
||||||
|
SurfaceInfo surface = GetSurface(result.primitiveIndex);
|
||||||
|
vec3 surfacepos = origin + L * result.t;
|
||||||
|
|
||||||
|
if (surface.Sky == 0.0)
|
||||||
|
{
|
||||||
|
incoming += TraceSunLight(surfacepos, surface.Normal);
|
||||||
|
|
||||||
|
uint LightStart = surface.LightStart;
|
||||||
|
uint LightEnd = surface.LightEnd;
|
||||||
|
for (uint j = LightStart; j < LightEnd; j++)
|
||||||
|
{
|
||||||
|
incoming += TraceLight(surfacepos, surface.Normal, lights[lightIndexes[j]], 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// incoming *= TraceAmbientOcclusion(surfacepos, surface.Normal);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
incoming = SunColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
incoming = vec3(1.0, 0.0, 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fragcolor = vec4(incoming, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
)glsl";
|
24
src/lightmapper/glsl/vert_viewer.glsl.h
Normal file
24
src/lightmapper/glsl/vert_viewer.glsl.h
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
static const char* vert_viewer_glsl = R"glsl(
|
||||||
|
|
||||||
|
#include <shaders/lightmap/binding_viewer.glsl>
|
||||||
|
|
||||||
|
layout(location = 0) out vec3 FragRay;
|
||||||
|
|
||||||
|
vec2 positions[4] = vec2[](
|
||||||
|
vec2(0.0, 0.0),
|
||||||
|
vec2(1.0, 0.0),
|
||||||
|
vec2(0.0, 1.0),
|
||||||
|
vec2(1.0, 1.0)
|
||||||
|
);
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec4 viewpos = vec4(positions[gl_VertexIndex] * 2.0 - 1.0, 1.0, 1.0);
|
||||||
|
viewpos.x /= ProjX;
|
||||||
|
viewpos.y = -viewpos.y / ProjY;
|
||||||
|
FragRay = (ViewToWorld * viewpos).xyz - CameraPos;
|
||||||
|
|
||||||
|
gl_Position = vec4(positions[gl_VertexIndex] * 2.0 - 1.0, 1.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
)glsl";
|
|
@ -5,6 +5,7 @@
|
||||||
#include "vk_lightmapper.h"
|
#include "vk_lightmapper.h"
|
||||||
#include "renderdoc_app.h"
|
#include "renderdoc_app.h"
|
||||||
#include "doom_levelmesh.h"
|
#include "doom_levelmesh.h"
|
||||||
|
#include "levelmeshviewer.h"
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
@ -12,10 +13,14 @@
|
||||||
|
|
||||||
static RENDERDOC_API_1_4_2* rdoc_api;
|
static RENDERDOC_API_1_4_2* rdoc_api;
|
||||||
|
|
||||||
|
extern bool showviewer;
|
||||||
|
|
||||||
GPURaytracer::GPURaytracer()
|
GPURaytracer::GPURaytracer()
|
||||||
{
|
{
|
||||||
LoadRenderDoc();
|
LoadRenderDoc();
|
||||||
mDevice = std::make_unique<VulkanRenderDevice>();
|
if (showviewer)
|
||||||
|
mViewer = std::make_unique<LevelMeshViewer>();
|
||||||
|
mDevice = std::make_unique<VulkanRenderDevice>(mViewer.get());
|
||||||
PrintVulkanInfo();
|
PrintVulkanInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,6 +82,9 @@ void GPURaytracer::Raytrace(DoomLevelMesh* mesh)
|
||||||
{
|
{
|
||||||
mDevice->GetTextureManager()->DownloadLightmap(arrayIndex, mesh->LMTextureData.Data() + arrayIndex * mesh->LMTextureSize * mesh->LMTextureSize * 4);
|
mDevice->GetTextureManager()->DownloadLightmap(arrayIndex, mesh->LMTextureData.Data() + arrayIndex * mesh->LMTextureSize * mesh->LMTextureSize * 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mViewer)
|
||||||
|
mViewer->Exec(mDevice.get(), mesh->SunDirection, mesh->SunColor, 1.0f);
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "vk_renderdevice.h"
|
#include "vk_renderdevice.h"
|
||||||
|
|
||||||
class DoomLevelMesh;
|
class DoomLevelMesh;
|
||||||
|
class LevelMeshViewer;
|
||||||
|
|
||||||
class GPURaytracer
|
class GPURaytracer
|
||||||
{
|
{
|
||||||
|
@ -16,5 +17,6 @@ private:
|
||||||
void PrintVulkanInfo();
|
void PrintVulkanInfo();
|
||||||
void LoadRenderDoc();
|
void LoadRenderDoc();
|
||||||
|
|
||||||
|
std::unique_ptr<LevelMeshViewer> mViewer;
|
||||||
std::unique_ptr<VulkanRenderDevice> mDevice;
|
std::unique_ptr<VulkanRenderDevice> mDevice;
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,6 +9,15 @@ LevelMesh::LevelMesh()
|
||||||
|
|
||||||
AddEmptyMesh();
|
AddEmptyMesh();
|
||||||
UpdateCollision();
|
UpdateCollision();
|
||||||
|
|
||||||
|
Mesh.MaxVertices = std::max(Mesh.Vertices.Size() * 2, (unsigned int)10000);
|
||||||
|
Mesh.MaxIndexes = std::max(Mesh.Indexes.Size() * 2, (unsigned int)10000);
|
||||||
|
Mesh.MaxSurfaces = std::max(Mesh.SurfaceIndexes.Size() * 2, (unsigned int)10000);
|
||||||
|
Mesh.MaxUniforms = std::max(Mesh.Uniforms.Size() * 2, (unsigned int)10000);
|
||||||
|
Mesh.MaxSurfaceIndexes = std::max(Mesh.SurfaceIndexes.Size() * 2, (unsigned int)10000);
|
||||||
|
Mesh.MaxNodes = (int)std::max(Collision->get_nodes().size() * 2, (size_t)10000);
|
||||||
|
Mesh.MaxLights = 100'000;
|
||||||
|
Mesh.MaxLightIndexes = 4 * 1024 * 1024;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LevelMesh::AddEmptyMesh()
|
void LevelMesh::AddEmptyMesh()
|
||||||
|
|
326
src/lightmapper/levelmeshviewer.cpp
Normal file
326
src/lightmapper/levelmeshviewer.cpp
Normal file
|
@ -0,0 +1,326 @@
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
|
||||||
|
#include "levelmeshviewer.h"
|
||||||
|
#include "vk_renderdevice.h"
|
||||||
|
#include "framework/matrix.h"
|
||||||
|
#include <windowsx.h>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <zvulkan/vulkanswapchain.h>
|
||||||
|
|
||||||
|
LevelMeshViewer::LevelMeshViewer()
|
||||||
|
{
|
||||||
|
CreateViewerWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
LevelMeshViewer::~LevelMeshViewer()
|
||||||
|
{
|
||||||
|
DestroyViewerWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LevelMeshViewer::RenderFrame()
|
||||||
|
{
|
||||||
|
RECT clientRect = {};
|
||||||
|
GetClientRect(WindowHandle, &clientRect);
|
||||||
|
int width = clientRect.right;
|
||||||
|
int height = clientRect.bottom;
|
||||||
|
if (width <= 0 || height <= 0)
|
||||||
|
{
|
||||||
|
Sleep(500);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderDevice->ResizeSwapChain(width, height);
|
||||||
|
|
||||||
|
VSMatrix movematrix;
|
||||||
|
movematrix.loadIdentity();
|
||||||
|
movematrix.rotate((float)Yaw, 0.0f, 1.0f, 0.0);
|
||||||
|
movematrix.rotate((float)Pitch, 1.0f, 0.0f, 0.0);
|
||||||
|
if (MoveLeft)
|
||||||
|
{
|
||||||
|
CameraPos += (movematrix * FVector4(-10.0f, 0.0f, 0.0f, 1.0f)).XYZ();
|
||||||
|
}
|
||||||
|
if (MoveRight)
|
||||||
|
{
|
||||||
|
CameraPos += (movematrix * FVector4(10.0f, 0.0f, 0.0f, 1.0f)).XYZ();
|
||||||
|
}
|
||||||
|
if (MoveForward)
|
||||||
|
{
|
||||||
|
CameraPos += (movematrix * FVector4(0.0f, 0.0f, 10.0f, 1.0f)).XYZ();
|
||||||
|
}
|
||||||
|
if (MoveBackward)
|
||||||
|
{
|
||||||
|
CameraPos += (movematrix * FVector4(0.0f, 0.0f, -10.0f, 1.0f)).XYZ();
|
||||||
|
}
|
||||||
|
|
||||||
|
VSMatrix worldToView;
|
||||||
|
worldToView.loadIdentity();
|
||||||
|
worldToView.rotate((float)-Pitch, 1.0f, 0.0f, 0.0);
|
||||||
|
worldToView.rotate((float)-Yaw, 0.0f, 1.0f, 0.0);
|
||||||
|
worldToView.translate(-CameraPos.X, -CameraPos.Y, -CameraPos.Z);
|
||||||
|
|
||||||
|
VSMatrix viewToWorld;
|
||||||
|
worldToView.inverseMatrix(viewToWorld);
|
||||||
|
|
||||||
|
RenderDevice->DrawViewer(CameraPos, viewToWorld, 60.0f, width / (float)height, SunDir, SunColor, SunIntensity);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LevelMeshViewer::OnMouseMove(double dx, double dy)
|
||||||
|
{
|
||||||
|
Yaw += dx * 0.1;
|
||||||
|
while (Yaw < 0.0) Yaw += 360.0;
|
||||||
|
while (Yaw >= 360.0) Yaw -= 360.0;
|
||||||
|
|
||||||
|
Pitch += dy * 0.1;
|
||||||
|
if (Pitch < -90.0) Pitch = -90.0;
|
||||||
|
if (Pitch > 90.0) Pitch = 90.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LevelMeshViewer::OnKeyDown(WPARAM key)
|
||||||
|
{
|
||||||
|
if (key == 'A')
|
||||||
|
{
|
||||||
|
MoveLeft = true;
|
||||||
|
}
|
||||||
|
else if (key == 'D')
|
||||||
|
{
|
||||||
|
MoveRight = true;
|
||||||
|
}
|
||||||
|
else if (key == 'W')
|
||||||
|
{
|
||||||
|
MoveForward = true;
|
||||||
|
}
|
||||||
|
else if (key == 'S')
|
||||||
|
{
|
||||||
|
MoveBackward = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LevelMeshViewer::OnKeyUp(WPARAM key)
|
||||||
|
{
|
||||||
|
if (key == 'A')
|
||||||
|
{
|
||||||
|
MoveLeft = false;
|
||||||
|
}
|
||||||
|
else if (key == 'D')
|
||||||
|
{
|
||||||
|
MoveRight = false;
|
||||||
|
}
|
||||||
|
else if (key == 'W')
|
||||||
|
{
|
||||||
|
MoveForward = false;
|
||||||
|
}
|
||||||
|
else if (key == 'S')
|
||||||
|
{
|
||||||
|
MoveBackward = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LevelMeshViewer::Exec(VulkanRenderDevice* renderdevice, const FVector3& sundir, const FVector3& suncolor, float sunintensity)
|
||||||
|
{
|
||||||
|
RenderDevice = renderdevice;
|
||||||
|
SunDir = sundir;
|
||||||
|
SunColor = suncolor;
|
||||||
|
SunIntensity = sunintensity;
|
||||||
|
bool exitFlag = false;
|
||||||
|
while (!exitFlag)
|
||||||
|
{
|
||||||
|
MSG msg = {};
|
||||||
|
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
|
||||||
|
{
|
||||||
|
if (msg.message == WM_QUIT)
|
||||||
|
{
|
||||||
|
exitFlag = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
TranslateMessage(&msg);
|
||||||
|
DispatchMessage(&msg);
|
||||||
|
}
|
||||||
|
RenderFrame();
|
||||||
|
}
|
||||||
|
ShowWindow(WindowHandle, SW_HIDE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LevelMeshViewer::CreateViewerWindow()
|
||||||
|
{
|
||||||
|
WNDCLASSEX classdesc = {};
|
||||||
|
classdesc.cbSize = sizeof(WNDCLASSEX);
|
||||||
|
classdesc.hInstance = GetModuleHandle(nullptr);
|
||||||
|
classdesc.lpszClassName = L"LevelMeshViewerWindow";
|
||||||
|
classdesc.lpfnWndProc = &LevelMeshViewer::WindowProc;
|
||||||
|
classdesc.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
|
||||||
|
classdesc.hbrBackground = CreateSolidBrush(RGB(0, 0, 0));
|
||||||
|
BOOL result = RegisterClassEx(&classdesc);
|
||||||
|
if (!result)
|
||||||
|
throw std::runtime_error("RegisterClassEx failed");
|
||||||
|
|
||||||
|
HDC screenDC = GetDC(0);
|
||||||
|
int dpi = GetDeviceCaps(screenDC, LOGPIXELSX);
|
||||||
|
ReleaseDC(0, screenDC);
|
||||||
|
auto applyDpi = [=](int i) { return (i * dpi + (96 / 2)) / 96; };
|
||||||
|
|
||||||
|
// Create and show the window
|
||||||
|
WindowHandle = CreateWindowEx(WS_EX_APPWINDOW, L"LevelMeshViewerWindow", L"ZDRay Viewer", WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_MAXIMIZE, applyDpi(100), applyDpi(50), applyDpi(1400), applyDpi(800), 0, 0, GetModuleHandle(nullptr), this);
|
||||||
|
if (!WindowHandle)
|
||||||
|
throw std::runtime_error("CreateWindowEx failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
void LevelMeshViewer::DestroyViewerWindow()
|
||||||
|
{
|
||||||
|
if (WindowHandle)
|
||||||
|
DestroyWindow(WindowHandle);
|
||||||
|
WindowHandle = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LevelMeshViewer::OnClose()
|
||||||
|
{
|
||||||
|
PostQuitMessage(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
LRESULT LevelMeshViewer::OnWindowMessage(UINT msg, WPARAM wparam, LPARAM lparam)
|
||||||
|
{
|
||||||
|
/*if (msg == WM_RBUTTONDOWN)
|
||||||
|
{
|
||||||
|
if (!MouseLocked)
|
||||||
|
{
|
||||||
|
GetCursorPos(&LockPosition);
|
||||||
|
::ShowCursor(FALSE);
|
||||||
|
|
||||||
|
RECT box = {};
|
||||||
|
GetClientRect(WindowHandle, &box);
|
||||||
|
|
||||||
|
POINT center = {};
|
||||||
|
center.x = box.right / 2;
|
||||||
|
center.y = box.bottom / 2;
|
||||||
|
ClientToScreen(WindowHandle, ¢er);
|
||||||
|
|
||||||
|
SetCursorPos(center.x, center.y);
|
||||||
|
MouseLocked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (msg == WM_RBUTTONUP)
|
||||||
|
{
|
||||||
|
if (MouseLocked)
|
||||||
|
{
|
||||||
|
MouseLocked = false;
|
||||||
|
SetCursorPos(LockPosition.x, LockPosition.y);
|
||||||
|
::ShowCursor(TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else*/ if (msg == WM_MOUSEMOVE)
|
||||||
|
{
|
||||||
|
if (MouseLocked && GetFocus() != 0)
|
||||||
|
{
|
||||||
|
RECT box = {};
|
||||||
|
GetClientRect(WindowHandle, &box);
|
||||||
|
|
||||||
|
POINT center = {};
|
||||||
|
center.x = box.right / 2;
|
||||||
|
center.y = box.bottom / 2;
|
||||||
|
int mousex = GET_X_LPARAM(lparam) - center.x;
|
||||||
|
int mousey = GET_Y_LPARAM(lparam) - center.y;
|
||||||
|
|
||||||
|
ClientToScreen(WindowHandle, ¢er);
|
||||||
|
SetCursorPos(center.x, center.y);
|
||||||
|
|
||||||
|
double dpiscale = GetDpiScale();
|
||||||
|
OnMouseMove(mousex / dpiscale, mousey / dpiscale);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetCursor((HCURSOR)LoadImage(0, IDC_ARROW, IMAGE_CURSOR, LR_DEFAULTSIZE, LR_DEFAULTSIZE, LR_SHARED));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (msg == WM_SETFOCUS)
|
||||||
|
{
|
||||||
|
if (MouseLocked)
|
||||||
|
{
|
||||||
|
GetCursorPos(&LockPosition);
|
||||||
|
::ShowCursor(FALSE);
|
||||||
|
|
||||||
|
RECT box = {};
|
||||||
|
GetClientRect(WindowHandle, &box);
|
||||||
|
|
||||||
|
POINT center = {};
|
||||||
|
center.x = box.right / 2;
|
||||||
|
center.y = box.bottom / 2;
|
||||||
|
ClientToScreen(WindowHandle, ¢er);
|
||||||
|
|
||||||
|
SetCursorPos(center.x, center.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (msg == WM_KILLFOCUS)
|
||||||
|
{
|
||||||
|
if (MouseLocked)
|
||||||
|
{
|
||||||
|
SetCursorPos(LockPosition.x, LockPosition.y);
|
||||||
|
::ShowCursor(TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (msg == WM_CLOSE)
|
||||||
|
{
|
||||||
|
OnClose();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if (msg == WM_KEYDOWN)
|
||||||
|
{
|
||||||
|
OnKeyDown(wparam);
|
||||||
|
}
|
||||||
|
else if (msg == WM_KEYUP)
|
||||||
|
{
|
||||||
|
OnKeyUp(wparam);
|
||||||
|
}
|
||||||
|
|
||||||
|
return DefWindowProc(WindowHandle, msg, wparam, lparam);
|
||||||
|
}
|
||||||
|
|
||||||
|
double LevelMeshViewer::GetDpiScale() const
|
||||||
|
{
|
||||||
|
return GetDpiForWindow(WindowHandle) / 96.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int LevelMeshViewer::GetPixelWidth() const
|
||||||
|
{
|
||||||
|
RECT box = {};
|
||||||
|
GetClientRect(WindowHandle, &box);
|
||||||
|
return box.right;
|
||||||
|
}
|
||||||
|
|
||||||
|
int LevelMeshViewer::GetPixelHeight() const
|
||||||
|
{
|
||||||
|
RECT box = {};
|
||||||
|
GetClientRect(WindowHandle, &box);
|
||||||
|
return box.bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
LRESULT LevelMeshViewer::WindowProc(HWND windowhandle, UINT msg, WPARAM wparam, LPARAM lparam)
|
||||||
|
{
|
||||||
|
if (msg == WM_CREATE)
|
||||||
|
{
|
||||||
|
CREATESTRUCT* createstruct = (CREATESTRUCT*)lparam;
|
||||||
|
LevelMeshViewer* viewport = (LevelMeshViewer*)createstruct->lpCreateParams;
|
||||||
|
viewport->WindowHandle = windowhandle;
|
||||||
|
SetWindowLongPtr(windowhandle, GWLP_USERDATA, (LONG_PTR)viewport);
|
||||||
|
return viewport->OnWindowMessage(msg, wparam, lparam);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LevelMeshViewer* viewport = (LevelMeshViewer*)GetWindowLongPtr(windowhandle, GWLP_USERDATA);
|
||||||
|
if (viewport)
|
||||||
|
{
|
||||||
|
LRESULT result = viewport->OnWindowMessage(msg, wparam, lparam);
|
||||||
|
if (msg == WM_DESTROY)
|
||||||
|
{
|
||||||
|
SetWindowLongPtr(windowhandle, GWLP_USERDATA, 0);
|
||||||
|
viewport->WindowHandle = 0;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return DefWindowProc(windowhandle, msg, wparam, lparam);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
67
src/lightmapper/levelmeshviewer.h
Normal file
67
src/lightmapper/levelmeshviewer.h
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "framework/vectors.h"
|
||||||
|
|
||||||
|
class VulkanRenderDevice;
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
|
||||||
|
#define WIN32_MEAN_AND_LEAN
|
||||||
|
#define NOMINMAX
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
class LevelMeshViewer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LevelMeshViewer();
|
||||||
|
~LevelMeshViewer();
|
||||||
|
|
||||||
|
void Exec(VulkanRenderDevice* renderdevice, const FVector3& sundir, const FVector3& suncolor, float sunintensity);
|
||||||
|
HWND GetWindowHandle() { return WindowHandle; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void RenderFrame();
|
||||||
|
|
||||||
|
void OnMouseMove(double dx, double dy);
|
||||||
|
void OnKeyDown(WPARAM key);
|
||||||
|
void OnKeyUp(WPARAM key);
|
||||||
|
void OnClose();
|
||||||
|
|
||||||
|
void CreateViewerWindow();
|
||||||
|
void DestroyViewerWindow();
|
||||||
|
|
||||||
|
double GetDpiScale() const;
|
||||||
|
int GetPixelWidth() const;
|
||||||
|
int GetPixelHeight() const;
|
||||||
|
|
||||||
|
LRESULT OnWindowMessage(UINT msg, WPARAM wparam, LPARAM lparam);
|
||||||
|
static LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
|
||||||
|
|
||||||
|
VulkanRenderDevice* RenderDevice = nullptr;
|
||||||
|
HWND WindowHandle = 0;
|
||||||
|
bool MouseLocked = true;
|
||||||
|
POINT LockPosition = {};
|
||||||
|
|
||||||
|
double Yaw = 0.0;
|
||||||
|
double Pitch = 0.0;
|
||||||
|
|
||||||
|
bool MoveLeft = false;
|
||||||
|
bool MoveRight = false;
|
||||||
|
bool MoveForward = false;
|
||||||
|
bool MoveBackward = false;
|
||||||
|
FVector3 CameraPos = FVector3(0.0f, 70.0f, -128.0f);
|
||||||
|
FVector3 SunDir = FVector3(0.0f, 0.0f, 0.0f);
|
||||||
|
FVector3 SunColor = FVector3(0.0f, 0.0f, 0.0f);
|
||||||
|
float SunIntensity = 0.0f;
|
||||||
|
};
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
class LevelMeshViewer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LevelMeshViewer() { }
|
||||||
|
void Exec(VulkanRenderDevice* renderdevice) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -3,8 +3,21 @@
|
||||||
#include "vk_levelmesh.h"
|
#include "vk_levelmesh.h"
|
||||||
#include "vk_lightmapper.h"
|
#include "vk_lightmapper.h"
|
||||||
#include "stacktrace.h"
|
#include "stacktrace.h"
|
||||||
|
#include "levelmeshviewer.h"
|
||||||
|
#include "framework/matrix.h"
|
||||||
|
#include "glsl/vert_viewer.glsl.h"
|
||||||
|
#include "glsl/frag_viewer.glsl.h"
|
||||||
|
#include "glsl/binding_viewer.glsl.h"
|
||||||
|
#include "glsl/polyfill_rayquery.glsl.h"
|
||||||
|
#include "glsl/montecarlo.glsl.h"
|
||||||
|
#include "glsl/trace_ambient_occlusion.glsl.h"
|
||||||
|
#include "glsl/trace_bounce.glsl.h"
|
||||||
|
#include "glsl/trace_levelmesh.glsl.h"
|
||||||
|
#include "glsl/trace_light.glsl.h"
|
||||||
|
#include "glsl/trace_sunlight.glsl.h"
|
||||||
#include <zvulkan/vulkanbuilders.h>
|
#include <zvulkan/vulkanbuilders.h>
|
||||||
#include <zvulkan/vulkancompatibledevice.h>
|
#include <zvulkan/vulkancompatibledevice.h>
|
||||||
|
#include <zvulkan/vulkanswapchain.h>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
extern bool VKDebug;
|
extern bool VKDebug;
|
||||||
|
@ -21,8 +34,34 @@ void VulkanPrintLog(const char* typestr, const std::string& msg)
|
||||||
printf(" %s\n", CaptureStackTraceText(2).c_str());
|
printf(" %s\n", CaptureStackTraceText(2).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
VulkanRenderDevice::VulkanRenderDevice()
|
VulkanRenderDevice::VulkanRenderDevice(LevelMeshViewer* viewer)
|
||||||
{
|
{
|
||||||
|
if (viewer)
|
||||||
|
{
|
||||||
|
#ifdef WIN32
|
||||||
|
auto instance = VulkanInstanceBuilder()
|
||||||
|
.RequireSurfaceExtensions()
|
||||||
|
.DebugLayer(VKDebug)
|
||||||
|
.Create();
|
||||||
|
|
||||||
|
auto surface = VulkanSurfaceBuilder()
|
||||||
|
.Win32Window(viewer->GetWindowHandle())
|
||||||
|
.Create(instance);
|
||||||
|
|
||||||
|
device = VulkanDeviceBuilder()
|
||||||
|
.Surface(surface)
|
||||||
|
.OptionalRayQuery()
|
||||||
|
.RequireExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME)
|
||||||
|
.Create(instance);
|
||||||
|
|
||||||
|
swapchain = VulkanSwapChainBuilder()
|
||||||
|
.Create(device.get());
|
||||||
|
#else
|
||||||
|
VulkanError("No viewer supported on this platform");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
auto instance = VulkanInstanceBuilder()
|
auto instance = VulkanInstanceBuilder()
|
||||||
.DebugLayer(VKDebug)
|
.DebugLayer(VKDebug)
|
||||||
.Create();
|
.Create();
|
||||||
|
@ -31,6 +70,7 @@ VulkanRenderDevice::VulkanRenderDevice()
|
||||||
.OptionalRayQuery()
|
.OptionalRayQuery()
|
||||||
.RequireExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME)
|
.RequireExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME)
|
||||||
.Create(instance);
|
.Create(instance);
|
||||||
|
}
|
||||||
|
|
||||||
useRayQuery = !NoRtx && device->PhysicalDevice.Features.RayQuery.rayQuery;
|
useRayQuery = !NoRtx && device->PhysicalDevice.Features.RayQuery.rayQuery;
|
||||||
|
|
||||||
|
@ -44,6 +84,8 @@ VulkanRenderDevice::VulkanRenderDevice()
|
||||||
descriptors->AddBindlessTextureIndex(GetTextureManager()->GetNullTextureView(), GetSamplerManager()->Get());
|
descriptors->AddBindlessTextureIndex(GetTextureManager()->GetNullTextureView(), GetSamplerManager()->Get());
|
||||||
descriptors->AddBindlessTextureIndex(GetTextureManager()->GetNullTextureView(), GetSamplerManager()->Get());
|
descriptors->AddBindlessTextureIndex(GetTextureManager()->GetNullTextureView(), GetSamplerManager()->Get());
|
||||||
descriptors->UpdateBindlessDescriptorSet();
|
descriptors->UpdateBindlessDescriptorSet();
|
||||||
|
|
||||||
|
CreateViewerObjects();
|
||||||
}
|
}
|
||||||
|
|
||||||
VulkanRenderDevice::~VulkanRenderDevice()
|
VulkanRenderDevice::~VulkanRenderDevice()
|
||||||
|
@ -51,6 +93,238 @@ VulkanRenderDevice::~VulkanRenderDevice()
|
||||||
vkDeviceWaitIdle(device->device);
|
vkDeviceWaitIdle(device->device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VulkanRenderDevice::DrawViewer(const FVector3& cameraPos, const VSMatrix& viewToWorld, float fovy, float aspect, const FVector3& sundir, const FVector3& suncolor, float sunintensity)
|
||||||
|
{
|
||||||
|
int imageIndex = GetCommands()->AcquireImage();
|
||||||
|
if (imageIndex < 0)
|
||||||
|
{
|
||||||
|
Sleep(500);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteDescriptors write;
|
||||||
|
write.AddBuffer(Viewer.DescriptorSet.get(), 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, GetLevelMesh()->GetSurfaceIndexBuffer());
|
||||||
|
write.AddBuffer(Viewer.DescriptorSet.get(), 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, GetLevelMesh()->GetSurfaceBuffer());
|
||||||
|
write.AddBuffer(Viewer.DescriptorSet.get(), 2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, GetLevelMesh()->GetLightBuffer());
|
||||||
|
write.AddBuffer(Viewer.DescriptorSet.get(), 3, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, GetLevelMesh()->GetLightIndexBuffer());
|
||||||
|
write.AddBuffer(Viewer.DescriptorSet.get(), 4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, GetLevelMesh()->GetPortalBuffer());
|
||||||
|
if (useRayQuery)
|
||||||
|
{
|
||||||
|
write.AddAccelerationStructure(Viewer.DescriptorSet.get(), 5, GetLevelMesh()->GetAccelStruct());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
write.AddBuffer(Viewer.DescriptorSet.get(), 5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, GetLevelMesh()->GetNodeBuffer());
|
||||||
|
}
|
||||||
|
write.AddBuffer(Viewer.DescriptorSet.get(), 6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, GetLevelMesh()->GetVertexBuffer());
|
||||||
|
write.AddBuffer(Viewer.DescriptorSet.get(), 7, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, GetLevelMesh()->GetIndexBuffer());
|
||||||
|
write.Execute(device.get());
|
||||||
|
|
||||||
|
auto commands = GetCommands()->GetDrawCommands();
|
||||||
|
|
||||||
|
RenderPassBegin()
|
||||||
|
.RenderPass(Viewer.RenderPass.get())
|
||||||
|
.Framebuffer(Framebuffers[imageIndex].get())
|
||||||
|
.RenderArea(0, 0, CurrentWidth, CurrentHeight)
|
||||||
|
.AddClearColor(0.0f, 0.0f, 0.0f, 1.0f)
|
||||||
|
.AddClearDepth(1.0f)
|
||||||
|
.Execute(commands);
|
||||||
|
|
||||||
|
VkViewport viewport = {};
|
||||||
|
viewport.width = (float)CurrentWidth;
|
||||||
|
viewport.height = (float)CurrentHeight;
|
||||||
|
viewport.maxDepth = 1.0f;
|
||||||
|
commands->setViewport(0, 1, &viewport);
|
||||||
|
|
||||||
|
VkRect2D scissor = {};
|
||||||
|
scissor.extent.width = CurrentWidth;
|
||||||
|
scissor.extent.height = CurrentHeight;
|
||||||
|
commands->setScissor(0, 1, &scissor);
|
||||||
|
|
||||||
|
float f = 1.0f / std::tan(fovy * (pi::pif() / 360.0f));
|
||||||
|
|
||||||
|
ViewerPushConstants pushconstants;
|
||||||
|
pushconstants.ViewToWorld = viewToWorld;
|
||||||
|
pushconstants.CameraPos = cameraPos;
|
||||||
|
pushconstants.ProjX = f / aspect;
|
||||||
|
pushconstants.ProjY = f;
|
||||||
|
pushconstants.SunDir = sundir;
|
||||||
|
pushconstants.SunColor = suncolor;
|
||||||
|
pushconstants.SunIntensity = sunintensity;
|
||||||
|
|
||||||
|
commands->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, Viewer.PipelineLayout.get(), 0, Viewer.DescriptorSet.get());
|
||||||
|
commands->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, Viewer.PipelineLayout.get(), 1, descriptors->GetBindlessSet());
|
||||||
|
commands->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, Viewer.Pipeline.get());
|
||||||
|
commands->pushConstants(Viewer.PipelineLayout.get(), VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(ViewerPushConstants), &pushconstants);
|
||||||
|
commands->draw(4, 1, 0, 0);
|
||||||
|
commands->endRenderPass();
|
||||||
|
|
||||||
|
GetCommands()->SubmitAndWait(imageIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
static FString LoadPrivateShaderLump(const char* lumpname)
|
||||||
|
{
|
||||||
|
static std::map<FString, FString> sources =
|
||||||
|
{
|
||||||
|
{ "shaders/lightmap/binding_viewer.glsl", binding_viewer_glsl },
|
||||||
|
{ "shaders/lightmap/montecarlo.glsl", montecarlo_glsl },
|
||||||
|
{ "shaders/lightmap/polyfill_rayquery.glsl", polyfill_rayquery_glsl },
|
||||||
|
{ "shaders/lightmap/trace_ambient_occlusion.glsl", trace_ambient_occlusion_glsl },
|
||||||
|
{ "shaders/lightmap/trace_bounce.glsl", trace_bounce_glsl },
|
||||||
|
{ "shaders/lightmap/trace_levelmesh.glsl", trace_levelmesh_glsl },
|
||||||
|
{ "shaders/lightmap/trace_light.glsl", trace_light_glsl },
|
||||||
|
{ "shaders/lightmap/trace_sunlight.glsl", trace_sunlight_glsl },
|
||||||
|
};
|
||||||
|
|
||||||
|
auto it = sources.find(lumpname);
|
||||||
|
if (it != sources.end())
|
||||||
|
return it->second;
|
||||||
|
else
|
||||||
|
return FString();
|
||||||
|
}
|
||||||
|
|
||||||
|
static FString LoadPublicShaderLump(const char* lumpname)
|
||||||
|
{
|
||||||
|
return LoadPrivateShaderLump(lumpname);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ShaderIncludeResult OnInclude(FString headerName, FString includerName, size_t depth, bool system)
|
||||||
|
{
|
||||||
|
if (depth > 8)
|
||||||
|
{
|
||||||
|
return ShaderIncludeResult("Too much include recursion!");
|
||||||
|
}
|
||||||
|
|
||||||
|
FString includeguardname;
|
||||||
|
includeguardname << "_HEADERGUARD_" << headerName.GetChars();
|
||||||
|
includeguardname.ReplaceChars("/\\.", '_');
|
||||||
|
|
||||||
|
FString code;
|
||||||
|
code << "#ifndef " << includeguardname.GetChars() << "\n";
|
||||||
|
code << "#define " << includeguardname.GetChars() << "\n";
|
||||||
|
code << "#line 1\n";
|
||||||
|
|
||||||
|
if (system)
|
||||||
|
code << LoadPrivateShaderLump(headerName.GetChars()).GetChars() << "\n";
|
||||||
|
else
|
||||||
|
code << LoadPublicShaderLump(headerName.GetChars()).GetChars() << "\n";
|
||||||
|
|
||||||
|
code << "#endif\n";
|
||||||
|
|
||||||
|
return ShaderIncludeResult(headerName.GetChars(), code.GetChars());
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanRenderDevice::CreateViewerObjects()
|
||||||
|
{
|
||||||
|
DescriptorSetLayoutBuilder builder;
|
||||||
|
builder.AddBinding(0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
|
builder.AddBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
|
builder.AddBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
|
builder.AddBinding(3, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
|
builder.AddBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
|
if (useRayQuery)
|
||||||
|
{
|
||||||
|
builder.AddBinding(5, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
builder.AddBinding(5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
|
}
|
||||||
|
builder.AddBinding(6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
|
builder.AddBinding(7, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
|
builder.DebugName("Viewer.DescriptorSetLayout");
|
||||||
|
Viewer.DescriptorSetLayout = builder.Create(device.get());
|
||||||
|
|
||||||
|
Viewer.DescriptorPool = DescriptorPoolBuilder()
|
||||||
|
.AddPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1)
|
||||||
|
.AddPoolSize(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 6)
|
||||||
|
.MaxSets(1)
|
||||||
|
.DebugName("Viewer.DescriptorPool")
|
||||||
|
.Create(device.get());
|
||||||
|
|
||||||
|
Viewer.DescriptorSet = Viewer.DescriptorPool->allocate(Viewer.DescriptorSetLayout.get());
|
||||||
|
Viewer.DescriptorSet->SetDebugName("raytrace.descriptorSet1");
|
||||||
|
|
||||||
|
std::string versionBlock = R"(
|
||||||
|
#version 460
|
||||||
|
#extension GL_GOOGLE_include_directive : enable
|
||||||
|
#extension GL_EXT_nonuniform_qualifier : enable
|
||||||
|
)";
|
||||||
|
|
||||||
|
if (useRayQuery)
|
||||||
|
{
|
||||||
|
versionBlock += "#extension GL_EXT_ray_query : require\r\n";
|
||||||
|
versionBlock += "#define USE_RAYQUERY\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
auto onIncludeLocal = [](std::string headerName, std::string includerName, size_t depth) { return OnInclude(headerName.c_str(), includerName.c_str(), depth, false); };
|
||||||
|
auto onIncludeSystem = [](std::string headerName, std::string includerName, size_t depth) { return OnInclude(headerName.c_str(), includerName.c_str(), depth, true); };
|
||||||
|
|
||||||
|
Viewer.VertexShader = ShaderBuilder()
|
||||||
|
.Type(ShaderType::Vertex)
|
||||||
|
.AddSource("versionblock", versionBlock)
|
||||||
|
.AddSource("vert_viewer.glsl", vert_viewer_glsl)
|
||||||
|
.OnIncludeLocal(onIncludeLocal)
|
||||||
|
.OnIncludeSystem(onIncludeSystem)
|
||||||
|
.DebugName("Viewer.VertexShader")
|
||||||
|
.Create("vertex", device.get());
|
||||||
|
|
||||||
|
Viewer.FragmentShader = ShaderBuilder()
|
||||||
|
.Type(ShaderType::Fragment)
|
||||||
|
.AddSource("versionblock", versionBlock)
|
||||||
|
.AddSource("frag_viewer.glsl", frag_viewer_glsl)
|
||||||
|
.OnIncludeLocal(onIncludeLocal)
|
||||||
|
.OnIncludeSystem(onIncludeSystem)
|
||||||
|
.DebugName("Viewer.FragmentShader")
|
||||||
|
.Create("vertex", device.get());
|
||||||
|
|
||||||
|
Viewer.PipelineLayout = PipelineLayoutBuilder()
|
||||||
|
.AddSetLayout(Viewer.DescriptorSetLayout.get())
|
||||||
|
.AddSetLayout(descriptors->GetBindlessLayout())
|
||||||
|
.AddPushConstantRange(VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(ViewerPushConstants))
|
||||||
|
.DebugName("Viewer.PipelineLayout")
|
||||||
|
.Create(device.get());
|
||||||
|
|
||||||
|
Viewer.RenderPass = RenderPassBuilder()
|
||||||
|
.AddAttachment(VK_FORMAT_B8G8R8A8_UNORM, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR)
|
||||||
|
.AddSubpass()
|
||||||
|
.AddSubpassColorAttachmentRef(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)
|
||||||
|
.Create(device.get());
|
||||||
|
|
||||||
|
Viewer.Pipeline = GraphicsPipelineBuilder()
|
||||||
|
.RenderPass(Viewer.RenderPass.get())
|
||||||
|
.Layout(Viewer.PipelineLayout.get())
|
||||||
|
.Topology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP)
|
||||||
|
.AddVertexShader(Viewer.VertexShader.get())
|
||||||
|
.AddFragmentShader(Viewer.FragmentShader.get())
|
||||||
|
.AddDynamicState(VK_DYNAMIC_STATE_VIEWPORT)
|
||||||
|
.AddDynamicState(VK_DYNAMIC_STATE_SCISSOR)
|
||||||
|
.DebugName("Viewer.Pipeline")
|
||||||
|
.Create(device.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanRenderDevice::ResizeSwapChain(int width, int height)
|
||||||
|
{
|
||||||
|
if (width <= 0 || height <= 0 || (width == CurrentWidth && height == CurrentHeight && swapchain->Lost()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
CurrentWidth = width;
|
||||||
|
CurrentHeight = height;
|
||||||
|
Framebuffers.clear();
|
||||||
|
|
||||||
|
swapchain->Create(width, height, 1, true, false, false);
|
||||||
|
|
||||||
|
for (int imageIndex = 0; imageIndex < swapchain->ImageCount(); imageIndex++)
|
||||||
|
{
|
||||||
|
Framebuffers.push_back(FramebufferBuilder()
|
||||||
|
.RenderPass(Viewer.RenderPass.get())
|
||||||
|
.AddAttachment(swapchain->GetImageView(imageIndex))
|
||||||
|
.Size(width, height)
|
||||||
|
.DebugName("framebuffer")
|
||||||
|
.Create(GetDevice()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
VkCommandBufferManager::VkCommandBufferManager(VulkanRenderDevice* fb) : fb(fb)
|
VkCommandBufferManager::VkCommandBufferManager(VulkanRenderDevice* fb) : fb(fb)
|
||||||
|
@ -59,9 +333,26 @@ VkCommandBufferManager::VkCommandBufferManager(VulkanRenderDevice* fb) : fb(fb)
|
||||||
.QueueFamily(fb->GetDevice()->GraphicsFamily)
|
.QueueFamily(fb->GetDevice()->GraphicsFamily)
|
||||||
.DebugName("mCommandPool")
|
.DebugName("mCommandPool")
|
||||||
.Create(fb->GetDevice());
|
.Create(fb->GetDevice());
|
||||||
|
|
||||||
|
mImageAvailableSemaphore = SemaphoreBuilder()
|
||||||
|
.DebugName("mImageAvailableSemaphore")
|
||||||
|
.Create(fb->GetDevice());
|
||||||
|
|
||||||
|
mRenderFinishedSemaphore = SemaphoreBuilder()
|
||||||
|
.DebugName("mRenderFinishedSemaphore")
|
||||||
|
.Create(fb->GetDevice());
|
||||||
|
|
||||||
|
mPresentFinishedFence = FenceBuilder()
|
||||||
|
.DebugName("mPresentFinishedFence")
|
||||||
|
.Create(fb->GetDevice());
|
||||||
}
|
}
|
||||||
|
|
||||||
void VkCommandBufferManager::SubmitAndWait()
|
int VkCommandBufferManager::AcquireImage()
|
||||||
|
{
|
||||||
|
return fb->GetSwapChain()->AcquireImage(mImageAvailableSemaphore.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void VkCommandBufferManager::SubmitAndWait(int imageIndex)
|
||||||
{
|
{
|
||||||
if (mTransferCommands)
|
if (mTransferCommands)
|
||||||
{
|
{
|
||||||
|
@ -76,6 +367,24 @@ void VkCommandBufferManager::SubmitAndWait()
|
||||||
vkDeviceWaitIdle(fb->GetDevice()->device);
|
vkDeviceWaitIdle(fb->GetDevice()->device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (imageIndex >= 0 && mDrawCommands)
|
||||||
|
{
|
||||||
|
mDrawCommands->end();
|
||||||
|
|
||||||
|
QueueSubmit()
|
||||||
|
.AddCommandBuffer(mDrawCommands.get())
|
||||||
|
.AddWait(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, mImageAvailableSemaphore.get())
|
||||||
|
.AddSignal(mRenderFinishedSemaphore.get())
|
||||||
|
.Execute(fb->GetDevice(), fb->GetDevice()->GraphicsQueue, mPresentFinishedFence.get());
|
||||||
|
|
||||||
|
DrawDeleteList->Add(std::move(mDrawCommands));
|
||||||
|
|
||||||
|
fb->GetSwapChain()->QueuePresent(imageIndex, mRenderFinishedSemaphore.get());
|
||||||
|
|
||||||
|
vkWaitForFences(fb->GetDevice()->device, 1, &mPresentFinishedFence->fence, VK_TRUE, std::numeric_limits<uint64_t>::max());
|
||||||
|
vkResetFences(fb->GetDevice()->device, 1, &mPresentFinishedFence->fence);
|
||||||
|
}
|
||||||
|
|
||||||
TransferDeleteList = std::make_unique<DeleteList>();
|
TransferDeleteList = std::make_unique<DeleteList>();
|
||||||
DrawDeleteList = std::make_unique<DeleteList>();
|
DrawDeleteList = std::make_unique<DeleteList>();
|
||||||
}
|
}
|
||||||
|
@ -90,6 +399,16 @@ VulkanCommandBuffer* VkCommandBufferManager::GetTransferCommands()
|
||||||
return mTransferCommands.get();
|
return mTransferCommands.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VulkanCommandBuffer* VkCommandBufferManager::GetDrawCommands()
|
||||||
|
{
|
||||||
|
if (!mDrawCommands)
|
||||||
|
{
|
||||||
|
mDrawCommands = mCommandPool->createBuffer();
|
||||||
|
mDrawCommands->begin();
|
||||||
|
}
|
||||||
|
return mDrawCommands.get();
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
VkTextureManager::VkTextureManager(VulkanRenderDevice* fb) : fb(fb)
|
VkTextureManager::VkTextureManager(VulkanRenderDevice* fb) : fb(fb)
|
||||||
|
@ -102,7 +421,7 @@ void VkTextureManager::CreateNullTexture()
|
||||||
NullTexture = ImageBuilder()
|
NullTexture = ImageBuilder()
|
||||||
.Format(VK_FORMAT_R8G8B8A8_UNORM)
|
.Format(VK_FORMAT_R8G8B8A8_UNORM)
|
||||||
.Size(1, 1)
|
.Size(1, 1)
|
||||||
.Usage(VK_IMAGE_USAGE_SAMPLED_BIT)
|
.Usage(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT)
|
||||||
.DebugName("VkTextureManager.NullTexture")
|
.DebugName("VkTextureManager.NullTexture")
|
||||||
.Create(fb->GetDevice());
|
.Create(fb->GetDevice());
|
||||||
|
|
||||||
|
@ -124,7 +443,7 @@ void VkTextureManager::CreateNullTexture()
|
||||||
|
|
||||||
PipelineBarrier()
|
PipelineBarrier()
|
||||||
.AddImage(NullTexture.get(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_ASPECT_COLOR_BIT)
|
.AddImage(NullTexture.get(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_ASPECT_COLOR_BIT)
|
||||||
.Execute(fb->GetCommands()->GetTransferCommands(), VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
|
.Execute(fb->GetCommands()->GetTransferCommands(), VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
|
||||||
|
|
||||||
VkBufferImageCopy region = {};
|
VkBufferImageCopy region = {};
|
||||||
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
|
@ -138,7 +457,7 @@ void VkTextureManager::CreateNullTexture()
|
||||||
|
|
||||||
PipelineBarrier()
|
PipelineBarrier()
|
||||||
.AddImage(NullTexture.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_ASPECT_COLOR_BIT)
|
.AddImage(NullTexture.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_ASPECT_COLOR_BIT)
|
||||||
.Execute(fb->GetCommands()->GetTransferCommands(), VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
|
.Execute(fb->GetCommands()->GetTransferCommands(), VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VkTextureManager::CreateLightmap(int newLMTextureSize, int newLMTextureCount)
|
void VkTextureManager::CreateLightmap(int newLMTextureSize, int newLMTextureCount)
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "framework/textureid.h"
|
#include "framework/textureid.h"
|
||||||
#include "zvulkan/vulkanobjects.h"
|
#include "zvulkan/vulkanobjects.h"
|
||||||
#include "zvulkan/vulkanbuilders.h"
|
#include "zvulkan/vulkanbuilders.h"
|
||||||
|
#include "framework/matrix.h"
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
class VkLevelMesh;
|
class VkLevelMesh;
|
||||||
|
@ -12,14 +13,18 @@ class VkCommandBufferManager;
|
||||||
class VkDescriptorSetManager;
|
class VkDescriptorSetManager;
|
||||||
class VkTextureManager;
|
class VkTextureManager;
|
||||||
class VkSamplerManager;
|
class VkSamplerManager;
|
||||||
|
class VulkanSwapChain;
|
||||||
|
class LevelMeshViewer;
|
||||||
|
class VSMatrix;
|
||||||
|
|
||||||
class VulkanRenderDevice
|
class VulkanRenderDevice
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
VulkanRenderDevice();
|
VulkanRenderDevice(LevelMeshViewer* viewer);
|
||||||
~VulkanRenderDevice();
|
~VulkanRenderDevice();
|
||||||
|
|
||||||
VulkanDevice* GetDevice() { return device.get(); }
|
VulkanDevice* GetDevice() { return device.get(); }
|
||||||
|
VulkanSwapChain* GetSwapChain() { return swapchain.get(); }
|
||||||
VkCommandBufferManager* GetCommands() { return commands.get(); }
|
VkCommandBufferManager* GetCommands() { return commands.get(); }
|
||||||
VkDescriptorSetManager* GetDescriptorSetManager() { return descriptors.get(); }
|
VkDescriptorSetManager* GetDescriptorSetManager() { return descriptors.get(); }
|
||||||
VkTextureManager* GetTextureManager() { return textures.get(); }
|
VkTextureManager* GetTextureManager() { return textures.get(); }
|
||||||
|
@ -31,16 +36,38 @@ public:
|
||||||
|
|
||||||
bool IsRayQueryEnabled() const { return useRayQuery; }
|
bool IsRayQueryEnabled() const { return useRayQuery; }
|
||||||
|
|
||||||
|
void ResizeSwapChain(int width, int height);
|
||||||
|
void DrawViewer(const FVector3& cameraPos, const VSMatrix& viewToWorld, float fovy, float aspect, const FVector3& sundir, const FVector3& suncolor, float sunintensity);
|
||||||
|
|
||||||
bool useRayQuery = false;
|
bool useRayQuery = false;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void CreateViewerObjects();
|
||||||
|
|
||||||
std::shared_ptr<VulkanDevice> device;
|
std::shared_ptr<VulkanDevice> device;
|
||||||
|
std::shared_ptr<VulkanSwapChain> swapchain;
|
||||||
std::unique_ptr<VkCommandBufferManager> commands;
|
std::unique_ptr<VkCommandBufferManager> commands;
|
||||||
std::unique_ptr<VkDescriptorSetManager> descriptors;
|
std::unique_ptr<VkDescriptorSetManager> descriptors;
|
||||||
std::unique_ptr<VkTextureManager> textures;
|
std::unique_ptr<VkTextureManager> textures;
|
||||||
std::unique_ptr<VkSamplerManager> samplers;
|
std::unique_ptr<VkSamplerManager> samplers;
|
||||||
std::unique_ptr<VkLevelMesh> levelmesh;
|
std::unique_ptr<VkLevelMesh> levelmesh;
|
||||||
std::unique_ptr<VkLightmapper> lightmapper;
|
std::unique_ptr<VkLightmapper> lightmapper;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
std::unique_ptr<VulkanDescriptorSetLayout> DescriptorSetLayout;
|
||||||
|
std::unique_ptr<VulkanDescriptorPool> DescriptorPool;
|
||||||
|
std::unique_ptr<VulkanDescriptorSet> DescriptorSet;
|
||||||
|
std::unique_ptr<VulkanShader> VertexShader;
|
||||||
|
std::unique_ptr<VulkanShader> FragmentShader;
|
||||||
|
std::unique_ptr<VulkanRenderPass> RenderPass;
|
||||||
|
std::unique_ptr<VulkanPipelineLayout> PipelineLayout;
|
||||||
|
std::unique_ptr<VulkanPipeline> Pipeline;
|
||||||
|
} Viewer;
|
||||||
|
|
||||||
|
int CurrentWidth = 0;
|
||||||
|
int CurrentHeight = 0;
|
||||||
|
std::vector<std::unique_ptr<VulkanFramebuffer>> Framebuffers;
|
||||||
};
|
};
|
||||||
|
|
||||||
class VkCommandBufferManager
|
class VkCommandBufferManager
|
||||||
|
@ -48,13 +75,16 @@ class VkCommandBufferManager
|
||||||
public:
|
public:
|
||||||
VkCommandBufferManager(VulkanRenderDevice* fb);
|
VkCommandBufferManager(VulkanRenderDevice* fb);
|
||||||
|
|
||||||
void SubmitAndWait();
|
void SubmitAndWait(int imageIndex = -1);
|
||||||
|
|
||||||
VulkanCommandBuffer* GetTransferCommands();
|
VulkanCommandBuffer* GetTransferCommands();
|
||||||
|
VulkanCommandBuffer* GetDrawCommands();
|
||||||
|
|
||||||
void PushGroup(VulkanCommandBuffer* cmdbuffer, const FString& name) { }
|
void PushGroup(VulkanCommandBuffer* cmdbuffer, const FString& name) { }
|
||||||
void PopGroup(VulkanCommandBuffer* cmdbuffer) { }
|
void PopGroup(VulkanCommandBuffer* cmdbuffer) { }
|
||||||
|
|
||||||
|
int AcquireImage();
|
||||||
|
|
||||||
class DeleteList
|
class DeleteList
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -90,6 +120,20 @@ private:
|
||||||
std::unique_ptr<VulkanCommandPool> mCommandPool;
|
std::unique_ptr<VulkanCommandPool> mCommandPool;
|
||||||
std::unique_ptr<VulkanCommandBuffer> mTransferCommands;
|
std::unique_ptr<VulkanCommandBuffer> mTransferCommands;
|
||||||
std::unique_ptr<VulkanCommandBuffer> mDrawCommands;
|
std::unique_ptr<VulkanCommandBuffer> mDrawCommands;
|
||||||
|
std::unique_ptr<VulkanSemaphore> mImageAvailableSemaphore;
|
||||||
|
std::unique_ptr<VulkanSemaphore> mRenderFinishedSemaphore;
|
||||||
|
std::unique_ptr<VulkanFence> mPresentFinishedFence;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ViewerPushConstants
|
||||||
|
{
|
||||||
|
VSMatrix ViewToWorld;
|
||||||
|
FVector3 CameraPos;
|
||||||
|
float ProjX;
|
||||||
|
FVector3 SunDir;
|
||||||
|
float ProjY;
|
||||||
|
FVector3 SunColor;
|
||||||
|
float SunIntensity;
|
||||||
};
|
};
|
||||||
|
|
||||||
class VkTextureImage
|
class VkTextureImage
|
||||||
|
|
|
@ -118,6 +118,7 @@ int LMDims = 1024;
|
||||||
bool VKDebug = false;
|
bool VKDebug = false;
|
||||||
bool DumpMesh = false;
|
bool DumpMesh = false;
|
||||||
bool NoRtx = false;
|
bool NoRtx = false;
|
||||||
|
bool showviewer = false;
|
||||||
|
|
||||||
int ambientSampleCount = 2048;
|
int ambientSampleCount = 2048;
|
||||||
|
|
||||||
|
@ -160,10 +161,11 @@ static option long_opts[] =
|
||||||
{"dump-mesh", no_argument, 0, 1004},
|
{"dump-mesh", no_argument, 0, 1004},
|
||||||
{"preview", no_argument, 0, 1005},
|
{"preview", no_argument, 0, 1005},
|
||||||
{"no-rtx", no_argument, 0, 1006},
|
{"no-rtx", no_argument, 0, 1006},
|
||||||
|
{"viewer", no_argument, 0, 1007},
|
||||||
{0,0,0,0}
|
{0,0,0,0}
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char short_opts[] = "wVgGvbNrReEm:o:f:p:s:d:PqtzZXx5cj:S:D:::";
|
static const char short_opts[] = "wVgGvbNrReEm:o:f:p:s:d:PqtzZXx5cj:S:D::::";
|
||||||
|
|
||||||
// CODE --------------------------------------------------------------------
|
// CODE --------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -480,6 +482,9 @@ static void ParseArgs(int argc, char **argv)
|
||||||
case 1006:
|
case 1006:
|
||||||
NoRtx = true;
|
NoRtx = true;
|
||||||
break;
|
break;
|
||||||
|
case 1007:
|
||||||
|
showviewer = true;
|
||||||
|
break;
|
||||||
case 1000:
|
case 1000:
|
||||||
ShowUsage();
|
ShowUsage();
|
||||||
exit(0);
|
exit(0);
|
||||||
|
|
Loading…
Reference in a new issue