VDB palettes: three dedicated 640x480 live windows (not strips)
Replace the in-render-window palette strips with three separate 640x480 windows, one per VDB display palette (secondary/aux1/aux2). Each has its own GL context (rt_main wglMakeCurrent-s each per tick) and shows the palette as a 16x16 color grid, redrawn every 50ms so it animates live regardless of the VPX render cadence. make_gl_window() factored out; strips + VPX_VDBSTRIP removed. Confirmed live: aux1 = red/green/olive/black status checkerboard, aux2 = a 4-region color map (green/blue/red/purple, 64 entries each), secondary = the animated one (black between flashes). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -410,7 +410,6 @@ static void vpx_write(Bitu port, Bitu val, Bitu iolen) {
|
|||||||
* Declared here so rt_draw() below can see it. */
|
* Declared here so rt_draw() below can see it. */
|
||||||
struct VDBPalette { unsigned char waddr, raddr, sub, mask; unsigned char ram[768]; };
|
struct VDBPalette { unsigned char waddr, raddr, sub, mask; unsigned char ram[768]; };
|
||||||
static VDBPalette vdb_pal[3];
|
static VDBPalette vdb_pal[3];
|
||||||
static bool vpx_show_vdb_strips = true; /* draw live palette strips (VPX_VDBSTRIP=0 off) */
|
|
||||||
|
|
||||||
/* ================= Phase 3b: live render backend (VPX_RENDER=1) ==========
|
/* ================= Phase 3b: live render backend (VPX_RENDER=1) ==========
|
||||||
* Reconstructs the DPL scene graph from the FIFO message stream (protocol
|
* Reconstructs the DPL scene graph from the FIFO message stream (protocol
|
||||||
@@ -650,34 +649,30 @@ static void rt_draw(HDC dc, const VFrame &f, int cw, int ch) {
|
|||||||
glDisable(GL_TEXTURE_2D);
|
glDisable(GL_TEXTURE_2D);
|
||||||
glDisable(GL_LIGHTING);
|
glDisable(GL_LIGHTING);
|
||||||
}
|
}
|
||||||
/* Live VDB palette strips: the three display color maps (secondary/aux1/
|
SwapBuffers(dc);
|
||||||
* aux2) as 256-wide bars along the bottom, updating in real time as the
|
}
|
||||||
* game rewrites them (VPX_VDBSTRIP=0 to hide). Read straight from the VDB
|
|
||||||
* storage -- a torn read is invisible at this cadence. */
|
/* ---- VDB palette windows: one 640x480 window per display palette ---------
|
||||||
if (vpx_show_vdb_strips) {
|
* Each shows a 16x16 grid of the 256 colors, updated live. */
|
||||||
glDisable(GL_DEPTH_TEST);
|
static void pal_draw(HDC dc, int g, int cw, int ch) {
|
||||||
glDisable(GL_TEXTURE_2D);
|
glViewport(0, 0, cw, ch);
|
||||||
glDisable(GL_LIGHTING);
|
glClearColor(0.09f, 0.09f, 0.11f, 1.0f);
|
||||||
glMatrixMode(GL_PROJECTION); glLoadIdentity();
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
glOrtho(0, cw, ch, 0, -1, 1); /* screen pixels, y-down */
|
glDisable(GL_DEPTH_TEST);
|
||||||
glMatrixMode(GL_MODELVIEW); glLoadIdentity();
|
glDisable(GL_TEXTURE_2D);
|
||||||
int barh = 16, gap = 2;
|
glDisable(GL_LIGHTING);
|
||||||
int total = 3 * barh + 2 * gap;
|
glMatrixMode(GL_PROJECTION); glLoadIdentity();
|
||||||
int y0 = ch - total - 4;
|
glOrtho(0, 16, 16, 0, -1, 1); /* 16x16 grid, y-down */
|
||||||
for (int g = 0; g < 3; g++) {
|
glMatrixMode(GL_MODELVIEW); glLoadIdentity();
|
||||||
float y = (float)(y0 + g * (barh + gap));
|
glBegin(GL_QUADS);
|
||||||
glBegin(GL_QUADS);
|
for (int i = 0; i < 256; i++) {
|
||||||
for (int i = 0; i < 256; i++) {
|
float x = (float)(i % 16), y = (float)(i / 16);
|
||||||
float x0 = (float)i / 256.0f * cw;
|
const unsigned char *e = &vdb_pal[g].ram[i * 3];
|
||||||
float x1 = (float)(i + 1) / 256.0f * cw;
|
glColor3ub(e[0], e[1], e[2]);
|
||||||
const unsigned char *e = &vdb_pal[g].ram[i * 3];
|
glVertex2f(x, y); glVertex2f(x + 1, y);
|
||||||
glColor3ub(e[0], e[1], e[2]);
|
glVertex2f(x + 1, y + 1); glVertex2f(x, y + 1);
|
||||||
glVertex2f(x0, y); glVertex2f(x1, y);
|
|
||||||
glVertex2f(x1, y + barh); glVertex2f(x0, y + barh);
|
|
||||||
}
|
|
||||||
glEnd();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
glEnd();
|
||||||
SwapBuffers(dc);
|
SwapBuffers(dc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -686,6 +681,28 @@ static LRESULT CALLBACK rt_wndproc(HWND w, UINT msg, WPARAM wp, LPARAM lp) {
|
|||||||
return DefWindowProcA(w, msg, wp, lp);
|
return DefWindowProcA(w, msg, wp, lp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Create a visible window with its own GL context (each window gets its own
|
||||||
|
* so we can render several from one thread by wglMakeCurrent-ing each). */
|
||||||
|
static bool make_gl_window(const char *title, int w, int h, int x, int y,
|
||||||
|
HWND *out_wnd, HDC *out_dc, HGLRC *out_gl) {
|
||||||
|
RECT r = { 0, 0, w, h };
|
||||||
|
AdjustWindowRect(&r, WS_OVERLAPPEDWINDOW, FALSE);
|
||||||
|
HWND wnd = CreateWindowA("VPXGL", title, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
|
||||||
|
x, y, r.right - r.left, r.bottom - r.top, NULL, NULL,
|
||||||
|
GetModuleHandleA(NULL), NULL);
|
||||||
|
if (!wnd) return false;
|
||||||
|
HDC dc = GetDC(wnd);
|
||||||
|
PIXELFORMATDESCRIPTOR pfd; memset(&pfd, 0, sizeof pfd);
|
||||||
|
pfd.nSize = sizeof pfd; pfd.nVersion = 1;
|
||||||
|
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
|
||||||
|
pfd.iPixelType = PFD_TYPE_RGBA; pfd.cColorBits = 24; pfd.cDepthBits = 24;
|
||||||
|
SetPixelFormat(dc, ChoosePixelFormat(dc, &pfd), &pfd);
|
||||||
|
HGLRC gl = wglCreateContext(dc);
|
||||||
|
if (!gl) return false;
|
||||||
|
*out_wnd = wnd; *out_dc = dc; *out_gl = gl;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static DWORD WINAPI rt_main(LPVOID) {
|
static DWORD WINAPI rt_main(LPVOID) {
|
||||||
WNDCLASSA wc; memset(&wc, 0, sizeof wc);
|
WNDCLASSA wc; memset(&wc, 0, sizeof wc);
|
||||||
wc.style = CS_OWNDC;
|
wc.style = CS_OWNDC;
|
||||||
@@ -694,41 +711,50 @@ static DWORD WINAPI rt_main(LPVOID) {
|
|||||||
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||||
wc.lpszClassName = "VPXGL";
|
wc.lpszClassName = "VPXGL";
|
||||||
RegisterClassA(&wc);
|
RegisterClassA(&wc);
|
||||||
RECT r = { 0, 0, 832, 512 };
|
|
||||||
AdjustWindowRect(&r, WS_OVERLAPPEDWINDOW, FALSE);
|
HWND wnd; HDC dc; HGLRC gl;
|
||||||
HWND wnd = CreateWindowA("VPXGL", "VPX VelociRender (emulated)",
|
if (!make_gl_window("VPX VelociRender (emulated)", 832, 512, 40, 40,
|
||||||
WS_OVERLAPPEDWINDOW | WS_VISIBLE, 40, 40,
|
&wnd, &dc, &gl)) return 1;
|
||||||
r.right - r.left, r.bottom - r.top, NULL, NULL, wc.hInstance, NULL);
|
|
||||||
if (!wnd) return 1;
|
/* three 640x480 windows, one per VDB display palette */
|
||||||
HDC dc = GetDC(wnd);
|
static const char *pal_titles[3] = {
|
||||||
PIXELFORMATDESCRIPTOR pfd; memset(&pfd, 0, sizeof pfd);
|
"VDB palette 0 - secondary", "VDB palette 1 - aux1",
|
||||||
pfd.nSize = sizeof pfd; pfd.nVersion = 1;
|
"VDB palette 2 - aux2" };
|
||||||
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
|
HWND pwnd[3]; HDC pdc[3]; HGLRC pgl[3];
|
||||||
pfd.iPixelType = PFD_TYPE_RGBA; pfd.cColorBits = 24; pfd.cDepthBits = 24;
|
bool phave[3] = { false, false, false };
|
||||||
int pf = ChoosePixelFormat(dc, &pfd);
|
for (int g = 0; g < 3; g++)
|
||||||
SetPixelFormat(dc, pf, &pfd);
|
phave[g] = make_gl_window(pal_titles[g], 640, 480,
|
||||||
HGLRC gl = wglCreateContext(dc);
|
920, 40 + g * 500, &pwnd[g], &pdc[g], &pgl[g]);
|
||||||
if (!gl) return 1;
|
|
||||||
wglMakeCurrent(dc, gl);
|
|
||||||
VFrame cur;
|
VFrame cur;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
DWORD w = MsgWaitForMultipleObjects(1, &rt_event, FALSE, INFINITE,
|
/* 50ms timeout so the palette windows animate even between VPX
|
||||||
|
* frames (pal0 is rewritten continuously by the game). */
|
||||||
|
DWORD w = MsgWaitForMultipleObjects(1, &rt_event, FALSE, 50,
|
||||||
QS_ALLINPUT);
|
QS_ALLINPUT);
|
||||||
MSG msg;
|
MSG msg;
|
||||||
while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) {
|
while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||||
TranslateMessage(&msg);
|
TranslateMessage(&msg);
|
||||||
DispatchMessageA(&msg);
|
DispatchMessageA(&msg);
|
||||||
}
|
}
|
||||||
bool redraw = false;
|
|
||||||
if (w == WAIT_OBJECT_0) {
|
if (w == WAIT_OBJECT_0) {
|
||||||
|
bool redraw = false;
|
||||||
EnterCriticalSection(&rt_lock);
|
EnterCriticalSection(&rt_lock);
|
||||||
if (rt_new) { cur = rt_pending; rt_new = false; redraw = true; }
|
if (rt_new) { cur = rt_pending; rt_new = false; redraw = true; }
|
||||||
LeaveCriticalSection(&rt_lock);
|
LeaveCriticalSection(&rt_lock);
|
||||||
|
if (redraw && cur.valid) {
|
||||||
|
wglMakeCurrent(dc, gl);
|
||||||
|
RECT cr; GetClientRect(wnd, &cr);
|
||||||
|
rt_draw(dc, cur, cr.right, cr.bottom);
|
||||||
|
rt_frames++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (redraw && cur.valid) {
|
/* redraw the palette windows every tick (live) */
|
||||||
RECT cr; GetClientRect(wnd, &cr);
|
for (int g = 0; g < 3; g++) {
|
||||||
rt_draw(dc, cur, cr.right, cr.bottom);
|
if (!phave[g]) continue;
|
||||||
rt_frames++;
|
wglMakeCurrent(pdc[g], pgl[g]);
|
||||||
|
RECT cr; GetClientRect(pwnd[g], &cr);
|
||||||
|
pal_draw(pdc[g], g, cr.right, cr.bottom);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1237,9 +1263,6 @@ void VPXLOG_Init(void) {
|
|||||||
if (fifo_dump_fp == NULL) LOG_MSG("VPXLOG: cannot open fifodump '%s'", fd);
|
if (fifo_dump_fp == NULL) LOG_MSG("VPXLOG: cannot open fifodump '%s'", fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *vs = getenv("VPX_VDBSTRIP");
|
|
||||||
if (vs && vs[0] == '0') vpx_show_vdb_strips = false;
|
|
||||||
|
|
||||||
const char *rn = getenv("VPX_RENDER");
|
const char *rn = getenv("VPX_RENDER");
|
||||||
if (rn && rn[0] && rn[0] != '0') {
|
if (rn && rn[0] && rn[0] != '0') {
|
||||||
vpx_render_start();
|
vpx_render_start();
|
||||||
|
|||||||
Reference in New Issue
Block a user