#include "window.h" #include "vwf.h" byte decode_character(byte chr) { int c = chr - 0x50; if ((c < 0) || ((c >= 0x60) && (c < 0x64)) || (c >= 0x6E)) c = QUESTION_MARK; return c; } int get_tile_number(int x, int y) { x--; y--; return m2_coord_table[x + ((y >> 1) * 28)] + (y & 1) * 32; } int get_tile_number_with_offset(int x, int y) { return get_tile_number(x, y) + *tile_offset; } int get_tile_number_grid(int x, int y) { return x + (y * 32); } int expand_bit_depth(byte row, int foreground) { foreground &= 0xF; return m2_bits_to_nybbles[row + (foreground * 256)]; } byte reduce_bit_depth(int row, int foreground) { int foregroundRow = row * 0x11111111; row ^= foregroundRow; int lower = m2_nybbles_to_bits[row & 0xFFFF]; int upper = m2_nybbles_to_bits[(row >> 16) & 0xFFFF]; return lower | (upper << 4); } byte print_character(byte chr, int x, int y, int font, int foreground) { // 0x64 to 0x6C (inclusive) is YOU WON if ((chr >= 0x64) && (chr <= 0x6C)) { print_special_character(chr + 0xF0, x, y); return 8; } // 0x6D is an arrow -> else if (chr == 0x6D) { print_special_character(0x9D, x, y); return 8; } return print_character_with_callback(chr, x, y, font, foreground, vram, &get_tile_number_with_offset, TRUE); } byte print_character_to_ram(byte chr, int *dest, int xOffset, int font, int foreground) { return print_character_with_callback(chr, xOffset, 0, font, foreground, dest, &get_tile_number_grid, FALSE); } void print_special_character(int tile, int x, int y) { // Special graphics must be tile-aligned x >>= 3; y >>= 3; unsigned short sourceTileIndex = tile + *tile_offset; unsigned short destTileIndex = get_tile_number(x, y) + *tile_offset; (*tilemap_pointer)[x + (y * 32)] = destTileIndex | *palette_mask; (*tilemap_pointer)[x + ((y + 1) * 32)] = (destTileIndex + 32) | *palette_mask; cpufastset(&vram[sourceTileIndex * 8], &vram[destTileIndex * 8], 8); cpufastset(&vram[(sourceTileIndex + 32) * 8], &vram[(destTileIndex + 32) * 8], 8); } byte print_character_with_callback(byte chr, int x, int y, int font, int foreground, int *dest, int (*getTileCallback)(int, int), int useTilemap) { int tileWidth = m2_font_widths[font]; int tileHeight = m2_font_heights[font]; int widths = m2_widths_table[font][chr]; int paletteMask = *palette_mask; byte *glyphRows = &m2_font_table[font][chr * tileWidth * tileHeight * 8]; int virtualWidth = widths & 0xFF; int leftPortionWidth = 8 - (x & 7); int tileX = x >> 3; int tileY = y >> 3; for (int dTileY = 0; dTileY < tileHeight; dTileY++) // dest tile Y { int dTileX = 0; int renderedWidth = widths >> 8; while (renderedWidth > 0) { // Glue the leftmost part of the glyph onto the rightmost part of the canvas int tileIndex = getTileCallback(tileX + dTileX, tileY + dTileY); //get_tile_number(tileX + dTileX, tileY + dTileY) + tileOffset; for (int row = 0; row < 8; row++) { int canvasRow = dest[(tileIndex * 8) + row]; byte glyphRow = glyphRows[row + (dTileY * 8 * tileWidth) + (dTileX * 8)] & ((1 << leftPortionWidth) - 1); glyphRow <<= (8 - leftPortionWidth); int expandedGlyphRow = expand_bit_depth(glyphRow, foreground); int expandedGlyphRowMask = ~expand_bit_depth(glyphRow, 0xF); canvasRow &= expandedGlyphRowMask; canvasRow |= expandedGlyphRow; dest[(tileIndex * 8) + row] = canvasRow; } if (useTilemap) (*tilemap_pointer)[tileX + dTileX + ((tileY + dTileY) * 32)] = paletteMask | tileIndex; if (renderedWidth - leftPortionWidth > 0 && leftPortionWidth < 8) { // Glue the rightmost part of the glyph onto the leftmost part of the next tile // on the canvas tileIndex = getTileCallback(tileX + dTileX + 1, tileY + dTileY); //get_tile_number(tileX + dTileX + 1, tileY + dTileY) + tileOffset; for (int row = 0; row < 8; row++) { int canvasRow = dest[(tileIndex * 8) + row]; byte glyphRow = glyphRows[row + (dTileY * 8 * tileWidth) + (dTileX * 8)] >> leftPortionWidth; int expandedGlyphRow = expand_bit_depth(glyphRow, foreground); int expandedGlyphRowMask = ~expand_bit_depth(glyphRow, 0xF); canvasRow &= expandedGlyphRowMask; canvasRow |= expandedGlyphRow; dest[(tileIndex * 8) + row] = canvasRow; } if (useTilemap) (*tilemap_pointer)[tileX + dTileX + 1 + ((tileY + dTileY) * 32)] = paletteMask | tileIndex; } renderedWidth -= 8; dTileX++; } } return virtualWidth; } int print_window_header_string(int *dest, byte *str, int x, int y) { int pixelX = x & 7; int *destOffset = dest + ((x & ~7) + (y * 32)); for (;;) { byte code = *(str + 1); if (code == 0xFF) { if (*str == 0) break; str += 2; continue; } pixelX += print_character_to_ram(decode_character(*str++), destOffset, pixelX, 4, 0xF); } return pixelX - (x & 7); } void clear_window_header(int *dest) { dest += (0x10 + (0x11 * 32)) * 8; clear_rect_ram(dest, 16, 0x33333333); } void weld_entry(WINDOW *window, byte *str) { weld_entry_custom(window, str, 0, 0xF); } void weld_entry_custom(WINDOW *window, byte *str, int font, int foreground) { int chr = decode_character(*str); int x = window->pixel_x + (window->window_x + window->text_x) * 8; int y = (window->window_y + window->text_y) * 8; x += print_character(chr, x, y, font, foreground); window->pixel_x = x & 7; window->text_x = (x >> 3) - window->window_x; } // Returns: ____XXXX = number of characters printed // XXXX____ = number of pixels printed int print_string(byte *str, int x, int y) { byte chr; int initialX = x; int charCount = 0; while (str[1] != 0xFF) { x += print_character(decode_character(*str++), x, y, 0, 0xF); charCount++; } int totalWidth = x - initialX; return (charCount & 0xFFFF) | (totalWidth << 16); } void clear_tile(int x, int y, int pixels) { int tileIndex = get_tile_number(x, y) + *tile_offset; cpufastset(&pixels, &vram[tileIndex * 8], CPUFASTSET_FILL | 8); } void clear_rect(int x, int y, int width, int height, int pixels) { for (int tileY = 0; tileY < height; tileY++) { for (int tileX = 0; tileX < width; tileX++) { clear_tile(x + tileX, y + tileY, pixels); } } } void clear_rect_ram(int *dest, int tileCount, int pixels) { cpufastset(&pixels, dest, CPUFASTSET_FILL | (tileCount * 8)); } void clear_window(WINDOW *window) { clear_rect(window->window_x, window->window_y, window->window_width, window->window_height, 0x44444444); } void print_blankstr(int x, int y, int width) { clear_rect(x, y, width, 2, 0x44444444); } void copy_tile(int xSource, int ySource, int xDest, int yDest) { int sourceTileIndex = get_tile_number(xSource, ySource) + *tile_offset; int destTileIndex = get_tile_number(xDest, yDest) + *tile_offset; cpufastset(&vram[sourceTileIndex * 8], &vram[destTileIndex * 8], 8); } void copy_tile_up(int x, int y) { copy_tile(x, y, x, y - 2); } void print_space(WINDOW *window) { byte space = 0x50; weld_entry(window, &space); }