From 3e800b90d313acbefb9ef2d08ce9161978496bb2 Mon Sep 17 00:00:00 2001 From: Ray Chason Date: Tue, 4 Aug 2026 15:55:36 -0400 Subject: [PATCH] Support pet and tile decals in 16 color mode --- sys/msdos/vidvga.c | 173 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 147 insertions(+), 26 deletions(-) diff --git a/sys/msdos/vidvga.c b/sys/msdos/vidvga.c index 6052cb9fa..101862e10 100644 --- a/sys/msdos/vidvga.c +++ b/sys/msdos/vidvga.c @@ -121,6 +121,7 @@ static void vga_scrollmap(boolean); static void vga_redrawmap(boolean); static void vga_cliparound(int, int); static void decal_planar(struct planar_cell_struct *, unsigned); +static void decal_oview_planar(struct overview_planar_cell_struct *, unsigned); #endif #ifdef POSITIONBAR @@ -141,6 +142,7 @@ static void vga_WriteStr(char *, int, int, int, int); static char __far *vga_FontPtrs(void); #ifdef TILES_IN_GLYPHMAP +static int glyph_to_tilenum(unsigned); static void read_planar_tile(unsigned, struct planar_cell_struct *); static void read_planar_tile_O(unsigned, struct overview_planar_cell_struct *); @@ -243,6 +245,10 @@ static int vp[SCREENPLANES] = { 8, 4, 2, 1 }; #ifdef TILES_IN_GLYPHMAP static struct planar_cell_struct **cell_cache; static struct overview_planar_cell_struct **cell_cache_O; + +enum { delimdecal, petdecal, piledecal, NUMDECALS }; +static struct cellplane *decal_alpha[NUMDECALS] = { 0 }; +static struct overview_cellplane *decal_oview_alpha[NUMDECALS] = { 0 }; #endif /* static int g_attribute; */ /* Current attribute to use */ @@ -442,8 +448,8 @@ vga_xputg(const glyph_info *glyphinfo, } else if (!iflags.over_view) { if ((col >= clipx) && (col <= clipxmax)) { struct planar_cell_struct planecell; - read_planar_tile(glyphnum, &planecell); - if (map[ry][col].special) + read_planar_tile(glyph_to_tilenum(glyphnum), &planecell); + if (special) decal_planar(&planecell, special); vga_DisplayCell(&planecell, col - clipx, row); if (bkglyphinfo->framecolor != NO_COLOR) { @@ -459,7 +465,9 @@ vga_xputg(const glyph_info *glyphinfo, } } else { struct overview_planar_cell_struct planecell_O; - read_planar_tile_O(glyphnum, &planecell_O); + read_planar_tile_O(glyph_to_tilenum(glyphnum), &planecell_O); + if (special) + decal_oview_planar(&planecell_O, special); vga_DisplayCell_O(&planecell_O, col, row); } if (col < (CO - 1)) @@ -546,13 +554,15 @@ vga_redrawmap(boolean clearfirst) t = map[y][x].glyph; if (!iflags.over_view) { struct planar_cell_struct planecell; - read_planar_tile(t, &planecell); + read_planar_tile(glyph_to_tilenum(t), &planecell); if (map[y][x].special) decal_planar(&planecell, map[y][x].special); vga_DisplayCell(&planecell, x - clipx, y + TOP_MAP_ROW); } else { struct overview_planar_cell_struct planecell_O; - read_planar_tile_O(t, &planecell_O); + read_planar_tile_O(glyph_to_tilenum(t), &planecell_O); + if (map[y][x].special) + decal_oview_planar(&planecell_O, map[y][x].special); vga_DisplayCell_O(&planecell_O, x, y + TOP_MAP_ROW); } } @@ -684,7 +694,7 @@ boolean left; for (x = i; x < j; x += 2) { struct planar_cell_struct planecell; t = map[y][x].glyph; - read_planar_tile(t, &planecell); + read_planar_tile(glyph_to_tilenum(t), &planecell); if (map[y][x].special) decal_planar(&planecell, map[y][x].special); vga_DisplayCell(&planecell, x - clipx, y + TOP_MAP_ROW); @@ -693,13 +703,23 @@ boolean left; } #endif /* SCROLLMAP */ +static int +glyph_to_tilenum(unsigned glyph) +{ + /* We don't have enough colors to show the statues */ + if (glyph_is_statue(glyph)) { + glyph = GLYPH_OBJ_OFF + STATUE; + } + + return glyphmap[glyph].tileidx; +} + static void -read_planar_tile(unsigned glyph, struct planar_cell_struct *cell) +read_planar_tile(unsigned tilenum, struct planar_cell_struct *cell) { struct planar_cell_struct *pcell; unsigned char indexes[TILE_Y][TILE_X]; unsigned plane, y, byte, bit; - int tilenum = glyphmap[glyph].tileidx; /* Get the processed tile from the cache if we can */ pcell = cell_cache[tilenum]; @@ -707,7 +727,7 @@ read_planar_tile(unsigned glyph, struct planar_cell_struct *cell) /* Process the tile */ pcell = (struct planar_cell_struct *) alloc(sizeof(*pcell)); cell_cache[tilenum] = pcell; - read_tile_indexes(glyph, indexes); + read_tile_indexes(tilenum, indexes); /* pcell->plane[0..3].image[0..15][0..1] */ for (plane = 0; plane < SCREENPLANES; ++plane) { for (y = 0; y < TILE_Y; ++y) { @@ -729,12 +749,11 @@ read_planar_tile(unsigned glyph, struct planar_cell_struct *cell) } static void -read_planar_tile_O(unsigned glyph, struct overview_planar_cell_struct *cell) +read_planar_tile_O(unsigned tilenum, struct overview_planar_cell_struct *cell) { struct overview_planar_cell_struct *pcell; unsigned char indexes[TILE_Y][TILE_X]; unsigned plane, y, bit; - int tilenum = glyphmap[glyph].tileidx; /* Get the processed tile from the cache if we can */ pcell = cell_cache_O[tilenum]; @@ -742,7 +761,7 @@ read_planar_tile_O(unsigned glyph, struct overview_planar_cell_struct *cell) /* Process the tile */ pcell = (struct overview_planar_cell_struct *) alloc(sizeof(*pcell)); cell_cache_O[tilenum] = pcell; - read_tile_indexes(glyph, indexes); + read_tile_indexes(tilenum, indexes); /* pcell->plane[0..3].image[0..15][0..0] */ for (plane = 0; plane < SCREENPLANES; ++plane) { for (y = 0; y < TILE_Y; ++y) { @@ -762,19 +781,12 @@ read_planar_tile_O(unsigned glyph, struct overview_planar_cell_struct *cell) } static void -read_tile_indexes(unsigned glyph, unsigned char (*indexes)[TILE_X]) +read_tile_indexes(unsigned tilenum, unsigned char (*indexes)[TILE_X]) { const struct TileImage *tile; unsigned x, y; - int tilenum; - - /* We don't have enough colors to show the statues */ - if (glyph_is_statue(glyph)) { - glyph = GLYPH_OBJ_OFF + STATUE; - } /* Get the tile from the image */ - tilenum = glyphmap[glyph].tileidx; tile = get_tile(tilenum); /* Map to a 16 bit palette; assume colors laid out as in default tileset */ @@ -792,13 +804,122 @@ read_tile_indexes(unsigned glyph, unsigned char (*indexes)[TILE_X]) } static void -decal_planar(struct planar_cell_struct *gpcs UNUSED, unsigned special) +decal_planar(struct planar_cell_struct *gpcs, unsigned special) { - if (special & MG_CORPSE) { - } else if (special & MG_INVIS) { - } else if (special & MG_DETECT) { - } else if (special & MG_PET) { - } else if (special & MG_RIDDEN) { + int decalnum; /* indexes decal_alpha */ + int decal_tile; /* tile index of decal */ + + /* Which decal do we use? */ + if ((special & MG_PET) != 0 && iflags.hilite_pet) { + decalnum = petdecal; + decal_tile = Tile_petmark; + } else if ((special & MG_OBJPILE) != 0 && iflags.hilite_pile) { + decalnum = piledecal; + decal_tile = Tile_pilemark; + } else { + /* No decal */ + return; + } + + /* Read the decal */ + struct planar_cell_struct decal; + read_planar_tile(decal_tile, &decal); + + /* Build the alpha channel for the decal */ + struct cellplane *alpha = decal_alpha[decalnum]; + + if (alpha == NULL) { + /* Read the delimiter to get the background color */ + struct planar_cell_struct delim; + read_planar_tile(Tile_delimiter, &delim); + + /* Allocate space for the alpha channel */ + alpha = (struct cellplane *) alloc(sizeof(*alpha)); + decal_alpha[decalnum] = alpha; + memset(alpha, 0x00, sizeof(*alpha)); + + /* Alpha channel is 0 where all planes of the decal match the + background, and 1 otherwise */ + for (unsigned i = 0; i < SCREENPLANES; ++i) { + uint8_t background = (delim.plane[i].image[0][0] & 0x80) ? 0xFF : 0x00; + for (unsigned j = 0; j < MAX_ROWS_PER_CELL; ++j) { + for (unsigned k = 0; k < MAX_BYTES_PER_CELL; ++k) { + /* Set alpha to 1 wherever the decal doesn't match the + background */ + alpha->image[j][k] |= decal.plane[i].image[j][k] ^ background; + } + } + } + } + + /* Apply the decal to the tile */ + for (unsigned i = 0; i < SCREENPLANES; ++i) { + for (unsigned j = 0; j < MAX_ROWS_PER_CELL; ++j) { + for (unsigned k = 0; k < MAX_BYTES_PER_CELL; ++k) { + uint8_t b1 = gpcs->plane[i].image[j][k]; + uint8_t b2 = decal.plane[i].image[j][k]; + uint8_t a = alpha->image[j][k]; + gpcs->plane[i].image[j][k] = (b1 & ~a) | (b2 & a); + } + } + } +} + +static void +decal_oview_planar(struct overview_planar_cell_struct *gpcs, unsigned special) +{ + int decalnum; /* indexes decal_alpha */ + int decal_tile; /* tile index of decal */ + + /* Which decal do we use? */ + if ((special & MG_PET) != 0 && iflags.hilite_pet) { + decalnum = petdecal; + decal_tile = Tile_petmark; + } else if ((special & MG_OBJPILE) != 0 && iflags.hilite_pile) { + decalnum = piledecal; + decal_tile = Tile_pilemark; + } else { + /* No decal */ + return; + } + + /* Read the decal */ + struct overview_planar_cell_struct decal; + read_planar_tile_O(decal_tile, &decal); + + /* Build the alpha channel for the decal */ + struct overview_cellplane *alpha = decal_oview_alpha[decalnum]; + + if (alpha == NULL) { + /* Read the delimiter to get the background color */ + struct planar_cell_struct delim; /* not overview_planar_cell_struct */ + read_planar_tile(Tile_delimiter, &delim); + + /* Allocate space for the alpha channel */ + alpha = (struct overview_cellplane *) alloc(sizeof(*alpha)); + decal_oview_alpha[decalnum] = alpha; + memset(alpha, 0x00, sizeof(*alpha)); + + /* Alpha channel is 0 where all planes of the decal match the + background, and 1 otherwise */ + for (unsigned i = 0; i < SCREENPLANES; ++i) { + uint8_t background = (delim.plane[i].image[0][0] & 0x80) ? 0xFF : 0x00; + for (unsigned j = 0; j < MAX_ROWS_PER_CELL; ++j) { + /* Set alpha to 1 wherever the decal doesn't match the + background */ + alpha->image[j][0] |= decal.plane[i].image[j][0] ^ background; + } + } + } + + /* Apply the decal to the tile */ + for (unsigned i = 0; i < SCREENPLANES; ++i) { + for (unsigned j = 0; j < MAX_ROWS_PER_CELL; ++j) { + uint8_t b1 = gpcs->plane[i].image[j][0]; + uint8_t b2 = decal.plane[i].image[j][0]; + uint8_t a = alpha->image[j][0]; + gpcs->plane[i].image[j][0] = (b1 & ~a) | (b2 & a); + } } } #endif /* TILES_IN_GLYPHMAP */