From f1a231b6cced1b0d4586c0c8e6d68cfe4c68487c Mon Sep 17 00:00:00 2001 From: starfrost013 Date: Sun, 30 Mar 2025 23:56:42 +0100 Subject: [PATCH] Implement GDI-B. Rewrite text rendering code for perfect implementation of GDI-C, GDI-D and GDI-E text classes. Fucking hell that took forever.... --- .../86box/nv/classes/vid_nv3_classes.h | 9 +- src/include/86box/nv/render/vid_nv3_render.h | 7 +- src/include/86box/nv/vid_nv3.h | 4 +- .../classes/nv3_class_00c_win95_gdi_text.c | 132 ++++-- .../nv/nv3/render/nv3_render_primitives.c | 385 +++++++++++++----- 5 files changed, 392 insertions(+), 145 deletions(-) diff --git a/src/include/86box/nv/classes/vid_nv3_classes.h b/src/include/86box/nv/classes/vid_nv3_classes.h index 4f52bf789..e3a1bf7aa 100644 --- a/src/include/86box/nv/classes/vid_nv3_classes.h +++ b/src/include/86box/nv/classes/vid_nv3_classes.h @@ -165,6 +165,7 @@ typedef enum nv3_pgraph_class_e /* Type B: Clipped Rectangle */ #define NV3_W95TXT_B_CLIP_TOPLEFT 0x07F4 #define NV3_W95TXT_B_CLIP_BOTTOMRIGHT 0x07F8 +#define NV3_W95TXT_B_COLOR 0x07FC #define NV3_W95TXT_B_CLIP_CLIPRECT_START 0x0800 #define NV3_W95TXT_B_CLIP_CLIPRECT_SIZE 128 // Number of rects #define NV3_W95TXT_B_CLIP_CLIPRECT_END 0x09FF @@ -610,20 +611,20 @@ typedef struct nv3_object_class_00C uint8_t reserved3[0x1F0]; nv3_clip_16_t clip_b; uint32_t color_b; // Color for Clip B - nv3_clip_16_t rect_clip[64]; + nv3_clip_16_t clipped_rect[64]; uint8_t reserved4[0x1E8]; nv3_clip_16_t clip_c; uint32_t color1_c; nv3_size_16_t size_c; nv3_position_16_t point_c; - uint32_t color1_c_bitmap[128]; + uint32_t bitmap_c[128]; uint8_t reserved5[0x368]; nv3_clip_16_t clip_d; uint32_t color1_d; nv3_size_16_t size_in_d; nv3_size_16_t size_out_d; nv3_position_16_t point_d; - uint32_t mono_color1_d[128]; + uint32_t bitmap_d[128]; uint8_t reserved6[0x364]; nv3_clip_16_t clip_e; uint32_t color0_e; @@ -631,7 +632,7 @@ typedef struct nv3_object_class_00C nv3_size_16_t size_in_e; nv3_size_16_t size_out_e; nv3_position_16_t point_e; - uint32_t mono_color1_e[128]; + uint32_t bitmap_e[128]; uint8_t reserved7[0xB7F]; } nv3_win95_text_t; diff --git a/src/include/86box/nv/render/vid_nv3_render.h b/src/include/86box/nv/render/vid_nv3_render.h index fe429da74..9b5acd06d 100644 --- a/src/include/86box/nv/render/vid_nv3_render.h +++ b/src/include/86box/nv/render/vid_nv3_render.h @@ -31,7 +31,8 @@ uint32_t nv3_render_downconvert_color(nv3_grobj_t grobj, nv3_color_expanded_t co uint32_t nv3_render_set_pattern_color(nv3_color_expanded_t pattern_colour, bool use_color1); /* Primitives */ -void nv3_render_rect(nv3_position_16_t position, nv3_size_16_t size, uint32_t color, nv3_grobj_t grobj); +void nv3_render_rect(nv3_position_16_t position, nv3_size_16_t size, uint32_t color, nv3_grobj_t grobj); // Render an A (unclipped) GDI rect +void nv3_render_rect_clipped(nv3_clip_16_t clip, uint32_t color, nv3_grobj_t grobj); // Render a B (clipped) GDI rect. /* Chroma */ bool nv3_render_chroma_test(uint32_t color, nv3_grobj_t grobj); @@ -41,5 +42,5 @@ void nv3_render_blit_image(uint32_t color, nv3_grobj_t grobj); void nv3_render_blit_screen2screen(nv3_grobj_t grobj); /* GDI */ -void nv3_render_gdi_type_d(nv3_grobj_t grobj, uint32_t param); /* GDI Type-D: Clipped 1bpp text */ -void nv3_render_gdi_type_e(nv3_grobj_t grobj, uint32_t param); /* GDI Type-E: Clipped 1bpp two-colour text */ \ No newline at end of file +void nv3_render_gdi_transparent_bitmap(bool clip, uint32_t color, uint32_t bitmap_data, nv3_grobj_t grobj); +void nv3_render_gdi_1bpp_bitmap(uint32_t color0, uint32_t color1, uint32_t bitmap_data, nv3_grobj_t grobj); /* GDI Type-E: Clipped 1bpp colour-expanded bitmap */ \ No newline at end of file diff --git a/src/include/86box/nv/vid_nv3.h b/src/include/86box/nv/vid_nv3.h index ed55e050d..1957984d2 100644 --- a/src/include/86box/nv/vid_nv3.h +++ b/src/include/86box/nv/vid_nv3.h @@ -1229,7 +1229,9 @@ typedef struct nv3_pgraph_s struct nv3_object_class_00A lin; struct nv3_object_class_00B triangle; struct nv3_object_class_00C win95_gdi_text; - nv3_position_16_t win95_gdi_text_current_position; /* This is here so we can hold the current state of the image draw */ + /* These are here so we can hold the current state of the image draw */ + uint32_t win95_gdi_text_bit_count; + nv3_position_16_t win95_gdi_text_current_position; struct nv3_object_class_00D m2mf; struct nv3_object_class_00E scaled_image_from_memory; struct nv3_object_class_010 blit; diff --git a/src/video/nv/nv3/classes/nv3_class_00c_win95_gdi_text.c b/src/video/nv/nv3/classes/nv3_class_00c_win95_gdi_text.c index a32358912..e2f640fac 100644 --- a/src/video/nv/nv3/classes/nv3_class_00c_win95_gdi_text.c +++ b/src/video/nv/nv3/classes/nv3_class_00c_win95_gdi_text.c @@ -39,6 +39,11 @@ void nv3_class_00c_method(uint32_t param, uint32_t method_id, nv3_ramin_context_ nv3->pgraph.win95_gdi_text.color_a = param; nv_log("Method Execution: GDI-A Color 0x%08x\n", nv3->pgraph.win95_gdi_text.color_a); break; + /* Type B: Clipped Rectangle */ + case NV3_W95TXT_B_COLOR: + nv3->pgraph.win95_gdi_text.color_b = param; + nv_log("Method Execution: GDI-B Color 0x%08x\n", nv3->pgraph.win95_gdi_text.color_b); + break; case NV3_W95TXT_B_CLIP_TOPLEFT: nv3->pgraph.win95_gdi_text.clip_b.left = (param & 0xFFFF); nv3->pgraph.win95_gdi_text.clip_b.top = ((param >> 16) & 0xFFFF); @@ -47,20 +52,53 @@ void nv3_class_00c_method(uint32_t param, uint32_t method_id, nv3_ramin_context_ case NV3_W95TXT_B_CLIP_BOTTOMRIGHT: nv3->pgraph.win95_gdi_text.clip_b.bottom = (param & 0xFFFF); nv3->pgraph.win95_gdi_text.clip_b.right = ((param >> 16) & 0xFFFF); - nv_log("Method Execution: GDI-B Clip Bottom,Right %04x,%04x", nv3->pgraph.win95_gdi_text.clip_b.left, nv3->pgraph.win95_gdi_text.clip_b.top); + nv_log("Method Execution: GDI-B Clip Bottom,Right %04x,%04x", nv3->pgraph.win95_gdi_text.clip_b.right, nv3->pgraph.win95_gdi_text.clip_b.bottom); + break; + /* Type C: Unclipped Bitmap */ + case NV3_W95TXT_C_CLIP_COLOR: + nv3->pgraph.win95_gdi_text.color1_c = param; + nv_log("Method Execution: GDI-C Color 0x%08x\n", nv3->pgraph.win95_gdi_text.color1_c); + break; + case NV3_W95TXT_C_CLIP_SIZE: + nv3->pgraph.win95_gdi_text.size_c.w = (param & 0xFFFF); + nv3->pgraph.win95_gdi_text.size_c.h = ((param >> 16) & 0xFFFF); + + nv3->pgraph.win95_gdi_text_bit_count = 0; + nv_log("Method Execution: GDI-C Size In %04x,%04x\n", nv3->pgraph.win95_gdi_text.size_c.w, nv3->pgraph.win95_gdi_text.size_c.h); + break; + case NV3_W95TXT_C_CLIP_POSITION: + nv3->pgraph.win95_gdi_text.point_c.x = (param & 0xFFFF); + nv3->pgraph.win95_gdi_text.point_c.y = ((param >> 16) & 0xFFFF); + nv_log("Method Execution: GDI-C Point %04x,%04x\n", nv3->pgraph.win95_gdi_text.point_c.x, nv3->pgraph.win95_gdi_text.point_c.y); + + nv3->pgraph.win95_gdi_text_current_position.x = nv3->pgraph.win95_gdi_text.point_c.x ; + nv3->pgraph.win95_gdi_text_current_position.y = nv3->pgraph.win95_gdi_text.point_c.y; + + break; + case NV3_W95TXT_C_CLIP_TOPLEFT: + nv3->pgraph.win95_gdi_text.clip_c.left = (param & 0xFFFF); + nv3->pgraph.win95_gdi_text.clip_c.top = ((param >> 16) & 0xFFFF); + nv_log("Method Execution: GDI-C Clip Left,Top %04x,%04x\n", nv3->pgraph.win95_gdi_text.clip_c.left, nv3->pgraph.win95_gdi_text.clip_c.top); + break; + case NV3_W95TXT_C_CLIP_BOTTOMRIGHT: + nv3->pgraph.win95_gdi_text.clip_c.right = (param & 0xFFFF); + nv3->pgraph.win95_gdi_text.clip_c.bottom = ((param >> 16) & 0xFFFF); + /* is it "only if we are out of the top left or the bottom right or is it "all of them"*/ + nv_log("Method Execution: GDI-C Clip Right,Bottom %04x,%04x\n", nv3->pgraph.win95_gdi_text.clip_c.left, nv3->pgraph.win95_gdi_text.clip_c.top); break; /* Type B and C not implemented YET, as they are not used by NT GDI driver */ case NV3_W95TXT_D_CLIP_TOPLEFT: nv3->pgraph.win95_gdi_text.clip_d.left = (param & 0xFFFF); nv3->pgraph.win95_gdi_text.clip_d.top = ((param >> 16) & 0xFFFF); - nv_log("Method Execution: GDI-A Clip Left,Top %04x,%04x\n", nv3->pgraph.win95_gdi_text.clip_d.left, nv3->pgraph.win95_gdi_text.clip_d.top); + nv_log("Method Execution: GDI-D Clip Left,Top %04x,%04x\n", nv3->pgraph.win95_gdi_text.clip_d.left, nv3->pgraph.win95_gdi_text.clip_d.top); break; case NV3_W95TXT_D_CLIP_BOTTOMRIGHT: nv3->pgraph.win95_gdi_text.clip_d.right = (param & 0xFFFF); nv3->pgraph.win95_gdi_text.clip_d.bottom = ((param >> 16) & 0xFFFF); /* is it "only if we are out of the top left or the bottom right or is it "all of them"*/ - nv_log("Method Execution: GDI-A Clip Right,Bottom %04x,%04x\n", nv3->pgraph.win95_gdi_text.clip_d.left, nv3->pgraph.win95_gdi_text.clip_d.top); + nv_log("Method Execution: GDI-D Clip Right,Bottom %04x,%04x\n", nv3->pgraph.win95_gdi_text.clip_d.left, nv3->pgraph.win95_gdi_text.clip_d.top); break; + case NV3_W95TXT_D_CLIP_COLOR: nv3->pgraph.win95_gdi_text.color1_d = param; nv_log("Method Execution: GDI-D Color 0x%08x\n", nv3->pgraph.win95_gdi_text.color_a); @@ -80,29 +118,21 @@ void nv3_class_00c_method(uint32_t param, uint32_t method_id, nv3_ramin_context_ nv3->pgraph.win95_gdi_text.point_d.y = ((param >> 16) & 0xFFFF); nv_log("Method Execution: GDI-D Point %04x,%04x\n", nv3->pgraph.win95_gdi_text.point_d.x, nv3->pgraph.win95_gdi_text.point_d.y); - /* small case*/ - if (nv3->pgraph.win95_gdi_text.size_in_d.w < 0x0010) - { - nv3->pgraph.win95_gdi_text_current_position.x = (nv3->pgraph.win95_gdi_text.point_d.x + (nv3->pgraph.win95_gdi_text.size_in_d.w - 1)); - nv3->pgraph.win95_gdi_text_current_position.y = (nv3->pgraph.win95_gdi_text.point_d.y); - } - /* large case: draw (7-0) (15-8)*/ - else - { - uint16_t large_start = (nv3->pgraph.win95_gdi_text.size_in_d.w >> 1) - 1; - nv3->pgraph.win95_gdi_text_current_position.x = (nv3->pgraph.win95_gdi_text.point_d.x + large_start); - nv3->pgraph.win95_gdi_text_current_position.y = (nv3->pgraph.win95_gdi_text.point_d.y); - } + nv3->pgraph.win95_gdi_text_current_position.x = nv3->pgraph.win95_gdi_text.point_d.x; + nv3->pgraph.win95_gdi_text_current_position.y = nv3->pgraph.win95_gdi_text.point_d.y; + nv3->pgraph.win95_gdi_text_bit_count = 0; break; /* Type E: Two-colour 1bpp */ case NV3_W95TXT_E_CLIP_TOPLEFT: nv3->pgraph.win95_gdi_text.clip_e.left = (param & 0xFFFF); nv3->pgraph.win95_gdi_text.clip_e.top = ((param >> 16) & 0xFFFF); + nv_log("Method Execution: GDI-E Clip Left,Top 0x%08x\n", nv3->pgraph.win95_gdi_text.clip_e.left, nv3->pgraph.win95_gdi_text.clip_e.top); break; case NV3_W95TXT_E_CLIP_BOTTOMRIGHT: nv3->pgraph.win95_gdi_text.clip_e.right = (param & 0xFFFF); nv3->pgraph.win95_gdi_text.clip_e.bottom = ((param >> 16) & 0xFFFF); + nv_log("Method Execution: GDI-E Clip Bottom,Right 0x%08x\n", nv3->pgraph.win95_gdi_text.clip_e.right, nv3->pgraph.win95_gdi_text.clip_e.bottom); /* is it "only if we are out of the top left or the bottom right or is it "all of them"*/ break; case NV3_W95TXT_E_CLIP_COLOR_0: @@ -127,11 +157,9 @@ void nv3_class_00c_method(uint32_t param, uint32_t method_id, nv3_ramin_context_ nv3->pgraph.win95_gdi_text.point_e.x = (param & 0xFFFF); nv3->pgraph.win95_gdi_text.point_e.y = ((param >> 16) & 0xFFFF); - uint16_t large_start = (nv3->pgraph.win95_gdi_text.size_in_e.w >> 1) - 1; - - //nv3->pgraph.win95_gdi_text_current_position.x = (nv3->pgraph.win95_gdi_text.point_e.x + large_start); nv3->pgraph.win95_gdi_text_current_position.x = nv3->pgraph.win95_gdi_text.point_e.x; nv3->pgraph.win95_gdi_text_current_position.y = nv3->pgraph.win95_gdi_text.point_e.y; + nv3->pgraph.win95_gdi_text_bit_count = 0; nv_log("Method Execution: GDI-E Point %04x,%04x\n", nv3->pgraph.win95_gdi_text.point_e.x, nv3->pgraph.win95_gdi_text.point_e.y); break; @@ -139,9 +167,8 @@ void nv3_class_00c_method(uint32_t param, uint32_t method_id, nv3_ramin_context_ /* Type A submission: these are the same things as rectangles */ if (method_id >= NV3_W95TXT_A_RECT_START && method_id <= NV3_W95TXT_A_RECT_END) { - uint32_t index = (method_id - NV3_RECTANGLE_START) >> 3; + uint32_t index = (method_id - NV3_W95TXT_A_RECT_START) >> 3; - // IN THIS ONE SPECIFIC PLACE, ****AND ONLY THIS ONE SPECIFIC PLACE****, X AND Y ARE SWAPPED???? */ // If the size is submitted, render it. if (method_id & 0x04) @@ -149,8 +176,8 @@ void nv3_class_00c_method(uint32_t param, uint32_t method_id, nv3_ramin_context_ nv3->pgraph.win95_gdi_text.rect_a_size[index].w = (param >> 16) & 0xFFFF; nv3->pgraph.win95_gdi_text.rect_a_size[index].h = param & 0xFFFF; - nv_log("Method Execution: Rect GDI-A%d Size=%d,%d Color=0x%08x\n", index, nv3->pgraph.win95_gdi_text.rect_a_size[index].w, - nv3->pgraph.win95_gdi_text.rect_a_size[index].h, nv3->pgraph.win95_gdi_text.color_a); + nv_log("Method Execution: Rect GDI-A%d Size=%d,%d", index, nv3->pgraph.win95_gdi_text.rect_a_size[index].w, + nv3->pgraph.win95_gdi_text.rect_a_size[index].h); nv3_render_rect(nv3->pgraph.win95_gdi_text.rect_a_position[index], nv3->pgraph.win95_gdi_text.rect_a_size[index], nv3->pgraph.win95_gdi_text.color_a, grobj); @@ -163,14 +190,62 @@ void nv3_class_00c_method(uint32_t param, uint32_t method_id, nv3_ramin_context_ nv_log("Method Execution: Rect GDI-A%d Position=%d,%d\n", index, nv3->pgraph.win95_gdi_text.rect_a_position[index].x, nv3->pgraph.win95_gdi_text.rect_a_position[index].y); } + return; } + /* Type B: Clipped Rectangle */ + else if (method_id >= NV3_W95TXT_B_CLIP_CLIPRECT_START && method_id <= NV3_W95TXT_B_CLIP_CLIPRECT_END) + { + uint32_t index = (method_id - NV3_W95TXT_B_CLIP_CLIPRECT_START) >> 3; + + /* Works slightly differently, we define the bounds of the rectangle instead. */ + if (method_id & 0x04) + { + nv3->pgraph.win95_gdi_text.clipped_rect[index].right = (param & 0xFFFF); + nv3->pgraph.win95_gdi_text.clipped_rect[index].bottom = ((param >> 16) & 0xFFFF); + + nv_log("Method Execution: Rect GDI-B%d Right,Bottom=%d,%d\n", index, nv3->pgraph.win95_gdi_text.clipped_rect[index].right, + nv3->pgraph.win95_gdi_text.clipped_rect[index].bottom); + + nv3_render_rect_clipped(nv3->pgraph.win95_gdi_text.clipped_rect[index], + nv3->pgraph.win95_gdi_text.color_b, grobj); + } + else // left,top + { + nv3->pgraph.win95_gdi_text.clipped_rect[index].left = (param & 0xFFFF); + nv3->pgraph.win95_gdi_text.clipped_rect[index].top = ((param >> 16) & 0xFFFF); + + nv_log("Method Execution: Rect GDI-B%d Left,Top=%d,%d\n", index, + nv3->pgraph.win95_gdi_text.clipped_rect[index].left, nv3->pgraph.win95_gdi_text.clipped_rect[index].top); + } + + return; + } + /* Type C */ + else if (method_id >= NV3_W95TXT_C_CLIP_CLIPRECT_START && method_id <= NV3_W95TXT_C_CLIP_CLIPRECT_END) + { + /* lol */ + uint32_t index = (method_id - NV3_W95TXT_C_CLIP_CLIPRECT_START) >> 3; + + nv3->pgraph.win95_gdi_text.bitmap_c[index] = param; + + /* Mammoth logger! */ + nv_log("Method Execution: Rect GDI-C%d Data=%08x Size%04x,%04x Point%04x,%04x Color=%08x Clip Left=0x%04x Right=0x%04x Top=0x%04x Bottom=0x%04x", + index, param, nv3->pgraph.win95_gdi_text.size_c.w, nv3->pgraph.win95_gdi_text.size_c.h, + nv3->pgraph.win95_gdi_text.point_c.x, nv3->pgraph.win95_gdi_text.point_c.y, + nv3->pgraph.win95_gdi_text.color1_c, + nv3->pgraph.win95_gdi_text.clip_c.left, nv3->pgraph.win95_gdi_text.clip_c.right, + nv3->pgraph.win95_gdi_text.clip_c.top, nv3->pgraph.win95_gdi_text.clip_c.bottom); + + nv3_render_gdi_transparent_bitmap(false, nv3->pgraph.win95_gdi_text.color1_c, nv3->pgraph.win95_gdi_text.bitmap_c[index], grobj); + return; + } else if (method_id >= NV3_W95TXT_D_CLIP_CLIPRECT_START && method_id <= NV3_W95TXT_D_CLIP_CLIPRECT_END) { /* lol */ uint32_t index = (method_id - NV3_W95TXT_D_CLIP_CLIPRECT_START) >> 3; - nv3->pgraph.win95_gdi_text.mono_color1_d[index] = param; + nv3->pgraph.win95_gdi_text.bitmap_d[index] = param; /* Mammoth logger! */ nv_log("Method Execution: Rect GDI-D%d Data=%08x SizeIn%04x,%04x SizeOut%04x,%04x Point%04x,%04x Color=%08x Clip Left=0x%04x Right=0x%04x Top=0x%04x Bottom=0x%04x", @@ -178,9 +253,10 @@ void nv3_class_00c_method(uint32_t param, uint32_t method_id, nv3_ramin_context_ nv3->pgraph.win95_gdi_text.size_out_d.w, nv3->pgraph.win95_gdi_text.size_out_d.h, nv3->pgraph.win95_gdi_text.point_d.x, nv3->pgraph.win95_gdi_text.point_d.y, nv3->pgraph.win95_gdi_text.color1_d, - nv3->pgraph.win95_gdi_text.clip_d.left, nv3->pgraph.win95_gdi_text.clip_d.right, nv3->pgraph.win95_gdi_text.clip_d.top, nv3->pgraph.win95_gdi_text.clip_d.bottom); + nv3->pgraph.win95_gdi_text.clip_d.left, nv3->pgraph.win95_gdi_text.clip_d.right, + nv3->pgraph.win95_gdi_text.clip_d.top, nv3->pgraph.win95_gdi_text.clip_d.bottom); - nv3_render_gdi_type_d(grobj, nv3->pgraph.win95_gdi_text.mono_color1_d[index]); + nv3_render_gdi_transparent_bitmap(true, nv3->pgraph.win95_gdi_text.color1_d, nv3->pgraph.win95_gdi_text.bitmap_d[index], grobj); return; } else if (method_id >= NV3_W95TXT_E_CLIP_CLIPRECT_START && method_id <= NV3_W95TXT_E_CLIP_CLIPRECT_END) @@ -188,7 +264,7 @@ void nv3_class_00c_method(uint32_t param, uint32_t method_id, nv3_ramin_context_ /* lol */ uint32_t index = (method_id - NV3_W95TXT_E_CLIP_CLIPRECT_START) >> 3; - nv3->pgraph.win95_gdi_text.mono_color1_d[index] = param; + nv3->pgraph.win95_gdi_text.bitmap_e[index] = param; /* Mammoth logger! */ nv_log("Method Execution: Rect GDI-E%d Data=%08x SizeIn%04x,%04x SizeOut%04x,%04x Point%04x,%04x Color=%08x Clip Left=0x%04x Right=0x%04x Top=0x%04x Bottom=0x%04x", @@ -198,7 +274,7 @@ void nv3_class_00c_method(uint32_t param, uint32_t method_id, nv3_ramin_context_ nv3->pgraph.win95_gdi_text.color1_e, nv3->pgraph.win95_gdi_text.clip_e.left, nv3->pgraph.win95_gdi_text.clip_e.right, nv3->pgraph.win95_gdi_text.clip_e.top, nv3->pgraph.win95_gdi_text.clip_e.bottom); - nv3_render_gdi_type_e(grobj, nv3->pgraph.win95_gdi_text.mono_color1_d[index]); + nv3_render_gdi_1bpp_bitmap(nv3->pgraph.win95_gdi_text.color0_e, nv3->pgraph.win95_gdi_text.color1_e, nv3->pgraph.win95_gdi_text.bitmap_e[index], grobj); return; } diff --git a/src/video/nv/nv3/render/nv3_render_primitives.c b/src/video/nv/nv3/render/nv3_render_primitives.c index 4695d05b7..487f41731 100644 --- a/src/video/nv/nv3/render/nv3_render_primitives.c +++ b/src/video/nv/nv3/render/nv3_render_primitives.c @@ -46,140 +46,307 @@ void nv3_render_rect(nv3_position_16_t position, nv3_size_16_t size, uint32_t co } } -void nv3_render_text_1bpp(bool bit, nv3_grobj_t grobj) +/* Render GDI-B clipped rectangle */ +void nv3_render_rect_clipped(nv3_clip_16_t clip, uint32_t color, nv3_grobj_t grobj) { - uint16_t clip_x = nv3->pgraph.win95_gdi_text.point_d.x + nv3->pgraph.win95_gdi_text.size_out_d.w; - uint16_t clip_y = nv3->pgraph.win95_gdi_text.point_d.y + nv3->pgraph.win95_gdi_text.size_out_d.h; + nv3_position_16_t current_pos = {0}; - /* they send more data than they need */ - if (nv3->pgraph.win95_gdi_text_current_position.y >= clip_y) - bit = false; - - uint32_t final_color; - - // if it's a 0 bit we don't need to do anything - if (bit) + for (int32_t y = clip.top; y < clip.bottom; y++) { - switch (nv3->nvbase.svga.bpp) + current_pos.y = y; + + for (int32_t x = clip.left; x < clip.right; x++) { - case 8: - final_color = (nv3->pgraph.win95_gdi_text.color1_d & 0xFF); /* do we need to add anything? mul blend perhaps? */ - break; - case 15: - case 16: - final_color = (nv3->pgraph.win95_gdi_text.color1_d & 0xFFFF); /* do we need to add anything? mul blend perhaps? */ - break; - case 32: - final_color = (nv3->pgraph.win95_gdi_text.color1_d); /* do we need to add anything? mul blend perhaps? */ - break; + current_pos.x = x; + + /* compare against the global clip too */ + if (current_pos.x >= nv3->pgraph.win95_gdi_text.clip_b.left + && current_pos.x <= nv3->pgraph.win95_gdi_text.clip_b.right + && current_pos.y >= nv3->pgraph.win95_gdi_text.clip_b.top + && current_pos.y <= nv3->pgraph.win95_gdi_text.clip_b.bottom) + { + nv3_render_write_pixel(current_pos, color, grobj); + } } } +} - /* in type d colour0 is always transparent */ - if (bit) - nv3_render_write_pixel(nv3->pgraph.win95_gdi_text_current_position, final_color, grobj); - - /* increment the position - the bitmap is stored horizontally backward */ - nv3->pgraph.win95_gdi_text_current_position.x--; - - /* check if we need to go down a line */ - if (nv3->pgraph.win95_gdi_text_current_position.x < nv3->pgraph.win95_gdi_text.point_d.x) +void nv3_render_gdi_transparent_bitmap_blit(bool bit, bool clip, uint32_t color, nv3_grobj_t grobj) +{ + /* If the bit is set, and cliping is enabled (Type D) tru and lcip */ + if (bit && clip) { - nv3->pgraph.win95_gdi_text_current_position.x = (nv3->pgraph.win95_gdi_text.point_d.x + nv3->pgraph.win95_gdi_text.size_in_d.w - 1); - - nv3->pgraph.win95_gdi_text_current_position.y++; + /* Turn the bit off if we need to clip (Type D ) */ + if (nv3->pgraph.win95_gdi_text_current_position.x < nv3->pgraph.win95_gdi_text.clip_d.left + || nv3->pgraph.win95_gdi_text_current_position.x > nv3->pgraph.win95_gdi_text.clip_d.right + || nv3->pgraph.win95_gdi_text_current_position.y < nv3->pgraph.win95_gdi_text.clip_d.top + || nv3->pgraph.win95_gdi_text_current_position.y > nv3->pgraph.win95_gdi_text.clip_d.bottom) + { + bit = false; + } + + /* + Also clip if we are outside of the SIZE_OUT range + We only need to do this in one direction just to get rid of the crud sent by NV + */ + uint32_t clip_x = nv3->pgraph.win95_gdi_text.point_d.x + (nv3->pgraph.win95_gdi_text.size_out_d.w); + uint32_t clip_y = nv3->pgraph.win95_gdi_text.point_d.y + (nv3->pgraph.win95_gdi_text.size_out_d.h); + + if (nv3->pgraph.win95_gdi_text_current_position.x >= clip_x + || nv3->pgraph.win95_gdi_text_current_position.y >= clip_y) + bit = false; } - /* check if we are in the clipping rectangle */ - if (nv3->pgraph.win95_gdi_text_current_position.x < nv3->pgraph.win95_gdi_text.clip_d.left - || nv3->pgraph.win95_gdi_text_current_position.x > nv3->pgraph.win95_gdi_text.clip_d.right - || nv3->pgraph.win95_gdi_text_current_position.y < nv3->pgraph.win95_gdi_text.clip_d.top - || nv3->pgraph.win95_gdi_text_current_position.y > nv3->pgraph.win95_gdi_text.clip_d.bottom) + /* We don't need to and it, because it seems the Riva only uses non-packed bpp formats for this class */ + if (bit) + nv3_render_write_pixel(nv3->pgraph.win95_gdi_text_current_position, color, grobj); + + /* + Check if we've reached the bottom + Because we check the bits in reverse, we go forward (bits 7,6,5 were set for a 1x3 bitmap) + */ + + uint32_t end_x = (clip) ? nv3->pgraph.win95_gdi_text.point_d.x + nv3->pgraph.win95_gdi_text.size_in_d.w : nv3->pgraph.win95_gdi_text.point_c.x + nv3->pgraph.win95_gdi_text.size_c.w; + + nv3->pgraph.win95_gdi_text_current_position.x++; + + if (nv3->pgraph.win95_gdi_text_current_position.x >= end_x) { + nv3->pgraph.win95_gdi_text_current_position.y++; + + if (!clip) + nv3->pgraph.win95_gdi_text_current_position.x = nv3->pgraph.win95_gdi_text.point_c.x; + else + nv3->pgraph.win95_gdi_text_current_position.x = nv3->pgraph.win95_gdi_text.point_d.x; + } +} + +/* Originally written 23 March 2025, but then, redone, properly, on 30 March 2025 */ +void nv3_render_gdi_transparent_bitmap(bool clip, uint32_t color, uint32_t bitmap_data, nv3_grobj_t grobj) +{ + /* + First, we need to figure out how many bits we have left. + If we have less than 32, don't process all of the bits. + + Bits are processed in the following order: [7-0] [15-8] [23-16] [31-24] + TODO: Store this somewhere, so it doesn't need to be recalculated. + + We store a global bit count for this purpose. + */ + + uint32_t bitmap_size = (clip) ? nv3->pgraph.win95_gdi_text.size_in_d.w * nv3->pgraph.win95_gdi_text.size_in_d.h : nv3->pgraph.win95_gdi_text.size_c.w * nv3->pgraph.win95_gdi_text.size_c.h; + uint32_t bits_remaining_in_bitmap = bitmap_size - nv3->pgraph.win95_gdi_text_bit_count; + + /* we have to interpret every bit in reverse bit order but in the right byte order */ + + bool current_bit = false; + + /* Start by rendering bits 7 through 0 */ + for (int32_t bit = 7; bit >= 0; bit--) + { + current_bit = (bitmap_data >> bit) & 0x01; + + nv3_render_gdi_transparent_bitmap_blit(current_bit, clip, color, grobj); + nv3->pgraph.win95_gdi_text_bit_count++; + bits_remaining_in_bitmap--; + + if (!bits_remaining_in_bitmap) + break; + } + + /* IF we're done, let's return */ + if (!bits_remaining_in_bitmap) return; - } -} -void nv3_render_gdi_type_d(nv3_grobj_t grobj, uint32_t param) -{ - // reset when a position is submitted - nv3_position_16_t start_position = nv3->pgraph.win95_gdi_text_current_position; - - /* Go through the bitmap that was sent, bit by bit. */ - for (int32_t bit_num = 0; bit_num <= 31; bit_num++) + /* Now for 15 through 8 */ + for (int32_t bit = 15; bit >= 8; bit--) { - bool bit = (param >> bit_num) & 0x01; + current_bit = (bitmap_data >> bit) & 0x01; - nv3_render_text_1bpp(bit, grobj); + nv3_render_gdi_transparent_bitmap_blit(current_bit, clip, color, grobj); + nv3->pgraph.win95_gdi_text_bit_count++; + bits_remaining_in_bitmap--; + + if (!bits_remaining_in_bitmap) + break; } -} -/* 2-colour 1bpp color-expanded text from [7-0] */ -void nv3_render_text_1bpp_2color(uint32_t byte, nv3_grobj_t grobj) -{ - for (int32_t bit_num = 0; bit_num <= 7; bit_num++) + /* IF we're done, let's return */ + if (!bits_remaining_in_bitmap) + return; + + /* Now for 23 through 16 */ + for (int32_t bit = 23; bit >= 16; bit--) { - bool bit = (byte >> bit_num) & 0x01; + current_bit = (bitmap_data >> bit) & 0x01; - uint16_t clip_x = nv3->pgraph.win95_gdi_text.point_e.x + nv3->pgraph.win95_gdi_text.size_out_e.w; - uint16_t clip_y = nv3->pgraph.win95_gdi_text.point_e.y + nv3->pgraph.win95_gdi_text.size_out_e.h; - - // if it's a 0 bit we don't need to do anything - - uint32_t final_color; - - switch (nv3->nvbase.svga.bpp) - { - case 8: - final_color = (bit) ? (nv3->pgraph.win95_gdi_text.color1_e & 0xFF) : (nv3->pgraph.win95_gdi_text.color0_e & 0xFF); /* do we need to add anything? mul blend perhaps? */ - break; - case 15: - case 16: - final_color = (bit) ? (nv3->pgraph.win95_gdi_text.color1_e & 0xFFFF) : (nv3->pgraph.win95_gdi_text.color0_e & 0xFFFF); /* do we need to add anything? mul blend perhaps? */ - break; - case 32: - final_color = (bit) ? nv3->pgraph.win95_gdi_text.color1_e : nv3->pgraph.win95_gdi_text.color0_e; /* do we need to add anything? mul blend perhaps? */ - break; - } + nv3_render_gdi_transparent_bitmap_blit(current_bit, clip, color, grobj); + nv3->pgraph.win95_gdi_text_bit_count++; + bits_remaining_in_bitmap--; - nv3_render_write_pixel(nv3->pgraph.win95_gdi_text_current_position, final_color, grobj); - - /* increment the position - the bitmap is stored horizontally backward */ - nv3->pgraph.win95_gdi_text_current_position.x--; - - /* see if we need to go to the next line */ - if (nv3->pgraph.win95_gdi_text_current_position.x < nv3->pgraph.win95_gdi_text.point_e.x) - { - nv3->pgraph.win95_gdi_text_current_position.x = nv3->pgraph.win95_gdi_text.point_e.x + (nv3->pgraph.win95_gdi_text.size_out_e.w - 1); - nv3->pgraph.win95_gdi_text_current_position.y++; - } - - /* check if we are in the clipping rectangle */ - if (nv3->pgraph.win95_gdi_text_current_position.x < nv3->pgraph.win95_gdi_text.clip_e.left - || nv3->pgraph.win95_gdi_text_current_position.x > nv3->pgraph.win95_gdi_text.clip_e.right - || nv3->pgraph.win95_gdi_text_current_position.y < nv3->pgraph.win95_gdi_text.clip_e.top - || nv3->pgraph.win95_gdi_text_current_position.y > nv3->pgraph.win95_gdi_text.clip_e.bottom) - { - return; - } + if (!bits_remaining_in_bitmap) + break; } - + /* IF we're done, let's return */ + if (!bits_remaining_in_bitmap) + return; + + /* Now for 31 through 24 */ + for (int32_t bit = 31; bit >= 24; bit--) + { + current_bit = (bitmap_data >> bit) & 0x01; + + nv3_render_gdi_transparent_bitmap_blit(current_bit, clip, color, grobj); + nv3->pgraph.win95_gdi_text_bit_count++; + bits_remaining_in_bitmap--; + + if (!bits_remaining_in_bitmap) + break; + } + + /* IF we're done, let's return */ + if (!bits_remaining_in_bitmap) + return; } -void nv3_render_gdi_type_e(nv3_grobj_t grobj, uint32_t param) +void nv3_render_gdi_1bpp_bitmap_blit(bool bit, uint32_t color0, uint32_t color1, nv3_grobj_t grobj) { - // reset when a position is submitted - nv3_position_16_t start_position = nv3->pgraph.win95_gdi_text_current_position; + /* We can't force the bit off because this is a 1bpp bitmap */ + bool skip = false; - /* we have to interpret every bit in reverse order but in the right bit order */ - uint8_t byte0 = ((param & 0xFF000000) >> 24); - uint8_t byte1 = ((param & 0xFF0000) >> 16); - uint8_t byte2 = ((param & 0xFF00) >> 8); - uint8_t byte3 = (param & 0xFF); + /* For Type E, always clip */ + /* Turn the bit off if we need to clip (Type D ) */ + if (nv3->pgraph.win95_gdi_text_current_position.x < nv3->pgraph.win95_gdi_text.clip_e.left + || nv3->pgraph.win95_gdi_text_current_position.x > nv3->pgraph.win95_gdi_text.clip_e.right + || nv3->pgraph.win95_gdi_text_current_position.y < nv3->pgraph.win95_gdi_text.clip_e.top + || nv3->pgraph.win95_gdi_text_current_position.y > nv3->pgraph.win95_gdi_text.clip_e.bottom) + { + skip = true; + } - nv3_render_text_1bpp_2color(byte0, grobj); - nv3_render_text_1bpp_2color(byte1, grobj); - nv3_render_text_1bpp_2color(byte2, grobj); - nv3_render_text_1bpp_2color(byte3, grobj); + /* + Also clip if we are outside of the SIZE_OUT range + We only need to do this in one direction just to get rid of the crud sent by NV + */ + uint32_t clip_x = nv3->pgraph.win95_gdi_text.point_e.x + (nv3->pgraph.win95_gdi_text.size_out_e.w); + uint32_t clip_y = nv3->pgraph.win95_gdi_text.point_e.y + (nv3->pgraph.win95_gdi_text.size_out_e.h); + + if (nv3->pgraph.win95_gdi_text_current_position.x >= clip_x + || nv3->pgraph.win95_gdi_text_current_position.y >= clip_y) + skip = true; + + /* We don't need to and it, because it seems the Riva only uses non-packed bpp formats for this class */ + if (!skip) + { + if (bit) + nv3_render_write_pixel(nv3->pgraph.win95_gdi_text_current_position, nv3->pgraph.win95_gdi_text.color1_e, grobj); + else + nv3_render_write_pixel(nv3->pgraph.win95_gdi_text_current_position, nv3->pgraph.win95_gdi_text.color0_e, grobj); + } + + + /* + Check if we've reached the bottom, if so, advance to the next horizontal lin + Because we check the bits in reverse, we go forward (bits 7,6,5 were set for a 1x3 bitmap) + */ + + uint32_t end_x = nv3->pgraph.win95_gdi_text.point_e.x + nv3->pgraph.win95_gdi_text.size_in_e.w; + + nv3->pgraph.win95_gdi_text_current_position.x++; + + if (nv3->pgraph.win95_gdi_text_current_position.x >= end_x) + { + nv3->pgraph.win95_gdi_text_current_position.y++; + nv3->pgraph.win95_gdi_text_current_position.x = nv3->pgraph.win95_gdi_text.point_e.x; + } +} + +/* Originally written 23 March 2025, but then, redone, properly, on 30 March 2025 */ +void nv3_render_gdi_1bpp_bitmap(uint32_t color0, uint32_t color1, uint32_t bitmap_data, nv3_grobj_t grobj) +{ + /* + First, we need to figure out how many bits we have left. + If we have less than 32, don't process all of the bits. + + Bits are processed in the following order: [7-0] [15-8] [23-16] [31-24] + TODO: Store this somewhere, so it doesn't need to be recalculated. + + We store a global bit count for this purpose. + */ + + uint32_t bitmap_size = nv3->pgraph.win95_gdi_text.size_in_e.w * nv3->pgraph.win95_gdi_text.size_in_e.h; + uint32_t bits_remaining_in_bitmap = bitmap_size - nv3->pgraph.win95_gdi_text_bit_count; + + /* we have to interpret every bit in reverse bit order but in the right byte order */ + + bool current_bit = false; + + /* Start by rendering bits 7 through 0 */ + for (int32_t bit = 7; bit >= 0; bit--) + { + current_bit = (bitmap_data >> bit) & 0x01; + + nv3_render_gdi_1bpp_bitmap_blit(current_bit, color0, color1, grobj); + nv3->pgraph.win95_gdi_text_bit_count++; + bits_remaining_in_bitmap--; + + if (!bits_remaining_in_bitmap) + break; + } + + /* IF we're done, let's return */ + if (!bits_remaining_in_bitmap) + return; + + /* Now for 15 through 8 */ + for (int32_t bit = 15; bit >= 8; bit--) + { + current_bit = (bitmap_data >> bit) & 0x01; + + nv3_render_gdi_1bpp_bitmap_blit(current_bit, color0, color1, grobj); + nv3->pgraph.win95_gdi_text_bit_count++; + bits_remaining_in_bitmap--; + + if (!bits_remaining_in_bitmap) + break; + } + + /* IF we're done, let's return */ + if (!bits_remaining_in_bitmap) + return; + + /* Now for 23 through 16 */ + for (int32_t bit = 23; bit >= 16; bit--) + { + current_bit = (bitmap_data >> bit) & 0x01; + + nv3_render_gdi_1bpp_bitmap_blit(current_bit, color0, color1, grobj); + nv3->pgraph.win95_gdi_text_bit_count++; + bits_remaining_in_bitmap--; + + if (!bits_remaining_in_bitmap) + break; + } + + /* IF we're done, let's return */ + if (!bits_remaining_in_bitmap) + return; + + /* Now for 31 through 24 */ + for (int32_t bit = 31; bit >= 24; bit--) + { + current_bit = (bitmap_data >> bit) & 0x01; + + nv3_render_gdi_1bpp_bitmap_blit(current_bit, color0, color1, grobj); + nv3->pgraph.win95_gdi_text_bit_count++; + bits_remaining_in_bitmap--; + + if (!bits_remaining_in_bitmap) + break; + } + + /* IF we're done, let's return */ + if (!bits_remaining_in_bitmap) + return; } \ No newline at end of file