MS-DOS: some optimizations for tile handling
* In both the 16 color and the VESA mode, the tileset image is loaded
and split into individual tiles; the tiles are then processed into a
form that is compatible with the video mode in use. For 16 color mode,
a tile is processed each time it is displayed, leading to slow
redrawing. For VESA mode, each tile is processed at startup, leading
to long startup times. Both modes are changed so that the tile is
processed once, when it is first displayed, and the result is cached.
* Use memcpy when splitting the image into tiles.
* Only load the tileset once. In 16 color mode, for reasons I do not
understand, the gr_init function is called twice, leading to delay
in startup. This does not happen in VESA mode.
This commit is contained in:
+59
-24
@@ -60,6 +60,8 @@ static unsigned long vesa_DoublePixels(unsigned long);
|
||||
static unsigned long vesa_TriplePixels(unsigned long);
|
||||
static void vesa_WriteStr(const char *, int, int, int, int);
|
||||
static unsigned char __far *vesa_FontPtrs(void);
|
||||
static unsigned char *vesa_tile(unsigned);
|
||||
static unsigned char *vesa_oview_tile(unsigned);
|
||||
/* static void vesa_process_tile(struct TileImage *tile); */
|
||||
|
||||
#ifdef POSITIONBAR
|
||||
@@ -849,7 +851,7 @@ vesa_redrawmap(void)
|
||||
for (cy = 0; cy < ROWNO; ++cy) {
|
||||
for (py = 0; py < vesa_oview_height; ++py) {
|
||||
for (cx = 0; cx < COLNO; ++cx) {
|
||||
tile = vesa_oview_tiles[map[cy][cx].tileidx];
|
||||
tile = vesa_oview_tile(map[cy][cx].tileidx);
|
||||
vesa_WritePixelRow(offset + p_row_width * cx, tile + p_row_width * py, p_row_width);
|
||||
}
|
||||
x = COLNO * vesa_oview_width;
|
||||
@@ -869,7 +871,7 @@ vesa_redrawmap(void)
|
||||
for (cy = clipy; cy <= (unsigned) clipymax && cy < ROWNO; ++cy) {
|
||||
for (py = 0; py < (unsigned) iflags.wc_tile_height; ++py) {
|
||||
for (cx = clipx; cx <= (unsigned) clipxmax && cx < COLNO; ++cx) {
|
||||
tile = vesa_tiles[map[cy][cx].tileidx];
|
||||
tile = vesa_tile(map[cy][cx].tileidx);
|
||||
vesa_WritePixelRow(offset + p_row_width * (cx - clipx), tile + p_row_width * py, p_row_width);
|
||||
}
|
||||
x = (cx - clipx) * iflags.wc_tile_width;
|
||||
@@ -1053,8 +1055,6 @@ vesa_Init(void)
|
||||
{
|
||||
static boolean inited = FALSE;
|
||||
const struct Pixel *paletteptr;
|
||||
unsigned i;
|
||||
unsigned num_pixels, num_oview_pixels;
|
||||
const char *tile_file;
|
||||
const char *font_name;
|
||||
int tilefailure = 0;
|
||||
@@ -1186,31 +1186,33 @@ vesa_Init(void)
|
||||
|
||||
/* Process tiles for the current video mode */
|
||||
vesa_tiles = (unsigned char **) alloc(total_tiles_used * sizeof(void *));
|
||||
memset(vesa_tiles, 0, total_tiles_used * sizeof(void *));
|
||||
vesa_oview_tiles = (unsigned char **) alloc(total_tiles_used * sizeof(void *));
|
||||
num_pixels = iflags.wc_tile_width * iflags.wc_tile_height;
|
||||
num_oview_pixels = vesa_oview_width * vesa_oview_height;
|
||||
memset(vesa_oview_tiles, 0, total_tiles_used * sizeof(void *));
|
||||
set_tile_type(vesa_pixel_size > 8);
|
||||
for (i = 0; i < (unsigned) total_tiles_used; ++i) {
|
||||
const struct TileImage *tile = get_tile(i);
|
||||
struct TileImage *ov_tile = stretch_tile(tile, vesa_oview_width, vesa_oview_height);
|
||||
}
|
||||
|
||||
RESTORE_WARNING_FORMAT_NONLITERAL
|
||||
|
||||
/* Return processed pixels for a normal tile */
|
||||
static unsigned char *
|
||||
vesa_tile(unsigned index)
|
||||
{
|
||||
if (vesa_tiles[index] == NULL) {
|
||||
unsigned num_pixels = iflags.wc_tile_width * iflags.wc_tile_height;
|
||||
const struct TileImage *tile = get_tile(index);
|
||||
unsigned j;
|
||||
unsigned char *t_img = (unsigned char *) alloc(num_pixels * vesa_pixel_bytes);
|
||||
unsigned char *ot_img = (unsigned char *) alloc(num_oview_pixels * vesa_pixel_bytes);
|
||||
vesa_tiles[i] = t_img;
|
||||
vesa_oview_tiles[i] = ot_img;
|
||||
vesa_tiles[index] = t_img;
|
||||
switch (vesa_pixel_bytes) {
|
||||
case 1:
|
||||
memcpy(t_img, tile->indexes, num_pixels);
|
||||
memcpy(ot_img, ov_tile->indexes, num_oview_pixels);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
for (j = 0; j < num_pixels; ++j) {
|
||||
((uint16_t *)t_img)[j] = vesa_MakeColor(tile->pixels[j]);
|
||||
}
|
||||
for (j = 0; j < num_oview_pixels; ++j) {
|
||||
((uint16_t *)ot_img)[j] = vesa_MakeColor(ov_tile->pixels[j]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
@@ -1220,6 +1222,42 @@ vesa_Init(void)
|
||||
t_img[3*j + 1] = (color >> 8) & 0xFF;
|
||||
t_img[3*j + 2] = (color >> 16) & 0xFF;
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
for (j = 0; j < num_pixels; ++j) {
|
||||
((uint32_t *)t_img)[j] = vesa_MakeColor(tile->pixels[j]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return vesa_tiles[index];
|
||||
}
|
||||
|
||||
/* Return processed pixels for an overview tile */
|
||||
static unsigned char *
|
||||
vesa_oview_tile(unsigned index)
|
||||
{
|
||||
if (vesa_oview_tiles[index] == NULL) {
|
||||
unsigned num_oview_pixels = vesa_oview_width * vesa_oview_height;
|
||||
const struct TileImage *tile = get_tile(index);
|
||||
struct TileImage *ov_tile = stretch_tile(tile, vesa_oview_width, vesa_oview_height);
|
||||
unsigned j;
|
||||
unsigned char *ot_img = (unsigned char *) alloc(num_oview_pixels * vesa_pixel_bytes);
|
||||
vesa_oview_tiles[index] = ot_img;
|
||||
switch (vesa_pixel_bytes) {
|
||||
case 1:
|
||||
memcpy(ot_img, ov_tile->indexes, num_oview_pixels);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
for (j = 0; j < num_oview_pixels; ++j) {
|
||||
((uint16_t *)ot_img)[j] = vesa_MakeColor(ov_tile->pixels[j]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
for (j = 0; j < num_oview_pixels; ++j) {
|
||||
unsigned long color = vesa_MakeColor(ov_tile->pixels[j]);
|
||||
ot_img[3*j + 0] = color & 0xFF;
|
||||
@@ -1229,9 +1267,6 @@ vesa_Init(void)
|
||||
break;
|
||||
|
||||
case 4:
|
||||
for (j = 0; j < num_pixels; ++j) {
|
||||
((uint32_t *)t_img)[j] = vesa_MakeColor(tile->pixels[j]);
|
||||
}
|
||||
for (j = 0; j < num_oview_pixels; ++j) {
|
||||
((uint32_t *)ot_img)[j] = vesa_MakeColor(ov_tile->pixels[j]);
|
||||
}
|
||||
@@ -1239,10 +1274,9 @@ vesa_Init(void)
|
||||
}
|
||||
free_tile(ov_tile);
|
||||
}
|
||||
free_tiles();
|
||||
}
|
||||
|
||||
RESTORE_WARNING_FORMAT_NONLITERAL
|
||||
return vesa_oview_tiles[index];
|
||||
}
|
||||
|
||||
/* Set the size of the map viewport */
|
||||
static void
|
||||
@@ -1314,6 +1348,7 @@ vesa_Finish(void)
|
||||
}
|
||||
free(vesa_tiles);
|
||||
free(vesa_oview_tiles);
|
||||
free_tiles();
|
||||
vesa_SwitchMode(MODETEXT);
|
||||
windowprocs.win_cliparound = tty_cliparound;
|
||||
g_attribute = attrib_text_normal;
|
||||
@@ -1873,11 +1908,11 @@ vesa_DisplayCell(int tilenum, int col, int row)
|
||||
unsigned p_row_width;
|
||||
|
||||
if (iflags.over_view) {
|
||||
tile = vesa_oview_tiles[tilenum];
|
||||
tile = vesa_oview_tile(tilenum);
|
||||
t_width = vesa_oview_width;
|
||||
t_height = vesa_oview_height;
|
||||
} else {
|
||||
tile = vesa_tiles[tilenum];
|
||||
tile = vesa_tile(tilenum);
|
||||
t_width = iflags.wc_tile_width;
|
||||
t_height = iflags.wc_tile_height;
|
||||
}
|
||||
|
||||
+71
-25
@@ -213,8 +213,8 @@ int vp[SCREENPLANES] = { 8, 4, 2, 1 };
|
||||
#endif
|
||||
int vp2[SCREENPLANES] = { 1, 2, 4, 8 };
|
||||
|
||||
static struct planar_cell_struct planecell;
|
||||
static struct overview_planar_cell_struct planecell_O;
|
||||
static struct planar_cell_struct **cell_cache;
|
||||
static struct overview_planar_cell_struct **cell_cache_O;
|
||||
|
||||
/* static int g_attribute; */ /* Current attribute to use */
|
||||
|
||||
@@ -410,6 +410,7 @@ vga_xputg(const glyph_info *glyphinfo,
|
||||
vga_WriteChar(ch, col, row, attr);
|
||||
} 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)
|
||||
decal_planar(&planecell, special);
|
||||
@@ -426,6 +427,7 @@ vga_xputg(const glyph_info *glyphinfo,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
struct overview_planar_cell_struct planecell_O;
|
||||
read_planar_tile_O(glyphnum, &planecell_O);
|
||||
vga_DisplayCell_O(&planecell_O, col, row);
|
||||
}
|
||||
@@ -512,11 +514,13 @@ vga_redrawmap(boolean clearfirst)
|
||||
} else {
|
||||
t = map[y][x].glyph;
|
||||
if (!iflags.over_view) {
|
||||
struct planar_cell_struct planecell;
|
||||
read_planar_tile(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);
|
||||
vga_DisplayCell_O(&planecell_O, x, y + TOP_MAP_ROW);
|
||||
}
|
||||
@@ -643,6 +647,7 @@ boolean left;
|
||||
}
|
||||
for (y = 0; y < ROWNO; ++y) {
|
||||
for (x = i; x < j; x += 2) {
|
||||
struct planar_cell_struct planecell;
|
||||
t = map[y][x].glyph;
|
||||
read_planar_tile(t, &planecell);
|
||||
if (map[y][x].special)
|
||||
@@ -656,47 +661,69 @@ boolean left;
|
||||
static void
|
||||
read_planar_tile(unsigned glyph, 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;
|
||||
|
||||
read_tile_indexes(glyph, indexes);
|
||||
/* cell->plane[0..3].image[0..15][0..1] */
|
||||
for (plane = 0; plane < SCREENPLANES; ++plane) {
|
||||
for (y = 0; y < TILE_Y; ++y) {
|
||||
for (byte = 0; byte < MAX_BYTES_PER_CELL; ++byte) {
|
||||
unsigned char b = 0;
|
||||
for (bit = 0; bit < 8; ++bit) {
|
||||
unsigned char x = byte * 8 + bit;
|
||||
unsigned char i = indexes[y][x];
|
||||
b <<= 1;
|
||||
if (i & (0x8 >> plane)) b |= 1;
|
||||
/* Get the processed tile from the cache if we can */
|
||||
pcell = cell_cache[tilenum];
|
||||
if (pcell == NULL) {
|
||||
/* Process the tile */
|
||||
pcell = (struct planar_cell_struct *) alloc(sizeof(*pcell));
|
||||
cell_cache[tilenum] = pcell;
|
||||
read_tile_indexes(glyph, indexes);
|
||||
/* pcell->plane[0..3].image[0..15][0..1] */
|
||||
for (plane = 0; plane < SCREENPLANES; ++plane) {
|
||||
for (y = 0; y < TILE_Y; ++y) {
|
||||
for (byte = 0; byte < MAX_BYTES_PER_CELL; ++byte) {
|
||||
unsigned char b = 0;
|
||||
for (bit = 0; bit < 8; ++bit) {
|
||||
unsigned char x = byte * 8 + bit;
|
||||
unsigned char i = indexes[y][x];
|
||||
b <<= 1;
|
||||
if (i & (0x8 >> plane)) b |= 1;
|
||||
}
|
||||
pcell->plane[plane].image[y][byte] = b;
|
||||
}
|
||||
cell->plane[plane].image[y][byte] = b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*cell = *pcell;
|
||||
}
|
||||
|
||||
static void
|
||||
read_planar_tile_O(unsigned glyph, 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;
|
||||
|
||||
read_tile_indexes(glyph, indexes);
|
||||
/* cell->plane[0..3].image[0..15][0..0] */
|
||||
for (plane = 0; plane < SCREENPLANES; ++plane) {
|
||||
for (y = 0; y < TILE_Y; ++y) {
|
||||
unsigned char b = 0;
|
||||
for (bit = 0; bit < 8; ++bit) {
|
||||
unsigned char x = bit * 2;
|
||||
unsigned char i = indexes[y][x];
|
||||
b <<= 1;
|
||||
if (i & (0x8 >> plane)) b |= 1;
|
||||
/* Get the processed tile from the cache if we can */
|
||||
pcell = cell_cache_O[tilenum];
|
||||
if (pcell == NULL) {
|
||||
/* Process the tile */
|
||||
pcell = (struct overview_planar_cell_struct *) alloc(sizeof(*pcell));
|
||||
cell_cache_O[tilenum] = pcell;
|
||||
read_tile_indexes(glyph, indexes);
|
||||
/* pcell->plane[0..3].image[0..15][0..0] */
|
||||
for (plane = 0; plane < SCREENPLANES; ++plane) {
|
||||
for (y = 0; y < TILE_Y; ++y) {
|
||||
unsigned char b = 0;
|
||||
for (bit = 0; bit < 8; ++bit) {
|
||||
unsigned char x = bit * 2;
|
||||
unsigned char i = indexes[y][x];
|
||||
b <<= 1;
|
||||
if (i & (0x8 >> plane)) b |= 1;
|
||||
}
|
||||
pcell->plane[plane].image[y][0] = b;
|
||||
}
|
||||
cell->plane[plane].image[y][0] = b;
|
||||
}
|
||||
}
|
||||
|
||||
*cell = *pcell;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -782,6 +809,15 @@ vga_Init(void)
|
||||
/* term_clear_screen() */ /* not vga_clear_screen() */
|
||||
return;
|
||||
}
|
||||
|
||||
if (cell_cache == NULL) {
|
||||
cell_cache = (struct planar_cell_struct **) alloc(
|
||||
total_tiles_used * sizeof(cell_cache[0]));
|
||||
memset(cell_cache, 0, total_tiles_used * sizeof(cell_cache[0]));
|
||||
cell_cache_O = (struct overview_planar_cell_struct **) alloc(
|
||||
total_tiles_used * sizeof(cell_cache_O[0]));
|
||||
memset(cell_cache_O, 0, total_tiles_used * sizeof(cell_cache_O[0]));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (iflags.usevga) {
|
||||
@@ -860,7 +896,17 @@ vga_SwitchMode(unsigned int mode)
|
||||
void
|
||||
vga_Finish(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
free_tiles();
|
||||
for (i = 0; i < total_tiles_used; ++i) {
|
||||
free(cell_cache[i]);
|
||||
free(cell_cache_O[i]);
|
||||
}
|
||||
free(cell_cache);
|
||||
cell_cache = NULL;
|
||||
free(cell_cache_O);
|
||||
cell_cache_O = NULL;
|
||||
vga_SwitchMode(MODETEXT);
|
||||
windowprocs.win_cliparound = tty_cliparound;
|
||||
g_attribute = attrib_text_normal;
|
||||
|
||||
+13
-11
@@ -30,6 +30,9 @@ read_tiles(const char *filename, boolean true_color)
|
||||
char header[16];
|
||||
boolean ok;
|
||||
|
||||
if (tiles != NULL)
|
||||
return;
|
||||
|
||||
/* Fill the image structure with known values */
|
||||
image.width = 0;
|
||||
image.height = 0;
|
||||
@@ -283,7 +286,7 @@ split_tiles(const struct TileSetImage *image)
|
||||
{
|
||||
unsigned tile_rows, tile_cols;
|
||||
size_t tile_size, i, j;
|
||||
unsigned x1, y1, x2, y2;
|
||||
unsigned x1, y1, y2;
|
||||
|
||||
/* Get the number of tiles */
|
||||
tile_rows = image->height / iflags.wc_tile_height;
|
||||
@@ -308,16 +311,15 @@ split_tiles(const struct TileSetImage *image)
|
||||
tile->indexes = (unsigned char *) alloc(tile_size);
|
||||
}
|
||||
for (y2 = 0; y2 < (unsigned) iflags.wc_tile_height; ++y2) {
|
||||
for (x2 = 0; x2 < (unsigned) iflags.wc_tile_width; ++x2) {
|
||||
unsigned x = x1 * iflags.wc_tile_width + x2;
|
||||
unsigned y = y1 * iflags.wc_tile_height + y2;
|
||||
|
||||
i = y * image->width + x;
|
||||
j = y2 * tile->width + x2;
|
||||
tile->pixels[j] = image->pixels[i];
|
||||
if (image->indexes != NULL) {
|
||||
tile->indexes[j] = image->indexes[i];
|
||||
}
|
||||
unsigned y = y1 * iflags.wc_tile_height + y2;
|
||||
unsigned x = x1 * iflags.wc_tile_width;
|
||||
i = y * image->width;
|
||||
j = y2 * tile->width;
|
||||
memcpy(tile->pixels + j, image->pixels + i + x,
|
||||
sizeof(tile->pixels[0]) * iflags.wc_tile_width);
|
||||
if (image->indexes != NULL) {
|
||||
memcpy(tile->indexes + j, image->indexes + i + x,
|
||||
iflags.wc_tile_width);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user