mirror of
https://github.com/AxioDL/metaforce.git
synced 2025-12-08 13:04:56 +00:00
New code style refactor
This commit is contained in:
@@ -8,163 +8,142 @@
|
||||
#include <thread>
|
||||
|
||||
static logvisor::Module AthenaLog("Athena");
|
||||
static void AthenaExc(athena::error::Level level, const char* file,
|
||||
const char*, int line, const char* fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
AthenaLog.report(logvisor::Level(level), fmt, ap);
|
||||
va_end(ap);
|
||||
static void AthenaExc(athena::error::Level level, const char* file, const char*, int line, const char* fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
AthenaLog.report(logvisor::Level(level), fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
static float s_Percent = 0.f;
|
||||
static DWORD s_mainThreadId;
|
||||
static void UpdatePercent(float percent)
|
||||
{
|
||||
s_Percent = percent;
|
||||
PostThreadMessage(s_mainThreadId, WM_USER+1, 0, 0);
|
||||
static void UpdatePercent(float percent) {
|
||||
s_Percent = percent;
|
||||
PostThreadMessage(s_mainThreadId, WM_USER + 1, 0, 0);
|
||||
}
|
||||
|
||||
static const DWORD dwStyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
|
||||
static VISIRenderer* s_Renderer;
|
||||
|
||||
static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if (uMsg == WM_SIZING)
|
||||
{
|
||||
RECT& dragRect = reinterpret_cast<RECT&>(lParam);
|
||||
RECT tmpRect = dragRect;
|
||||
tmpRect.bottom = tmpRect.top + 512;
|
||||
tmpRect.right = tmpRect.left + 768;
|
||||
AdjustWindowRect(&tmpRect, dwStyle, FALSE);
|
||||
dragRect = tmpRect;
|
||||
return TRUE;
|
||||
}
|
||||
else if (uMsg == WM_CLOSE)
|
||||
{
|
||||
s_Renderer->Terminate();
|
||||
return 0;
|
||||
}
|
||||
return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
||||
static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||
if (uMsg == WM_SIZING) {
|
||||
RECT& dragRect = reinterpret_cast<RECT&>(lParam);
|
||||
RECT tmpRect = dragRect;
|
||||
tmpRect.bottom = tmpRect.top + 512;
|
||||
tmpRect.right = tmpRect.left + 768;
|
||||
AdjustWindowRect(&tmpRect, dwStyle, FALSE);
|
||||
dragRect = tmpRect;
|
||||
return TRUE;
|
||||
} else if (uMsg == WM_CLOSE) {
|
||||
s_Renderer->Terminate();
|
||||
return 0;
|
||||
}
|
||||
return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
int wmain(int argc, const hecl::SystemChar** argv)
|
||||
{
|
||||
if (argc > 1 && !wcscmp(argv[1], L"--dlpackage"))
|
||||
{
|
||||
printf("%s\n", URDE_DLPACKAGE);
|
||||
return 100;
|
||||
int wmain(int argc, const hecl::SystemChar** argv) {
|
||||
if (argc > 1 && !wcscmp(argv[1], L"--dlpackage")) {
|
||||
printf("%s\n", URDE_DLPACKAGE);
|
||||
return 100;
|
||||
}
|
||||
|
||||
logvisor::RegisterStandardExceptions();
|
||||
logvisor::RegisterConsoleLogger();
|
||||
atSetExceptionHandler(AthenaExc);
|
||||
VISIRenderer renderer(argc, argv);
|
||||
s_Renderer = &renderer;
|
||||
|
||||
int instIdx = -1;
|
||||
if (argc > 3)
|
||||
instIdx = _wtoi(argv[3]);
|
||||
|
||||
WNDCLASS wndClass = {CS_NOCLOSE, WindowProc, 0, 0, GetModuleHandle(nullptr), 0, 0, 0, 0, L"VISIGenWindow"};
|
||||
RegisterClassW(&wndClass);
|
||||
|
||||
RECT clientRect = {0, 0, 768, 512};
|
||||
AdjustWindowRect(&clientRect, dwStyle, FALSE);
|
||||
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
if (instIdx != -1) {
|
||||
x = (instIdx & 1) != 0;
|
||||
y = (instIdx & 2) != 0;
|
||||
}
|
||||
|
||||
HWND window = CreateWindowW(L"VISIGenWindow", L"VISIGen", dwStyle, x, y, clientRect.right - clientRect.left,
|
||||
clientRect.bottom - clientRect.top, NULL, NULL, NULL, NULL);
|
||||
|
||||
PIXELFORMATDESCRIPTOR pfd = {sizeof(PIXELFORMATDESCRIPTOR),
|
||||
1,
|
||||
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL, // Flags
|
||||
PFD_TYPE_RGBA, // The kind of framebuffer. RGBA or palette.
|
||||
32, // Colordepth of the framebuffer.
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
24, // Number of bits for the depthbuffer
|
||||
8, // Number of bits for the stencilbuffer
|
||||
0, // Number of Aux buffers in the framebuffer.
|
||||
PFD_MAIN_PLANE,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0};
|
||||
|
||||
HDC deviceContext = GetDC(window);
|
||||
int pf = ChoosePixelFormat(deviceContext, &pfd);
|
||||
SetPixelFormat(deviceContext, pf, &pfd);
|
||||
HGLRC glContext = wglCreateContext(deviceContext);
|
||||
ShowWindow(window, SW_SHOW);
|
||||
|
||||
s_mainThreadId = GetCurrentThreadId();
|
||||
|
||||
/* Spawn client thread */
|
||||
std::thread clientThread([&]() {
|
||||
wglMakeCurrent(deviceContext, glContext);
|
||||
renderer.Run(UpdatePercent);
|
||||
PostThreadMessage(s_mainThreadId, WM_USER, 0, 0);
|
||||
});
|
||||
|
||||
/* Pump messages */
|
||||
MSG msg = {0};
|
||||
while (GetMessage(&msg, NULL, 0, 0)) {
|
||||
if (!msg.hwnd) {
|
||||
/* PostThreadMessage events */
|
||||
switch (msg.message) {
|
||||
case WM_USER:
|
||||
/* Quit message from client thread */
|
||||
PostQuitMessage(0);
|
||||
continue;
|
||||
case WM_USER + 1:
|
||||
/* Update window title from client thread */
|
||||
wchar_t title[256];
|
||||
StringCbPrintfW(title, 512, L"VISIGen [%g%%]", s_Percent * 100.f);
|
||||
SetWindowTextW(window, title);
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
logvisor::RegisterStandardExceptions();
|
||||
logvisor::RegisterConsoleLogger();
|
||||
atSetExceptionHandler(AthenaExc);
|
||||
VISIRenderer renderer(argc, argv);
|
||||
s_Renderer = &renderer;
|
||||
renderer.Terminate();
|
||||
if (clientThread.joinable())
|
||||
clientThread.join();
|
||||
|
||||
int instIdx = -1;
|
||||
if (argc > 3)
|
||||
instIdx = _wtoi(argv[3]);
|
||||
wglDeleteContext(glContext);
|
||||
|
||||
WNDCLASS wndClass =
|
||||
{
|
||||
CS_NOCLOSE,
|
||||
WindowProc,
|
||||
0,
|
||||
0,
|
||||
GetModuleHandle(nullptr),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
L"VISIGenWindow"
|
||||
};
|
||||
RegisterClassW(&wndClass);
|
||||
|
||||
RECT clientRect = {0, 0, 768, 512};
|
||||
AdjustWindowRect(&clientRect, dwStyle, FALSE);
|
||||
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
if (instIdx != -1)
|
||||
{
|
||||
x = (instIdx & 1) != 0;
|
||||
y = (instIdx & 2) != 0;
|
||||
}
|
||||
|
||||
HWND window = CreateWindowW(L"VISIGenWindow", L"VISIGen", dwStyle,
|
||||
x, y,
|
||||
clientRect.right - clientRect.left,
|
||||
clientRect.bottom - clientRect.top,
|
||||
NULL, NULL, NULL, NULL);
|
||||
|
||||
PIXELFORMATDESCRIPTOR pfd =
|
||||
{
|
||||
sizeof(PIXELFORMATDESCRIPTOR),
|
||||
1,
|
||||
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL, //Flags
|
||||
PFD_TYPE_RGBA, //The kind of framebuffer. RGBA or palette.
|
||||
32, //Colordepth of the framebuffer.
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0, 0, 0, 0,
|
||||
24, //Number of bits for the depthbuffer
|
||||
8, //Number of bits for the stencilbuffer
|
||||
0, //Number of Aux buffers in the framebuffer.
|
||||
PFD_MAIN_PLANE,
|
||||
0,
|
||||
0, 0, 0
|
||||
};
|
||||
|
||||
HDC deviceContext = GetDC(window);
|
||||
int pf = ChoosePixelFormat(deviceContext, &pfd);
|
||||
SetPixelFormat(deviceContext, pf, &pfd);
|
||||
HGLRC glContext = wglCreateContext(deviceContext);
|
||||
ShowWindow(window, SW_SHOW);
|
||||
|
||||
s_mainThreadId = GetCurrentThreadId();
|
||||
|
||||
/* Spawn client thread */
|
||||
std::thread clientThread([&]()
|
||||
{
|
||||
wglMakeCurrent(deviceContext, glContext);
|
||||
renderer.Run(UpdatePercent);
|
||||
PostThreadMessage(s_mainThreadId, WM_USER, 0, 0);
|
||||
});
|
||||
|
||||
/* Pump messages */
|
||||
MSG msg = {0};
|
||||
while (GetMessage(&msg, NULL, 0, 0))
|
||||
{
|
||||
if (!msg.hwnd)
|
||||
{
|
||||
/* PostThreadMessage events */
|
||||
switch (msg.message)
|
||||
{
|
||||
case WM_USER:
|
||||
/* Quit message from client thread */
|
||||
PostQuitMessage(0);
|
||||
continue;
|
||||
case WM_USER+1:
|
||||
/* Update window title from client thread */
|
||||
wchar_t title[256];
|
||||
StringCbPrintfW(title, 512, L"VISIGen [%g%%]", s_Percent * 100.f);
|
||||
SetWindowTextW(window, title);
|
||||
continue;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
renderer.Terminate();
|
||||
if (clientThread.joinable())
|
||||
clientThread.join();
|
||||
|
||||
wglDeleteContext(glContext);
|
||||
|
||||
return renderer.ReturnVal();
|
||||
return renderer.ReturnVal();
|
||||
}
|
||||
|
||||
@@ -10,343 +10,296 @@
|
||||
#include <limits.h>
|
||||
#include <signal.h>
|
||||
|
||||
#define MWM_HINTS_FUNCTIONS (1L << 0)
|
||||
#define MWM_HINTS_FUNCTIONS (1L << 0)
|
||||
#define MWM_HINTS_DECORATIONS (1L << 1)
|
||||
|
||||
#define MWM_DECOR_BORDER (1L<<1)
|
||||
#define MWM_DECOR_RESIZEH (1L<<2)
|
||||
#define MWM_DECOR_TITLE (1L<<3)
|
||||
#define MWM_DECOR_MENU (1L<<4)
|
||||
#define MWM_DECOR_MINIMIZE (1L<<5)
|
||||
#define MWM_DECOR_MAXIMIZE (1L<<6)
|
||||
#define MWM_DECOR_BORDER (1L << 1)
|
||||
#define MWM_DECOR_RESIZEH (1L << 2)
|
||||
#define MWM_DECOR_TITLE (1L << 3)
|
||||
#define MWM_DECOR_MENU (1L << 4)
|
||||
#define MWM_DECOR_MINIMIZE (1L << 5)
|
||||
#define MWM_DECOR_MAXIMIZE (1L << 6)
|
||||
|
||||
#define MWM_FUNC_RESIZE (1L<<1)
|
||||
#define MWM_FUNC_MOVE (1L<<2)
|
||||
#define MWM_FUNC_MINIMIZE (1L<<3)
|
||||
#define MWM_FUNC_MAXIMIZE (1L<<4)
|
||||
#define MWM_FUNC_CLOSE (1L<<5)
|
||||
#define MWM_FUNC_RESIZE (1L << 1)
|
||||
#define MWM_FUNC_MOVE (1L << 2)
|
||||
#define MWM_FUNC_MINIMIZE (1L << 3)
|
||||
#define MWM_FUNC_MAXIMIZE (1L << 4)
|
||||
#define MWM_FUNC_CLOSE (1L << 5)
|
||||
|
||||
typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
|
||||
static glXCreateContextAttribsARBProc glXCreateContextAttribsARB = nullptr;
|
||||
|
||||
static const int ContextAttribList[7][7] =
|
||||
{
|
||||
{ GLX_CONTEXT_MAJOR_VERSION_ARB, 4,
|
||||
GLX_CONTEXT_MINOR_VERSION_ARB, 5,
|
||||
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
|
||||
0
|
||||
},
|
||||
{ GLX_CONTEXT_MAJOR_VERSION_ARB, 4,
|
||||
GLX_CONTEXT_MINOR_VERSION_ARB, 4,
|
||||
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
|
||||
0
|
||||
},
|
||||
{ GLX_CONTEXT_MAJOR_VERSION_ARB, 4,
|
||||
GLX_CONTEXT_MINOR_VERSION_ARB, 3,
|
||||
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
|
||||
0
|
||||
},
|
||||
{ GLX_CONTEXT_MAJOR_VERSION_ARB, 4,
|
||||
GLX_CONTEXT_MINOR_VERSION_ARB, 2,
|
||||
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
|
||||
0
|
||||
},
|
||||
{ GLX_CONTEXT_MAJOR_VERSION_ARB, 4,
|
||||
GLX_CONTEXT_MINOR_VERSION_ARB, 1,
|
||||
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
|
||||
0
|
||||
},
|
||||
{ GLX_CONTEXT_MAJOR_VERSION_ARB, 4,
|
||||
GLX_CONTEXT_MINOR_VERSION_ARB, 0,
|
||||
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
|
||||
0
|
||||
},
|
||||
{ GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
|
||||
GLX_CONTEXT_MINOR_VERSION_ARB, 3,
|
||||
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
|
||||
0
|
||||
},
|
||||
static const int ContextAttribList[7][7] = {
|
||||
{GLX_CONTEXT_MAJOR_VERSION_ARB, 4, GLX_CONTEXT_MINOR_VERSION_ARB, 5, GLX_CONTEXT_FLAGS_ARB,
|
||||
GLX_CONTEXT_CORE_PROFILE_BIT_ARB, 0},
|
||||
{GLX_CONTEXT_MAJOR_VERSION_ARB, 4, GLX_CONTEXT_MINOR_VERSION_ARB, 4, GLX_CONTEXT_FLAGS_ARB,
|
||||
GLX_CONTEXT_CORE_PROFILE_BIT_ARB, 0},
|
||||
{GLX_CONTEXT_MAJOR_VERSION_ARB, 4, GLX_CONTEXT_MINOR_VERSION_ARB, 3, GLX_CONTEXT_FLAGS_ARB,
|
||||
GLX_CONTEXT_CORE_PROFILE_BIT_ARB, 0},
|
||||
{GLX_CONTEXT_MAJOR_VERSION_ARB, 4, GLX_CONTEXT_MINOR_VERSION_ARB, 2, GLX_CONTEXT_FLAGS_ARB,
|
||||
GLX_CONTEXT_CORE_PROFILE_BIT_ARB, 0},
|
||||
{GLX_CONTEXT_MAJOR_VERSION_ARB, 4, GLX_CONTEXT_MINOR_VERSION_ARB, 1, GLX_CONTEXT_FLAGS_ARB,
|
||||
GLX_CONTEXT_CORE_PROFILE_BIT_ARB, 0},
|
||||
{GLX_CONTEXT_MAJOR_VERSION_ARB, 4, GLX_CONTEXT_MINOR_VERSION_ARB, 0, GLX_CONTEXT_FLAGS_ARB,
|
||||
GLX_CONTEXT_CORE_PROFILE_BIT_ARB, 0},
|
||||
{GLX_CONTEXT_MAJOR_VERSION_ARB, 3, GLX_CONTEXT_MINOR_VERSION_ARB, 3, GLX_CONTEXT_FLAGS_ARB,
|
||||
GLX_CONTEXT_CORE_PROFILE_BIT_ARB, 0},
|
||||
};
|
||||
|
||||
static bool s_glxError;
|
||||
static int ctxErrorHandler(Display */*dpy*/, XErrorEvent */*ev*/)
|
||||
{
|
||||
s_glxError = true;
|
||||
return 0;
|
||||
static int ctxErrorHandler(Display* /*dpy*/, XErrorEvent* /*ev*/) {
|
||||
s_glxError = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static logvisor::Module Log("visigen-xlib");
|
||||
static logvisor::Module AthenaLog("Athena");
|
||||
static void AthenaExc(athena::error::Level level, const char* /*file*/,
|
||||
const char*, int /*line*/, const char* fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
AthenaLog.report(logvisor::Level(level), fmt, ap);
|
||||
va_end(ap);
|
||||
static void AthenaExc(athena::error::Level level, const char* /*file*/, const char*, int /*line*/, const char* fmt,
|
||||
...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
AthenaLog.report(logvisor::Level(level), fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
static Display* xDisp;
|
||||
static Window windowId;
|
||||
|
||||
static void UpdatePercent(float percent)
|
||||
{
|
||||
XLockDisplay(xDisp);
|
||||
char title[256];
|
||||
snprintf(title, 256, "VISIGen [%g%%]", double(percent * 100.f));
|
||||
XChangeProperty(xDisp, windowId, XA_WM_NAME, XA_STRING, 8,
|
||||
PropModeReplace, reinterpret_cast<unsigned char*>(title), int(strlen(title)));
|
||||
XUnlockDisplay(xDisp);
|
||||
static void UpdatePercent(float percent) {
|
||||
XLockDisplay(xDisp);
|
||||
char title[256];
|
||||
snprintf(title, 256, "VISIGen [%g%%]", double(percent * 100.f));
|
||||
XChangeProperty(xDisp, windowId, XA_WM_NAME, XA_STRING, 8, PropModeReplace, reinterpret_cast<unsigned char*>(title),
|
||||
int(strlen(title)));
|
||||
XUnlockDisplay(xDisp);
|
||||
}
|
||||
|
||||
/* Empty handler for SIGINT */
|
||||
static void _sigint(int) {}
|
||||
|
||||
int main(int argc, const char** argv)
|
||||
{
|
||||
if (argc > 1 && !strcmp(argv[1], "--dlpackage"))
|
||||
{
|
||||
printf("%s\n", URDE_DLPACKAGE);
|
||||
return 100;
|
||||
int main(int argc, const char** argv) {
|
||||
if (argc > 1 && !strcmp(argv[1], "--dlpackage")) {
|
||||
printf("%s\n", URDE_DLPACKAGE);
|
||||
return 100;
|
||||
}
|
||||
|
||||
/* Program is portable to all locales */
|
||||
setlocale(LC_ALL, "");
|
||||
|
||||
logvisor::RegisterStandardExceptions();
|
||||
logvisor::RegisterConsoleLogger();
|
||||
atSetExceptionHandler(AthenaExc);
|
||||
VISIRenderer renderer(argc, argv);
|
||||
|
||||
if (!XInitThreads()) {
|
||||
Log.report(logvisor::Error, "X doesn't support multithreading");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Open Xlib Display */
|
||||
xDisp = XOpenDisplay(nullptr);
|
||||
if (!xDisp) {
|
||||
Log.report(logvisor::Error, "Can't open X display");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Default screen */
|
||||
int xDefaultScreen = DefaultScreen(xDisp);
|
||||
Screen* screen = ScreenOfDisplay(xDisp, xDefaultScreen);
|
||||
|
||||
/* Query framebuffer configurations */
|
||||
GLXFBConfig* fbConfigs = nullptr;
|
||||
int numFBConfigs = 0;
|
||||
fbConfigs = glXGetFBConfigs(xDisp, xDefaultScreen, &numFBConfigs);
|
||||
if (!fbConfigs || numFBConfigs == 0) {
|
||||
Log.report(logvisor::Error, "glXGetFBConfigs failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
VisualID selVisualId = 0;
|
||||
GLXFBConfig selFBConfig = nullptr;
|
||||
for (int i = 0; i < numFBConfigs; ++i) {
|
||||
GLXFBConfig config = fbConfigs[i];
|
||||
int visualId, depthSize, colorSize, doubleBuffer;
|
||||
glXGetFBConfigAttrib(xDisp, config, GLX_VISUAL_ID, &visualId);
|
||||
glXGetFBConfigAttrib(xDisp, config, GLX_DEPTH_SIZE, &depthSize);
|
||||
glXGetFBConfigAttrib(xDisp, config, GLX_BUFFER_SIZE, &colorSize);
|
||||
glXGetFBConfigAttrib(xDisp, config, GLX_DOUBLEBUFFER, &doubleBuffer);
|
||||
|
||||
/* Single-buffer only */
|
||||
if (doubleBuffer)
|
||||
continue;
|
||||
|
||||
if (colorSize >= 32 && depthSize >= 24 && visualId != 0) {
|
||||
selFBConfig = config;
|
||||
selVisualId = VisualID(visualId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
XFree(fbConfigs);
|
||||
|
||||
if (!selFBConfig) {
|
||||
Log.report(logvisor::Error, "unable to find suitable pixel format");
|
||||
return 1;
|
||||
}
|
||||
|
||||
XVisualInfo visTemplate = {};
|
||||
visTemplate.screen = xDefaultScreen;
|
||||
int numVisuals;
|
||||
XVisualInfo* visualList = XGetVisualInfo(xDisp, VisualScreenMask, &visTemplate, &numVisuals);
|
||||
Visual* selectedVisual = nullptr;
|
||||
for (int i = 0; i < numVisuals; ++i) {
|
||||
if (visualList[i].visualid == selVisualId) {
|
||||
selectedVisual = visualList[i].visual;
|
||||
break;
|
||||
}
|
||||
}
|
||||
XFree(visualList);
|
||||
|
||||
/* Create colormap */
|
||||
Colormap colormapId = XCreateColormap(xDisp, screen->root, selectedVisual, AllocNone);
|
||||
|
||||
/* Create window */
|
||||
XSetWindowAttributes swa;
|
||||
swa.colormap = colormapId;
|
||||
swa.border_pixmap = 0;
|
||||
swa.event_mask = 0;
|
||||
|
||||
int instIdx = -1;
|
||||
if (argc > 3)
|
||||
instIdx = atoi(argv[3]);
|
||||
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
if (instIdx != -1) {
|
||||
x = (instIdx & 1) != 0;
|
||||
y = (instIdx & 2) != 0;
|
||||
}
|
||||
|
||||
windowId = XCreateWindow(xDisp, screen->root, x, y, 768, 512, 10, CopyFromParent, CopyFromParent, selectedVisual,
|
||||
CWBorderPixel | CWEventMask | CWColormap, &swa);
|
||||
|
||||
if (!glXCreateContextAttribsARB) {
|
||||
glXCreateContextAttribsARB = reinterpret_cast<glXCreateContextAttribsARBProc>(
|
||||
glXGetProcAddressARB(reinterpret_cast<const GLubyte*>("glXCreateContextAttribsARB")));
|
||||
if (!glXCreateContextAttribsARB) {
|
||||
Log.report(logvisor::Error, "unable to resolve glXCreateContextAttribsARB");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
s_glxError = false;
|
||||
XErrorHandler oldHandler = XSetErrorHandler(ctxErrorHandler);
|
||||
GLXContext glxCtx = nullptr;
|
||||
for (uint32_t attribIdx = 0; attribIdx < std::extent<decltype(ContextAttribList)>::value; ++attribIdx) {
|
||||
glxCtx = glXCreateContextAttribsARB(xDisp, selFBConfig, nullptr, True, ContextAttribList[attribIdx]);
|
||||
if (glxCtx)
|
||||
break;
|
||||
}
|
||||
XSetErrorHandler(oldHandler);
|
||||
if (!glxCtx) {
|
||||
Log.report(logvisor::Fatal, "unable to make new GLX context");
|
||||
return 1;
|
||||
}
|
||||
GLXWindow glxWindow = glXCreateWindow(xDisp, selFBConfig, windowId, nullptr);
|
||||
if (!glxWindow) {
|
||||
Log.report(logvisor::Fatal, "unable to make new GLX window");
|
||||
return 1;
|
||||
}
|
||||
|
||||
XMapWindow(xDisp, windowId);
|
||||
|
||||
struct {
|
||||
unsigned long flags = 0;
|
||||
unsigned long functions = 0;
|
||||
unsigned long decorations = 0;
|
||||
long inputMode = 0;
|
||||
unsigned long status = 0;
|
||||
} wmHints;
|
||||
|
||||
Atom motifWmHints = XInternAtom(xDisp, "_MOTIF_WM_HINTS", True);
|
||||
if (motifWmHints) {
|
||||
wmHints.flags = MWM_HINTS_DECORATIONS | MWM_HINTS_FUNCTIONS;
|
||||
wmHints.decorations |= MWM_DECOR_BORDER | MWM_DECOR_TITLE | MWM_DECOR_MINIMIZE | MWM_DECOR_MENU;
|
||||
wmHints.functions |= MWM_FUNC_MOVE | MWM_FUNC_MINIMIZE;
|
||||
XChangeProperty(xDisp, windowId, motifWmHints, motifWmHints, 32, PropModeReplace,
|
||||
reinterpret_cast<unsigned char*>(&wmHints), 5);
|
||||
}
|
||||
|
||||
/* SIGINT will be used to cancel main thread when client thread ends
|
||||
* (also enables graceful quitting via ctrl-c) */
|
||||
pthread_t mainThread = pthread_self();
|
||||
struct sigaction s;
|
||||
s.sa_handler = _sigint;
|
||||
sigemptyset(&s.sa_mask);
|
||||
s.sa_flags = 0;
|
||||
sigaction(SIGINT, &s, nullptr);
|
||||
sigaction(SIGUSR2, &s, nullptr);
|
||||
|
||||
sigset_t waitmask, origmask;
|
||||
sigemptyset(&waitmask);
|
||||
sigaddset(&waitmask, SIGINT);
|
||||
sigaddset(&waitmask, SIGUSR2);
|
||||
pthread_sigmask(SIG_BLOCK, &waitmask, &origmask);
|
||||
|
||||
int x11Fd = ConnectionNumber(xDisp);
|
||||
|
||||
/* Spawn client thread */
|
||||
bool clientRunning = true;
|
||||
std::mutex initmt;
|
||||
std::condition_variable initcv;
|
||||
std::unique_lock<std::mutex> outerLk(initmt);
|
||||
std::thread clientThread([&]() {
|
||||
std::unique_lock<std::mutex> innerLk(initmt);
|
||||
innerLk.unlock();
|
||||
initcv.notify_one();
|
||||
|
||||
XLockDisplay(xDisp);
|
||||
if (!glXMakeContextCurrent(xDisp, glxWindow, glxWindow, glxCtx))
|
||||
Log.report(logvisor::Fatal, "unable to make GLX context current");
|
||||
XUnlockDisplay(xDisp);
|
||||
|
||||
renderer.Run(UpdatePercent);
|
||||
clientRunning = false;
|
||||
|
||||
XLockDisplay(xDisp);
|
||||
XClientMessageEvent exitEvent = {};
|
||||
exitEvent.type = ClientMessage;
|
||||
exitEvent.window = windowId;
|
||||
exitEvent.format = 32;
|
||||
XSendEvent(xDisp, windowId, 0, 0, reinterpret_cast<XEvent*>(&exitEvent));
|
||||
XFlush(xDisp);
|
||||
XUnlockDisplay(xDisp);
|
||||
});
|
||||
initcv.wait(outerLk);
|
||||
|
||||
/* Begin application event loop */
|
||||
while (clientRunning) {
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(x11Fd, &fds);
|
||||
if (pselect(x11Fd + 1, &fds, nullptr, nullptr, nullptr, &origmask) < 0) {
|
||||
/* SIGINT/SIGUSR2 handled here */
|
||||
if (errno == EINTR || errno == SIGUSR2)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Program is portable to all locales */
|
||||
setlocale(LC_ALL, "");
|
||||
|
||||
logvisor::RegisterStandardExceptions();
|
||||
logvisor::RegisterConsoleLogger();
|
||||
atSetExceptionHandler(AthenaExc);
|
||||
VISIRenderer renderer(argc, argv);
|
||||
|
||||
if (!XInitThreads())
|
||||
{
|
||||
Log.report(logvisor::Error, "X doesn't support multithreading");
|
||||
return 1;
|
||||
if (FD_ISSET(x11Fd, &fds)) {
|
||||
XLockDisplay(xDisp);
|
||||
while (XPending(xDisp)) {
|
||||
XEvent event;
|
||||
XNextEvent(xDisp, &event);
|
||||
if (XFilterEvent(&event, None))
|
||||
continue;
|
||||
}
|
||||
XUnlockDisplay(xDisp);
|
||||
}
|
||||
}
|
||||
|
||||
/* Open Xlib Display */
|
||||
xDisp = XOpenDisplay(nullptr);
|
||||
if (!xDisp)
|
||||
{
|
||||
Log.report(logvisor::Error, "Can't open X display");
|
||||
return 1;
|
||||
}
|
||||
renderer.Terminate();
|
||||
pthread_cancel(clientThread.native_handle());
|
||||
if (clientThread.joinable())
|
||||
clientThread.join();
|
||||
|
||||
/* Default screen */
|
||||
int xDefaultScreen = DefaultScreen(xDisp);
|
||||
Screen* screen = ScreenOfDisplay(xDisp, xDefaultScreen);
|
||||
|
||||
/* Query framebuffer configurations */
|
||||
GLXFBConfig* fbConfigs = nullptr;
|
||||
int numFBConfigs = 0;
|
||||
fbConfigs = glXGetFBConfigs(xDisp, xDefaultScreen, &numFBConfigs);
|
||||
if (!fbConfigs || numFBConfigs == 0)
|
||||
{
|
||||
Log.report(logvisor::Error, "glXGetFBConfigs failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
VisualID selVisualId = 0;
|
||||
GLXFBConfig selFBConfig = nullptr;
|
||||
for (int i=0 ; i<numFBConfigs ; ++i)
|
||||
{
|
||||
GLXFBConfig config = fbConfigs[i];
|
||||
int visualId, depthSize, colorSize, doubleBuffer;
|
||||
glXGetFBConfigAttrib(xDisp, config, GLX_VISUAL_ID, &visualId);
|
||||
glXGetFBConfigAttrib(xDisp, config, GLX_DEPTH_SIZE, &depthSize);
|
||||
glXGetFBConfigAttrib(xDisp, config, GLX_BUFFER_SIZE, &colorSize);
|
||||
glXGetFBConfigAttrib(xDisp, config, GLX_DOUBLEBUFFER, &doubleBuffer);
|
||||
|
||||
/* Single-buffer only */
|
||||
if (doubleBuffer)
|
||||
continue;
|
||||
|
||||
if (colorSize >= 32 && depthSize >= 24 && visualId != 0)
|
||||
{
|
||||
selFBConfig = config;
|
||||
selVisualId = VisualID(visualId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
XFree(fbConfigs);
|
||||
|
||||
if (!selFBConfig)
|
||||
{
|
||||
Log.report(logvisor::Error, "unable to find suitable pixel format");
|
||||
return 1;
|
||||
}
|
||||
|
||||
XVisualInfo visTemplate = {};
|
||||
visTemplate.screen = xDefaultScreen;
|
||||
int numVisuals;
|
||||
XVisualInfo* visualList = XGetVisualInfo(xDisp, VisualScreenMask, &visTemplate, &numVisuals);
|
||||
Visual* selectedVisual = nullptr;
|
||||
for (int i=0 ; i<numVisuals ; ++i)
|
||||
{
|
||||
if (visualList[i].visualid == selVisualId)
|
||||
{
|
||||
selectedVisual = visualList[i].visual;
|
||||
break;
|
||||
}
|
||||
}
|
||||
XFree(visualList);
|
||||
|
||||
/* Create colormap */
|
||||
Colormap colormapId = XCreateColormap(xDisp, screen->root, selectedVisual, AllocNone);
|
||||
|
||||
/* Create window */
|
||||
XSetWindowAttributes swa;
|
||||
swa.colormap = colormapId;
|
||||
swa.border_pixmap = 0;
|
||||
swa.event_mask = 0;
|
||||
|
||||
int instIdx = -1;
|
||||
if (argc > 3)
|
||||
instIdx = atoi(argv[3]);
|
||||
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
if (instIdx != -1)
|
||||
{
|
||||
x = (instIdx & 1) != 0;
|
||||
y = (instIdx & 2) != 0;
|
||||
}
|
||||
|
||||
windowId = XCreateWindow(xDisp, screen->root, x, y, 768, 512, 10,
|
||||
CopyFromParent, CopyFromParent, selectedVisual,
|
||||
CWBorderPixel | CWEventMask | CWColormap, &swa);
|
||||
|
||||
if (!glXCreateContextAttribsARB)
|
||||
{
|
||||
glXCreateContextAttribsARB = reinterpret_cast<glXCreateContextAttribsARBProc>(
|
||||
glXGetProcAddressARB(reinterpret_cast<const GLubyte*>("glXCreateContextAttribsARB")));
|
||||
if (!glXCreateContextAttribsARB)
|
||||
{
|
||||
Log.report(logvisor::Error, "unable to resolve glXCreateContextAttribsARB");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
s_glxError = false;
|
||||
XErrorHandler oldHandler = XSetErrorHandler(ctxErrorHandler);
|
||||
GLXContext glxCtx = nullptr;
|
||||
for (uint32_t attribIdx=0 ; attribIdx<std::extent<decltype(ContextAttribList)>::value ; ++attribIdx)
|
||||
{
|
||||
glxCtx = glXCreateContextAttribsARB(xDisp, selFBConfig, nullptr, True, ContextAttribList[attribIdx]);
|
||||
if (glxCtx)
|
||||
break;
|
||||
}
|
||||
XSetErrorHandler(oldHandler);
|
||||
if (!glxCtx)
|
||||
{
|
||||
Log.report(logvisor::Fatal, "unable to make new GLX context");
|
||||
return 1;
|
||||
}
|
||||
GLXWindow glxWindow = glXCreateWindow(xDisp, selFBConfig, windowId, nullptr);
|
||||
if (!glxWindow)
|
||||
{
|
||||
Log.report(logvisor::Fatal, "unable to make new GLX window");
|
||||
return 1;
|
||||
}
|
||||
|
||||
XMapWindow(xDisp, windowId);
|
||||
|
||||
struct
|
||||
{
|
||||
unsigned long flags = 0;
|
||||
unsigned long functions = 0;
|
||||
unsigned long decorations = 0;
|
||||
long inputMode = 0;
|
||||
unsigned long status = 0;
|
||||
} wmHints;
|
||||
|
||||
Atom motifWmHints = XInternAtom(xDisp, "_MOTIF_WM_HINTS", True);
|
||||
if (motifWmHints)
|
||||
{
|
||||
wmHints.flags = MWM_HINTS_DECORATIONS | MWM_HINTS_FUNCTIONS;
|
||||
wmHints.decorations |= MWM_DECOR_BORDER | MWM_DECOR_TITLE | MWM_DECOR_MINIMIZE | MWM_DECOR_MENU;
|
||||
wmHints.functions |= MWM_FUNC_MOVE | MWM_FUNC_MINIMIZE;
|
||||
XChangeProperty(xDisp, windowId, motifWmHints, motifWmHints, 32, PropModeReplace, reinterpret_cast<unsigned char*>(&wmHints), 5);
|
||||
}
|
||||
|
||||
/* SIGINT will be used to cancel main thread when client thread ends
|
||||
* (also enables graceful quitting via ctrl-c) */
|
||||
pthread_t mainThread = pthread_self();
|
||||
struct sigaction s;
|
||||
s.sa_handler = _sigint;
|
||||
sigemptyset(&s.sa_mask);
|
||||
s.sa_flags = 0;
|
||||
sigaction(SIGINT, &s, nullptr);
|
||||
sigaction(SIGUSR2, &s, nullptr);
|
||||
|
||||
sigset_t waitmask, origmask;
|
||||
sigemptyset(&waitmask);
|
||||
sigaddset(&waitmask, SIGINT);
|
||||
sigaddset(&waitmask, SIGUSR2);
|
||||
pthread_sigmask(SIG_BLOCK, &waitmask, &origmask);
|
||||
|
||||
int x11Fd = ConnectionNumber(xDisp);
|
||||
|
||||
/* Spawn client thread */
|
||||
bool clientRunning = true;
|
||||
std::mutex initmt;
|
||||
std::condition_variable initcv;
|
||||
std::unique_lock<std::mutex> outerLk(initmt);
|
||||
std::thread clientThread([&]()
|
||||
{
|
||||
std::unique_lock<std::mutex> innerLk(initmt);
|
||||
innerLk.unlock();
|
||||
initcv.notify_one();
|
||||
|
||||
XLockDisplay(xDisp);
|
||||
if (!glXMakeContextCurrent(xDisp, glxWindow, glxWindow, glxCtx))
|
||||
Log.report(logvisor::Fatal, "unable to make GLX context current");
|
||||
XUnlockDisplay(xDisp);
|
||||
|
||||
renderer.Run(UpdatePercent);
|
||||
clientRunning = false;
|
||||
|
||||
XLockDisplay(xDisp);
|
||||
XClientMessageEvent exitEvent = {};
|
||||
exitEvent.type = ClientMessage;
|
||||
exitEvent.window = windowId;
|
||||
exitEvent.format = 32;
|
||||
XSendEvent(xDisp, windowId, 0, 0, reinterpret_cast<XEvent*>(&exitEvent));
|
||||
XFlush(xDisp);
|
||||
XUnlockDisplay(xDisp);
|
||||
});
|
||||
initcv.wait(outerLk);
|
||||
|
||||
/* Begin application event loop */
|
||||
while (clientRunning)
|
||||
{
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(x11Fd, &fds);
|
||||
if (pselect(x11Fd+1, &fds, nullptr, nullptr, nullptr, &origmask) < 0)
|
||||
{
|
||||
/* SIGINT/SIGUSR2 handled here */
|
||||
if (errno == EINTR || errno == SIGUSR2)
|
||||
break;
|
||||
}
|
||||
|
||||
if (FD_ISSET(x11Fd, &fds))
|
||||
{
|
||||
XLockDisplay(xDisp);
|
||||
while (XPending(xDisp))
|
||||
{
|
||||
XEvent event;
|
||||
XNextEvent(xDisp, &event);
|
||||
if (XFilterEvent(&event, None)) continue;
|
||||
}
|
||||
XUnlockDisplay(xDisp);
|
||||
}
|
||||
}
|
||||
|
||||
renderer.Terminate();
|
||||
pthread_cancel(clientThread.native_handle());
|
||||
if (clientThread.joinable())
|
||||
clientThread.join();
|
||||
|
||||
return renderer.ReturnVal();
|
||||
return renderer.ReturnVal();
|
||||
}
|
||||
|
||||
@@ -11,380 +11,318 @@
|
||||
|
||||
static logvisor::Module Log("VISIBuilder");
|
||||
|
||||
VISIBuilder::PVSRenderCache::PVSRenderCache(VISIRenderer& renderer)
|
||||
: m_renderer(renderer)
|
||||
{
|
||||
m_cache.reserve(1000);
|
||||
}
|
||||
VISIBuilder::PVSRenderCache::PVSRenderCache(VISIRenderer& renderer) : m_renderer(renderer) { m_cache.reserve(1000); }
|
||||
|
||||
static std::unique_ptr<VISIRenderer::RGBA8[]> RGBABuf(new VISIRenderer::RGBA8[256 * 256 * 6]);
|
||||
|
||||
const VISIBuilder::Leaf& VISIBuilder::PVSRenderCache::GetLeaf(const zeus::CVector3f& vec)
|
||||
{
|
||||
auto search = m_cache.find(vec);
|
||||
if (search != m_cache.cend())
|
||||
{
|
||||
//Log.report(logvisor::Info, "Cache hit");
|
||||
return *search->second;
|
||||
}
|
||||
const VISIBuilder::Leaf& VISIBuilder::PVSRenderCache::GetLeaf(const zeus::CVector3f& vec) {
|
||||
auto search = m_cache.find(vec);
|
||||
if (search != m_cache.cend()) {
|
||||
// Log.report(logvisor::Info, "Cache hit");
|
||||
return *search->second;
|
||||
}
|
||||
|
||||
//Log.report(logvisor::Info, "Rendering");
|
||||
bool needsTransparent = false;
|
||||
m_renderer.RenderPVSOpaque(RGBABuf.get(), vec, needsTransparent);
|
||||
std::unique_ptr<Leaf> leafOut = std::make_unique<Leaf>();
|
||||
for (unsigned i=0 ; i<768*512 ; ++i)
|
||||
{
|
||||
const VISIRenderer::RGBA8& pixel = RGBABuf[i];
|
||||
uint32_t id = (pixel.b << 16) | (pixel.g << 8) | pixel.r;
|
||||
if (id != 0)
|
||||
leafOut->setBit(id - 1);
|
||||
}
|
||||
// Log.report(logvisor::Info, "Rendering");
|
||||
bool needsTransparent = false;
|
||||
m_renderer.RenderPVSOpaque(RGBABuf.get(), vec, needsTransparent);
|
||||
std::unique_ptr<Leaf> leafOut = std::make_unique<Leaf>();
|
||||
for (unsigned i = 0; i < 768 * 512; ++i) {
|
||||
const VISIRenderer::RGBA8& pixel = RGBABuf[i];
|
||||
uint32_t id = (pixel.b << 16) | (pixel.g << 8) | pixel.r;
|
||||
if (id != 0)
|
||||
leafOut->setBit(id - 1);
|
||||
}
|
||||
|
||||
auto setBitLambda = [&](int idx) { leafOut->setBit(idx); };
|
||||
auto setLightLambda = [&](int idx, EPVSVisSetState state)
|
||||
{
|
||||
if (state != EPVSVisSetState::EndOfTree)
|
||||
leafOut->setLightEnum(m_lightMetaBit + idx * 2, state);
|
||||
};
|
||||
if (needsTransparent)
|
||||
m_renderer.RenderPVSTransparent(setBitLambda, vec);
|
||||
m_renderer.RenderPVSEntitiesAndLights(setBitLambda, setLightLambda, vec);
|
||||
auto setBitLambda = [&](int idx) { leafOut->setBit(idx); };
|
||||
auto setLightLambda = [&](int idx, EPVSVisSetState state) {
|
||||
if (state != EPVSVisSetState::EndOfTree)
|
||||
leafOut->setLightEnum(m_lightMetaBit + idx * 2, state);
|
||||
};
|
||||
if (needsTransparent)
|
||||
m_renderer.RenderPVSTransparent(setBitLambda, vec);
|
||||
m_renderer.RenderPVSEntitiesAndLights(setBitLambda, setLightLambda, vec);
|
||||
|
||||
return *m_cache.emplace(std::make_pair(vec, std::move(leafOut))).first->second;
|
||||
return *m_cache.emplace(std::make_pair(vec, std::move(leafOut))).first->second;
|
||||
}
|
||||
|
||||
void VISIBuilder::Progress::report(int divisions)
|
||||
{
|
||||
m_prog += 1.f / divisions;
|
||||
//printf(" %g%% \r", m_prog * 100.f);
|
||||
//fflush(stdout);
|
||||
if (m_updatePercent)
|
||||
m_updatePercent(m_prog);
|
||||
void VISIBuilder::Progress::report(int divisions) {
|
||||
m_prog += 1.f / divisions;
|
||||
// printf(" %g%% \r", m_prog * 100.f);
|
||||
// fflush(stdout);
|
||||
if (m_updatePercent)
|
||||
m_updatePercent(m_prog);
|
||||
}
|
||||
|
||||
void VISIBuilder::Node::buildChildren(int level, int divisions, const zeus::CAABox& curAabb,
|
||||
PVSRenderCache& rc, Progress& prog, const std::function<bool()>& terminate)
|
||||
{
|
||||
if (terminate())
|
||||
void VISIBuilder::Node::buildChildren(int level, int divisions, const zeus::CAABox& curAabb, PVSRenderCache& rc,
|
||||
Progress& prog, const std::function<bool()>& terminate) {
|
||||
if (terminate())
|
||||
return;
|
||||
|
||||
// Recurse in while building node structure
|
||||
if (level < VISI_MAX_LEVEL) {
|
||||
// Heuristic split
|
||||
int splits[3];
|
||||
splits[0] = (curAabb.max.x() - curAabb.min.x() >= VISI_MIN_LENGTH) ? 2 : 1;
|
||||
splits[1] = (curAabb.max.y() - curAabb.min.y() >= VISI_MIN_LENGTH) ? 2 : 1;
|
||||
splits[2] = (curAabb.max.z() - curAabb.min.z() >= VISI_MIN_LENGTH) ? 2 : 1;
|
||||
|
||||
if (splits[0] == 2)
|
||||
flags |= 0x1;
|
||||
if (splits[1] == 2)
|
||||
flags |= 0x2;
|
||||
if (splits[2] == 2)
|
||||
flags |= 0x4;
|
||||
|
||||
int thisdiv = splits[0] * splits[1] * splits[2] * divisions;
|
||||
|
||||
if (flags) {
|
||||
childNodes.resize(8);
|
||||
|
||||
// Inward subdivide
|
||||
zeus::CAABox Z[2];
|
||||
if (flags & 0x4)
|
||||
curAabb.splitZ(Z[0], Z[1]);
|
||||
else
|
||||
Z[0] = curAabb;
|
||||
for (int i = 0; i < splits[2]; ++i) {
|
||||
zeus::CAABox Y[2];
|
||||
if (flags & 0x2)
|
||||
Z[i].splitY(Y[0], Y[1]);
|
||||
else
|
||||
Y[0] = Z[i];
|
||||
for (int j = 0; j < splits[1]; ++j) {
|
||||
zeus::CAABox X[2];
|
||||
if (flags & 0x1)
|
||||
Y[j].splitX(X[0], X[1]);
|
||||
else
|
||||
X[0] = Y[j];
|
||||
for (int k = 0; k < splits[0]; ++k) {
|
||||
childNodes[i * 4 + j * 2 + k].buildChildren(level + 1, thisdiv, X[k], rc, prog, terminate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Outward unsubdivide for like-leaves
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
if (flags & 0x4 && childNodes[0] == childNodes[4] && (!(flags & 0x1) || childNodes[1] == childNodes[5]) &&
|
||||
(!(flags & 0x2) || childNodes[2] == childNodes[6]) && (!(flags & 0x3) || childNodes[3] == childNodes[7])) {
|
||||
flags &= ~0x4;
|
||||
// Log.report(logvisor::Info, "Unsub Z");
|
||||
continue;
|
||||
}
|
||||
if (flags & 0x2 && childNodes[0] == childNodes[2] && (!(flags & 0x1) || childNodes[1] == childNodes[3]) &&
|
||||
(!(flags & 0x4) || childNodes[4] == childNodes[6]) && (!(flags & 0x5) || childNodes[5] == childNodes[7])) {
|
||||
flags &= ~0x2;
|
||||
// Log.report(logvisor::Info, "Unsub Y");
|
||||
continue;
|
||||
}
|
||||
if (flags & 0x1 && childNodes[0] == childNodes[1] && (!(flags & 0x2) || childNodes[2] == childNodes[3]) &&
|
||||
(!(flags & 0x4) || childNodes[4] == childNodes[5]) && (!(flags & 0x6) || childNodes[6] == childNodes[7])) {
|
||||
flags &= ~0x1;
|
||||
// Log.report(logvisor::Info, "Unsub X");
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!flags) {
|
||||
// This is now a leaf node
|
||||
for (int i = 0; i < 8; ++i)
|
||||
leaf |= childNodes[i].leaf;
|
||||
// Log.report(logvisor::Info, "Leaf Promote");
|
||||
return;
|
||||
|
||||
// Recurse in while building node structure
|
||||
if (level < VISI_MAX_LEVEL)
|
||||
{
|
||||
// Heuristic split
|
||||
int splits[3];
|
||||
splits[0] = (curAabb.max.x() - curAabb.min.x() >= VISI_MIN_LENGTH) ? 2 : 1;
|
||||
splits[1] = (curAabb.max.y() - curAabb.min.y() >= VISI_MIN_LENGTH) ? 2 : 1;
|
||||
splits[2] = (curAabb.max.z() - curAabb.min.z() >= VISI_MIN_LENGTH) ? 2 : 1;
|
||||
|
||||
if (splits[0] == 2)
|
||||
flags |= 0x1;
|
||||
if (splits[1] == 2)
|
||||
flags |= 0x2;
|
||||
if (splits[2] == 2)
|
||||
flags |= 0x4;
|
||||
|
||||
int thisdiv = splits[0] * splits[1] * splits[2] * divisions;
|
||||
|
||||
if (flags)
|
||||
{
|
||||
childNodes.resize(8);
|
||||
|
||||
// Inward subdivide
|
||||
zeus::CAABox Z[2];
|
||||
if (flags & 0x4)
|
||||
curAabb.splitZ(Z[0], Z[1]);
|
||||
else
|
||||
Z[0] = curAabb;
|
||||
for (int i=0 ; i<splits[2] ; ++i)
|
||||
{
|
||||
zeus::CAABox Y[2];
|
||||
if (flags & 0x2)
|
||||
Z[i].splitY(Y[0], Y[1]);
|
||||
else
|
||||
Y[0] = Z[i];
|
||||
for (int j=0 ; j<splits[1] ; ++j)
|
||||
{
|
||||
zeus::CAABox X[2];
|
||||
if (flags & 0x1)
|
||||
Y[j].splitX(X[0], X[1]);
|
||||
else
|
||||
X[0] = Y[j];
|
||||
for (int k=0 ; k<splits[0] ; ++k)
|
||||
{
|
||||
childNodes[i*4 + j*2 + k].buildChildren(level + 1, thisdiv, X[k], rc, prog, terminate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Outward unsubdivide for like-leaves
|
||||
for (int i=0 ; i<3 ; ++i)
|
||||
{
|
||||
if (flags & 0x4 &&
|
||||
childNodes[0] == childNodes[4] &&
|
||||
(!(flags & 0x1) || childNodes[1] == childNodes[5]) &&
|
||||
(!(flags & 0x2) || childNodes[2] == childNodes[6]) &&
|
||||
(!(flags & 0x3) || childNodes[3] == childNodes[7]))
|
||||
{
|
||||
flags &= ~0x4;
|
||||
//Log.report(logvisor::Info, "Unsub Z");
|
||||
continue;
|
||||
}
|
||||
if (flags & 0x2 &&
|
||||
childNodes[0] == childNodes[2] &&
|
||||
(!(flags & 0x1) || childNodes[1] == childNodes[3]) &&
|
||||
(!(flags & 0x4) || childNodes[4] == childNodes[6]) &&
|
||||
(!(flags & 0x5) || childNodes[5] == childNodes[7]))
|
||||
{
|
||||
flags &= ~0x2;
|
||||
//Log.report(logvisor::Info, "Unsub Y");
|
||||
continue;
|
||||
}
|
||||
if (flags & 0x1 &&
|
||||
childNodes[0] == childNodes[1] &&
|
||||
(!(flags & 0x2) || childNodes[2] == childNodes[3]) &&
|
||||
(!(flags & 0x4) || childNodes[4] == childNodes[5]) &&
|
||||
(!(flags & 0x6) || childNodes[6] == childNodes[7]))
|
||||
{
|
||||
flags &= ~0x1;
|
||||
//Log.report(logvisor::Info, "Unsub X");
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!flags)
|
||||
{
|
||||
// This is now a leaf node
|
||||
for (int i=0 ; i<8 ; ++i)
|
||||
leaf |= childNodes[i].leaf;
|
||||
//Log.report(logvisor::Info, "Leaf Promote");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!flags)
|
||||
{
|
||||
// This is a child node
|
||||
zeus::CVector3f center = curAabb.center();
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(curAabb.min.x(), curAabb.min.y(), curAabb.min.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(center.x(), curAabb.min.y(), curAabb.min.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(curAabb.max.x(), curAabb.min.y(), curAabb.min.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(curAabb.min.x(), center.y(), curAabb.min.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(center.x(), center.y(), curAabb.min.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(curAabb.max.x(), center.y(), curAabb.min.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(curAabb.min.x(), curAabb.max.y(), curAabb.min.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(center.x(), curAabb.max.y(), curAabb.min.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(curAabb.max.x(), curAabb.max.y(), curAabb.min.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(curAabb.min.x(), curAabb.min.y(), center.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(center.x(), curAabb.min.y(), center.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(curAabb.max.x(), curAabb.min.y(), center.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(curAabb.min.x(), center.y(), center.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(center.x(), center.y(), center.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(curAabb.max.x(), center.y(), center.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(curAabb.min.x(), curAabb.max.y(), center.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(center.x(), curAabb.max.y(), center.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(curAabb.max.x(), curAabb.max.y(), center.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(curAabb.min.x(), curAabb.min.y(), curAabb.max.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(center.x(), curAabb.min.y(), curAabb.max.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(curAabb.max.x(), curAabb.min.y(), curAabb.max.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(curAabb.min.x(), center.y(), curAabb.max.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(center.x(), center.y(), curAabb.max.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(curAabb.max.x(), center.y(), curAabb.max.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(curAabb.min.x(), curAabb.max.y(), curAabb.max.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(center.x(), curAabb.max.y(), curAabb.max.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(curAabb.max.x(), curAabb.max.y(), curAabb.max.z()));
|
||||
if (!flags) {
|
||||
// This is a child node
|
||||
zeus::CVector3f center = curAabb.center();
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(curAabb.min.x(), curAabb.min.y(), curAabb.min.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(center.x(), curAabb.min.y(), curAabb.min.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(curAabb.max.x(), curAabb.min.y(), curAabb.min.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(curAabb.min.x(), center.y(), curAabb.min.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(center.x(), center.y(), curAabb.min.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(curAabb.max.x(), center.y(), curAabb.min.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(curAabb.min.x(), curAabb.max.y(), curAabb.min.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(center.x(), curAabb.max.y(), curAabb.min.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(curAabb.max.x(), curAabb.max.y(), curAabb.min.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(curAabb.min.x(), curAabb.min.y(), center.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(center.x(), curAabb.min.y(), center.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(curAabb.max.x(), curAabb.min.y(), center.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(curAabb.min.x(), center.y(), center.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(center.x(), center.y(), center.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(curAabb.max.x(), center.y(), center.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(curAabb.min.x(), curAabb.max.y(), center.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(center.x(), curAabb.max.y(), center.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(curAabb.max.x(), curAabb.max.y(), center.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(curAabb.min.x(), curAabb.min.y(), curAabb.max.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(center.x(), curAabb.min.y(), curAabb.max.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(curAabb.max.x(), curAabb.min.y(), curAabb.max.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(curAabb.min.x(), center.y(), curAabb.max.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(center.x(), center.y(), curAabb.max.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(curAabb.max.x(), center.y(), curAabb.max.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(curAabb.min.x(), curAabb.max.y(), curAabb.max.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(center.x(), curAabb.max.y(), curAabb.max.z()));
|
||||
leaf |= rc.GetLeaf(zeus::CVector3f(curAabb.max.x(), curAabb.max.y(), curAabb.max.z()));
|
||||
|
||||
prog.report(divisions);
|
||||
}
|
||||
prog.report(divisions);
|
||||
}
|
||||
}
|
||||
|
||||
static const int NumChildTable[] =
|
||||
{
|
||||
0, 2, 2, 4, 2, 4, 4, 8
|
||||
};
|
||||
static const int NumChildTable[] = {0, 2, 2, 4, 2, 4, 4, 8};
|
||||
|
||||
void VISIBuilder::Node::calculateSizesAndOffs(size_t& cur, size_t leafSz)
|
||||
{
|
||||
cur += 1;
|
||||
flags |= 0x18;
|
||||
void VISIBuilder::Node::calculateSizesAndOffs(size_t& cur, size_t leafSz) {
|
||||
cur += 1;
|
||||
flags |= 0x18;
|
||||
|
||||
if (flags & 0x7)
|
||||
{
|
||||
int splits[3];
|
||||
splits[0] = (flags & 0x1) ? 2 : 1;
|
||||
splits[1] = (flags & 0x2) ? 2 : 1;
|
||||
splits[2] = (flags & 0x4) ? 2 : 1;
|
||||
if (flags & 0x7) {
|
||||
int splits[3];
|
||||
splits[0] = (flags & 0x1) ? 2 : 1;
|
||||
splits[1] = (flags & 0x2) ? 2 : 1;
|
||||
splits[2] = (flags & 0x4) ? 2 : 1;
|
||||
|
||||
// Inward accumulate
|
||||
const size_t startCur = cur;
|
||||
size_t maxDelta = 0;
|
||||
for (int i=0 ; i<splits[2] ; ++i)
|
||||
for (int j=0 ; j<splits[1] ; ++j)
|
||||
for (int k=0 ; k<splits[0] ; ++k)
|
||||
{
|
||||
const size_t nodeSel = i*4 + j*2 + k;
|
||||
const size_t delta = cur - startCur;
|
||||
if (delta > maxDelta)
|
||||
maxDelta = delta;
|
||||
childRelOffs[nodeSel] = delta;
|
||||
childNodes[nodeSel].calculateSizesAndOffs(cur, leafSz);
|
||||
}
|
||||
|
||||
const int numChildren = NumChildTable[flags & 0x7];
|
||||
if (maxDelta > 0xffff)
|
||||
{
|
||||
cur += (numChildren - 1) * 3;
|
||||
flags |= 0x40;
|
||||
}
|
||||
else if (maxDelta > 0xff)
|
||||
{
|
||||
cur += (numChildren - 1) * 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
cur += numChildren - 1;
|
||||
flags |= 0x20;
|
||||
// Inward accumulate
|
||||
const size_t startCur = cur;
|
||||
size_t maxDelta = 0;
|
||||
for (int i = 0; i < splits[2]; ++i)
|
||||
for (int j = 0; j < splits[1]; ++j)
|
||||
for (int k = 0; k < splits[0]; ++k) {
|
||||
const size_t nodeSel = i * 4 + j * 2 + k;
|
||||
const size_t delta = cur - startCur;
|
||||
if (delta > maxDelta)
|
||||
maxDelta = delta;
|
||||
childRelOffs[nodeSel] = delta;
|
||||
childNodes[nodeSel].calculateSizesAndOffs(cur, leafSz);
|
||||
}
|
||||
|
||||
const int numChildren = NumChildTable[flags & 0x7];
|
||||
if (maxDelta > 0xffff) {
|
||||
cur += (numChildren - 1) * 3;
|
||||
flags |= 0x40;
|
||||
} else if (maxDelta > 0xff) {
|
||||
cur += (numChildren - 1) * 2;
|
||||
} else {
|
||||
cur += numChildren - 1;
|
||||
flags |= 0x20;
|
||||
}
|
||||
} else {
|
||||
if (!leaf)
|
||||
flags &= ~0x8;
|
||||
else
|
||||
{
|
||||
if (!leaf)
|
||||
flags &= ~0x8;
|
||||
else
|
||||
cur += leafSz;
|
||||
}
|
||||
cur += leafSz;
|
||||
}
|
||||
}
|
||||
|
||||
void VISIBuilder::Node::writeNodes(athena::io::MemoryWriter& w, size_t leafBytes) const
|
||||
{
|
||||
w.writeUByte(flags);
|
||||
void VISIBuilder::Node::writeNodes(athena::io::MemoryWriter& w, size_t leafBytes) const {
|
||||
w.writeUByte(flags);
|
||||
|
||||
if (flags & 0x7)
|
||||
{
|
||||
int splits[3];
|
||||
splits[0] = (flags & 0x1) ? 2 : 1;
|
||||
splits[1] = (flags & 0x2) ? 2 : 1;
|
||||
splits[2] = (flags & 0x4) ? 2 : 1;
|
||||
if (flags & 0x7) {
|
||||
int splits[3];
|
||||
splits[0] = (flags & 0x1) ? 2 : 1;
|
||||
splits[1] = (flags & 0x2) ? 2 : 1;
|
||||
splits[2] = (flags & 0x4) ? 2 : 1;
|
||||
|
||||
// Write offsets
|
||||
for (int i=0 ; i<splits[2] ; ++i)
|
||||
for (int j=0 ; j<splits[1] ; ++j)
|
||||
for (int k=0 ; k<splits[0] ; ++k)
|
||||
{
|
||||
const size_t nodeSel = i*4 + j*2 + k;
|
||||
if (nodeSel == 0)
|
||||
continue;
|
||||
const size_t offset = childRelOffs[nodeSel];
|
||||
if (flags & 0x40)
|
||||
{
|
||||
w.writeUByte((offset >> 16) & 0xff);
|
||||
w.writeUByte((offset >> 8) & 0xff);
|
||||
w.writeUByte(offset & 0xff);
|
||||
}
|
||||
else if (flags & 0x20)
|
||||
{
|
||||
w.writeUByte(offset & 0xff);
|
||||
}
|
||||
else
|
||||
{
|
||||
w.writeUint16Big(offset);
|
||||
}
|
||||
}
|
||||
// Write offsets
|
||||
for (int i = 0; i < splits[2]; ++i)
|
||||
for (int j = 0; j < splits[1]; ++j)
|
||||
for (int k = 0; k < splits[0]; ++k) {
|
||||
const size_t nodeSel = i * 4 + j * 2 + k;
|
||||
if (nodeSel == 0)
|
||||
continue;
|
||||
const size_t offset = childRelOffs[nodeSel];
|
||||
if (flags & 0x40) {
|
||||
w.writeUByte((offset >> 16) & 0xff);
|
||||
w.writeUByte((offset >> 8) & 0xff);
|
||||
w.writeUByte(offset & 0xff);
|
||||
} else if (flags & 0x20) {
|
||||
w.writeUByte(offset & 0xff);
|
||||
} else {
|
||||
w.writeUint16Big(offset);
|
||||
}
|
||||
}
|
||||
|
||||
// Inward iterate
|
||||
for (int i=0 ; i<splits[2] ; ++i)
|
||||
for (int j=0 ; j<splits[1] ; ++j)
|
||||
for (int k=0 ; k<splits[0] ; ++k)
|
||||
{
|
||||
const size_t nodeSel = i*4 + j*2 + k;
|
||||
childNodes[nodeSel].writeNodes(w, leafBytes);
|
||||
}
|
||||
}
|
||||
else if (leaf)
|
||||
{
|
||||
leaf.write(w, leafBytes);
|
||||
}
|
||||
// Inward iterate
|
||||
for (int i = 0; i < splits[2]; ++i)
|
||||
for (int j = 0; j < splits[1]; ++j)
|
||||
for (int k = 0; k < splits[0]; ++k) {
|
||||
const size_t nodeSel = i * 4 + j * 2 + k;
|
||||
childNodes[nodeSel].writeNodes(w, leafBytes);
|
||||
}
|
||||
} else if (leaf) {
|
||||
leaf.write(w, leafBytes);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint8_t> VISIBuilder::build(const zeus::CAABox& fullAabb,
|
||||
size_t modelCount,
|
||||
std::vector<uint8_t> VISIBuilder::build(const zeus::CAABox& fullAabb, size_t modelCount,
|
||||
const std::vector<VISIRenderer::Entity>& entities,
|
||||
const std::vector<VISIRenderer::Light>& lights,
|
||||
size_t layer2LightCount,
|
||||
FPercent updatePercent,
|
||||
ProcessType parentPid)
|
||||
{
|
||||
//Log.report(logvisor::Info, "Started!");
|
||||
const std::vector<VISIRenderer::Light>& lights, size_t layer2LightCount,
|
||||
FPercent updatePercent, ProcessType parentPid) {
|
||||
// Log.report(logvisor::Info, "Started!");
|
||||
|
||||
size_t featureCount = modelCount + entities.size();
|
||||
renderCache.m_lightMetaBit = featureCount;
|
||||
size_t featureCount = modelCount + entities.size();
|
||||
renderCache.m_lightMetaBit = featureCount;
|
||||
|
||||
Progress prog(updatePercent);
|
||||
Progress prog(updatePercent);
|
||||
#ifndef _WIN32
|
||||
parentPid = getppid();
|
||||
auto terminate = [this, parentPid]()
|
||||
{
|
||||
return renderCache.m_renderer.m_terminate || (parentPid ? kill(parentPid, 0) : false);
|
||||
};
|
||||
parentPid = getppid();
|
||||
auto terminate = [this, parentPid]() {
|
||||
return renderCache.m_renderer.m_terminate || (parentPid ? kill(parentPid, 0) : false);
|
||||
};
|
||||
#else
|
||||
auto terminate = [this, parentPid]()
|
||||
{
|
||||
DWORD exitCode = 0;
|
||||
if (!GetExitCodeProcess(parentPid, &exitCode))
|
||||
return renderCache.m_renderer.m_terminate;
|
||||
return renderCache.m_renderer.m_terminate || (parentPid ? exitCode != STILL_ACTIVE : false);
|
||||
};
|
||||
auto terminate = [this, parentPid]() {
|
||||
DWORD exitCode = 0;
|
||||
if (!GetExitCodeProcess(parentPid, &exitCode))
|
||||
return renderCache.m_renderer.m_terminate;
|
||||
return renderCache.m_renderer.m_terminate || (parentPid ? exitCode != STILL_ACTIVE : false);
|
||||
};
|
||||
#endif
|
||||
rootNode.buildChildren(0, 1, fullAabb, renderCache, prog, terminate);
|
||||
if (terminate())
|
||||
return {};
|
||||
rootNode.buildChildren(0, 1, fullAabb, renderCache, prog, terminate);
|
||||
if (terminate())
|
||||
return {};
|
||||
|
||||
// Lights cache their CPVSVisSet result enum as 2 bits
|
||||
size_t leafBitsCount = featureCount + lights.size() * 2;
|
||||
size_t leafBytesCount = ROUND_UP_8(leafBitsCount) / 8;
|
||||
// Lights cache their CPVSVisSet result enum as 2 bits
|
||||
size_t leafBitsCount = featureCount + lights.size() * 2;
|
||||
size_t leafBytesCount = ROUND_UP_8(leafBitsCount) / 8;
|
||||
|
||||
// Calculate octree size and store relative offsets
|
||||
size_t octreeSz = 0;
|
||||
rootNode.calculateSizesAndOffs(octreeSz, leafBytesCount);
|
||||
// Calculate octree size and store relative offsets
|
||||
size_t octreeSz = 0;
|
||||
rootNode.calculateSizesAndOffs(octreeSz, leafBytesCount);
|
||||
|
||||
size_t visiSz = 34 + entities.size() * 4 + lights.size() * leafBytesCount + 36 + octreeSz;
|
||||
size_t roundedVisiSz = ROUND_UP_32(visiSz);
|
||||
size_t visiSz = 34 + entities.size() * 4 + lights.size() * leafBytesCount + 36 + octreeSz;
|
||||
size_t roundedVisiSz = ROUND_UP_32(visiSz);
|
||||
|
||||
std::vector<uint8_t> dataOut(roundedVisiSz, 0);
|
||||
athena::io::MemoryWriter w(dataOut.data(), roundedVisiSz);
|
||||
w.writeUint32Big('VISI');
|
||||
w.writeUint32Big(2);
|
||||
w.writeBool(true);
|
||||
w.writeBool(true);
|
||||
w.writeUint32Big(featureCount);
|
||||
w.writeUint32Big(lights.size());
|
||||
w.writeUint32Big(layer2LightCount);
|
||||
w.writeUint32Big(entities.size());
|
||||
w.writeUint32Big(leafBytesCount);
|
||||
w.writeUint32Big(lights.size());
|
||||
std::vector<uint8_t> dataOut(roundedVisiSz, 0);
|
||||
athena::io::MemoryWriter w(dataOut.data(), roundedVisiSz);
|
||||
w.writeUint32Big('VISI');
|
||||
w.writeUint32Big(2);
|
||||
w.writeBool(true);
|
||||
w.writeBool(true);
|
||||
w.writeUint32Big(featureCount);
|
||||
w.writeUint32Big(lights.size());
|
||||
w.writeUint32Big(layer2LightCount);
|
||||
w.writeUint32Big(entities.size());
|
||||
w.writeUint32Big(leafBytesCount);
|
||||
w.writeUint32Big(lights.size());
|
||||
|
||||
for (const VISIRenderer::Entity& e : entities)
|
||||
{
|
||||
w.writeUint32Big(e.entityId);
|
||||
}
|
||||
for (const VISIRenderer::Entity& e : entities) {
|
||||
w.writeUint32Big(e.entityId);
|
||||
}
|
||||
|
||||
for (const VISIRenderer::Light& l : lights)
|
||||
{
|
||||
const VISIBuilder::Leaf& leaf = renderCache.GetLeaf(l.point);
|
||||
leaf.write(w, leafBytesCount);
|
||||
}
|
||||
for (const VISIRenderer::Light& l : lights) {
|
||||
const VISIBuilder::Leaf& leaf = renderCache.GetLeaf(l.point);
|
||||
leaf.write(w, leafBytesCount);
|
||||
}
|
||||
|
||||
w.writeVec3fBig(fullAabb.min);
|
||||
w.writeVec3fBig(fullAabb.max);
|
||||
w.writeUint32Big(featureCount + lights.size());
|
||||
w.writeUint32Big(lights.size());
|
||||
w.writeUint32Big(octreeSz);
|
||||
rootNode.writeNodes(w, leafBytesCount);
|
||||
w.writeVec3fBig(fullAabb.min);
|
||||
w.writeVec3fBig(fullAabb.max);
|
||||
w.writeUint32Big(featureCount + lights.size());
|
||||
w.writeUint32Big(lights.size());
|
||||
w.writeUint32Big(octreeSz);
|
||||
rootNode.writeNodes(w, leafBytesCount);
|
||||
|
||||
w.seekAlign32();
|
||||
w.seekAlign32();
|
||||
|
||||
//Log.report(logvisor::Info, "Finished!");
|
||||
return dataOut;
|
||||
// Log.report(logvisor::Info, "Finished!");
|
||||
return dataOut;
|
||||
}
|
||||
|
||||
@@ -12,125 +12,106 @@ using ProcessType = HANDLE;
|
||||
using ProcessType = pid_t;
|
||||
#endif
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <> struct hash<zeus::CVector3f>
|
||||
{
|
||||
size_t operator()(const zeus::CVector3f& val) const noexcept
|
||||
{
|
||||
zeus::simd_floats f(val.mSimd);
|
||||
return XXH64(&f[0], 12, 0);
|
||||
namespace std {
|
||||
template <>
|
||||
struct hash<zeus::CVector3f> {
|
||||
size_t operator()(const zeus::CVector3f& val) const noexcept {
|
||||
zeus::simd_floats f(val.mSimd);
|
||||
return XXH64(&f[0], 12, 0);
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
|
||||
struct VISIBuilder {
|
||||
struct Leaf {
|
||||
std::vector<uint8_t> bits;
|
||||
void setBit(size_t bit) {
|
||||
size_t byte = bit / 8;
|
||||
if (byte >= bits.size())
|
||||
bits.resize(byte + 1);
|
||||
bits[byte] |= 1 << (bit & 0x7);
|
||||
}
|
||||
void setLightEnum(size_t bit, EPVSVisSetState state) {
|
||||
size_t byte0 = bit / 8;
|
||||
size_t byte1 = (bit + 1) / 8;
|
||||
if (byte1 >= bits.size())
|
||||
bits.resize(byte1 + 1);
|
||||
|
||||
if (byte0 == byte1) {
|
||||
bits[byte0] |= int(state) << (bit & 0x7);
|
||||
} else {
|
||||
bits[byte0] |= (int(state) << 7) & 0x1;
|
||||
bits[byte1] |= (int(state) >> 1) & 0x1;
|
||||
}
|
||||
}
|
||||
bool operator==(const Leaf& other) const {
|
||||
if (bits.size() != other.bits.size())
|
||||
return false;
|
||||
if (memcmp(bits.data(), other.bits.data(), bits.size()))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
Leaf& operator|=(const Leaf& other) {
|
||||
if (bits.size() < other.bits.size())
|
||||
bits.resize(other.bits.size());
|
||||
for (int i = 0; i < other.bits.size(); ++i)
|
||||
bits[i] |= other.bits[i];
|
||||
return *this;
|
||||
}
|
||||
operator bool() const { return bits.size() != 0; }
|
||||
|
||||
void write(athena::io::MemoryWriter& w, size_t leafBytes) const {
|
||||
for (size_t i = 0; i < leafBytes; ++i) {
|
||||
if (i < bits.size())
|
||||
w.writeUByte(bits[i]);
|
||||
else
|
||||
w.writeUByte(0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class PVSRenderCache {
|
||||
friend struct VISIBuilder;
|
||||
VISIRenderer& m_renderer;
|
||||
std::unordered_map<zeus::CVector3f, std::unique_ptr<Leaf>> m_cache;
|
||||
size_t m_lightMetaBit;
|
||||
|
||||
public:
|
||||
PVSRenderCache(VISIRenderer& renderer);
|
||||
const Leaf& GetLeaf(const zeus::CVector3f& vec);
|
||||
} renderCache;
|
||||
|
||||
class Progress {
|
||||
float m_prog = 0.f;
|
||||
FPercent m_updatePercent;
|
||||
|
||||
public:
|
||||
void report(int divisions);
|
||||
Progress(FPercent updatePercent) : m_updatePercent(updatePercent) {}
|
||||
};
|
||||
|
||||
struct Node {
|
||||
std::vector<Node> childNodes;
|
||||
size_t childRelOffs[8] = {};
|
||||
Leaf leaf;
|
||||
uint8_t flags = 0;
|
||||
|
||||
void buildChildren(int level, int divisions, const zeus::CAABox& curAabb, PVSRenderCache& rc, Progress& prog,
|
||||
const std::function<bool()>& terminate);
|
||||
void calculateSizesAndOffs(size_t& cur, size_t leafSz);
|
||||
void writeNodes(athena::io::MemoryWriter& w, size_t leafBytes) const;
|
||||
|
||||
bool operator==(const Node& other) const {
|
||||
if ((flags & 0x7) || (other.flags & 0x7))
|
||||
return false;
|
||||
return leaf == other.leaf;
|
||||
}
|
||||
} rootNode;
|
||||
|
||||
std::vector<uint8_t> build(const zeus::CAABox& fullAabb, size_t modelCount,
|
||||
const std::vector<VISIRenderer::Entity>& entities,
|
||||
const std::vector<VISIRenderer::Light>& lights, size_t layer2LightCount,
|
||||
FPercent updatePercent, ProcessType parentPid);
|
||||
|
||||
VISIBuilder(VISIRenderer& renderer) : renderCache(renderer) {}
|
||||
};
|
||||
}
|
||||
|
||||
struct VISIBuilder
|
||||
{
|
||||
struct Leaf
|
||||
{
|
||||
std::vector<uint8_t> bits;
|
||||
void setBit(size_t bit)
|
||||
{
|
||||
size_t byte = bit / 8;
|
||||
if (byte >= bits.size())
|
||||
bits.resize(byte + 1);
|
||||
bits[byte] |= 1 << (bit & 0x7);
|
||||
}
|
||||
void setLightEnum(size_t bit, EPVSVisSetState state)
|
||||
{
|
||||
size_t byte0 = bit / 8;
|
||||
size_t byte1 = (bit + 1) / 8;
|
||||
if (byte1 >= bits.size())
|
||||
bits.resize(byte1 + 1);
|
||||
|
||||
if (byte0 == byte1)
|
||||
{
|
||||
bits[byte0] |= int(state) << (bit & 0x7);
|
||||
}
|
||||
else
|
||||
{
|
||||
bits[byte0] |= (int(state) << 7) & 0x1;
|
||||
bits[byte1] |= (int(state) >> 1) & 0x1;
|
||||
}
|
||||
}
|
||||
bool operator==(const Leaf& other) const
|
||||
{
|
||||
if (bits.size() != other.bits.size())
|
||||
return false;
|
||||
if (memcmp(bits.data(), other.bits.data(), bits.size()))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
Leaf& operator|=(const Leaf& other)
|
||||
{
|
||||
if (bits.size() < other.bits.size())
|
||||
bits.resize(other.bits.size());
|
||||
for (int i=0 ; i<other.bits.size() ; ++i)
|
||||
bits[i] |= other.bits[i];
|
||||
return *this;
|
||||
}
|
||||
operator bool() const { return bits.size() != 0; }
|
||||
|
||||
void write(athena::io::MemoryWriter& w, size_t leafBytes) const
|
||||
{
|
||||
for (size_t i=0 ; i<leafBytes ; ++i)
|
||||
{
|
||||
if (i < bits.size())
|
||||
w.writeUByte(bits[i]);
|
||||
else
|
||||
w.writeUByte(0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class PVSRenderCache
|
||||
{
|
||||
friend struct VISIBuilder;
|
||||
VISIRenderer& m_renderer;
|
||||
std::unordered_map<zeus::CVector3f, std::unique_ptr<Leaf>> m_cache;
|
||||
size_t m_lightMetaBit;
|
||||
public:
|
||||
PVSRenderCache(VISIRenderer& renderer);
|
||||
const Leaf& GetLeaf(const zeus::CVector3f& vec);
|
||||
} renderCache;
|
||||
|
||||
class Progress
|
||||
{
|
||||
float m_prog = 0.f;
|
||||
FPercent m_updatePercent;
|
||||
public:
|
||||
void report(int divisions);
|
||||
Progress(FPercent updatePercent) : m_updatePercent(updatePercent) {}
|
||||
};
|
||||
|
||||
struct Node
|
||||
{
|
||||
std::vector<Node> childNodes;
|
||||
size_t childRelOffs[8] = {};
|
||||
Leaf leaf;
|
||||
uint8_t flags = 0;
|
||||
|
||||
void buildChildren(int level, int divisions, const zeus::CAABox& curAabb,
|
||||
PVSRenderCache& rc, Progress& prog, const std::function<bool()>& terminate);
|
||||
void calculateSizesAndOffs(size_t& cur, size_t leafSz);
|
||||
void writeNodes(athena::io::MemoryWriter& w, size_t leafBytes) const;
|
||||
|
||||
bool operator==(const Node& other) const
|
||||
{
|
||||
if ((flags & 0x7) || (other.flags & 0x7))
|
||||
return false;
|
||||
return leaf == other.leaf;
|
||||
}
|
||||
} rootNode;
|
||||
|
||||
std::vector<uint8_t> build(const zeus::CAABox& fullAabb,
|
||||
size_t modelCount,
|
||||
const std::vector<VISIRenderer::Entity>& entities,
|
||||
const std::vector<VISIRenderer::Light>& lights,
|
||||
size_t layer2LightCount,
|
||||
FPercent updatePercent,
|
||||
ProcessType parentPid);
|
||||
|
||||
VISIBuilder(VISIRenderer& renderer) : renderCache(renderer) {}
|
||||
};
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,104 +6,89 @@
|
||||
#include "zeus/CMatrix4f.hpp"
|
||||
#include "zeus/CAABox.hpp"
|
||||
|
||||
typedef void(*FPercent)(float);
|
||||
typedef void (*FPercent)(float);
|
||||
|
||||
enum class EPVSVisSetState
|
||||
{
|
||||
EndOfTree,
|
||||
NodeFound,
|
||||
OutOfBounds
|
||||
};
|
||||
enum class EPVSVisSetState { EndOfTree, NodeFound, OutOfBounds };
|
||||
|
||||
class VISIRenderer
|
||||
{
|
||||
friend struct VISIBuilder;
|
||||
class VISIRenderer {
|
||||
friend struct VISIBuilder;
|
||||
|
||||
int m_argc;
|
||||
const hecl::SystemChar** m_argv;
|
||||
int m_return = 0;
|
||||
int m_argc;
|
||||
const hecl::SystemChar** m_argv;
|
||||
int m_return = 0;
|
||||
|
||||
zeus::CAABox m_totalAABB;
|
||||
zeus::CAABox m_totalAABB;
|
||||
|
||||
struct UniformBuffer
|
||||
{
|
||||
zeus::CMatrix4f m_xf;
|
||||
} m_uniformBuffer;
|
||||
struct UniformBuffer {
|
||||
zeus::CMatrix4f m_xf;
|
||||
} m_uniformBuffer;
|
||||
|
||||
struct Model
|
||||
{
|
||||
GLenum topology;
|
||||
zeus::CAABox aabb;
|
||||
struct Model {
|
||||
GLenum topology;
|
||||
zeus::CAABox aabb;
|
||||
|
||||
struct Vert
|
||||
{
|
||||
zeus::CVector3f pos;
|
||||
zeus::CColor color;
|
||||
};
|
||||
std::vector<Vert> verts;
|
||||
|
||||
std::vector<uint32_t> idxs;
|
||||
GLuint vbo, ibo, vao;
|
||||
|
||||
struct Surface
|
||||
{
|
||||
uint32_t first;
|
||||
uint32_t count;
|
||||
bool transparent;
|
||||
};
|
||||
std::vector<Surface> surfaces;
|
||||
struct Vert {
|
||||
zeus::CVector3f pos;
|
||||
zeus::CColor color;
|
||||
};
|
||||
std::vector<Vert> verts;
|
||||
|
||||
struct Entity
|
||||
{
|
||||
uint32_t entityId;
|
||||
zeus::CAABox aabb;
|
||||
GLuint vbo, vao;
|
||||
std::vector<uint32_t> idxs;
|
||||
GLuint vbo, ibo, vao;
|
||||
|
||||
struct Surface {
|
||||
uint32_t first;
|
||||
uint32_t count;
|
||||
bool transparent;
|
||||
};
|
||||
std::vector<Surface> surfaces;
|
||||
};
|
||||
|
||||
struct Light
|
||||
{
|
||||
zeus::CVector3f point;
|
||||
GLuint vbo, vao;
|
||||
};
|
||||
struct Entity {
|
||||
uint32_t entityId;
|
||||
zeus::CAABox aabb;
|
||||
GLuint vbo, vao;
|
||||
};
|
||||
|
||||
GLuint m_vtxShader, m_fragShader, m_program, m_uniLoc;
|
||||
GLuint m_uniformBufferGL;
|
||||
GLuint m_aabbIBO;
|
||||
bool SetupShaders();
|
||||
struct Light {
|
||||
zeus::CVector3f point;
|
||||
GLuint vbo, vao;
|
||||
};
|
||||
|
||||
std::vector<Model> m_models;
|
||||
std::vector<Entity> m_entities;
|
||||
std::vector<Light> m_lights;
|
||||
bool SetupVertexBuffersAndFormats();
|
||||
GLuint m_vtxShader, m_fragShader, m_program, m_uniLoc;
|
||||
GLuint m_uniformBufferGL;
|
||||
GLuint m_aabbIBO;
|
||||
bool SetupShaders();
|
||||
|
||||
size_t m_queryCount;
|
||||
std::unique_ptr<GLuint[]> m_queries;
|
||||
std::unique_ptr<bool[]> m_queryBools;
|
||||
std::vector<Model> m_models;
|
||||
std::vector<Entity> m_entities;
|
||||
std::vector<Light> m_lights;
|
||||
bool SetupVertexBuffersAndFormats();
|
||||
|
||||
FPercent m_updatePercent;
|
||||
size_t m_queryCount;
|
||||
std::unique_ptr<GLuint[]> m_queries;
|
||||
std::unique_ptr<bool[]> m_queryBools;
|
||||
|
||||
static std::vector<Model::Vert> AABBToVerts(const zeus::CAABox& aabb,
|
||||
const zeus::CColor& color);
|
||||
FPercent m_updatePercent;
|
||||
|
||||
static std::vector<Model::Vert> AABBToVerts(const zeus::CAABox& aabb, const zeus::CColor& color);
|
||||
|
||||
public:
|
||||
bool m_terminate = false;
|
||||
struct RGBA8
|
||||
{
|
||||
uint8_t r;
|
||||
uint8_t g;
|
||||
uint8_t b;
|
||||
uint8_t a;
|
||||
};
|
||||
bool m_terminate = false;
|
||||
struct RGBA8 {
|
||||
uint8_t r;
|
||||
uint8_t g;
|
||||
uint8_t b;
|
||||
uint8_t a;
|
||||
};
|
||||
|
||||
VISIRenderer(int argc, const hecl::SystemChar** argv) : m_argc(argc), m_argv(argv) {}
|
||||
void Run(FPercent updatePercent);
|
||||
void Terminate();
|
||||
void RenderPVSOpaque(RGBA8* bufOut, const zeus::CVector3f& pos, bool& needTransparent);
|
||||
void RenderPVSTransparent(const std::function<void(int)>& passFunc, const zeus::CVector3f& pos);
|
||||
void RenderPVSEntitiesAndLights(const std::function<void(int)>& passFunc,
|
||||
const std::function<void(int, EPVSVisSetState)>& lightPassFunc,
|
||||
const zeus::CVector3f& pos);
|
||||
int ReturnVal() const { return m_return; }
|
||||
VISIRenderer(int argc, const hecl::SystemChar** argv) : m_argc(argc), m_argv(argv) {}
|
||||
void Run(FPercent updatePercent);
|
||||
void Terminate();
|
||||
void RenderPVSOpaque(RGBA8* bufOut, const zeus::CVector3f& pos, bool& needTransparent);
|
||||
void RenderPVSTransparent(const std::function<void(int)>& passFunc, const zeus::CVector3f& pos);
|
||||
void RenderPVSEntitiesAndLights(const std::function<void(int)>& passFunc,
|
||||
const std::function<void(int, EPVSVisSetState)>& lightPassFunc,
|
||||
const zeus::CVector3f& pos);
|
||||
int ReturnVal() const { return m_return; }
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user