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:
parent
65e48d7c6f
commit
30092b9b15
4
Makefile
4
Makefile
@ -56,7 +56,9 @@ common/keyboard.hpp: common/keyboard.py
|
|||||||
common/keyboard.cpp: common/keyboard.py common/keyboard.hpp
|
common/keyboard.cpp: common/keyboard.py common/keyboard.hpp
|
||||||
python common/keyboard.py definition > $@
|
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
|
games/tetris.elf: games/tetris.o sh/lib1funcs.o
|
||||||
|
|
||||||
|
10
common/copy.hpp
Normal file
10
common/copy.hpp
Normal 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
41
common/draw_font.cpp
Normal 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
52
common/draw_font.hpp
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,3 +1,8 @@
|
|||||||
|
// this file is designed to be platform-agnostic
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
// metrics are 26.6 fixed point
|
// metrics are 26.6 fixed point
|
||||||
struct glyph_metrics {
|
struct glyph_metrics {
|
||||||
int32_t width;
|
int32_t width;
|
||||||
|
26
common/palette.cpp
Normal file
26
common/palette.cpp
Normal 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
5
common/palette.hpp
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
namespace palette {
|
||||||
|
|
||||||
|
void vdp2_cram_32grays(uint32_t colors_per_palette, uint32_t color_bank_index);
|
||||||
|
|
||||||
|
}
|
@ -7,37 +7,16 @@
|
|||||||
|
|
||||||
#include "../common/keyboard.hpp"
|
#include "../common/keyboard.hpp"
|
||||||
#include "../common/font.hpp"
|
#include "../common/font.hpp"
|
||||||
|
#include "../common/draw_font.hpp"
|
||||||
|
#include "../common/palette.hpp"
|
||||||
|
|
||||||
/* begin font */
|
/* begin font */
|
||||||
|
|
||||||
extern void * _dejavusans_start __asm("_binary_res_dejavusansmono_font_bin_start");
|
extern void * _dejavusans_start __asm("_binary_res_dejavusansmono_font_bin_start");
|
||||||
|
|
||||||
constexpr inline uint16_t rgb15_gray(uint32_t intensity)
|
/* end font */
|
||||||
{
|
|
||||||
return ((intensity & 31) << 10) // blue
|
|
||||||
| ((intensity & 31) << 5 ) // green
|
|
||||||
| ((intensity & 31) << 0 ); // red
|
|
||||||
}
|
|
||||||
|
|
||||||
void vdp2_color_palette(uint32_t colors, uint32_t color_bank)
|
/* square stuff */
|
||||||
{
|
|
||||||
/* 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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct color {
|
struct color {
|
||||||
uint8_t r;
|
uint8_t r;
|
||||||
@ -45,77 +24,6 @@ struct color {
|
|||||||
uint8_t b;
|
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] = {
|
const static color colors[16] = {
|
||||||
{255, 255, 255}, // (SPD / transparent) 0
|
{255, 255, 255}, // (SPD / transparent) 0
|
||||||
{0, 255, 255}, // I (cyan) 1
|
{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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t font_color_address, font_character_address;
|
static struct draw_font::state font_state;
|
||||||
static const font * font;
|
|
||||||
static const glyph * glyphs;
|
|
||||||
|
|
||||||
static uint32_t global_cmd_ix = 0;
|
static uint32_t global_cmd_ix = 0;
|
||||||
|
|
||||||
@ -340,11 +246,8 @@ void smpc_int(void) {
|
|||||||
char16_t c = keysym_to_char16(k);
|
char16_t c = keysym_to_char16(k);
|
||||||
if (k != keysym::UNKNOWN && c != -1) {
|
if (k != keysym::UNKNOWN && c != -1) {
|
||||||
text[0] = c;
|
text[0] = c;
|
||||||
global_cmd_ix = draw_utf16_string(font_color_address,
|
x += draw_font::horizontal_string(font_state,
|
||||||
font_character_address,
|
global_cmd_ix, // modified
|
||||||
font->char_code_offset,
|
|
||||||
glyphs,
|
|
||||||
global_cmd_ix,
|
|
||||||
&text[0],
|
&text[0],
|
||||||
1,
|
1,
|
||||||
x,
|
x,
|
||||||
@ -362,15 +265,12 @@ void smpc_int(void) {
|
|||||||
int32_t qy = 150 << 6;
|
int32_t qy = 150 << 6;
|
||||||
uint32_t cmd_ix = 4;
|
uint32_t cmd_ix = 4;
|
||||||
|
|
||||||
cmd_ix = draw_utf16_string(font_color_address,
|
draw_font::horizontal_string(font_state,
|
||||||
font_character_address,
|
cmd_ix, // modified
|
||||||
font->char_code_offset,
|
&str_num[0],
|
||||||
glyphs,
|
2,
|
||||||
cmd_ix,
|
qx,
|
||||||
str_num,
|
qy);
|
||||||
2,
|
|
||||||
qx,
|
|
||||||
qy);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -447,26 +347,28 @@ static inline void v_blank_in() {
|
|||||||
while ((vdp2.reg.TVSTAT & TVSTAT__VBLANK) == 0);
|
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()
|
void main()
|
||||||
{
|
{
|
||||||
uint32_t top = (sizeof (union vdp1_vram));
|
uint32_t top = (sizeof (union vdp1_vram));
|
||||||
|
|
||||||
// begin font
|
top = init_font(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 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
|
|
||||||
|
|
||||||
|
|
||||||
// begin squares
|
// begin squares
|
||||||
|
|
||||||
@ -563,23 +465,11 @@ void main()
|
|||||||
vdp1.vram.cmd[3].XA = foo[1].x;
|
vdp1.vram.cmd[3].XA = foo[1].x;
|
||||||
vdp1.vram.cmd[3].YA = foo[1].y;
|
vdp1.vram.cmd[3].YA = foo[1].y;
|
||||||
|
|
||||||
int32_t qx = 8 << 6;
|
vdp1.vram.cmd[4].CTRL = CTRL__END;
|
||||||
int32_t qy = 150 << 6;
|
vdp1.vram.cmd[5].CTRL = CTRL__END;
|
||||||
|
|
||||||
uint32_t cmd_ix = 4;
|
vdp1.vram.cmd[6].CTRL = CTRL__END;
|
||||||
const char16_t _xx[] = u"xx";
|
global_cmd_ix = 6;
|
||||||
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;
|
|
||||||
|
|
||||||
// start drawing (execute the command list) on every frame
|
// start drawing (execute the command list) on every frame
|
||||||
vdp1.reg.PTMR = PTMR__PTM__FRAME_CHANGE;
|
vdp1.reg.PTMR = PTMR__PTM__FRAME_CHANGE;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user