188 lines
6.4 KiB
C++
188 lines
6.4 KiB
C++
|
|
#include "WickedEngine.h"
|
||
|
|
#include "voxel/VoxelRenderer.h"
|
||
|
|
#include <fstream>
|
||
|
|
#include <DbgHelp.h>
|
||
|
|
#pragma comment(lib, "dbghelp.lib")
|
||
|
|
|
||
|
|
// ── BVLE Voxels - Prototype Application ─────────────────────────
|
||
|
|
// Wicked Engine based voxel engine prototype for performance validation.
|
||
|
|
|
||
|
|
// ── Crash handler: writes stack trace + minidump on unhandled exception ──
|
||
|
|
static LONG WINAPI CrashHandler(EXCEPTION_POINTERS* ep) {
|
||
|
|
std::ofstream crash("bvle_crash.log", std::ios::trunc);
|
||
|
|
crash << "=== BVLE CRASH REPORT ===" << std::endl;
|
||
|
|
|
||
|
|
DWORD code = ep->ExceptionRecord->ExceptionCode;
|
||
|
|
PVOID addr = ep->ExceptionRecord->ExceptionAddress;
|
||
|
|
crash << "Exception code: 0x" << std::hex << code << std::endl;
|
||
|
|
crash << "Crash address: 0x" << addr << std::endl;
|
||
|
|
|
||
|
|
if (code == EXCEPTION_ACCESS_VIOLATION && ep->ExceptionRecord->NumberParameters >= 2) {
|
||
|
|
ULONG_PTR type = ep->ExceptionRecord->ExceptionInformation[0];
|
||
|
|
ULONG_PTR target = ep->ExceptionRecord->ExceptionInformation[1];
|
||
|
|
crash << (type == 0 ? "Reading" : "Writing") << " address: 0x" << std::hex << target << std::endl;
|
||
|
|
}
|
||
|
|
|
||
|
|
HANDLE process = GetCurrentProcess();
|
||
|
|
HANDLE thread = GetCurrentThread();
|
||
|
|
SymInitialize(process, NULL, TRUE);
|
||
|
|
|
||
|
|
CONTEXT* ctx = ep->ContextRecord;
|
||
|
|
STACKFRAME64 frame = {};
|
||
|
|
frame.AddrPC.Offset = ctx->Rip; frame.AddrPC.Mode = AddrModeFlat;
|
||
|
|
frame.AddrFrame.Offset = ctx->Rbp; frame.AddrFrame.Mode = AddrModeFlat;
|
||
|
|
frame.AddrStack.Offset = ctx->Rsp; frame.AddrStack.Mode = AddrModeFlat;
|
||
|
|
|
||
|
|
crash << "\nStack trace:" << std::endl;
|
||
|
|
for (int i = 0; i < 32; i++) {
|
||
|
|
if (!StackWalk64(IMAGE_FILE_MACHINE_AMD64, process, thread, &frame,
|
||
|
|
ctx, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL))
|
||
|
|
break;
|
||
|
|
char symbolBuf[sizeof(SYMBOL_INFO) + 256];
|
||
|
|
SYMBOL_INFO* symbol = (SYMBOL_INFO*)symbolBuf;
|
||
|
|
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||
|
|
symbol->MaxNameLen = 255;
|
||
|
|
DWORD64 disp64 = 0;
|
||
|
|
crash << " [" << i << "] 0x" << std::hex << frame.AddrPC.Offset;
|
||
|
|
if (SymFromAddr(process, frame.AddrPC.Offset, &disp64, symbol))
|
||
|
|
crash << " " << symbol->Name << " +0x" << disp64;
|
||
|
|
IMAGEHLP_LINE64 line = {}; line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
|
||
|
|
DWORD disp32 = 0;
|
||
|
|
if (SymGetLineFromAddr64(process, frame.AddrPC.Offset, &disp32, &line))
|
||
|
|
crash << " (" << line.FileName << ":" << std::dec << line.LineNumber << ")";
|
||
|
|
crash << std::endl;
|
||
|
|
}
|
||
|
|
|
||
|
|
HANDLE dumpFile = CreateFileA("bvle_crash.dmp", GENERIC_WRITE, 0, NULL,
|
||
|
|
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||
|
|
if (dumpFile != INVALID_HANDLE_VALUE) {
|
||
|
|
MINIDUMP_EXCEPTION_INFORMATION mei;
|
||
|
|
mei.ThreadId = GetCurrentThreadId();
|
||
|
|
mei.ExceptionPointers = ep;
|
||
|
|
mei.ClientPointers = FALSE;
|
||
|
|
MiniDumpWriteDump(process, GetCurrentProcessId(), dumpFile,
|
||
|
|
MiniDumpWithDataSegs, &mei, NULL, NULL);
|
||
|
|
CloseHandle(dumpFile);
|
||
|
|
}
|
||
|
|
|
||
|
|
crash.close();
|
||
|
|
SymCleanup(process);
|
||
|
|
return EXCEPTION_EXECUTE_HANDLER;
|
||
|
|
}
|
||
|
|
|
||
|
|
static wi::Application application;
|
||
|
|
static voxel::VoxelRenderPath renderPath;
|
||
|
|
|
||
|
|
int APIENTRY wWinMain(
|
||
|
|
_In_ HINSTANCE hInstance,
|
||
|
|
_In_opt_ HINSTANCE hPrevInstance,
|
||
|
|
_In_ LPWSTR lpCmdLine,
|
||
|
|
_In_ int nCmdShow)
|
||
|
|
{
|
||
|
|
SetUnhandledExceptionFilter(CrashHandler);
|
||
|
|
|
||
|
|
// Win32 window setup
|
||
|
|
static auto WndProc = [](HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) -> LRESULT
|
||
|
|
{
|
||
|
|
switch (message)
|
||
|
|
{
|
||
|
|
case WM_SIZE:
|
||
|
|
case WM_DPICHANGED:
|
||
|
|
if (application.is_window_active)
|
||
|
|
application.SetWindow(hWnd);
|
||
|
|
break;
|
||
|
|
case WM_CHAR:
|
||
|
|
switch (wParam)
|
||
|
|
{
|
||
|
|
case VK_BACK:
|
||
|
|
wi::gui::TextInputField::DeleteFromInput();
|
||
|
|
break;
|
||
|
|
case VK_RETURN:
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
wi::gui::TextInputField::AddInput((const wchar_t)wParam);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
case WM_INPUT:
|
||
|
|
wi::input::rawinput::ParseMessage((void*)lParam);
|
||
|
|
break;
|
||
|
|
case WM_KILLFOCUS:
|
||
|
|
application.is_window_active = false;
|
||
|
|
break;
|
||
|
|
case WM_SETFOCUS:
|
||
|
|
application.is_window_active = true;
|
||
|
|
break;
|
||
|
|
case WM_DESTROY:
|
||
|
|
PostQuitMessage(0);
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
return DefWindowProc(hWnd, message, wParam, lParam);
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
};
|
||
|
|
|
||
|
|
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
|
||
|
|
|
||
|
|
WNDCLASSEXW wcex = {};
|
||
|
|
wcex.cbSize = sizeof(WNDCLASSEX);
|
||
|
|
wcex.style = CS_HREDRAW | CS_VREDRAW;
|
||
|
|
wcex.lpfnWndProc = WndProc;
|
||
|
|
wcex.hInstance = hInstance;
|
||
|
|
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
|
||
|
|
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
|
||
|
|
wcex.lpszClassName = L"BVLEVoxels";
|
||
|
|
RegisterClassExW(&wcex);
|
||
|
|
|
||
|
|
HWND hWnd = CreateWindowW(
|
||
|
|
wcex.lpszClassName,
|
||
|
|
L"BVLE Voxels - Prototype",
|
||
|
|
WS_OVERLAPPEDWINDOW,
|
||
|
|
CW_USEDEFAULT, 0,
|
||
|
|
1920, 1080,
|
||
|
|
nullptr, nullptr, hInstance, nullptr
|
||
|
|
);
|
||
|
|
ShowWindow(hWnd, SW_SHOWMAXIMIZED);
|
||
|
|
|
||
|
|
// Initialize Wicked Engine (selects DX12 by default on Windows, Vulkan on Linux)
|
||
|
|
// Pass "vulkan" as command line argument to force Vulkan backend
|
||
|
|
// Pass "debugdevice" for D3D debug layer, "gpuvalidation" for GPU-based validation
|
||
|
|
application.SetWindow(hWnd);
|
||
|
|
wi::arguments::Parse(lpCmdLine);
|
||
|
|
|
||
|
|
|
||
|
|
// Redirect Wicked Engine log to file
|
||
|
|
wi::backlog::SetLogFile("bvle_backlog.txt");
|
||
|
|
|
||
|
|
// Info display
|
||
|
|
application.infoDisplay.active = true;
|
||
|
|
application.infoDisplay.watermark = false;
|
||
|
|
application.infoDisplay.resolution = true;
|
||
|
|
application.infoDisplay.fpsinfo = true;
|
||
|
|
application.infoDisplay.heap_allocation_counter = true;
|
||
|
|
|
||
|
|
// Check for "debug" argument to enable face-color debug mode
|
||
|
|
if (wi::arguments::HasArgument("debug")) {
|
||
|
|
renderPath.debugMode = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Activate our custom voxel render path
|
||
|
|
application.ActivatePath(&renderPath);
|
||
|
|
|
||
|
|
// Main loop
|
||
|
|
MSG msg = { 0 };
|
||
|
|
while (msg.message != WM_QUIT)
|
||
|
|
{
|
||
|
|
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||
|
|
TranslateMessage(&msg);
|
||
|
|
DispatchMessage(&msg);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
application.Run();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
wi::jobsystem::ShutDown();
|
||
|
|
return (int)msg.wParam;
|
||
|
|
}
|