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.
This commit is contained in:
Zack Buhman 2023-05-09 10:51:38 -07:00
parent 65e48d7c6f
commit 30092b9b15
8 changed files with 177 additions and 146 deletions

View File

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

10
common/copy.hpp Normal file
View File

@ -0,0 +1,10 @@
#include <stdint.h>
template <typename T>
inline void copy(T * dst, const T * src, int32_t n) noexcept
{
while (n > 0) {
*dst++ = *src++;
n -= (sizeof (T));
}
}

41
common/draw_font.cpp Normal file
View File

@ -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<const uint32_t *>(&glyph_bitmaps[0]);
copy<uint32_t>(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<uint8_t*>(buf);
font * font = reinterpret_cast<struct font*>(&data[0]);
glyph * glyphs = reinterpret_cast<struct glyph*>(&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;
}
}

52
common/draw_font.hpp Normal file
View File

@ -0,0 +1,52 @@
#include <stdint.h>
#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 <typename T>
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;
}
}

View File

@ -1,3 +1,8 @@
// this file is designed to be platform-agnostic
#pragma once
#include <stdint.h>
// metrics are 26.6 fixed point
struct glyph_metrics {
int32_t width;

26
common/palette.cpp Normal file
View File

@ -0,0 +1,26 @@
#include <stdint.h>
#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);
}
}
}

5
common/palette.hpp Normal file
View File

@ -0,0 +1,5 @@
namespace palette {
void vdp2_cram_32grays(uint32_t colors_per_palette, uint32_t color_bank_index);
}

View File

@ -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 <typename T>
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<const uint32_t *>(&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<uint32_t>(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<uint8_t*>(&_dejavusans_start);
const font * font = reinterpret_cast<struct font*>(&data[0]);
const glyph * glyphs = reinterpret_cast<struct glyph*>(&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,12 +265,9 @@ 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,
draw_font::horizontal_string(font_state,
cmd_ix, // modified
&str_num[0],
2,
qx,
qy);
@ -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;