diff --git a/Makefile b/Makefile index 6000863..7e81eb2 100644 --- a/Makefile +++ b/Makefile @@ -31,6 +31,7 @@ NESE_SRC_SRCS = f6502.c f6502_opcodes.c NESE_SRC_SRCS += nese.c nes.c cart.c mapper.c NESE_SRC_SRCS += ppu.c apu.c NESE_SRC_SRCS += memory.c serdes.c save.c rle.c +NESE_SRC_SRCS += overlay.c NESE_SRC_SRCS += $(OS)/port.c NESE_MAP_SRCS = $(notdir $(wildcard $(MAPDIR)/*.c)) diff --git a/src/charbits.h b/src/charbits.h new file mode 100644 index 0000000..205defd --- /dev/null +++ b/src/charbits.h @@ -0,0 +1,147 @@ +static const char chars[] = "\x7f!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`{|}~"; + +static const int char_w = 10U; +static const int char_h = 10U; +static const int charbit_size = (1U + ((char_w * char_h * 2) + 7) / 8); +static const int char_count = (sizeof(chars) - 1); + +static const uint8_t charbits[1794] = { + 0x09, 0x55, 0x55, 0x90, 0xaa, 0x16, 0x59, 0x69, 0x91, 0xa5, 0x16, 0x99, 0x66, + 0x91, 0x5a, 0x16, 0x69, 0x65, 0x91, 0xaa, 0x16, 0x55, 0x55, 0x41, 0x55, 0x15, + 0x07, 0x50, 0x05, 0x00, 0x69, 0x01, 0x94, 0x16, 0x40, 0x6a, 0x01, 0xa4, 0x15, + 0x40, 0x5a, 0x01, 0x55, 0x05, 0x90, 0x56, 0x00, 0x55, 0x01, 0x40, 0x15, 0x00, + 0x08, 0x55, 0x15, 0x90, 0xa6, 0x05, 0x69, 0x5a, 0x90, 0xa6, 0x05, 0x55, 0x55, + 0x40, 0x55, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0a, 0x54, 0x55, 0x40, 0x9a, 0x16, 0xa5, 0x69, 0x91, 0xaa, 0x5a, 0xa5, 0x69, + 0x95, 0xaa, 0x5a, 0xa5, 0x69, 0x45, 0x9a, 0x56, 0x54, 0x55, 0x01, 0x55, 0x15, + 0x09, 0x50, 0x05, 0x40, 0x69, 0x05, 0xa5, 0x6a, 0x91, 0x56, 0x15, 0xa5, 0x5a, + 0x51, 0x95, 0x16, 0xa9, 0x5a, 0x51, 0x69, 0x15, 0x54, 0x55, 0x00, 0x55, 0x01, + 0x0a, 0x00, 0x00, 0x50, 0x45, 0x15, 0x69, 0xa5, 0x95, 0x96, 0x56, 0x55, 0x5a, + 0x45, 0x69, 0x15, 0xa5, 0xa5, 0x95, 0x56, 0x5a, 0x55, 0x55, 0x45, 0x15, 0x55, + 0x0a, 0x50, 0x15, 0x40, 0xa9, 0x05, 0xa4, 0x69, 0x41, 0x9a, 0x16, 0xa5, 0x5a, + 0x91, 0x96, 0x5a, 0x69, 0x6a, 0x55, 0x6a, 0x5a, 0x54, 0x55, 0x05, 0x55, 0x55, + 0x05, 0x55, 0x00, 0x90, 0x16, 0x00, 0x69, 0x01, 0x90, 0x16, 0x00, 0x55, 0x01, + 0x40, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x54, 0x01, 0x50, 0x5a, 0x00, 0x69, 0x05, 0x90, 0x56, 0x00, 0x69, 0x01, + 0x90, 0x16, 0x00, 0x69, 0x01, 0x50, 0x5a, 0x00, 0x54, 0x05, 0x00, 0x55, 0x00, + 0x06, 0x55, 0x00, 0x90, 0x16, 0x00, 0xa5, 0x05, 0x40, 0x5a, 0x00, 0xa4, 0x05, + 0x40, 0x5a, 0x00, 0xa5, 0x05, 0x90, 0x56, 0x00, 0x55, 0x01, 0x40, 0x05, 0x00, + 0x0a, 0x00, 0x00, 0x40, 0x55, 0x05, 0xa4, 0x69, 0x51, 0xa9, 0x15, 0xa9, 0xaa, + 0x55, 0xa9, 0x55, 0xa4, 0x69, 0x45, 0x55, 0x15, 0x50, 0x55, 0x01, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x50, 0x16, 0x00, 0xa9, 0x05, + 0x50, 0x56, 0x00, 0x54, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x01, + 0x40, 0x5a, 0x00, 0xa5, 0x05, 0x90, 0x56, 0x00, 0x55, 0x05, 0x40, 0x15, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x15, 0x00, 0xa9, 0x05, + 0x50, 0x55, 0x00, 0x54, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x15, 0x00, 0xa4, 0x05, 0x40, 0x5a, 0x00, 0x54, 0x05, 0x00, 0x55, 0x00, + 0x07, 0x50, 0x05, 0x00, 0x69, 0x01, 0x94, 0x16, 0x40, 0x5a, 0x01, 0xa4, 0x05, + 0x50, 0x5a, 0x00, 0x69, 0x05, 0x90, 0x16, 0x00, 0x55, 0x01, 0x40, 0x15, 0x00, + 0x0a, 0x54, 0x55, 0x50, 0xaa, 0x16, 0x69, 0xa5, 0x95, 0x96, 0x5a, 0x69, 0xa6, + 0x95, 0x5a, 0x5a, 0x69, 0xa5, 0x55, 0xaa, 0x56, 0x54, 0x55, 0x05, 0x55, 0x15, + 0x09, 0x50, 0x05, 0x40, 0x69, 0x01, 0xa4, 0x16, 0x40, 0x69, 0x01, 0x90, 0x16, + 0x00, 0x69, 0x01, 0x95, 0x56, 0x90, 0xaa, 0x16, 0x55, 0x55, 0x41, 0x55, 0x15, + 0x0a, 0x54, 0x55, 0x50, 0xaa, 0x16, 0x69, 0xa5, 0x95, 0x96, 0x5a, 0x55, 0x6a, + 0x45, 0xa9, 0x55, 0xa5, 0x56, 0x91, 0xaa, 0x5a, 0x55, 0x55, 0x45, 0x55, 0x55, + 0x0a, 0x54, 0x55, 0x50, 0xaa, 0x16, 0x69, 0xa5, 0x55, 0x55, 0x5a, 0x54, 0x6a, + 0x55, 0x55, 0x5a, 0x69, 0xa5, 0x55, 0xaa, 0x56, 0x54, 0x55, 0x05, 0x55, 0x15, + 0x0a, 0x00, 0x55, 0x00, 0x94, 0x16, 0x50, 0x6a, 0x41, 0xa9, 0x16, 0xa5, 0x69, + 0x91, 0x96, 0x16, 0xa9, 0xaa, 0x55, 0x95, 0x56, 0x54, 0x55, 0x05, 0x40, 0x15, + 0x0a, 0x55, 0x55, 0x95, 0xaa, 0x5a, 0x69, 0x55, 0x95, 0xaa, 0x56, 0x55, 0xa5, + 0x55, 0x55, 0x5a, 0x69, 0xa5, 0x55, 0xaa, 0x56, 0x54, 0x55, 0x05, 0x55, 0x15, + 0x0a, 0x50, 0x15, 0x40, 0xa9, 0x05, 0xa5, 0x55, 0x90, 0x56, 0x05, 0xa9, 0x6a, + 0x91, 0x56, 0x5a, 0x69, 0xa5, 0x55, 0xaa, 0x56, 0x54, 0x55, 0x05, 0x55, 0x15, + 0x0a, 0x55, 0x55, 0x91, 0xaa, 0x5a, 0x55, 0x69, 0x45, 0x95, 0x56, 0x40, 0x5a, + 0x01, 0xa5, 0x15, 0x90, 0x56, 0x00, 0x69, 0x05, 0x50, 0x15, 0x00, 0x54, 0x01, + 0x0a, 0x54, 0x55, 0x50, 0xaa, 0x16, 0x69, 0xa5, 0x95, 0x5a, 0x5a, 0xa5, 0x6a, + 0x95, 0x96, 0x5a, 0x69, 0xa5, 0x55, 0xaa, 0x56, 0x54, 0x55, 0x05, 0x55, 0x15, + 0x0a, 0x54, 0x55, 0x50, 0xaa, 0x16, 0x69, 0xa5, 0x95, 0x56, 0x5a, 0xa5, 0xaa, + 0x45, 0x55, 0x5a, 0x50, 0x69, 0x05, 0xa9, 0x55, 0x50, 0x55, 0x01, 0x54, 0x05, + 0x05, 0x00, 0x00, 0x50, 0x05, 0x00, 0x69, 0x01, 0x90, 0x16, 0x00, 0x55, 0x01, + 0x90, 0x16, 0x00, 0x69, 0x01, 0x50, 0x15, 0x00, 0x54, 0x01, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x40, 0x15, 0x00, 0xa4, 0x05, 0x40, 0x5a, 0x00, 0x54, 0x05, + 0x40, 0x5a, 0x00, 0xa5, 0x05, 0x90, 0x56, 0x00, 0x55, 0x05, 0x40, 0x15, 0x00, + 0x08, 0x40, 0x15, 0x00, 0xa5, 0x05, 0x94, 0x56, 0x50, 0x5a, 0x05, 0x69, 0x15, + 0x50, 0x5a, 0x00, 0x94, 0x16, 0x00, 0xa5, 0x05, 0x40, 0x55, 0x00, 0x50, 0x05, + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x01, 0x90, 0x5a, 0x00, 0x55, 0x05, + 0x90, 0x5a, 0x00, 0x55, 0x05, 0x40, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x55, 0x00, 0x90, 0x16, 0x00, 0xa5, 0x05, 0x40, 0x69, 0x01, 0x50, 0x5a, + 0x40, 0x69, 0x05, 0xa5, 0x55, 0x90, 0x56, 0x01, 0x55, 0x05, 0x40, 0x15, 0x00, + 0x0a, 0x54, 0x55, 0x50, 0xaa, 0x16, 0x69, 0xa5, 0x55, 0x55, 0x5a, 0x54, 0x6a, + 0x05, 0x69, 0x55, 0x50, 0x55, 0x01, 0x69, 0x01, 0x50, 0x15, 0x00, 0x54, 0x01, + 0x0a, 0x54, 0x55, 0x50, 0xaa, 0x16, 0x69, 0xa5, 0x95, 0xa9, 0x59, 0x99, 0x99, + 0x95, 0xa9, 0x5a, 0x69, 0x55, 0x55, 0xaa, 0x56, 0x54, 0x55, 0x01, 0x55, 0x15, + 0x0a, 0x54, 0x55, 0x50, 0xaa, 0x16, 0x69, 0xa5, 0x95, 0x56, 0x5a, 0x69, 0xa5, + 0x95, 0xaa, 0x5a, 0x69, 0xa5, 0x95, 0x56, 0x5a, 0x55, 0x55, 0x45, 0x15, 0x55, + 0x0a, 0x55, 0x55, 0x90, 0xaa, 0x16, 0x69, 0xa5, 0x95, 0x56, 0x5a, 0xa9, 0x6a, + 0x95, 0x56, 0x5a, 0x69, 0xa5, 0x95, 0xaa, 0x56, 0x55, 0x55, 0x45, 0x55, 0x15, + 0x0a, 0x54, 0x55, 0x50, 0xaa, 0x16, 0x69, 0xa5, 0x95, 0x56, 0x55, 0x69, 0x55, + 0x95, 0x56, 0x15, 0x69, 0xa5, 0x55, 0xaa, 0x56, 0x54, 0x55, 0x05, 0x55, 0x15, + 0x0a, 0x55, 0x15, 0x90, 0xaa, 0x05, 0x69, 0x69, 0x91, 0x56, 0x5a, 0x69, 0xa5, + 0x95, 0x56, 0x5a, 0x69, 0x69, 0x95, 0xaa, 0x55, 0x55, 0x55, 0x41, 0x55, 0x05, + 0x0a, 0x55, 0x55, 0x91, 0xaa, 0x5a, 0x69, 0x55, 0x95, 0x56, 0x55, 0xa9, 0x6a, + 0x91, 0x56, 0x15, 0x69, 0x55, 0x91, 0xaa, 0x5a, 0x55, 0x55, 0x45, 0x55, 0x55, + 0x0a, 0x55, 0x55, 0x91, 0xaa, 0x5a, 0x69, 0x55, 0x95, 0x56, 0x55, 0xa9, 0x6a, + 0x91, 0x56, 0x15, 0x69, 0x55, 0x91, 0x16, 0x00, 0x55, 0x01, 0x40, 0x15, 0x00, + 0x0a, 0x54, 0x55, 0x50, 0xaa, 0x16, 0x69, 0xa5, 0x95, 0x56, 0x55, 0x69, 0xa9, + 0x95, 0x56, 0x5a, 0x69, 0xa5, 0x55, 0xaa, 0x59, 0x54, 0x55, 0x05, 0x55, 0x55, + 0x0a, 0x55, 0x54, 0x91, 0x56, 0x5a, 0x69, 0xa5, 0x95, 0x56, 0x5a, 0xa9, 0xaa, + 0x95, 0x56, 0x5a, 0x69, 0xa5, 0x95, 0x56, 0x5a, 0x55, 0x55, 0x45, 0x15, 0x55, + 0x05, 0x55, 0x00, 0x90, 0x16, 0x00, 0x69, 0x01, 0x90, 0x16, 0x00, 0x69, 0x01, + 0x90, 0x16, 0x00, 0x69, 0x01, 0x90, 0x16, 0x00, 0x55, 0x01, 0x40, 0x15, 0x00, + 0x0a, 0x00, 0x54, 0x01, 0x40, 0x5a, 0x00, 0xa4, 0x05, 0x40, 0x5a, 0x55, 0xa5, + 0x95, 0x56, 0x5a, 0x69, 0xa5, 0x55, 0xaa, 0x56, 0x54, 0x55, 0x05, 0x55, 0x15, + 0x0a, 0x55, 0x54, 0x91, 0x56, 0x5a, 0x69, 0x69, 0x95, 0xa6, 0x55, 0xa9, 0x56, + 0x91, 0xa6, 0x05, 0x69, 0x69, 0x91, 0x56, 0x5a, 0x55, 0x55, 0x45, 0x15, 0x55, + 0x09, 0x55, 0x00, 0x90, 0x16, 0x00, 0x69, 0x01, 0x90, 0x16, 0x00, 0x69, 0x01, + 0x90, 0x16, 0x00, 0x69, 0x55, 0x90, 0xaa, 0x16, 0x55, 0x55, 0x41, 0x55, 0x15, + 0x0a, 0x55, 0x54, 0x91, 0x56, 0x5a, 0xa9, 0xa9, 0x95, 0xaa, 0x5a, 0x69, 0xa6, + 0x95, 0x56, 0x5a, 0x69, 0xa5, 0x95, 0x56, 0x5a, 0x55, 0x55, 0x45, 0x15, 0x55, + 0x0a, 0x55, 0x54, 0x91, 0x56, 0x5a, 0xa9, 0xa5, 0x95, 0x6a, 0x5a, 0x69, 0xaa, + 0x95, 0x96, 0x5a, 0x69, 0xa5, 0x95, 0x56, 0x5a, 0x55, 0x55, 0x45, 0x15, 0x55, + 0x0a, 0x54, 0x55, 0x50, 0xaa, 0x16, 0x69, 0xa5, 0x95, 0x56, 0x5a, 0x69, 0xa5, + 0x95, 0x56, 0x5a, 0x69, 0xa5, 0x55, 0xaa, 0x56, 0x54, 0x55, 0x05, 0x55, 0x15, + 0x0a, 0x55, 0x55, 0x90, 0xaa, 0x16, 0x69, 0xa5, 0x95, 0x56, 0x5a, 0x69, 0xa5, + 0x95, 0xaa, 0x56, 0x69, 0x55, 0x95, 0x56, 0x15, 0x55, 0x01, 0x40, 0x15, 0x00, + 0x0a, 0x54, 0x55, 0x50, 0xaa, 0x16, 0x69, 0xa5, 0x95, 0x56, 0x5a, 0x69, 0xa5, + 0x95, 0x56, 0x5a, 0x69, 0x69, 0x55, 0xaa, 0x5a, 0x54, 0x55, 0x05, 0x55, 0x55, + 0x0a, 0x55, 0x55, 0x90, 0xaa, 0x16, 0x69, 0xa5, 0x95, 0x56, 0x5a, 0xa9, 0x6a, + 0x95, 0x56, 0x5a, 0x69, 0xa5, 0x95, 0x56, 0x5a, 0x55, 0x55, 0x45, 0x15, 0x55, + 0x0a, 0x54, 0x55, 0x50, 0xaa, 0x16, 0x69, 0xa5, 0x95, 0x56, 0x55, 0xa5, 0x6a, + 0x55, 0x55, 0x5a, 0x69, 0xa5, 0x55, 0xaa, 0x56, 0x54, 0x55, 0x05, 0x55, 0x15, + 0x09, 0x55, 0x55, 0x90, 0xaa, 0x16, 0x95, 0x56, 0x01, 0x69, 0x15, 0x90, 0x16, + 0x00, 0x69, 0x01, 0x90, 0x16, 0x00, 0x69, 0x01, 0x50, 0x15, 0x00, 0x54, 0x01, + 0x0a, 0x55, 0x54, 0x91, 0x56, 0x5a, 0x69, 0xa5, 0x95, 0x56, 0x5a, 0x69, 0xa5, + 0x95, 0x56, 0x5a, 0x69, 0xa5, 0x55, 0xaa, 0x56, 0x54, 0x55, 0x05, 0x55, 0x15, + 0x0a, 0x55, 0x54, 0x91, 0x56, 0x5a, 0x69, 0xa5, 0x95, 0x56, 0x5a, 0x69, 0xa5, + 0x55, 0x9a, 0x56, 0x94, 0x5a, 0x05, 0x65, 0x15, 0x40, 0x55, 0x00, 0x50, 0x01, + 0x0a, 0x55, 0x54, 0x91, 0x56, 0x5a, 0x69, 0xa5, 0x95, 0x56, 0x5a, 0x69, 0xa6, + 0x95, 0xaa, 0x5a, 0xa9, 0xa9, 0x95, 0x56, 0x5a, 0x55, 0x55, 0x45, 0x15, 0x55, + 0x0a, 0x55, 0x54, 0x91, 0x56, 0x5a, 0xa9, 0xa9, 0x55, 0xaa, 0x56, 0x94, 0x5a, + 0x55, 0xaa, 0x16, 0xa9, 0xa9, 0x95, 0x56, 0x5a, 0x55, 0x55, 0x45, 0x15, 0x55, + 0x09, 0x55, 0x55, 0x90, 0x96, 0x16, 0x69, 0x69, 0x91, 0x96, 0x16, 0xa5, 0x5a, + 0x41, 0x69, 0x15, 0x90, 0x56, 0x00, 0x69, 0x01, 0x50, 0x15, 0x00, 0x54, 0x01, + 0x0a, 0x55, 0x55, 0x91, 0xaa, 0x5a, 0x55, 0xa9, 0x05, 0xa5, 0x56, 0x94, 0x5a, + 0x55, 0x6a, 0x15, 0xa9, 0x55, 0x91, 0xaa, 0x5a, 0x55, 0x55, 0x45, 0x55, 0x55, + 0x06, 0x55, 0x01, 0x90, 0x5a, 0x00, 0x69, 0x05, 0x90, 0x56, 0x00, 0x69, 0x01, + 0x90, 0x16, 0x00, 0x69, 0x01, 0x90, 0x5a, 0x00, 0x55, 0x05, 0x40, 0x55, 0x00, + 0x07, 0x55, 0x00, 0x90, 0x16, 0x00, 0x69, 0x01, 0x50, 0x5a, 0x00, 0xa4, 0x05, + 0x40, 0x5a, 0x00, 0x94, 0x16, 0x00, 0x69, 0x01, 0x50, 0x15, 0x00, 0x54, 0x01, + 0x06, 0x55, 0x01, 0x90, 0x5a, 0x00, 0xa5, 0x05, 0x40, 0x5a, 0x00, 0xa4, 0x05, + 0x40, 0x5a, 0x00, 0xa5, 0x05, 0x90, 0x5a, 0x00, 0x55, 0x05, 0x40, 0x55, 0x00, + 0x08, 0x50, 0x01, 0x40, 0x59, 0x00, 0xa5, 0x16, 0x90, 0xa6, 0x05, 0x59, 0x59, + 0x50, 0x55, 0x05, 0x54, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x55, 0x55, 0x91, 0xaa, 0x5a, 0x55, 0x55, 0x45, 0x55, 0x55, + 0x07, 0x55, 0x00, 0x90, 0x16, 0x00, 0xa5, 0x05, 0x40, 0x69, 0x01, 0x50, 0x15, + 0x00, 0x54, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x50, 0x05, 0x40, 0x69, 0x01, 0xa4, 0x15, 0x50, 0x5a, 0x01, 0x69, 0x05, + 0x50, 0x5a, 0x00, 0xa4, 0x05, 0x40, 0x69, 0x01, 0x50, 0x15, 0x00, 0x54, 0x01, + 0x04, 0x15, 0x00, 0x90, 0x05, 0x00, 0x59, 0x00, 0x90, 0x05, 0x00, 0x59, 0x00, + 0x90, 0x05, 0x00, 0x59, 0x00, 0x90, 0x05, 0x00, 0x55, 0x00, 0x40, 0x05, 0x00, + 0x07, 0x55, 0x00, 0x90, 0x16, 0x00, 0xa5, 0x05, 0x40, 0x5a, 0x00, 0x94, 0x16, + 0x40, 0x5a, 0x01, 0xa5, 0x15, 0x90, 0x56, 0x00, 0x55, 0x05, 0x40, 0x15, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0x51, 0x6a, 0x5a, 0x69, 0x6a, + 0x55, 0x55, 0x55, 0x54, 0x55, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; diff --git a/src/linux/port.c b/src/linux/port.c index f63283d..8aee815 100644 --- a/src/linux/port.c +++ b/src/linux/port.c @@ -12,6 +12,7 @@ #include "cart.h" #include "nese.h" +#include "overlay.h" #include "port.h" #include "save.h" @@ -98,6 +99,8 @@ typedef struct { SDL_Texture* texture; SDL_Surface* target; SDL_Surface* screen; + SDL_Rect view; + Overlay overlay; } platform_data; @@ -309,7 +312,9 @@ int nese_frame_ready(void* plat_data) { SDL_LockTextureToSurface(plat->texture, NULL, &plat->target); - // TODO: Overlay + overlay_render(&plat->overlay, + nes_ppu_render_w, nes_ppu_render_h, + &plat->view, plat->renderer); SDL_RenderPresent(plat->renderer); @@ -357,12 +362,15 @@ static int plat_init(platform_data* plat) { ); if (0 == status) { + plat->view = (SDL_Rect){ + .w = nes_ppu_render_w * 8, + .h = nes_ppu_render_h * 7, + }; plat->window = SDL_CreateWindow( "NESe", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, - nes_ppu_render_w * 8, - nes_ppu_render_h * 7, + plat->view.w, plat->view.h, 0 ); if (NULL == plat->window) { @@ -418,6 +426,10 @@ static int plat_init(platform_data* plat) { } } + if (0 == status) { + status = overlay_init(&plat->overlay, plat->renderer); + } + if (0 == status) { plat->t_target = time_now(); } @@ -429,6 +441,7 @@ static void plat_done(platform_data* plat) { if (NULL != plat->texture) SDL_DestroyTexture(plat->texture); if (NULL != plat->renderer) SDL_DestroyRenderer(plat->renderer); if (NULL != plat->window) SDL_DestroyWindow(plat->window); + overlay_done(&plat->overlay); SDL_Quit(); } diff --git a/src/overlay.c b/src/overlay.c new file mode 100644 index 0000000..d584af1 --- /dev/null +++ b/src/overlay.c @@ -0,0 +1,280 @@ +#include + +#include "charbits.h" +#include "overlay.h" + + +/* Font */ + +typedef struct { + const uint8_t* bits; + uint8_t shift; +} bit_buffer; + +static void make_bit_buffer(bit_buffer* buf, + const uint8_t* bits) { + buf->bits = bits; + buf->shift = 0; +} + +static uint8_t get_bits(bit_buffer* buf) { + uint8_t val = ((buf->bits[0] >> buf->shift) & 3); + if (buf->shift == 6) { + buf->shift = 0; + buf->bits++; + } else { + buf->shift += 2; + } + return val; +} + +static const SDL_Color pal[2] = { + {0, 0, 0, 255}, {255, 255, 255, 255} +}; + +static SDL_Surface* create_char_surface(const uint8_t* bits) { + int w = *bits++; + bit_buffer buf = {0}; + make_bit_buffer(&buf, bits); + + SDL_Surface* surface = SDL_CreateRGBSurfaceWithFormat( + 0, w, char_h, 8, SDL_PIXELFORMAT_INDEX8 + ); + SDL_SetPaletteColors(surface->format->palette, pal, 1U, 2U); + SDL_SetColorKey(surface, SDL_TRUE, 0); + + uint8_t* line = surface->pixels; + for (int y = char_h; y > 0; --y) { + uint8_t* dst = line; + for (int x = w; x > 0; --x) { + *dst++ = get_bits(&buf); + } + for (int x = (char_w - w); x > 0; --x) get_bits(&buf); + line += surface->pitch; + } + + return surface; +} + +static SDL_Texture* create_char_texture(SDL_Renderer* rend, + const uint8_t* bits) { + SDL_Surface* surface = create_char_surface(bits); + SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_NONE); + SDL_Texture* texture = SDL_CreateTextureFromSurface( + rend, surface + ); + SDL_FreeSurface(surface); + return texture; +} + +int overlay_font_init(Overlay_font* font, SDL_Renderer* rend) { + font->chars = chars; + font->charbits = charbits; + font->char_count = char_count; + font->textures = calloc(char_count, sizeof(SDL_Texture*)); + if (NULL != font->textures) { + for (int i = 0; i < font->char_count; ++i) { + font->textures[i] = create_char_texture( + rend, &font->charbits[i * charbit_size] + ); + } + } + return (NULL != font->textures) ? 0 : -1; +} + +void overlay_font_done(Overlay_font* font) { + for (int i = 0; i < font->char_count; ++i) { + SDL_DestroyTexture(font->textures[i]); + } + free(font->textures); + font->textures = NULL; +} + + +#define overlay_start_x (char_w / 2) +#define overlay_start_y (char_h / 2) + +#define space_width ((char_w / 2) - 1) + +static inline int char_index(char c) { + if (c >= 'a' && c <= 'z') c += ('A' - 'a'); + if (c > ' ' && c < 'a') return (c - ' '); + if (c >= '{' && c <= '~') return (65 + c - '{'); + return 0; +} + +void overlay_font_measure(const Overlay_font* font, + const char* string, + int* w, int* h) { + *h = char_h; + int max_w = 1; + int cur_w = 1; + for (const char* c = string; *c; ++c) { + if (*c == '\n') { + if (cur_w > max_w) max_w = cur_w; + cur_w = 1; + *h += char_h; + } else if (*c == ' ') { + cur_w += space_width; + } else { + int index = char_index(*c); + int cw = font->charbits[index * charbit_size]; + cur_w += (cw - 1); + } + } + if (cur_w > max_w) max_w = cur_w; + *w = max_w; +} + +void overlay_font_render(Overlay_font* font, const char* string, + const SDL_Rect* target, + const SDL_Rect* view, + uint32_t color, SDL_Renderer *rend) { + int x = target->x; + int y = target->y; + for (const char* c = string; *c; ++c) { + if (*c == '\n') { + x = target->x; + y += (char_h + 1); + } else if (*c == ' ') { + x += space_width; + } else { + int index = char_index(*c); + int cw = font->charbits[index * charbit_size]; + SDL_Texture* texture = font->textures[index]; + + SDL_Rect rect = { + .x = ((x * view->w) / target->w) + view->x, + .y = ((y * view->h) / target->h) + view->y, + .w = (cw * view->w) / target->w, + .h = (char_h * view->h) / target->h, + }; + + SDL_SetTextureColorMod( + texture, + ((color >> 16) & 0xFFU), + ((color >> 8) & 0xFFU), + ((color >> 0) & 0xFFU) + ); + SDL_SetTextureAlphaMod(texture, + ((color >> 24) & 0xFFU)); + SDL_RenderCopy(rend, texture, NULL, &rect); + + x += (cw - 1); + } + } +} + + +/* Overlay */ + +typedef struct Overlay_message_t { + char* string; + int id; + int expiry; + struct Overlay_message_t* next; +} Overlay_message; + + +int overlay_init(Overlay* overlay, SDL_Renderer* rend) { + overlay->messages = NULL; + overlay->next_id = 0; + overlay_font_init(&overlay->font, rend); + return 0; +} + +int overlay_clear(Overlay* overlay) { + int n_cleared = 0; + Overlay_message* next = NULL; + for ( Overlay_message* message = overlay->messages; + NULL != message; + message = next) { + next = message->next; + free(message->string); + free(message); + ++n_cleared; + } + overlay->messages = NULL; + return n_cleared; +} + +void overlay_done(Overlay* overlay) { + overlay_clear(overlay); + overlay_font_done(&overlay->font); +} + +int overlay_clear_message(Overlay* overlay, int id) { + int result = -1; + Overlay_message* last = NULL; + Overlay_message* message = overlay->messages; + for ( ; + NULL != message && message->id != id; + last = message, message = message->next + ); + if (NULL != message) { + result = 0; + if (NULL == last) { + overlay->messages = message->next; + } else { + last->next = message->next; + } + free(message->string); + free(message); + } + return result; +} + +int overlay_add_message(Overlay* overlay, + const char* string, int expiry) { + Overlay_message* message = calloc(1, sizeof(*message)); + message->string = strdup(string); + message->id = ++(overlay->next_id); + message->expiry = expiry; + message->next = NULL; + if (NULL == overlay->messages) { + overlay->messages = message; + } else { + Overlay_message* last = overlay->messages; + for ( ; NULL != last->next; last = last->next); + last->next = message; + } + return message->id; +} + +void overlay_render(Overlay* overlay, int w, int h, + const SDL_Rect* view, SDL_Renderer* rend) { + SDL_Rect target = { + .x = overlay_start_x, + .y = overlay_start_y, + .w = w, + .h = h, + }; + for ( Overlay_message* message = overlay->messages; + NULL != message; + message = message->next) { + overlay_font_render(&overlay->font, message->string, + &target, view, + 0xFFFFFFFFU, rend); + target.y += (char_h + 1); + } +} + +void overlay_step(Overlay* overlay) { + Overlay_message* last = NULL, *next = NULL; + for ( Overlay_message* message = overlay->messages; + NULL != message; + message = next) { + next = message->next; + if (message->expiry > 0 && --(message->expiry) == 0) { + if (NULL == last) { + overlay->messages = message->next; + } else { + last->next = message->next; + } + free(message->string); + free(message); + } else { + last = message; + } + } +} diff --git a/src/overlay.h b/src/overlay.h new file mode 100644 index 0000000..c5ce5ee --- /dev/null +++ b/src/overlay.h @@ -0,0 +1,47 @@ +#ifndef NESE_OVERLAY_H_ +#define NESE_OVERLAY_H_ + +#include + + +typedef struct { + const char* chars; + const uint8_t* charbits; + int char_count; + SDL_Texture** textures; +} Overlay_font; + +int overlay_font_init(Overlay_font*, SDL_Renderer*); +void overlay_font_done(Overlay_font*); + +void overlay_font_measure(const Overlay_font*, + const char* string, + int* w, int* h); +void overlay_font_render(Overlay_font*, const char* string, + const SDL_Rect* target, + const SDL_Rect* view, + uint32_t color, SDL_Renderer*); + + +struct Overlay_message_t; + +typedef struct { + struct Overlay_message_t* messages; + int next_id; + Overlay_font font; +} Overlay; + +int overlay_init(Overlay*, SDL_Renderer*); +void overlay_done(Overlay*); + +int overlay_add_message(Overlay*, const char*, int expiry); +int overlay_clear_message(Overlay*, int id); +int overlay_clear(Overlay*); + +void overlay_step(Overlay*); + +void overlay_render(Overlay*, int w, int h, + const SDL_Rect* view, SDL_Renderer*); + + +#endif // NESE_OVERLAY_H_