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....

This commit is contained in:
starfrost013
2025-03-30 23:56:42 +01:00
parent c8e7bfac9e
commit f1a231b6cc
5 changed files with 392 additions and 145 deletions

View File

@@ -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;

View File

@@ -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 */
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 */

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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;
}