From 30092b9b1583d32c5cf810711cfa26c5c1b58727 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Tue, 9 May 2023 10:51:38 -0700 Subject: [PATCH] input_keyboard: factor out font handling functions I might later question this decision. I liked how each "hardware" example was roughly one self-contained file. In the "input_keyboard" case, this is no longer true. --- Makefile | 4 +- common/copy.hpp | 10 +++ common/draw_font.cpp | 41 +++++++++ common/draw_font.hpp | 52 ++++++++++++ common/font.hpp | 5 ++ common/palette.cpp | 26 ++++++ common/palette.hpp | 5 ++ smpc/input_keyboard.cpp | 180 ++++++++-------------------------------- 8 files changed, 177 insertions(+), 146 deletions(-) create mode 100644 common/copy.hpp create mode 100644 common/draw_font.cpp create mode 100644 common/draw_font.hpp create mode 100644 common/palette.cpp create mode 100644 common/palette.hpp diff --git a/Makefile b/Makefile index 35ff630..aeae80d 100644 --- a/Makefile +++ b/Makefile @@ -56,7 +56,9 @@ common/keyboard.hpp: common/keyboard.py common/keyboard.cpp: common/keyboard.py common/keyboard.hpp python common/keyboard.py definition > $@ -smpc/input_keyboard.elf: smpc/input_keyboard.o sh/lib1funcs.o res/dejavusansmono.font.bin.o common/keyboard.o +smpc/input_keyboard.o: common/keyboard.hpp + +smpc/input_keyboard.elf: smpc/input_keyboard.o sh/lib1funcs.o res/dejavusansmono.font.bin.o common/keyboard.o common/draw_font.o common/palette.o games/tetris.elf: games/tetris.o sh/lib1funcs.o diff --git a/common/copy.hpp b/common/copy.hpp new file mode 100644 index 0000000..4df90fc --- /dev/null +++ b/common/copy.hpp @@ -0,0 +1,10 @@ +#include + +template +inline void copy(T * dst, const T * src, int32_t n) noexcept +{ + while (n > 0) { + *dst++ = *src++; + n -= (sizeof (T)); + } +} diff --git a/common/draw_font.cpp b/common/draw_font.cpp new file mode 100644 index 0000000..e9311ce --- /dev/null +++ b/common/draw_font.cpp @@ -0,0 +1,41 @@ +#include "vdp1.h" + +#include "font.hpp" +#include "copy.hpp" +#include "draw_font.hpp" + +uint32_t pixel_data(const uint32_t top, const uint8_t * glyph_bitmaps, const uint32_t size) +{ + const uint32_t table_size = (size + 0x20 - 1) & (-0x20); + const uint32_t table_address = top - table_size; + + uint32_t * table = &vdp1.vram.u32[(table_address / 4)]; + + const uint32_t * buf = reinterpret_cast(&glyph_bitmaps[0]); + + copy(table, buf, size); + + return table_address; +} + +namespace draw_font { + +uint32_t font_data(void * buf, uint32_t top, state& state) +{ + uint8_t * data = reinterpret_cast(buf); + + font * font = reinterpret_cast(&data[0]); + glyph * glyphs = reinterpret_cast(&data[(sizeof (struct font))]); + // there are three 32-bit fields before the start of `glyphs` + const uint8_t * glyph_bitmaps = &data[(sizeof (struct font)) + ((sizeof (struct glyph)) * font->glyph_index)]; + + top = pixel_data(top, glyph_bitmaps, font->bitmap_offset); + + state.character_address = top; + state._font = font; + state._glyphs = glyphs; + + return top; +} + +} diff --git a/common/draw_font.hpp b/common/draw_font.hpp new file mode 100644 index 0000000..77fe7c3 --- /dev/null +++ b/common/draw_font.hpp @@ -0,0 +1,52 @@ +#include + +#include "font.hpp" + +namespace draw_font { + +struct state { + uint32_t color_address; + uint32_t character_address; + font * _font; + glyph * _glyphs; +}; + +uint32_t font_data(void * buf, uint32_t top, state& state); + +template +uint32_t horizontal_string(state const& s, + uint32_t& cmd_ix, + const T * string, + const uint32_t length, + const int32_t x, + const int32_t y) +{ + int32_t total_advance = 0; + + for (uint32_t i = 0; i < length; i++) { + const T c = string[i]; + //assert(c <= s.char_code_offset); + const T c_offset = c - s._font->char_code_offset; + + glyph_bitmap const& bitmap = s._glyphs[c_offset].bitmap; + glyph_metrics const& metrics = s._glyphs[c_offset].metrics; + + if (bitmap.pitch != 0) { + vdp1.vram.cmd[cmd_ix].CTRL = CTRL__JP__JUMP_NEXT | CTRL__COMM__NORMAL_SPRITE; + vdp1.vram.cmd[cmd_ix].LINK = 0; + vdp1.vram.cmd[cmd_ix].PMOD = PMOD__COLOR_MODE__COLOR_BANK_256; + vdp1.vram.cmd[cmd_ix].COLR = s.color_address; + vdp1.vram.cmd[cmd_ix].SRCA = SRCA(s.character_address + bitmap.offset); + vdp1.vram.cmd[cmd_ix].SIZE = SIZE__X(bitmap.pitch) | SIZE__Y(bitmap.rows); + vdp1.vram.cmd[cmd_ix].XA = (total_advance + x + metrics.horiBearingX) >> 6; + vdp1.vram.cmd[cmd_ix].YA = (y - metrics.horiBearingY) >> 6; + cmd_ix++; + } + + total_advance += metrics.horiAdvance; + } + + return total_advance; +} + +} diff --git a/common/font.hpp b/common/font.hpp index acd5315..6fb5ef4 100644 --- a/common/font.hpp +++ b/common/font.hpp @@ -1,3 +1,8 @@ +// this file is designed to be platform-agnostic +#pragma once + +#include + // metrics are 26.6 fixed point struct glyph_metrics { int32_t width; diff --git a/common/palette.cpp b/common/palette.cpp new file mode 100644 index 0000000..d6395f5 --- /dev/null +++ b/common/palette.cpp @@ -0,0 +1,26 @@ +#include + +#include "vdp2.h" + +#include "palette.hpp" + +constexpr inline uint16_t rgb15_gray(uint32_t intensity) +{ + return ((intensity & 31) << 10) // blue + | ((intensity & 31) << 5 ) // green + | ((intensity & 31) << 0 ); // red +} + +namespace palette { + +void vdp2_cram_32grays(uint32_t colors_per_palette, uint32_t color_bank_index) +{ + /* generate a palette of 32 grays */ + uint16_t * table = &vdp2.cram.u16[colors_per_palette * color_bank_index]; + + for (uint32_t i = 0; i <= 31; i++) { + table[i] = rgb15_gray(i); + } +} + +} diff --git a/common/palette.hpp b/common/palette.hpp new file mode 100644 index 0000000..7f99a7a --- /dev/null +++ b/common/palette.hpp @@ -0,0 +1,5 @@ +namespace palette { + + void vdp2_cram_32grays(uint32_t colors_per_palette, uint32_t color_bank_index); + +} diff --git a/smpc/input_keyboard.cpp b/smpc/input_keyboard.cpp index cb14976..52904a0 100644 --- a/smpc/input_keyboard.cpp +++ b/smpc/input_keyboard.cpp @@ -7,37 +7,16 @@ #include "../common/keyboard.hpp" #include "../common/font.hpp" +#include "../common/draw_font.hpp" +#include "../common/palette.hpp" /* begin font */ extern void * _dejavusans_start __asm("_binary_res_dejavusansmono_font_bin_start"); -constexpr inline uint16_t rgb15_gray(uint32_t intensity) -{ - return ((intensity & 31) << 10) // blue - | ((intensity & 31) << 5 ) // green - | ((intensity & 31) << 0 ); // red -} +/* end font */ -void vdp2_color_palette(uint32_t colors, uint32_t color_bank) -{ - /* generate a palette of 32 grays */ - - uint16_t * table = &vdp2.cram.u16[colors * color_bank]; - - for (uint32_t i = 0; i <= 31; i++) { - table[i] = rgb15_gray(i); - } -} - -template -void copy(T * dst, const T * src, int32_t n) noexcept -{ - while (n > 0) { - *dst++ = *src++; - n -= (sizeof (T)); - } -} +/* square stuff */ struct color { uint8_t r; @@ -45,77 +24,6 @@ struct color { uint8_t b; }; -uint32_t pixel_data(const uint32_t top, const uint8_t * glyph_bitmaps, const uint32_t bitmap_offset) -{ - const uint32_t * buf = reinterpret_cast(&glyph_bitmaps[0]); - - const uint32_t table_size = (bitmap_offset + 0x20 - 1) & (-0x20); - const uint32_t table_address = top - table_size; - - uint32_t * table = &vdp1.vram.u32[(table_address / 4)]; - - copy(table, buf, bitmap_offset); - - return table_address; -} - -uint32_t font_data(uint32_t top, const font ** font_out, const glyph ** glyphs_out) -{ - uint8_t * data = reinterpret_cast(&_dejavusans_start); - - const font * font = reinterpret_cast(&data[0]); - const glyph * glyphs = reinterpret_cast(&data[(sizeof (struct font))]); - // there are three 32-bit fields before the start of `glyphs` - const uint8_t * glyph_bitmaps = &data[(sizeof (struct font)) + ((sizeof (struct glyph)) * font->glyph_index)]; - - top = pixel_data(top, glyph_bitmaps, font->bitmap_offset); - - *font_out = font; - *glyphs_out = glyphs; - - return top; -} - -uint32_t draw_utf16_string(const uint32_t color_address, - const uint32_t character_address, - const uint32_t char_code_offset, - const glyph * glyphs, - uint32_t cmd_ix, - const char16_t * string, - const uint32_t length, - int32_t& x, - int32_t& y) -{ - for (uint32_t i = 0; i < length; i++) { - const char16_t c = string[i]; - //assert(c <= char_code_offset); - const uint16_t c_offset = c - char_code_offset; - - const glyph_bitmap& bitmap = glyphs[c_offset].bitmap; - const glyph_metrics& metrics = glyphs[c_offset].metrics; - - if (bitmap.pitch != 0) { - vdp1.vram.cmd[cmd_ix].CTRL = CTRL__JP__JUMP_NEXT | CTRL__COMM__NORMAL_SPRITE; - vdp1.vram.cmd[cmd_ix].LINK = 0; - vdp1.vram.cmd[cmd_ix].PMOD = PMOD__ECD | PMOD__COLOR_MODE__COLOR_BANK_256; - vdp1.vram.cmd[cmd_ix].COLR = color_address; // non-palettized (rgb15) color data - vdp1.vram.cmd[cmd_ix].SRCA = SRCA(character_address + bitmap.offset); - vdp1.vram.cmd[cmd_ix].SIZE = SIZE__X(bitmap.pitch) | SIZE__Y(bitmap.rows); - vdp1.vram.cmd[cmd_ix].XA = (x + metrics.horiBearingX) >> 6; - vdp1.vram.cmd[cmd_ix].YA = (y - metrics.horiBearingY) >> 6; - cmd_ix++; - } - - x += metrics.horiAdvance; - } - - return cmd_ix; -} - -/* end font */ - -/* square stuff */ - const static color colors[16] = { {255, 255, 255}, // (SPD / transparent) 0 {0, 255, 255}, // I (cyan) 1 @@ -261,9 +169,7 @@ uint32_t print_hex(char16_t * c, uint32_t len, uint32_t n) return ret; } -static uint32_t font_color_address, font_character_address; -static const font * font; -static const glyph * glyphs; +static struct draw_font::state font_state; static uint32_t global_cmd_ix = 0; @@ -340,11 +246,8 @@ void smpc_int(void) { char16_t c = keysym_to_char16(k); if (k != keysym::UNKNOWN && c != -1) { text[0] = c; - global_cmd_ix = draw_utf16_string(font_color_address, - font_character_address, - font->char_code_offset, - glyphs, - global_cmd_ix, + x += draw_font::horizontal_string(font_state, + global_cmd_ix, // modified &text[0], 1, x, @@ -362,15 +265,12 @@ void smpc_int(void) { int32_t qy = 150 << 6; uint32_t cmd_ix = 4; - cmd_ix = draw_utf16_string(font_color_address, - font_character_address, - font->char_code_offset, - glyphs, - cmd_ix, - str_num, - 2, - qx, - qy); + draw_font::horizontal_string(font_state, + cmd_ix, // modified + &str_num[0], + 2, + qx, + qy); } break; default: @@ -447,26 +347,28 @@ static inline void v_blank_in() { while ((vdp2.reg.TVSTAT & TVSTAT__VBLANK) == 0); } +uint32_t init_font(uint32_t top) +{ + // 256 is the number of colors in the color palette, not the number of grays + // that are used by the font. + constexpr uint32_t colors_per_palette = 256; + constexpr uint32_t color_bank_index = 0; // completely random and arbitrary value + + palette::vdp2_cram_32grays(colors_per_palette, color_bank_index); + // For color bank color, COLR is concatenated bitwise with pixel data. See + // Figure 6.17 in the VDP1 manual. + font_state.color_address = color_bank_index << 8; + + top = font_data(&_dejavusans_start, top, font_state); + + return top; +} + void main() { uint32_t top = (sizeof (union vdp1_vram)); - // begin font - - // 256 is the number of colors in the color palette, not the number of grays - // that are used by the font. - constexpr uint32_t font_colors = 256; - constexpr uint32_t font_color_bank = 0; // completely random and arbitrary value - - vdp2_color_palette(font_colors, font_color_bank); - // For color bank color, COLR is concatenated bitwise with pixel data. See - // Figure 6.17 in the VDP1 manual. - font_color_address = font_color_bank << 8; - - top = font_character_address = font_data(top, &font, &glyphs); - - // end font - + top = init_font(top); // begin squares @@ -563,23 +465,11 @@ void main() vdp1.vram.cmd[3].XA = foo[1].x; vdp1.vram.cmd[3].YA = foo[1].y; - int32_t qx = 8 << 6; - int32_t qy = 150 << 6; + vdp1.vram.cmd[4].CTRL = CTRL__END; + vdp1.vram.cmd[5].CTRL = CTRL__END; - uint32_t cmd_ix = 4; - const char16_t _xx[] = u"xx"; - cmd_ix = draw_utf16_string(font_color_address, - font_character_address, - font->char_code_offset, - glyphs, - cmd_ix, - _string, - ((sizeof (_xx)) / (sizeof (_xx[0]))) - 1, - qx, - qy); - - vdp1.vram.cmd[cmd_ix].CTRL = CTRL__END; - global_cmd_ix = cmd_ix; + vdp1.vram.cmd[6].CTRL = CTRL__END; + global_cmd_ix = 6; // start drawing (execute the command list) on every frame vdp1.reg.PTMR = PTMR__PTM__FRAME_CHANGE;