Merge remote-tracking branch 'origin/master' into optimized-lookup
This commit is contained in:
commit
fd810cafea
|
@ -2,3 +2,7 @@ img2cpi
|
|||
img2cpi.o
|
||||
wsvpn
|
||||
wsvpn.o
|
||||
cpi2png
|
||||
cc-common.o
|
||||
vim.state
|
||||
__pycache__
|
||||
|
|
14
Makefile
14
Makefile
|
@ -1,7 +1,19 @@
|
|||
CPPFLAGS += -Idependencies -Idependencies/mongoose
|
||||
LDLIBS += -lm
|
||||
|
||||
all: img2cpi wsvpn
|
||||
all: img2cpi cpi2png wsvpn
|
||||
|
||||
test-cpi2png: cpi2png
|
||||
./cpi2png ./cpi-images/rat.cpi /tmp/rat.png
|
||||
|
||||
img2cpi: img2cpi.c cc-common.o dependencies/stb/stb_image.o dependencies/stb/stb_image_resize2.o
|
||||
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o "$@" $(CPPFLAGS)
|
||||
|
||||
cpi2png: cpi2png.c cc-common.o dependencies/stb/stb_image_write.o
|
||||
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o "$@" $(CPPFLAGS)
|
||||
|
||||
dependencies/stb/%.o: dependencies/stb/%.h
|
||||
$(CC) -DSTB_IMAGE_IMPLEMENTATION -DSTB_IMAGE_RESIZE_IMPLEMENTATION -DSTB_IMAGE_WRITE_IMPLEMENTATION -x c $^ -c -o "$@"
|
||||
|
||||
wsvpn: wsvpn.o dependencies/mongoose/mongoose.o
|
||||
$(CC) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o "$@"
|
||||
|
|
|
@ -0,0 +1,296 @@
|
|||
#include "cc-common.h"
|
||||
|
||||
const struct palette cc_default_palette = PALETTE(
|
||||
{ { 0xf0, 0xf0, 0xf0, 0xff } },
|
||||
{ { 0xf2, 0xb2, 0x33, 0xff } },
|
||||
{ { 0xe5, 0x7f, 0xd8, 0xff } },
|
||||
{ { 0x99, 0xb2, 0xf2, 0xff } },
|
||||
{ { 0xde, 0xde, 0x6c, 0xff } },
|
||||
{ { 0x7f, 0xcc, 0x19, 0xff } },
|
||||
{ { 0xf2, 0xb2, 0xcc, 0xff } },
|
||||
{ { 0x4c, 0x4c, 0x4c, 0xff } },
|
||||
{ { 0x99, 0x99, 0x99, 0xff } },
|
||||
{ { 0x4c, 0x99, 0xb2, 0xff } },
|
||||
{ { 0xb2, 0x66, 0xe5, 0xff } },
|
||||
{ { 0x33, 0x66, 0xcc, 0xff } },
|
||||
{ { 0x7f, 0x66, 0x4c, 0xff } },
|
||||
{ { 0x57, 0xa6, 0x4e, 0xff } },
|
||||
{ { 0xcc, 0x4c, 0x4c, 0xff } },
|
||||
{ { 0x11, 0x11, 0x11, 0xff } }
|
||||
), cc_default_gray_palette = PALETTE(
|
||||
{ { 0xf0, 0xf0, 0xf0, 0xff } },
|
||||
{ { 0x9d, 0x9d, 0x9d, 0xff } },
|
||||
{ { 0xbe, 0xbe, 0xbe, 0xff } },
|
||||
{ { 0xbf, 0xbf, 0xbf, 0xff } },
|
||||
{ { 0xb8, 0xb8, 0xb8, 0xff } },
|
||||
{ { 0x76, 0x76, 0x76, 0xff } },
|
||||
{ { 0xd0, 0xd0, 0xd0, 0xff } },
|
||||
{ { 0x4c, 0x4c, 0x4c, 0xff } },
|
||||
{ { 0x99, 0x99, 0x99, 0xff } },
|
||||
{ { 0x87, 0x87, 0x87, 0xff } },
|
||||
{ { 0xa9, 0xa9, 0xa9, 0xff } },
|
||||
{ { 0x77, 0x77, 0x77, 0xff } },
|
||||
{ { 0x65, 0x65, 0x65, 0xff } },
|
||||
{ { 0x6e, 0x6e, 0x6e, 0xff } },
|
||||
{ { 0x76, 0x76, 0x76, 0xff } },
|
||||
{ { 0x11, 0x11, 0x11, 0xff } }
|
||||
);
|
||||
|
||||
const GlyphBitmap cc_font_atlas[256] = {
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x44, 0x6c, 0x44, 0x54, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x7c, 0x54, 0x7c, 0x44, 0x6c, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x28, 0x7c, 0x7c, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x10, 0x38, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x38, 0x10, 0x7c, 0x7c, 0x10, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x10, 0x38, 0x7c, 0x7c, 0x10, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x7e, 0x7e, 0x66, 0x42, 0x42, 0x66, 0x7e, 0x7e, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x1c, 0x0c, 0x34, 0x48, 0x48, 0x30, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x10, 0x38, 0x10, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x3c, 0x24, 0x3c, 0x20, 0x60, 0x60, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x3e, 0x22, 0x3e, 0x22, 0x66, 0x66, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x40, 0x70, 0x7c, 0x70, 0x40, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x04, 0x1c, 0x7c, 0x1c, 0x04, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x38, 0x7c, 0x10, 0x10, 0x7c, 0x38, 0x10, 0x00, 0x00, },
|
||||
{ 0x00, 0x24, 0x24, 0x24, 0x24, 0x24, 0x00, 0x24, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x3c, 0x54, 0x54, 0x34, 0x14, 0x14, 0x14, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x3c, 0x60, 0x58, 0x44, 0x34, 0x0c, 0x78, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x38, 0x7c, 0x10, 0x7c, 0x38, 0x10, 0x7c, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x38, 0x7c, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x10, 0x10, 0x10, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x10, 0x18, 0x7c, 0x18, 0x10, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x10, 0x30, 0x7c, 0x30, 0x10, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x7c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x24, 0x7e, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x10, 0x10, 0x38, 0x38, 0x7c, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x7c, 0x38, 0x38, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x14, 0x14, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x28, 0x28, 0x7c, 0x28, 0x7c, 0x28, 0x28, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x3c, 0x40, 0x38, 0x04, 0x78, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x44, 0x48, 0x08, 0x10, 0x20, 0x24, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x28, 0x10, 0x34, 0x58, 0x48, 0x34, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x0c, 0x10, 0x20, 0x20, 0x20, 0x10, 0x0c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x30, 0x08, 0x04, 0x04, 0x04, 0x08, 0x30, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x24, 0x18, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x10, 0x10, 0x7c, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x04, 0x08, 0x08, 0x10, 0x20, 0x20, 0x40, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x44, 0x4c, 0x54, 0x64, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x30, 0x10, 0x10, 0x10, 0x10, 0x7c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x44, 0x04, 0x18, 0x20, 0x44, 0x7c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x44, 0x04, 0x18, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x0c, 0x14, 0x24, 0x44, 0x7c, 0x04, 0x04, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x7c, 0x40, 0x78, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x18, 0x20, 0x40, 0x78, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x7c, 0x44, 0x04, 0x08, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x44, 0x44, 0x38, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x44, 0x44, 0x3c, 0x04, 0x08, 0x30, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, },
|
||||
{ 0x00, 0x04, 0x08, 0x10, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x20, 0x10, 0x08, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x44, 0x04, 0x08, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x3c, 0x42, 0x5a, 0x5a, 0x5e, 0x40, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x44, 0x7c, 0x44, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x78, 0x44, 0x78, 0x44, 0x44, 0x44, 0x78, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x44, 0x40, 0x40, 0x40, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x78, 0x44, 0x44, 0x44, 0x44, 0x44, 0x78, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x7c, 0x40, 0x70, 0x40, 0x40, 0x40, 0x7c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x7c, 0x40, 0x70, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x3c, 0x40, 0x4c, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x44, 0x44, 0x7c, 0x44, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x44, 0x48, 0x70, 0x48, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x44, 0x6c, 0x54, 0x44, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x44, 0x64, 0x54, 0x4c, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x78, 0x44, 0x78, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x44, 0x44, 0x44, 0x44, 0x48, 0x34, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x78, 0x44, 0x78, 0x44, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x3c, 0x40, 0x38, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x7c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x44, 0x44, 0x44, 0x44, 0x28, 0x28, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x44, 0x44, 0x44, 0x44, 0x54, 0x6c, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x44, 0x28, 0x10, 0x28, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x44, 0x28, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x7c, 0x04, 0x08, 0x10, 0x20, 0x40, 0x7c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x40, 0x20, 0x20, 0x10, 0x08, 0x08, 0x04, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x38, 0x04, 0x3c, 0x44, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x40, 0x40, 0x58, 0x64, 0x44, 0x44, 0x78, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x38, 0x44, 0x40, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x04, 0x04, 0x34, 0x4c, 0x44, 0x44, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x38, 0x44, 0x7c, 0x40, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x0c, 0x10, 0x3c, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x3c, 0x44, 0x44, 0x3c, 0x04, 0x78, 0x00, 0x00, },
|
||||
{ 0x00, 0x40, 0x40, 0x58, 0x64, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x04, 0x00, 0x04, 0x04, 0x04, 0x44, 0x44, 0x38, 0x00, 0x00, },
|
||||
{ 0x00, 0x20, 0x20, 0x24, 0x28, 0x30, 0x28, 0x24, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x08, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x68, 0x54, 0x54, 0x44, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x78, 0x44, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x58, 0x64, 0x44, 0x78, 0x40, 0x40, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x34, 0x4c, 0x44, 0x3c, 0x04, 0x04, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x58, 0x64, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x3c, 0x40, 0x38, 0x04, 0x78, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x10, 0x38, 0x10, 0x10, 0x10, 0x08, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x28, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x44, 0x44, 0x54, 0x54, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x3c, 0x04, 0x78, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x7c, 0x08, 0x10, 0x20, 0x7c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x0c, 0x10, 0x10, 0x20, 0x10, 0x10, 0x0c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x30, 0x08, 0x08, 0x04, 0x08, 0x08, 0x30, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x32, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x24, 0x48, 0x12, 0x24, 0x48, 0x12, 0x24, 0x48, 0x12, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0xf0, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x0f, 0x0f, 0x0f, 0x0f, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0xf0, 0xf0, 0xf0, 0xf0, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0xff, 0xff, 0xff, 0xff, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, },
|
||||
{ 0xf0, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, },
|
||||
{ 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, },
|
||||
{ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, },
|
||||
{ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, },
|
||||
{ 0x0f, 0x0f, 0x0f, 0x0f, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, },
|
||||
{ 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x0f, 0xf0, 0xf0, 0xf0, 0xf0, },
|
||||
{ 0xf0, 0xf0, 0xf0, 0xf0, 0x0f, 0x0f, 0x0f, 0xf0, 0xf0, 0xf0, 0xf0, },
|
||||
{ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0xf0, 0xf0, 0xf0, 0xf0, },
|
||||
{ 0x7f, 0x7f, 0x7f, 0x7f, 0x0f, 0x0f, 0x0f, 0xf0, 0xf0, 0xf0, 0xf0, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, },
|
||||
{ 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, },
|
||||
{ 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, },
|
||||
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x10, 0x38, 0x44, 0x40, 0x44, 0x38, 0x10, 0x00, 0x00, },
|
||||
{ 0x00, 0x18, 0x24, 0x20, 0x78, 0x20, 0x20, 0x7c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x44, 0x38, 0x44, 0x44, 0x44, 0x38, 0x44, 0x00, 0x00, },
|
||||
{ 0x00, 0x44, 0x28, 0x7c, 0x10, 0x7c, 0x10, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x3c, 0x60, 0x58, 0x44, 0x34, 0x0c, 0x78, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x3c, 0x4a, 0x52, 0x52, 0x4a, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x30, 0x08, 0x38, 0x48, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x14, 0x28, 0x50, 0x28, 0x14, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x7c, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x3c, 0x5a, 0x5a, 0x56, 0x42, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x30, 0x48, 0x48, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x10, 0x10, 0x7c, 0x10, 0x10, 0x00, 0x7c, 0x00, 0x00, },
|
||||
{ 0x00, 0x40, 0x20, 0x60, 0x40, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x60, 0x20, 0x60, 0x20, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x7a, 0x40, 0x40, 0x00, },
|
||||
{ 0x00, 0x3c, 0x54, 0x54, 0x34, 0x14, 0x14, 0x14, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, },
|
||||
{ 0x00, 0x20, 0x60, 0x20, 0x20, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x50, 0x28, 0x14, 0x28, 0x50, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x44, 0x48, 0x08, 0x10, 0x2c, 0x2c, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x44, 0x48, 0x08, 0x10, 0x24, 0x28, 0x4c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x64, 0x28, 0x68, 0x10, 0x2c, 0x2c, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x00, 0x10, 0x20, 0x40, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x60, 0x00, 0x38, 0x44, 0x7c, 0x44, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x0c, 0x00, 0x38, 0x44, 0x7c, 0x44, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x44, 0x38, 0x44, 0x7c, 0x44, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x28, 0x50, 0x38, 0x44, 0x7c, 0x44, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x28, 0x00, 0x38, 0x44, 0x7c, 0x44, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x00, 0x38, 0x44, 0x7c, 0x44, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x3c, 0x50, 0x50, 0x78, 0x50, 0x50, 0x5c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x44, 0x40, 0x40, 0x44, 0x38, 0x08, 0x10, 0x00, 0x00, },
|
||||
{ 0x00, 0x60, 0x00, 0x7c, 0x40, 0x78, 0x40, 0x7c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x0c, 0x00, 0x7c, 0x40, 0x78, 0x40, 0x7c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x44, 0x7c, 0x40, 0x78, 0x40, 0x7c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x28, 0x00, 0x7c, 0x40, 0x78, 0x40, 0x7c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x30, 0x00, 0x38, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x18, 0x00, 0x38, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x28, 0x38, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x28, 0x00, 0x38, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x78, 0x44, 0x44, 0x64, 0x44, 0x44, 0x78, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x14, 0x28, 0x44, 0x64, 0x54, 0x4c, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x60, 0x38, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x0c, 0x38, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x44, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x28, 0x50, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x28, 0x38, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x44, 0x4c, 0x54, 0x64, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x60, 0x00, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x0c, 0x00, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x28, 0x00, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x28, 0x00, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x0c, 0x00, 0x44, 0x28, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x10, 0x18, 0x14, 0x18, 0x10, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x78, 0x44, 0x58, 0x44, 0x44, 0x44, 0x58, 0x40, 0x00, 0x00, },
|
||||
{ 0x00, 0x60, 0x00, 0x38, 0x04, 0x3c, 0x44, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x0c, 0x00, 0x38, 0x04, 0x3c, 0x44, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x44, 0x38, 0x04, 0x3c, 0x44, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x28, 0x50, 0x38, 0x04, 0x3c, 0x44, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x28, 0x00, 0x38, 0x04, 0x3c, 0x44, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x00, 0x38, 0x04, 0x3c, 0x44, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x2c, 0x52, 0x7c, 0x50, 0x2e, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x38, 0x44, 0x40, 0x44, 0x38, 0x08, 0x10, 0x00, 0x00, },
|
||||
{ 0x00, 0x60, 0x00, 0x38, 0x44, 0x7c, 0x40, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x0c, 0x00, 0x38, 0x44, 0x7c, 0x40, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x44, 0x38, 0x44, 0x7c, 0x40, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x28, 0x00, 0x38, 0x44, 0x7c, 0x40, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x30, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x18, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x28, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x28, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x08, 0x3c, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x28, 0x50, 0x78, 0x44, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x60, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x0c, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x44, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x28, 0x50, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x28, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x10, 0x00, 0x7c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x38, 0x4c, 0x54, 0x64, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x60, 0x00, 0x44, 0x44, 0x44, 0x44, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x0c, 0x00, 0x44, 0x44, 0x44, 0x44, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x28, 0x00, 0x44, 0x44, 0x44, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x28, 0x00, 0x44, 0x44, 0x44, 0x44, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x0c, 0x00, 0x44, 0x44, 0x44, 0x3c, 0x04, 0x78, 0x00, 0x00, },
|
||||
{ 0x00, 0x30, 0x10, 0x18, 0x14, 0x18, 0x10, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x28, 0x00, 0x44, 0x44, 0x44, 0x3c, 0x04, 0x78, 0x00, 0x00, },
|
||||
};
|
|
@ -0,0 +1,25 @@
|
|||
#ifndef _CC_COMMON_H_
|
||||
#define _CC_COMMON_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef uint8_t GlyphBitmap[11];
|
||||
|
||||
struct rgba { uint8_t r, g, b, a; };
|
||||
union color {
|
||||
struct rgba rgba;
|
||||
uint32_t v;
|
||||
};
|
||||
|
||||
struct palette {
|
||||
const uint8_t count;
|
||||
union color colors[] __attribute__((counted_by(count)));
|
||||
};
|
||||
|
||||
#define LENGTHOF(...) (sizeof(__VA_ARGS__) / sizeof(*(__VA_ARGS__)))
|
||||
#define PALETTE(...) { .count = LENGTHOF((union color[]){__VA_ARGS__}), .colors = {__VA_ARGS__} }
|
||||
|
||||
const extern GlyphBitmap cc_font_atlas[256];
|
||||
const extern struct palette cc_default_palette, cc_default_gray_palette;
|
||||
|
||||
#endif
|
37
cc-pic.py
37
cc-pic.py
|
@ -33,22 +33,25 @@ class Converter:
|
|||
]
|
||||
|
||||
DEFAULT_PALETTE = [
|
||||
240, 240, 240,
|
||||
242, 178, 51,
|
||||
229, 127, 216,
|
||||
153, 178, 242,
|
||||
222, 222, 108,
|
||||
127, 204, 25,
|
||||
242, 178, 204,
|
||||
76, 76, 76,
|
||||
153, 153, 153,
|
||||
76, 153, 178,
|
||||
178, 102, 229,
|
||||
51, 102, 204,
|
||||
127, 102, 76,
|
||||
87, 166, 78,
|
||||
204, 76, 76,
|
||||
17, 17, 17
|
||||
0xf0, 0xf0, 0xf0,
|
||||
0xf2, 0xb2, 0x33,
|
||||
0xe5, 0x7f, 0xd8,
|
||||
0x99, 0xb2, 0xf2,
|
||||
|
||||
0xde, 0xde, 0x6c,
|
||||
0x7f, 0xcc, 0x19,
|
||||
0xf2, 0xb2, 0xcc,
|
||||
0x4c, 0x4c, 0x4c,
|
||||
|
||||
0x99, 0x99, 0x99,
|
||||
0x4c, 0x99, 0xb2,
|
||||
0xb2, 0x66, 0xe5,
|
||||
0x33, 0x66, 0xcc,
|
||||
|
||||
0x7f, 0x66, 0x4c,
|
||||
0x57, 0xa6, 0x4e,
|
||||
0xcc, 0x4c, 0x4c,
|
||||
0x11, 0x11, 0x11
|
||||
]
|
||||
|
||||
DEFAULT_GRAYSCALE_PALETTE = [
|
||||
|
@ -399,7 +402,7 @@ def main():
|
|||
raise ValueError(f"invalid palette identifier: {args.palette!r}")
|
||||
|
||||
converter = Converter(canv, palette, dither=not args.nodither)
|
||||
converter._img.save("/tmp/_ccpictmp.png")
|
||||
# converter._img.save("/tmp/_ccpictmp.png")
|
||||
if args.textmode:
|
||||
with open(args.output_path, "w") as fp:
|
||||
converter.export(fp)
|
||||
|
|
22
ccpi.lua
22
ccpi.lua
|
@ -64,9 +64,29 @@ decoders[1] = function(image, fp)
|
|||
return true
|
||||
end
|
||||
|
||||
decoders[128] = function(image, fp)
|
||||
image.w = read_varint(fp)
|
||||
image.h = read_varint(fp)
|
||||
image.extras.n_frames = read_varint(fp)
|
||||
read_palette_full(image.palette, fp)
|
||||
local success, err = read_pixeldata_v0(image, fp)
|
||||
if not success then return false, err end
|
||||
image.extras.frames = {}
|
||||
for i = 1, image.extras.n_frames - 1 do
|
||||
local frame = { palette = {}, lines = {} }
|
||||
frame.w = image.w
|
||||
frame.h = image.h
|
||||
frame.scale = image.scale
|
||||
read_palette_full(frame.palette)
|
||||
local success, err = read_pixeldata_v0(frame, fp)
|
||||
if not success then return false, err end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
local function parse(fp)
|
||||
local res
|
||||
local image = { w = 0, h = 0, scale = 1.0, palette = {}, lines = {} }
|
||||
local image = { w = 0, h = 0, scale = 1.0, palette = {}, lines = {}, extras = {} }
|
||||
|
||||
local magic = fp.read(4)
|
||||
if magic == "CCPI" then
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
// x-run: make test-cpi2png
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stb/stb_image.h>
|
||||
#include <stb/stb_image_write.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cc-common.h"
|
||||
|
||||
bool read_varint(FILE *fp, unsigned int *out);
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc < 3) {
|
||||
fprintf(stderr, "Usage: %s [input.cpi] [output.png]\n", argv[0]);
|
||||
}
|
||||
|
||||
FILE *fp_in = fopen(argv[1], "rb");
|
||||
assert(fp_in != NULL && "Failed to open input file");
|
||||
|
||||
unsigned char header[4];
|
||||
|
||||
unsigned char version = 0;
|
||||
assert(fread(header, 1, 4, fp_in) == 4 && "Failed to read header: not enough bytes");
|
||||
if (0 == memcmp(header, "CCPI", 4)) { // Original CCPI (CPIv0)
|
||||
version = 0;
|
||||
} else if (0 == memcmp(header, "CPI", 3)) { // Newer CCPI (CPIvX)
|
||||
version = header[3];
|
||||
} else {
|
||||
assert(false && "Not a CPI/CCPI image: invalid header");
|
||||
}
|
||||
|
||||
if (version & 0x80) {
|
||||
fprintf(stderr, "Draft version: 0x%02x may not be supported properly! Here be dragons!\n", version);
|
||||
}
|
||||
|
||||
unsigned int width = 0, height = 0;
|
||||
|
||||
if (version == 0) {
|
||||
width = fgetc(fp_in);
|
||||
height = fgetc(fp_in);
|
||||
(void)fgetc(fp_in); // XXX: ignore scale
|
||||
} else if (version == 1) {
|
||||
assert(read_varint(fp_in, &width) && "Failed to read width varint");
|
||||
assert(read_varint(fp_in, &height) && "Failed to read height varint");
|
||||
} else {
|
||||
assert(false && "Failed to read size: unsupported version");
|
||||
}
|
||||
|
||||
union color *canvas = malloc(width * height * 6 * 9 * sizeof(union color));
|
||||
|
||||
|
||||
// XXX: may change in future when we introduce variable-size palettes
|
||||
// though, it may never change, if I'm being honest. Why would I choose
|
||||
// worse image quality with less colors when I can use all of them?
|
||||
union color *colors = calloc(16, sizeof(union color));
|
||||
|
||||
// NOTE: our `union color` type is 4 bytes long, while palette stored in the
|
||||
// file itself uses 3 bytes per color, so we can't just `fread` them at once,
|
||||
// sadly.
|
||||
for (int i = 0; i < 16; i++) {
|
||||
colors[i].rgba.r = fgetc(fp_in);
|
||||
colors[i].rgba.g = fgetc(fp_in);
|
||||
colors[i].rgba.b = fgetc(fp_in);
|
||||
colors[i].rgba.a = 0xff;
|
||||
}
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
unsigned char sym = fgetc(fp_in);
|
||||
unsigned char color = fgetc(fp_in);
|
||||
union color background = colors[color & 0xF];
|
||||
union color foreground = colors[color >> 4];
|
||||
for (int oy = 0; oy < 9; oy++) {
|
||||
for (int ox = 0; ox < 6; ox++) {
|
||||
union color pix = ((0x80 >> (ox + 1)) & cc_font_atlas[sym][oy + 1]) ? foreground : background;
|
||||
canvas[ox + (x + (y * 9 + oy) * width) * 6] = pix;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stbi_write_png(argv[2], width * 6, height * 9, 4, canvas, 0);
|
||||
|
||||
free(colors);
|
||||
free(canvas);
|
||||
fclose(fp_in);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
bool read_varint(FILE *fp, unsigned int *out) {
|
||||
int position = 0;
|
||||
|
||||
while (true) {
|
||||
unsigned char curr = fgetc(fp);
|
||||
*out |= (curr & 0x7F) << position;
|
||||
|
||||
if ((curr & 0x80) == 0) break;
|
||||
|
||||
position += 7;
|
||||
|
||||
if (position >= 32) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
336
img2cpi.c
336
img2cpi.c
|
@ -1,7 +1,8 @@
|
|||
// x-run: make img2cpi CC=clang
|
||||
// x-run: ~/scripts/runc.sh % -Wall -Wextra -lm --- ~/images/boykisser.png cpi-images/boykisser.cpi
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
#include <stb/stb_image.h>
|
||||
#define STB_IMAGE_RESIZE_IMPLEMENTATION
|
||||
#include <stb/stb_image_resize2.h>
|
||||
#include <argp.h>
|
||||
#include <stdio.h>
|
||||
|
@ -11,6 +12,7 @@
|
|||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <stdbool.h>
|
||||
#include "cc-common.h"
|
||||
|
||||
#define MAX_COLOR_DIFFERENCE 768
|
||||
#define K_MEANS_ITERATIONS 4
|
||||
|
@ -18,25 +20,10 @@
|
|||
# define HAS_POPCNT 1
|
||||
#endif
|
||||
|
||||
struct rgba { uint8_t r, g, b, a; };
|
||||
union color {
|
||||
struct rgba rgba;
|
||||
uint32_t v;
|
||||
};
|
||||
struct cc_char {
|
||||
unsigned char character;
|
||||
unsigned char bg, fg;
|
||||
};
|
||||
struct palette {
|
||||
const uint8_t count;
|
||||
union color colors[] __attribute__((counted_by(count)));
|
||||
};
|
||||
#define LENGTHOF(...) (sizeof(__VA_ARGS__) / sizeof(*(__VA_ARGS__)))
|
||||
#define PALETTE(...) { .count = LENGTHOF((union color[]){__VA_ARGS__}), .colors = {__VA_ARGS__} }
|
||||
typedef char GlyphBitmap[11];
|
||||
|
||||
const extern GlyphBitmap font_atlas[256];
|
||||
const extern struct palette DEFAULT_PALETTE, DEFAULT_GRAY_PALETTE;
|
||||
|
||||
struct arguments {
|
||||
int width, height;
|
||||
|
@ -216,11 +203,11 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
|
||||
// TODO: load palette, maybe calculate it too? k-means?
|
||||
const struct palette *palette = &DEFAULT_PALETTE;
|
||||
const struct palette *palette = &cc_default_palette;
|
||||
switch (args.palette_type) {
|
||||
case PALETTE_DEFAULT: palette = &DEFAULT_PALETTE; break;
|
||||
case PALETTE_DEFAULT_GRAY: palette = &DEFAULT_GRAY_PALETTE; break;
|
||||
case PALETTE_AUTO: palette = palette_k_means(src_image, &DEFAULT_PALETTE); break;
|
||||
case PALETTE_DEFAULT: palette = &cc_default_palette; break;
|
||||
case PALETTE_DEFAULT_GRAY: palette = &cc_default_gray_palette; break;
|
||||
case PALETTE_AUTO: palette = palette_k_means(src_image, &cc_default_palette); break;
|
||||
case PALETTE_LIST: assert(0 && "Not implemented"); break;
|
||||
case PALETTE_PATH: assert(0 && "Not implemented"); break;
|
||||
default: assert(0 && "Unreachable");
|
||||
|
@ -680,7 +667,7 @@ void convert_8x11(const struct image_pal *img, struct cc_char *characters, bool
|
|||
const int sym = closest_chunk_color_symbol(&chunk_palette_diffs, color, precise);
|
||||
float difference = 0;
|
||||
for (int oy = 0; oy < 11; oy++) {
|
||||
unsigned char sym_line = font_atlas[sym][oy];
|
||||
unsigned char sym_line = cc_font_atlas[sym][oy];
|
||||
for (int ox = 0; ox < 8; ox++) {
|
||||
bool lit = sym_line & (0x80 >> ox);
|
||||
difference += chunk_palette_diffs[ox][oy][lit ? color >> 4 : color & 0xF];
|
||||
|
@ -819,7 +806,7 @@ void k_means_end(struct k_means_state *state) {
|
|||
|
||||
struct palette *palette_k_means(const struct image *image, const struct palette *prototype) {
|
||||
if (!prototype) {
|
||||
prototype = &DEFAULT_PALETTE;
|
||||
prototype = &cc_default_palette;
|
||||
}
|
||||
struct palette *palette = custom_palette_from(prototype);
|
||||
|
||||
|
@ -872,12 +859,12 @@ float weighted_glyph_hamming_distance(const GlyphBitmap *lhs, const GlyphBitmap
|
|||
|
||||
uint8_t closest_glyph_symbol_fast(const GlyphBitmap *target) {
|
||||
uint8_t best = 0x01;
|
||||
int best_dist = glyph_hamming_distance(target, &font_atlas[best]);
|
||||
int best_dist = glyph_hamming_distance(target, &cc_font_atlas[best]);
|
||||
for (int sym = 0x02; sym <= 0xFF; sym++) {
|
||||
if (sym == '\t' || sym == '\n' || sym == '\r' || sym == '\x0e') {
|
||||
continue;
|
||||
}
|
||||
int dist = glyph_hamming_distance(target, &font_atlas[sym]);
|
||||
int dist = glyph_hamming_distance(target, &cc_font_atlas[sym]);
|
||||
if (dist <= best_dist) {
|
||||
best_dist = dist;
|
||||
best = sym;
|
||||
|
@ -888,12 +875,12 @@ uint8_t closest_glyph_symbol_fast(const GlyphBitmap *target) {
|
|||
|
||||
uint8_t closest_glyph_symbol_precise(const GlyphBitmap *target, const typeof(float[11][8]) *weights) {
|
||||
uint8_t best = 0x01;
|
||||
float best_dist = weighted_glyph_hamming_distance(target, &font_atlas[best], weights);
|
||||
float best_dist = weighted_glyph_hamming_distance(target, &cc_font_atlas[best], weights);
|
||||
for (int sym = 0x02; sym <= 0xFF; sym++) {
|
||||
if (sym == '\t' || sym == '\n' || sym == '\r' || sym == '\x0e') {
|
||||
continue;
|
||||
}
|
||||
float dist = weighted_glyph_hamming_distance(target, &font_atlas[sym], weights);
|
||||
float dist = weighted_glyph_hamming_distance(target, &cc_font_atlas[sym], weights);
|
||||
if (dist <= best_dist) {
|
||||
best_dist = dist;
|
||||
best = sym;
|
||||
|
@ -930,298 +917,3 @@ uint8_t closest_chunk_color_symbol(const typeof(float[8][11][0x10]) *chunk_palet
|
|||
return closest_glyph_symbol_fast(&glyph);
|
||||
}
|
||||
}
|
||||
|
||||
const struct palette DEFAULT_PALETTE = PALETTE(
|
||||
{ { 0xf0, 0xf0, 0xf0, 0xff } },
|
||||
{ { 0xf2, 0xb2, 0x33, 0xff } },
|
||||
{ { 0xe5, 0x7f, 0xd8, 0xff } },
|
||||
{ { 0x99, 0xb2, 0xf2, 0xff } },
|
||||
{ { 0xde, 0xde, 0x6c, 0xff } },
|
||||
{ { 0x7f, 0xcc, 0x19, 0xff } },
|
||||
{ { 0xf2, 0xb2, 0xcc, 0xff } },
|
||||
{ { 0x4c, 0x4c, 0x4c, 0xff } },
|
||||
{ { 0x99, 0x99, 0x99, 0xff } },
|
||||
{ { 0x4c, 0x99, 0xb2, 0xff } },
|
||||
{ { 0xb2, 0x66, 0xe5, 0xff } },
|
||||
{ { 0x33, 0x66, 0xcc, 0xff } },
|
||||
{ { 0x7f, 0x66, 0x4c, 0xff } },
|
||||
{ { 0x57, 0xa6, 0x4e, 0xff } },
|
||||
{ { 0xcc, 0x4c, 0x4c, 0xff } },
|
||||
{ { 0x11, 0x11, 0x11, 0xff } }
|
||||
), DEFAULT_GRAY_PALETTE = PALETTE(
|
||||
{ { 0xf0, 0xf0, 0xf0, 0xff } },
|
||||
{ { 0x9d, 0x9d, 0x9d, 0xff } },
|
||||
{ { 0xbe, 0xbe, 0xbe, 0xff } },
|
||||
{ { 0xbf, 0xbf, 0xbf, 0xff } },
|
||||
{ { 0xb8, 0xb8, 0xb8, 0xff } },
|
||||
{ { 0x76, 0x76, 0x76, 0xff } },
|
||||
{ { 0xd0, 0xd0, 0xd0, 0xff } },
|
||||
{ { 0x4c, 0x4c, 0x4c, 0xff } },
|
||||
{ { 0x99, 0x99, 0x99, 0xff } },
|
||||
{ { 0x87, 0x87, 0x87, 0xff } },
|
||||
{ { 0xa9, 0xa9, 0xa9, 0xff } },
|
||||
{ { 0x77, 0x77, 0x77, 0xff } },
|
||||
{ { 0x65, 0x65, 0x65, 0xff } },
|
||||
{ { 0x6e, 0x6e, 0x6e, 0xff } },
|
||||
{ { 0x76, 0x76, 0x76, 0xff } },
|
||||
{ { 0x11, 0x11, 0x11, 0xff } }
|
||||
);
|
||||
|
||||
const char font_atlas[256][11] = {
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x44, 0x6c, 0x44, 0x54, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x7c, 0x54, 0x7c, 0x44, 0x6c, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x28, 0x7c, 0x7c, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x10, 0x38, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x38, 0x10, 0x7c, 0x7c, 0x10, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x10, 0x38, 0x7c, 0x7c, 0x10, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x7e, 0x7e, 0x66, 0x42, 0x42, 0x66, 0x7e, 0x7e, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x1c, 0x0c, 0x34, 0x48, 0x48, 0x30, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x10, 0x38, 0x10, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x3c, 0x24, 0x3c, 0x20, 0x60, 0x60, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x3e, 0x22, 0x3e, 0x22, 0x66, 0x66, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x40, 0x70, 0x7c, 0x70, 0x40, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x04, 0x1c, 0x7c, 0x1c, 0x04, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x38, 0x7c, 0x10, 0x10, 0x7c, 0x38, 0x10, 0x00, 0x00, },
|
||||
{ 0x00, 0x24, 0x24, 0x24, 0x24, 0x24, 0x00, 0x24, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x3c, 0x54, 0x54, 0x34, 0x14, 0x14, 0x14, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x3c, 0x60, 0x58, 0x44, 0x34, 0x0c, 0x78, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x38, 0x7c, 0x10, 0x7c, 0x38, 0x10, 0x7c, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x38, 0x7c, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x10, 0x10, 0x10, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x10, 0x18, 0x7c, 0x18, 0x10, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x10, 0x30, 0x7c, 0x30, 0x10, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x7c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x24, 0x7e, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x10, 0x10, 0x38, 0x38, 0x7c, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x7c, 0x38, 0x38, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x14, 0x14, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x28, 0x28, 0x7c, 0x28, 0x7c, 0x28, 0x28, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x3c, 0x40, 0x38, 0x04, 0x78, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x44, 0x48, 0x08, 0x10, 0x20, 0x24, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x28, 0x10, 0x34, 0x58, 0x48, 0x34, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x0c, 0x10, 0x20, 0x20, 0x20, 0x10, 0x0c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x30, 0x08, 0x04, 0x04, 0x04, 0x08, 0x30, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x24, 0x18, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x10, 0x10, 0x7c, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x04, 0x08, 0x08, 0x10, 0x20, 0x20, 0x40, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x44, 0x4c, 0x54, 0x64, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x30, 0x10, 0x10, 0x10, 0x10, 0x7c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x44, 0x04, 0x18, 0x20, 0x44, 0x7c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x44, 0x04, 0x18, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x0c, 0x14, 0x24, 0x44, 0x7c, 0x04, 0x04, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x7c, 0x40, 0x78, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x18, 0x20, 0x40, 0x78, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x7c, 0x44, 0x04, 0x08, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x44, 0x44, 0x38, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x44, 0x44, 0x3c, 0x04, 0x08, 0x30, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, },
|
||||
{ 0x00, 0x04, 0x08, 0x10, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x20, 0x10, 0x08, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x44, 0x04, 0x08, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x3c, 0x42, 0x5a, 0x5a, 0x5e, 0x40, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x44, 0x7c, 0x44, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x78, 0x44, 0x78, 0x44, 0x44, 0x44, 0x78, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x44, 0x40, 0x40, 0x40, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x78, 0x44, 0x44, 0x44, 0x44, 0x44, 0x78, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x7c, 0x40, 0x70, 0x40, 0x40, 0x40, 0x7c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x7c, 0x40, 0x70, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x3c, 0x40, 0x4c, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x44, 0x44, 0x7c, 0x44, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x44, 0x48, 0x70, 0x48, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x44, 0x6c, 0x54, 0x44, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x44, 0x64, 0x54, 0x4c, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x78, 0x44, 0x78, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x44, 0x44, 0x44, 0x44, 0x48, 0x34, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x78, 0x44, 0x78, 0x44, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x3c, 0x40, 0x38, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x7c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x44, 0x44, 0x44, 0x44, 0x28, 0x28, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x44, 0x44, 0x44, 0x44, 0x54, 0x6c, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x44, 0x28, 0x10, 0x28, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x44, 0x28, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x7c, 0x04, 0x08, 0x10, 0x20, 0x40, 0x7c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x40, 0x20, 0x20, 0x10, 0x08, 0x08, 0x04, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x38, 0x04, 0x3c, 0x44, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x40, 0x40, 0x58, 0x64, 0x44, 0x44, 0x78, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x38, 0x44, 0x40, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x04, 0x04, 0x34, 0x4c, 0x44, 0x44, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x38, 0x44, 0x7c, 0x40, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x0c, 0x10, 0x3c, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x3c, 0x44, 0x44, 0x3c, 0x04, 0x78, 0x00, 0x00, },
|
||||
{ 0x00, 0x40, 0x40, 0x58, 0x64, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x04, 0x00, 0x04, 0x04, 0x04, 0x44, 0x44, 0x38, 0x00, 0x00, },
|
||||
{ 0x00, 0x20, 0x20, 0x24, 0x28, 0x30, 0x28, 0x24, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x08, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x68, 0x54, 0x54, 0x44, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x78, 0x44, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x58, 0x64, 0x44, 0x78, 0x40, 0x40, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x34, 0x4c, 0x44, 0x3c, 0x04, 0x04, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x58, 0x64, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x3c, 0x40, 0x38, 0x04, 0x78, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x10, 0x38, 0x10, 0x10, 0x10, 0x08, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x28, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x44, 0x44, 0x54, 0x54, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x3c, 0x04, 0x78, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x7c, 0x08, 0x10, 0x20, 0x7c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x0c, 0x10, 0x10, 0x20, 0x10, 0x10, 0x0c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x30, 0x08, 0x08, 0x04, 0x08, 0x08, 0x30, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x32, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x24, 0x48, 0x12, 0x24, 0x48, 0x12, 0x24, 0x48, 0x12, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0xf0, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x0f, 0x0f, 0x0f, 0x0f, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0xf0, 0xf0, 0xf0, 0xf0, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0xff, 0xff, 0xff, 0xff, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, },
|
||||
{ 0xf0, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, },
|
||||
{ 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, },
|
||||
{ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, },
|
||||
{ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, },
|
||||
{ 0x0f, 0x0f, 0x0f, 0x0f, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, },
|
||||
{ 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x0f, 0xf0, 0xf0, 0xf0, 0xf0, },
|
||||
{ 0xf0, 0xf0, 0xf0, 0xf0, 0x0f, 0x0f, 0x0f, 0xf0, 0xf0, 0xf0, 0xf0, },
|
||||
{ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0xf0, 0xf0, 0xf0, 0xf0, },
|
||||
{ 0x7f, 0x7f, 0x7f, 0x7f, 0x0f, 0x0f, 0x0f, 0xf0, 0xf0, 0xf0, 0xf0, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, },
|
||||
{ 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, },
|
||||
{ 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, },
|
||||
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x10, 0x38, 0x44, 0x40, 0x44, 0x38, 0x10, 0x00, 0x00, },
|
||||
{ 0x00, 0x18, 0x24, 0x20, 0x78, 0x20, 0x20, 0x7c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x44, 0x38, 0x44, 0x44, 0x44, 0x38, 0x44, 0x00, 0x00, },
|
||||
{ 0x00, 0x44, 0x28, 0x7c, 0x10, 0x7c, 0x10, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x3c, 0x60, 0x58, 0x44, 0x34, 0x0c, 0x78, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x3c, 0x4a, 0x52, 0x52, 0x4a, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x30, 0x08, 0x38, 0x48, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x14, 0x28, 0x50, 0x28, 0x14, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x7c, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x3c, 0x5a, 0x5a, 0x56, 0x42, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x30, 0x48, 0x48, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x10, 0x10, 0x7c, 0x10, 0x10, 0x00, 0x7c, 0x00, 0x00, },
|
||||
{ 0x00, 0x40, 0x20, 0x60, 0x40, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x60, 0x20, 0x60, 0x20, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x7a, 0x40, 0x40, 0x00, },
|
||||
{ 0x00, 0x3c, 0x54, 0x54, 0x34, 0x14, 0x14, 0x14, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, },
|
||||
{ 0x00, 0x20, 0x60, 0x20, 0x20, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x50, 0x28, 0x14, 0x28, 0x50, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x44, 0x48, 0x08, 0x10, 0x2c, 0x2c, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x44, 0x48, 0x08, 0x10, 0x24, 0x28, 0x4c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x64, 0x28, 0x68, 0x10, 0x2c, 0x2c, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x00, 0x10, 0x20, 0x40, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x60, 0x00, 0x38, 0x44, 0x7c, 0x44, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x0c, 0x00, 0x38, 0x44, 0x7c, 0x44, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x44, 0x38, 0x44, 0x7c, 0x44, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x28, 0x50, 0x38, 0x44, 0x7c, 0x44, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x28, 0x00, 0x38, 0x44, 0x7c, 0x44, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x00, 0x38, 0x44, 0x7c, 0x44, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x3c, 0x50, 0x50, 0x78, 0x50, 0x50, 0x5c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x44, 0x40, 0x40, 0x44, 0x38, 0x08, 0x10, 0x00, 0x00, },
|
||||
{ 0x00, 0x60, 0x00, 0x7c, 0x40, 0x78, 0x40, 0x7c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x0c, 0x00, 0x7c, 0x40, 0x78, 0x40, 0x7c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x44, 0x7c, 0x40, 0x78, 0x40, 0x7c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x28, 0x00, 0x7c, 0x40, 0x78, 0x40, 0x7c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x30, 0x00, 0x38, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x18, 0x00, 0x38, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x28, 0x38, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x28, 0x00, 0x38, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x78, 0x44, 0x44, 0x64, 0x44, 0x44, 0x78, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x14, 0x28, 0x44, 0x64, 0x54, 0x4c, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x60, 0x38, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x0c, 0x38, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x44, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x28, 0x50, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x28, 0x38, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x44, 0x4c, 0x54, 0x64, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x60, 0x00, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x0c, 0x00, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x28, 0x00, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x28, 0x00, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x0c, 0x00, 0x44, 0x28, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x10, 0x18, 0x14, 0x18, 0x10, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x78, 0x44, 0x58, 0x44, 0x44, 0x44, 0x58, 0x40, 0x00, 0x00, },
|
||||
{ 0x00, 0x60, 0x00, 0x38, 0x04, 0x3c, 0x44, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x0c, 0x00, 0x38, 0x04, 0x3c, 0x44, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x44, 0x38, 0x04, 0x3c, 0x44, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x28, 0x50, 0x38, 0x04, 0x3c, 0x44, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x28, 0x00, 0x38, 0x04, 0x3c, 0x44, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x00, 0x38, 0x04, 0x3c, 0x44, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x2c, 0x52, 0x7c, 0x50, 0x2e, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x38, 0x44, 0x40, 0x44, 0x38, 0x08, 0x10, 0x00, 0x00, },
|
||||
{ 0x00, 0x60, 0x00, 0x38, 0x44, 0x7c, 0x40, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x0c, 0x00, 0x38, 0x44, 0x7c, 0x40, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x44, 0x38, 0x44, 0x7c, 0x40, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x28, 0x00, 0x38, 0x44, 0x7c, 0x40, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x30, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x18, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x28, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x28, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x08, 0x3c, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x28, 0x50, 0x78, 0x44, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x60, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x0c, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x38, 0x44, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x28, 0x50, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x28, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x10, 0x00, 0x7c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x00, 0x00, 0x38, 0x4c, 0x54, 0x64, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x60, 0x00, 0x44, 0x44, 0x44, 0x44, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x0c, 0x00, 0x44, 0x44, 0x44, 0x44, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x10, 0x28, 0x00, 0x44, 0x44, 0x44, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x28, 0x00, 0x44, 0x44, 0x44, 0x44, 0x3c, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x0c, 0x00, 0x44, 0x44, 0x44, 0x3c, 0x04, 0x78, 0x00, 0x00, },
|
||||
{ 0x00, 0x30, 0x10, 0x18, 0x14, 0x18, 0x10, 0x38, 0x00, 0x00, 0x00, },
|
||||
{ 0x00, 0x28, 0x00, 0x44, 0x44, 0x44, 0x3c, 0x04, 0x78, 0x00, 0x00, },
|
||||
};
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
local args = { ... }
|
||||
local ccpi = require("ccpi")
|
||||
|
||||
local bit = {
|
||||
band = function(a, b) return a & b end,
|
||||
bor = function(a, b) return a | b end,
|
||||
blshift = function(a, b) return a << b end,
|
||||
brshift = function(a, b) return a >> b end,
|
||||
}
|
||||
|
||||
local function write_varint(fp, value)
|
||||
value = bit.band(value, 0xFFFFFFFF)
|
||||
mask = 0xFFFFFF80
|
||||
while true do
|
||||
if bit.band(value, mask) == 0 then
|
||||
fp:write(string.char(bit.band(value, 0xff)))
|
||||
return
|
||||
end
|
||||
|
||||
fp:write(string.char(bit.bor(0x80, bit.band(value, 0x7f))))
|
||||
value = bit.brshift(value, 7)
|
||||
end
|
||||
end
|
||||
|
||||
local function write_palette(fp, pal)
|
||||
for i = 1, 16 do
|
||||
fp:write(string.char(
|
||||
bit.brshift(pal[i], 16),
|
||||
bit.band(bit.brshift(pal[i], 8), 0xff),
|
||||
bit.band(pal[i], 0xff)
|
||||
))
|
||||
end
|
||||
end
|
||||
|
||||
local function write_pixeldata_v0(img, fp)
|
||||
for y = 1, img.h do
|
||||
for x = 1, img.w do
|
||||
fp:write(img.lines[y].s:sub(x, x))
|
||||
local bg = tonumber(img.lines[y].bg:sub(x, x), 16)
|
||||
local fg = tonumber(img.lines[y].fg:sub(x, x), 16)
|
||||
fp:write(string.char(bit.bor(bg, bit.blshift(fg, 4))))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local fp_out = io.open(table.remove(args, 1), "wb")
|
||||
fp_out:write("CPI" .. string.char(0x80))
|
||||
|
||||
local fp = io.open(table.remove(args, 1), "rb")
|
||||
print(fp, fp.close)
|
||||
local img, err = ccpi.parse({
|
||||
read = function(sz) return fp:read(sz) end,
|
||||
})
|
||||
fp:close()
|
||||
if err ~= nil then
|
||||
printError(err)
|
||||
return
|
||||
end
|
||||
|
||||
write_varint(fp_out, img.w)
|
||||
write_varint(fp_out, img.h)
|
||||
write_varint(fp_out, #args)
|
||||
|
||||
write_palette(fp_out, img.palette)
|
||||
write_pixeldata_v0(img, fp_out)
|
||||
|
||||
for i, arg in ipairs(args) do
|
||||
print(arg)
|
||||
local fp = io.open(arg, "rb")
|
||||
img, err = ccpi.parse({
|
||||
read = function(sz) return fp:read(sz) end,
|
||||
})
|
||||
fp:close()
|
||||
if err ~= nil then
|
||||
printError(err)
|
||||
return
|
||||
end
|
||||
write_palette(fp_out, img.palette)
|
||||
write_pixeldata_v0(img, fp_out)
|
||||
end
|
||||
|
||||
fp_out:close()
|
|
@ -0,0 +1,65 @@
|
|||
|
||||
from typing import Any, Literal
|
||||
from websockets import connect
|
||||
|
||||
HexDigit = Literal[
|
||||
"0", "1", "2", "3", "4", "5", "6", "7",
|
||||
"8", "9", "a", "b", "c", "d", "e", "f"
|
||||
]
|
||||
|
||||
class Packet:
|
||||
packet_id: int
|
||||
side: Literal["client", "server"]
|
||||
|
||||
def __init_subclass__(cls, packet_id: int, side: Literal["client", "server"]) -> None:
|
||||
cls.packet_id = packet_id
|
||||
cls.side = side
|
||||
|
||||
class PacketServerPing(Packet, packet_id=2, side="server"):
|
||||
pass
|
||||
|
||||
class PacketClientPong(Packet, packet_id=2, side="client"):
|
||||
pass
|
||||
|
||||
class PacketServerCapabilities(Packet, packet_id=0, side="server"):
|
||||
clients: int
|
||||
capabilities: list[str]
|
||||
|
||||
class PacketServerComputer(Packet, packet_id=18, side="server"):
|
||||
id: int
|
||||
label: str
|
||||
|
||||
class PacketServerScreen(Packet, packet_id=16, side="server"):
|
||||
cursorBlink: bool
|
||||
width: int
|
||||
height: int
|
||||
cursorX: int
|
||||
cursorY: int
|
||||
curFore: HexDigit
|
||||
curBack: HexDigit
|
||||
text: list[str]
|
||||
back: list[str]
|
||||
fore: list[str]
|
||||
palette: list[int]
|
||||
|
||||
class CCEvent:
|
||||
name: str
|
||||
args: list[Any]
|
||||
|
||||
class PacketClientEvent(Packet, packet_id=17, side="client"):
|
||||
events: list[CCEvent]
|
||||
|
||||
class CCAction:
|
||||
action: int
|
||||
|
||||
def __init_subclass__(cls, action: int) -> None:
|
||||
cls.action = action
|
||||
|
||||
class CCActionFile(CCAction, action=0):
|
||||
file: str
|
||||
contents: str
|
||||
checksum: int
|
||||
|
||||
class PacketServerFile(Packet, packet_id=34, side="server"):
|
||||
actions: list[CCAction]
|
||||
|
|
@ -0,0 +1,150 @@
|
|||
# x-run: python3 % ~/downloads/moZtoMP7HAA.mp4 /tmp/video.cani
|
||||
from typing import Literal
|
||||
from dataclasses import dataclass
|
||||
from struct import pack
|
||||
from sys import argv
|
||||
from subprocess import Popen, PIPE, run
|
||||
from tqdm import tqdm
|
||||
from tempfile import TemporaryDirectory
|
||||
from glob import glob
|
||||
from PIL import Image
|
||||
from functools import lru_cache
|
||||
|
||||
|
||||
PIX_BITS = [[1, 2], [4, 8], [16, 0]]
|
||||
|
||||
|
||||
@dataclass
|
||||
class VideoMetadata:
|
||||
framerate: Literal[20, 10, 5] = 10
|
||||
audio_channels: Literal[1, 2] = 2
|
||||
sample_rate: Literal[12000, 24000, 48000] = 48000
|
||||
screen_width: int = 164
|
||||
screen_height: int = 81
|
||||
|
||||
@property
|
||||
def audio_samples_per_frame(self) -> int:
|
||||
return self.sample_rate // self.framerate
|
||||
|
||||
def serialize(self) -> bytes:
|
||||
return bytes([ self.framerate, self.audio_channels ]) \
|
||||
+ pack("<HHH", self.sample_rate, self.screen_width, self.screen_height)
|
||||
|
||||
@dataclass
|
||||
class VideoFrame:
|
||||
audio: list[bytes]
|
||||
video: list[bytes]
|
||||
palette: list[int]
|
||||
|
||||
def serialize(self) -> bytes:
|
||||
return bytes.join(b"", self.audio) \
|
||||
+ bytes.join(b"", self.video) \
|
||||
+ bytes.join(b"", [ bytes.fromhex("%06x" % color) for color in self.palette ])
|
||||
|
||||
@lru_cache
|
||||
def _brightness(palette: tuple, i: int) -> float:
|
||||
r, g, b = palette[i * 3 : (i + 1) * 3]
|
||||
return (r + g + b) / 768
|
||||
|
||||
@lru_cache
|
||||
def _distance(palette: tuple, a: int, b: int) -> float:
|
||||
r1, g1, b1 = palette[a * 3 : (a + 1) * 3]
|
||||
r2, g2, b2 = palette[b * 3 : (b + 1) * 3]
|
||||
rd, gd, bd = r1 - r2, g1 - g2, b1 - b2
|
||||
return (rd * rd + gd * gd + bd * bd) / 1966608
|
||||
|
||||
@lru_cache
|
||||
def _get_colors(imgdata, palette: tuple, x: int, y: int) -> tuple[int, int]:
|
||||
brightest_i, brightest_l = 0, 0
|
||||
darkest_i, darkest_l = 0, 768
|
||||
for oy, line in enumerate(PIX_BITS):
|
||||
for ox in range(len(line)):
|
||||
pix = imgdata[x + ox, y + oy]
|
||||
assert pix < 16, f"{pix} is too big at {x+ox}:{y+oy}"
|
||||
brightness = _brightness(palette, pix)
|
||||
if brightness > brightest_l:
|
||||
brightest_l, brightest_i = brightness, pix
|
||||
if brightness < darkest_l:
|
||||
darkest_l, darkest_i = brightness, pix
|
||||
return darkest_i, brightest_i
|
||||
|
||||
@lru_cache()
|
||||
def _is_darker(palette: tuple, bg: int, fg: int, c: int) -> bool:
|
||||
return _distance(palette, bg, c) < _distance(palette, fg, c)
|
||||
|
||||
def _get_block(imgdata, palette: tuple, x: int, y: int) -> tuple[int, int, int]:
|
||||
dark_i, bri_i = _get_colors(imgdata, palette, x, y)
|
||||
assert dark_i < 16, f"{dark_i} is too big"
|
||||
assert bri_i < 16, f"{bri_i} is too big"
|
||||
out: int = 0
|
||||
for oy, line in enumerate(PIX_BITS):
|
||||
for ox, bit in enumerate(line):
|
||||
if not _is_darker(
|
||||
palette, dark_i, bri_i, imgdata[x + ox, y + oy]
|
||||
):
|
||||
out |= bit
|
||||
# bottom right pixel fix?
|
||||
if not _is_darker(palette, dark_i, bri_i, imgdata[x + 1, y + 2]):
|
||||
out ^= 31
|
||||
dark_i, bri_i = bri_i, dark_i
|
||||
return out, dark_i, bri_i
|
||||
|
||||
metadata = VideoMetadata(
|
||||
framerate=20,
|
||||
audio_channels=2,
|
||||
sample_rate=24000,
|
||||
screen_width=164,
|
||||
screen_height=81
|
||||
)
|
||||
|
||||
input_video = argv[1]
|
||||
|
||||
with TemporaryDirectory() as tmpdir:
|
||||
run([
|
||||
"ffmpeg",
|
||||
"-i", input_video,
|
||||
"-f", "s8",
|
||||
"-ac", str(metadata.audio_channels),
|
||||
"-ar", str(metadata.sample_rate),
|
||||
f"{tmpdir}/audio.s8"
|
||||
])
|
||||
|
||||
run([
|
||||
"ffmpeg",
|
||||
"-i", input_video,
|
||||
"-an",
|
||||
"-r", str(metadata.framerate),
|
||||
"-vf", f"scale={metadata.screen_width * 2}:{metadata.screen_height * 3}",
|
||||
f"{tmpdir}/video%06d.jpg"
|
||||
])
|
||||
|
||||
with open(argv[2], "w") as fp_out, open(f"{tmpdir}/audio.s8", "rb") as fp_audio:
|
||||
print(metadata.serialize().hex(), file=fp_out)
|
||||
for i, frame_path in tqdm(enumerate(glob(f"{tmpdir}/video*.jpg"))):
|
||||
with Image.open(frame_path) as img_in:
|
||||
img_in = img_in.convert("P", palette=Image.Palette.ADAPTIVE, colors=16)
|
||||
img_data = img_in.load()
|
||||
img_palette = tuple(img_in.getpalette()) # type: ignore
|
||||
|
||||
audio_samples = fp_audio.read(metadata.audio_samples_per_frame * metadata.audio_channels)
|
||||
|
||||
frame = VideoFrame(
|
||||
[
|
||||
audio_samples[i::metadata.audio_channels]
|
||||
for i in range(metadata.audio_channels)
|
||||
],
|
||||
[],
|
||||
[
|
||||
(r << 16) | (g << 8) | b
|
||||
for r, g, b
|
||||
in zip(img_palette[0::3], img_palette[1::3], img_palette[2::3]) # type: ignore
|
||||
])
|
||||
|
||||
for y in range(0, img_in.height - 2, 3):
|
||||
line = bytearray()
|
||||
for x in range(0, img_in.width - 1, 2):
|
||||
ch, bg, fg = _get_block(img_data, img_palette, x, y)
|
||||
line.extend([(ch + 0x80) & 0xFF, fg << 4 | bg])
|
||||
frame.video.append(line)
|
||||
|
||||
print(frame.serialize().hex(), file=fp_out)
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
local config = {
|
||||
{ filter = ".*charged.*", from = "ae2:charger", to = "create:basin" },
|
||||
{ filter = "!.*charged.*", from = "create:basin", to = "ae2:charger", limit = 1 }
|
||||
}
|
||||
|
||||
local function is_matching(pattern, value)
|
||||
if pattern:sub(1, 1) == "!" then
|
||||
return not is_matching(pattern:sub(2))
|
||||
end
|
||||
return value:match(pattern) ~= nil
|
||||
end
|
||||
|
||||
|
||||
local items = {}
|
||||
|
||||
parallel.waitForAll(function() -- Inventory listener
|
||||
while true do
|
||||
local new_items = {}
|
||||
peripheral.find("inventory", function(inv)
|
||||
local inv_items = peripheral.call(inv, "list")
|
||||
for slot, item in pairs(inv_items) do
|
||||
new_items[string.format("%s#%d", inv, slot)] = item
|
||||
end
|
||||
end)
|
||||
items = new_items
|
||||
os.sleep(0)
|
||||
end
|
||||
end, function() -- Executor
|
||||
while true do
|
||||
for i, rule in ipairs(config) do
|
||||
|
||||
end
|
||||
os.sleep(0)
|
||||
end
|
||||
end)
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
peripheral.find("modem", function(name)
|
||||
rednet.open(name)
|
||||
print("Opened modem " .. name .. " for rednet connections")
|
||||
end)
|
||||
|
||||
print("Hostname: " .. os.getComputerLabel())
|
||||
print("ID: " .. os.getComputerID())
|
||||
rednet.host("ramfs", os.getComputerLabel())
|
||||
|
||||
parallel.waitForAll(function()
|
||||
while true do
|
||||
local ev = { os.pullEvent() }
|
||||
if ev[1] == "ramfs:shutdown" then
|
||||
break
|
||||
end
|
||||
print(table.unpack(ev))
|
||||
end
|
||||
end, function() -- Shutdown routine
|
||||
os.pullEvent("ramfs:shutdown")
|
||||
end)
|
|
@ -0,0 +1,84 @@
|
|||
{
|
||||
"junk": [
|
||||
"metalbarrels:gold_tile_4"
|
||||
],
|
||||
"storage": [
|
||||
"create:item_vault_2",
|
||||
"create:item_vault_1"
|
||||
],
|
||||
"pull": [
|
||||
"minecraft:barrel_1",
|
||||
"NOT IMPLEMENTED"
|
||||
],
|
||||
"push": [
|
||||
{ "name": "*_nugget", "to": "metalbarrels:gold_tile_8" },
|
||||
{ "name": "*_ingot", "to": "metalbarrels:gold_tile_8" },
|
||||
{ "name": "minecraft:*coal", "to": "metalbarrels:gold_tile_9" },
|
||||
{ "name": "NOT IMPLEMENTED", "to": "NOT IMPLEMENTED" }
|
||||
],
|
||||
"stock": {
|
||||
"metalbarrels:gold_tile_13#1": { "name": "minecraft:spruce_log", "count": 64 },
|
||||
"metalbarrels:gold_tile_13#2": { "name": "minecraft:spruce_log", "count": 64 },
|
||||
"metalbarrels:gold_tile_13#3": { "name": "minecraft:spruce_planks", "count": 64 },
|
||||
"metalbarrels:gold_tile_13#10": { "name": "minecraft:oak_log", "count": 64 },
|
||||
"metalbarrels:gold_tile_13#11": { "name": "minecraft:oak_log", "count": 64 },
|
||||
"metalbarrels:gold_tile_13#12": { "name": "minecraft:oak_planks", "count": 64 },
|
||||
"metalbarrels:gold_tile_13#19": { "name": "minecraft:dark_oak_log", "count": 64 },
|
||||
"metalbarrels:gold_tile_13#20": { "name": "minecraft:dark_oak_log", "count": 64 },
|
||||
"metalbarrels:gold_tile_13#21": { "name": "minecraft:dark_oak_planks", "count": 64 },
|
||||
"metalbarrels:gold_tile_13#4": { "name": "minecraft:cobblestone", "count": 64 },
|
||||
"metalbarrels:gold_tile_13#5": { "name": "minecraft:cobblestone", "count": 64 },
|
||||
"metalbarrels:gold_tile_13#6": { "name": "minecraft:stone", "count": 64 },
|
||||
"metalbarrels:gold_tile_13#13": { "name": "minecraft:cobbled_deepslate", "count": 64 },
|
||||
"metalbarrels:gold_tile_13#14": { "name": "minecraft:cobbled_deepslate", "count": 64 },
|
||||
"metalbarrels:gold_tile_13#15": { "name": "minecraft:deepslate", "count": 64 },
|
||||
"metalbarrels:gold_tile_13#7": { "name": "minecraft:dirt", "count": 64 },
|
||||
"metalbarrels:gold_tile_13#16": { "name": "minecraft:sand", "count": 64 },
|
||||
"metalbarrels:gold_tile_13#25": { "name": "minecraft:gravel", "count": 64 },
|
||||
"metalbarrels:gold_tile_13#8": { "name": "minecraft:netherrack", "count": 64 },
|
||||
"metalbarrels:gold_tile_13#17": { "name": "minecraft:soul_sand", "count": 64 },
|
||||
"metalbarrels:gold_tile_13#22": { "name": "minecraft:andesite", "count": 64 },
|
||||
"metalbarrels:gold_tile_13#23": { "name": "minecraft:diorite", "count": 64 },
|
||||
"metalbarrels:gold_tile_13#24": { "name": "minecraft:granite", "count": 64 },
|
||||
"metalbarrels:gold_tile_13#31": { "name": "minecraft:tuff", "count": 64 },
|
||||
"metalbarrels:gold_tile_13#32": { "name": "expcaves:sediment_stone", "count": 64 },
|
||||
"metalbarrels:gold_tile_13#33": { "name": "expcaves:lavastone", "count": 64 },
|
||||
"metalbarrels:gold_tile_13#34": { "name": "expcaves:dirtstone", "count": 64 },
|
||||
"metalbarrels:gold_tile_13#42": { "name": "minecraft:calcite", "count": 64 },
|
||||
"metalbarrels:gold_tile_13#43": { "name": "minecraft:clay_ball", "count": 64 },
|
||||
"metalbarrels:gold_tile_13#40": { "name": "create:limestone", "count": 64 },
|
||||
"metalbarrels:gold_tile_13#49": { "name": "minecraft:stone_bricks", "count": 64 },
|
||||
"metalbarrels:gold_tile_13#50": { "name": "minecraft:cracked_stone_bricks", "count": 64 },
|
||||
"metalbarrels:gold_tile_13#51": { "name": "minecraft:moss_block", "count": 64 },
|
||||
"metalbarrels:gold_tile_13#41": { "name": "forbidden_arcanus:darkstone", "count": 64 },
|
||||
"metalbarrels:gold_tile_13#73": { "name": "minecraft:apple", "count": 64 },
|
||||
"metalbarrels:gold_tile_13#74": { "name": "minecraft:kelp", "count": 64 },
|
||||
"metalbarrels:gold_tile_13#75": { "name": "minecraft:oak_sapling", "count": 64 },
|
||||
"metalbarrels:gold_tile_13#76": { "name": "minecraft:spruce_sapling", "count": 64 },
|
||||
"metalbarrels:gold_tile_13#77": { "name": "minecraft:dark_oak_sapling", "count": 64 },
|
||||
"metalbarrels:gold_tile_13#81": { "name": "minecraft:stick", "count": 64 },
|
||||
"metalbarrels:gold_tile_13#26": { "name": "minecraft:nether_bricks", "count": 64 },
|
||||
"metalbarrels:gold_tile_13#35": { "name": "minecraft:magma_block", "count": 64 },
|
||||
|
||||
"metalbarrels:gold_tile_6#1": { "name": "kubejs:kinetic_mechanism", "count": 64 },
|
||||
"metalbarrels:gold_tile_6#2": { "name": "kubejs:kinetic_mechanism", "count": 64 },
|
||||
"metalbarrels:gold_tile_6#10": { "name": "create:andesite_alloy", "count": 64 },
|
||||
"metalbarrels:gold_tile_6#11": { "name": "create:andesite_alloy", "count": 64 },
|
||||
"metalbarrels:gold_tile_6#12": { "name": "thermal:cured_rubber", "count": 64 },
|
||||
"metalbarrels:gold_tile_6#19": { "name": "thermal:silver_coin", "count": 64 },
|
||||
"metalbarrels:gold_tile_6#20": { "name": "thermal:silver_coin", "count": 64 },
|
||||
"metalbarrels:gold_tile_6#21": { "name": "thermal:silver_coin", "count": 64 },
|
||||
|
||||
"metalbarrels:gold_tile_7#1": { "name": "minecraft:lapis_lazuli", "count": 64 },
|
||||
"metalbarrels:gold_tile_7#2": { "name": "minecraft:redstone", "count": 64 },
|
||||
"metalbarrels:gold_tile_7#3": { "name": "minecraft:coal", "count": 15 },
|
||||
"metalbarrels:gold_tile_7#4": { "name": "thermal:apatite", "count": 64 },
|
||||
"metalbarrels:gold_tile_7#5": { "name": "thermal:sulfur", "count": 64 },
|
||||
"metalbarrels:gold_tile_7#6": { "name": "thermal:niter", "count": 64 },
|
||||
"metalbarrels:gold_tile_7#7": { "name": "thermal:cinnabar", "count": 64 },
|
||||
"metalbarrels:gold_tile_7#10": { "name": "ae2:certus_quartz_dust", "count": 64 },
|
||||
"metalbarrels:gold_tile_7#11": { "name": "ae2:certus_crystal_seed", "count": 64 },
|
||||
"metalbarrels:gold_tile_7#12": { "name": "forbidden_arcanus:xpetrified_orb", "count": 16 }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,434 @@
|
|||
|
||||
local function draw_bar(y, c1, c2, p, fmt, ...)
|
||||
local str = string.format(fmt, ...)
|
||||
local tw = term.getSize()
|
||||
local w1 = math.ceil(p * tw)
|
||||
local w2 = tw - w1
|
||||
|
||||
local old_bg = term.getBackgroundColor()
|
||||
term.setCursorPos(1, y)
|
||||
term.setBackgroundColor(c1)
|
||||
term.write(str:sub(1, w1))
|
||||
local rem = w1 - #str
|
||||
if rem > 0 then
|
||||
term.write(string.rep(" ", rem))
|
||||
end
|
||||
|
||||
term.setBackgroundColor(c2)
|
||||
term.write(str:sub(w1 + 1, w1 + w2))
|
||||
|
||||
rem = math.min(tw - #str, w2)
|
||||
if rem > 0 then
|
||||
term.write(string.rep(" ", rem))
|
||||
end
|
||||
|
||||
term.setBackgroundColor(old_bg)
|
||||
end
|
||||
|
||||
function table.deepcopy(obj)
|
||||
if type(obj) ~= 'table' then return obj end
|
||||
local res = {}
|
||||
for k, v in pairs(obj) do res[table.deepcopy(k)] = table.deepcopy(v) end
|
||||
return res
|
||||
end
|
||||
|
||||
function spairs(t, order)
|
||||
-- collect the tbl_keys
|
||||
local tbl_keys = {}
|
||||
for k in pairs(t) do tbl_keys[#tbl_keys+1] = k end
|
||||
|
||||
-- if order function given, sort by it by passing the table and tbl_keys a, b,
|
||||
-- otherwise just sort the tbl_keys
|
||||
if order then
|
||||
table.sort(tbl_keys, function(a,b) return order(t, a, b) end)
|
||||
else
|
||||
table.sort(tbl_keys)
|
||||
end
|
||||
|
||||
-- return the iterator function
|
||||
local i = 0
|
||||
return function()
|
||||
i = i + 1
|
||||
if tbl_keys[i] then
|
||||
return tbl_keys[i], t[tbl_keys[i]]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function string.split(inputstr, sep)
|
||||
sep = sep or "%s"
|
||||
local t = {}
|
||||
for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
|
||||
table.insert(t, str)
|
||||
end
|
||||
return table.unpack(t)
|
||||
end
|
||||
|
||||
function map(tbl, fn)
|
||||
local out = {}
|
||||
for k, v in pairs(tbl) do
|
||||
out[k] = fn(k, v, tbl)
|
||||
end
|
||||
return out
|
||||
end
|
||||
|
||||
function filter(tbl, fil)
|
||||
local out = {}
|
||||
for k, v in pairs(tbl) do
|
||||
if fil(k, v, tbl) then
|
||||
out[k] = v
|
||||
end
|
||||
end
|
||||
return out
|
||||
end
|
||||
|
||||
function pop(tbl)
|
||||
local out = { k = nil, v = nil }
|
||||
for k, v in pairs(tbl) do
|
||||
out.k = k
|
||||
out.v = v
|
||||
table.remove(tbl, k)
|
||||
break
|
||||
end
|
||||
return out.k, out.v
|
||||
end
|
||||
|
||||
function groupby(tbl, fn)
|
||||
local out = {}
|
||||
for k, v in pairs(tbl) do
|
||||
local group = fn(k, v, tbl)
|
||||
out[group] = out[group] or {}
|
||||
table.insert(out[group], { k = k, v = v })
|
||||
end
|
||||
return out
|
||||
end
|
||||
|
||||
function reduce(tbl, operator, initial)
|
||||
local accumulator = initial
|
||||
for k, v in pairs(tbl) do
|
||||
accumulator = operator(k, v, accumulator, tbl)
|
||||
end
|
||||
return accumulator
|
||||
end
|
||||
|
||||
function pipe(input)
|
||||
local function chain(fn)
|
||||
return function(self, ...)
|
||||
fn(self, ...)
|
||||
return self
|
||||
end
|
||||
end
|
||||
return {
|
||||
_value = table.deepcopy(input),
|
||||
groupby = chain(function(self, fn) self._value = groupby(self._value, fn) end),
|
||||
filter = chain(function(self, fn) self._value = filter(self._value, fn) end),
|
||||
map = chain(function(self, fn) self._value = map(self._value, fn) end),
|
||||
reduce = chain(function(self, operator, initial) self._value = reduce(self._value, operator, initial) end),
|
||||
sort = chain(function(self, key)
|
||||
local out = {}
|
||||
for k, v in spairs(self._value, key) do
|
||||
table.insert(out, { k = k, v = v })
|
||||
end
|
||||
self._value = out
|
||||
end),
|
||||
get = function(self) return self._value end
|
||||
}
|
||||
end
|
||||
|
||||
local keyboard = {
|
||||
"qwertyuiop",
|
||||
"asdfghjkl\x1b",
|
||||
"zxcvbnm \xd7",
|
||||
}
|
||||
|
||||
local config = { stock = {}, trash = {}, take = {}, storage = {} }
|
||||
local item_state = { stock = {}, storage = {}, junk = {} }
|
||||
local storage_sizes = { stock = {}, storage = {}, junk = {} }
|
||||
local sort_mode, sort_inverse = "count", false
|
||||
local search_open, search_query = false, ""
|
||||
|
||||
local mon = peripheral.find("monitor")
|
||||
mon.setTextScale(0.5)
|
||||
mon.clear()
|
||||
mon.setPaletteColor(colors.blue, 0x131326) -- odd lines
|
||||
mon.setPaletteColor(colors.purple, 0x261326) -- even lines
|
||||
mon.setPaletteColor(colors.magenta, 0xaa55ff) -- search query
|
||||
mon.setPaletteColor(colors.cyan, 0x55aaff) -- keyboard
|
||||
mon.setPaletteColor(colors.brown, 0x262626) -- keyboard bg
|
||||
|
||||
parallel.waitForAll(function()
|
||||
while true do
|
||||
local fp = assert(io.open("/restock.json", "r"))
|
||||
config = textutils.unserializeJSON(fp:read("a"))
|
||||
fp:close()
|
||||
os.sleep(1)
|
||||
end
|
||||
end, function()
|
||||
while true do
|
||||
local new_state = {}
|
||||
local new_sizes = {}
|
||||
map(config.storage, function(i, inv)
|
||||
new_sizes[inv] = peripheral.call(inv, "size")
|
||||
for slot, item in pairs(peripheral.call(inv, "list")) do
|
||||
new_state[string.format("%s#%d", inv, slot)] = item
|
||||
end
|
||||
end)
|
||||
item_state.storage = new_state
|
||||
storage_sizes.storage = new_sizes
|
||||
os.sleep(0)
|
||||
end
|
||||
end, function()
|
||||
while true do
|
||||
local new_state = {}
|
||||
local new_sizes = {}
|
||||
map(
|
||||
groupby(config.stock, function(location)
|
||||
local storage = string.split(location, "#")
|
||||
return storage
|
||||
end
|
||||
), function(inv)
|
||||
new_sizes[inv] = peripheral.call(inv, "size")
|
||||
for slot, item in pairs(peripheral.call(inv, "list")) do
|
||||
new_state[string.format("%s#%d", inv, slot)] = item
|
||||
end
|
||||
end)
|
||||
item_state.stock = new_state
|
||||
storage_sizes.stock = new_sizes
|
||||
os.sleep(0)
|
||||
end
|
||||
end, function() -- IMPORT
|
||||
while true do
|
||||
map(
|
||||
groupby(config.stock, function(location) return ({ string.split(location, "#") })[1] end),
|
||||
function(stock_inv)
|
||||
local size = storage_sizes.stock[stock_inv] or 0
|
||||
for i = 1, size do
|
||||
local slot = string.format("%s#%d", stock_inv, i)
|
||||
local slot_stocked, slot_expected = item_state.stock[slot], config.stock[slot]
|
||||
if (slot_stocked and slot_expected and slot_stocked.name ~= slot_expected.name) or (slot_stocked ~= nil and slot_expected == nil) then
|
||||
for _, output in ipairs(config.storage) do
|
||||
if peripheral.call(stock_inv, "pushItems", output, i) ~= 0 then
|
||||
print("MOVE", slot, slot_stocked.name)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
os.sleep(0)
|
||||
end
|
||||
end, function() -- STOCK
|
||||
while true do
|
||||
local new_junk = {}
|
||||
local item_locations = groupby(item_state.storage, function(location, item)
|
||||
new_junk[item.name] = (new_junk[item.name] or 0) + item.count
|
||||
return item.name
|
||||
end)
|
||||
|
||||
local tw, th = term.getSize()
|
||||
map(config.stock, function(destination, item)
|
||||
local dst_container, dst_slot = string.split(destination, "#")
|
||||
new_junk[item.name] = nil
|
||||
if item_locations[item.name] == nil then return end
|
||||
local dst_item = item_state.stock[destination]
|
||||
local dst_count = dst_item and dst_item.count or 0
|
||||
if dst_count >= item.count then return end
|
||||
local missing = item.count - dst_count
|
||||
|
||||
local _, take_from = pop(filter(item_locations[item.name], function(_, src_item)
|
||||
local src_container, src_slot = string.split(src_item.k, "#")
|
||||
return src_container ~= dst_container
|
||||
end))
|
||||
|
||||
if not take_from then return end
|
||||
local src_container, src_slot = string.split(take_from.k, "#")
|
||||
local t = os.clock()
|
||||
local out = peripheral.call(dst_container, "pullItems", src_container, tonumber(src_slot), missing, tonumber(dst_slot))
|
||||
print(string.format("PUT %s*%d/%d to %s", item.name, out, missing, destination))
|
||||
-- print(string.format("%s -> %s (%s*%d) took %.2f", take_from.k, destination, item.name, item.count, os.clock() - t))
|
||||
end)
|
||||
item_state.junk = new_junk
|
||||
os.sleep(0)
|
||||
end
|
||||
end, function() -- JUNK
|
||||
while true do
|
||||
local y = 2
|
||||
for name, count in pairs(item_state.junk) do
|
||||
map(filter(item_state.storage, function(location, item)
|
||||
return item.name == name
|
||||
end), function(location, item)
|
||||
local junk_container, junk_slot = string.split(location, "#")
|
||||
for _, junk_output in ipairs(config.junk) do
|
||||
if peripheral.call(junk_container, "pushItems", junk_output, tonumber(junk_slot)) ~= 0 then
|
||||
print("JUNK OUT", item.name, "->", junk_container)
|
||||
break
|
||||
end
|
||||
end
|
||||
end)
|
||||
y = y + 1
|
||||
end
|
||||
os.sleep(0)
|
||||
end
|
||||
end, function() -- USER INPUT
|
||||
while true do
|
||||
local ev = { os.pullEvent() }
|
||||
if ev[1] == "char" and search_open then
|
||||
search_query = search_query .. ev[2]
|
||||
mon.setBackgroundColor(colors.gray)
|
||||
mon.setTextColor(colors.magenta)
|
||||
mon.setCursorPos(tw - 14, th - 20)
|
||||
mon.write("> " .. search_query)
|
||||
for i, line in ipairs(keyboard) do
|
||||
mon.setCursorPos(tw - 14, th - 20 + i)
|
||||
mon.setBackgroundColor(colors.brown)
|
||||
mon.setTextColor(colors.cyan)
|
||||
mon.write(line)
|
||||
end
|
||||
elseif ev[1] == "key" then
|
||||
if ev[2] == keys.enter then
|
||||
search_open = not search_open
|
||||
elseif ev[2] == keys.backspace and search_open then
|
||||
search_query = search_query:sub(1, #search_query - 1)
|
||||
mon.setBackgroundColor(colors.gray)
|
||||
mon.setTextColor(colors.magenta)
|
||||
mon.setCursorPos(tw - 14, th - 20)
|
||||
mon.write("> " .. search_query)
|
||||
for i, line in ipairs(keyboard) do
|
||||
mon.setCursorPos(tw - 14, th - 20 + i)
|
||||
mon.setBackgroundColor(colors.brown)
|
||||
mon.setTextColor(colors.cyan)
|
||||
mon.write(line)
|
||||
end
|
||||
end
|
||||
elseif ev[1] == "monitor_touch" then
|
||||
local tw, th = mon.getSize()
|
||||
local _, _, x, y = table.unpack(ev)
|
||||
if y == 3 or y == th then
|
||||
local new_mode
|
||||
if x >= 1 and x <= 8 then new_mode = "count"
|
||||
elseif x >= 10 and x <= (tw - 1) then new_mode = "name"
|
||||
elseif x == tw then
|
||||
search_open = not search_open
|
||||
end
|
||||
|
||||
if new_mode ~= nil and new_mode == sort_mode then
|
||||
sort_inverse = not sort_inverse
|
||||
elseif new_mode ~= nil then
|
||||
sort_mode = new_mode
|
||||
sort_inverse = false
|
||||
end
|
||||
elseif search_open and x >= (tw - 14) and x < (tw - 4) and y > (th - 20) and y <= (th - 17) then
|
||||
mon.setBackgroundColor(colors.gray)
|
||||
mon.setTextColor(colors.magenta)
|
||||
mon.setCursorPos(tw - 14, th - 20)
|
||||
mon.write("> " .. search_query)
|
||||
for i, line in ipairs(keyboard) do
|
||||
mon.setCursorPos(tw - 14, th - 20 + i)
|
||||
mon.setBackgroundColor(colors.brown)
|
||||
mon.setTextColor(colors.cyan)
|
||||
mon.write(line)
|
||||
end
|
||||
|
||||
local char = keyboard[20 - th + y]:sub(15 - tw + x, 15 - tw + x)
|
||||
if char >= "a" and char <= "z" then
|
||||
os.queueEvent("key", keys[char], false)
|
||||
os.queueEvent("char", char)
|
||||
os.queueEvent("key_up", keys[char])
|
||||
else
|
||||
-- 27 backspace (ev=259)
|
||||
-- 215 enter (ev=257)
|
||||
local code = nil
|
||||
|
||||
if char == "\x1b" then code = keys.backspace
|
||||
elseif char == "\xd7" then code = keys.enter
|
||||
end
|
||||
|
||||
if code then
|
||||
os.queueEvent("key", code, false)
|
||||
os.queueEvent("key_up", code)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end, function() -- STATUS
|
||||
|
||||
while true do
|
||||
local back_term = term.redirect(mon)
|
||||
local tw, th = term.getSize()
|
||||
term.setBackgroundColor(colors.black)
|
||||
term.setTextColor(colors.white)
|
||||
term.clear()
|
||||
|
||||
local usage = pipe(config.storage)
|
||||
:map(function(_, storage)
|
||||
local used, total = 0, storage_sizes.storage[storage] or 0
|
||||
for slot = 1, total do
|
||||
if item_state.storage[string.format("%s#%d", storage, slot)] then
|
||||
used = used + 1
|
||||
end
|
||||
end
|
||||
return { used = used, total = total }
|
||||
end)
|
||||
:reduce(function(_, info, acc)
|
||||
return { used = info.used + acc.used, total = info.total + acc.total }
|
||||
end, { used = 0, total = 0 }):get()
|
||||
|
||||
draw_bar(1, colors.lightGray, colors.gray, usage.used / usage.total, "Storage utilization: %7.3f%%", 100 * usage.used / usage.total)
|
||||
|
||||
term.setCursorPos(1, 3)
|
||||
term.setBackgroundColor(colors.gray)
|
||||
term.clearLine()
|
||||
local infoline = string.format("Count %s Name %s",
|
||||
(sort_mode == "count" and (sort_inverse and "\x1e" or "\x1f") or " "),
|
||||
(sort_mode == "name" and (sort_inverse and "\x1e" or "\x1f") or " "))
|
||||
local fg = sort_mode == "count" and "55555551f88888881" or "88888881f55555551"
|
||||
term.blit(infoline, fg, "77777777777777777")
|
||||
term.setCursorPos(tw, 3)
|
||||
term.write("\x0c")
|
||||
term.setCursorPos(1, th)
|
||||
term.clearLine()
|
||||
term.blit(infoline, fg, "77777777777777777")
|
||||
term.setCursorPos(tw, th)
|
||||
term.write("\x0c")
|
||||
|
||||
|
||||
pipe(item_state.storage)
|
||||
:groupby(function(slot, item) return item.name end)
|
||||
:filter(function(name, slots)
|
||||
if not search_open then return true end
|
||||
return string.match(name, search_query)
|
||||
end)
|
||||
:map(function(name, slots) return reduce(slots, function(_, slot, acc) return slot.v.count + acc end, 0) end)
|
||||
:sort(function(t, a, b)
|
||||
local swap = false
|
||||
if sort_mode == "count" then swap = t[a] > t[b] end
|
||||
if sort_mode == "name" then swap = a > b end
|
||||
return swap ~= sort_inverse
|
||||
end)
|
||||
:map(function(i, kv)
|
||||
if i >= (th - 4) then return end
|
||||
term.setCursorPos(1, 3 + i)
|
||||
term.setBackgroundColor((i % 2) == 0 and colors.blue or colors.purple)
|
||||
term.clearLine()
|
||||
term.write(string.format("%8d %s", kv.v, kv.k))
|
||||
end)
|
||||
|
||||
if search_open then
|
||||
mon.setBackgroundColor(colors.gray)
|
||||
mon.setTextColor(colors.magenta)
|
||||
term.setCursorPos(tw - 14, th - 20)
|
||||
term.write("> " .. search_query)
|
||||
for i, line in ipairs(keyboard) do
|
||||
term.setCursorPos(tw - 14, th - 20 + i)
|
||||
term.setBackgroundColor(colors.brown)
|
||||
term.setTextColor(colors.cyan)
|
||||
term.write(line)
|
||||
end
|
||||
end
|
||||
|
||||
term.redirect(back_term)
|
||||
os.sleep(1)
|
||||
end
|
||||
end)
|
|
@ -0,0 +1,11 @@
|
|||
# x-run: sanic stream_video:app
|
||||
from sanic import Request, Sanic, Websocket
|
||||
|
||||
app = Sanic("CCVideoStreamer")
|
||||
|
||||
@app.websocket("/stream")
|
||||
async def ws_stream(req: Request, ws: Websocket):
|
||||
with open("./video.cani", "r") as fp:
|
||||
for line in fp:
|
||||
await ws.send(bytes.fromhex(line.strip()))
|
||||
await ws.close()
|
|
@ -0,0 +1,83 @@
|
|||
|
||||
local url = "wss://kc.is.being.pet/ws"
|
||||
|
||||
local screen = peripheral.wrap("monitor_1")
|
||||
local speakers = {
|
||||
l = peripheral.wrap("speaker_1"),
|
||||
r = peripheral.wrap("speaker_0"),
|
||||
}
|
||||
|
||||
local ws = assert(http.websocket(url))
|
||||
|
||||
local function parse_u16(data)
|
||||
local v = table.remove(data, 1)
|
||||
v = bit.bor(v, bit.blshift(table.remove(data, 1), 8))
|
||||
return v, data
|
||||
end
|
||||
|
||||
local metadata_pkt = ws.receive()
|
||||
metadata_pkt = { string.byte(metadata_pkt, 1, #metadata_pkt) }
|
||||
local framerate = table.remove(metadata_pkt, 1)
|
||||
local n_channels = table.remove(metadata_pkt, 1)
|
||||
local sample_rate, data = parse_u16(metadata_pkt)
|
||||
local screen_w, data = parse_u16(data)
|
||||
local screen_h, data = parse_u16(data)
|
||||
local samples_per_frame = math.floor(sample_rate / framerate)
|
||||
|
||||
print(string.format("FPS: %d", framerate))
|
||||
print(string.format("Audio: %d channels, %d Hz", n_channels, sample_rate))
|
||||
print(string.format("Video: %dx%d", screen_w, screen_h))
|
||||
print(string.format("S/F: %d", samples_per_frame))
|
||||
|
||||
local function decode_s8(buf)
|
||||
local buffer = {}
|
||||
for i = 1, #buf do
|
||||
local v = buf[i]
|
||||
if bit32.band(v, 0x80) then
|
||||
v = bit32.bxor(v, 0x7F) - 128
|
||||
end
|
||||
table.insert(buffer, v)
|
||||
table.insert(buffer, v)
|
||||
end
|
||||
return buffer
|
||||
end
|
||||
|
||||
local function mkSpeakerCoro(p, b)
|
||||
return function()
|
||||
while not p.playAudio(b) do
|
||||
os.pullEvent("speaker_audio_empty")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
while true do
|
||||
local video_pkt = ws.receive()
|
||||
local channels = { l = {}, r = {} }
|
||||
local offset = 1
|
||||
channels.l = decode_s8({ string.byte(video_pkt, offset, offset + samples_per_frame - 1) })
|
||||
offset = offset + samples_per_frame
|
||||
channels.r = decode_s8({ string.byte(video_pkt, offset, offset + samples_per_frame - 1) })
|
||||
offset = offset + samples_per_frame
|
||||
for y = 1, screen_h do
|
||||
local tx, bg, fg = {}, {}, {}
|
||||
for x = 1, screen_w do
|
||||
table.insert(tx, string.sub(video_pkt, offset, offset))
|
||||
local color = string.byte(video_pkt, offset + 1, offset + 1)
|
||||
table.insert(bg, string.format("%x", bit.brshift(color, 4)))
|
||||
table.insert(fg, string.format("%x", bit.band(color, 0xF)))
|
||||
offset = offset + 2
|
||||
end
|
||||
screen.setCursorPos(1, y)
|
||||
screen.blit(table.concat(tx), table.concat(bg), table.concat(fg))
|
||||
end
|
||||
|
||||
for i = 1, 16 do
|
||||
local r, g, b = string.byte(video_pkt, offset, offset + 3)
|
||||
screen.setPaletteColor(bit.blshift(1, i - 1), bit.bor(bit.bor(bit.blshift(r, 16), bit.blshift(g, 8)), b))
|
||||
offset = offset + 3
|
||||
end
|
||||
|
||||
parallel.waitForAll(
|
||||
mkSpeakerCoro(speakers.l, channels.l),
|
||||
mkSpeakerCoro(speakers.r, channels.r))
|
||||
end
|
13
obcb-cc.lua
13
obcb-cc.lua
|
@ -26,9 +26,12 @@ local function send_chunk_subscribe_request(chunk)
|
|||
ws.send(string.char(0x14, bit.band(chunk, 0xFF), bit.band(bit.brshift(chunk, 8), 0xFF)), true)
|
||||
end
|
||||
|
||||
local shutdown = false
|
||||
|
||||
parallel.waitForAll(function()
|
||||
while true do
|
||||
while not shutdown do
|
||||
local data, is_binary = ws.receive()
|
||||
if data == nil then return end
|
||||
data = { string.byte(data, 1, #data) }
|
||||
local opcode = table.remove(data, 1)
|
||||
if opcode == 0x00 then -- hello
|
||||
|
@ -63,20 +66,25 @@ function()
|
|||
mon.setTextScale(0.5)
|
||||
mon.clear()
|
||||
local tw, th = term.getSize()
|
||||
term.clear()
|
||||
send_chunk_request(chunk_id)
|
||||
send_chunk_subscribe_request(chunk_id)
|
||||
term.setCursorPos(1, 3)
|
||||
print("Showing chunk " .. chunk_id)
|
||||
print(string.format("Screen: %dx%d", mon.getSize()))
|
||||
while true do
|
||||
while not shutdown do
|
||||
local ev = { os.pullEvent() }
|
||||
if ev[1] == "char" and ev[2] == "q" then
|
||||
shutdown = true
|
||||
ws.close()
|
||||
break
|
||||
elseif ev[1] == "obcb:hello" then
|
||||
term.setCursorPos(1, 1)
|
||||
term.clearLine()
|
||||
print(string.format("Hello: obcb v%d.%d", ev[2], ev[3]))
|
||||
elseif ev[1] == "obcb:clients" then
|
||||
term.setCursorPos(1, 2)
|
||||
term.clearLine()
|
||||
print("Clients: " .. ev[2])
|
||||
elseif ev[1] == "obcb:update" then
|
||||
for y = 1, 81 do
|
||||
|
@ -96,4 +104,5 @@ function()
|
|||
end
|
||||
end)
|
||||
|
||||
shutdown = true
|
||||
ws.close()
|
||||
|
|
50
wsvpn.c
50
wsvpn.c
|
@ -65,10 +65,10 @@ struct client {
|
|||
|
||||
struct client clients[MAX_CLIENTS] = { 0 };
|
||||
|
||||
static void handle_client(struct mg_connection *connection, int event_type, void *ev_data, void *fn_data);
|
||||
static void on_ws_connect(struct mg_connection *connection, struct mg_http_message *message, void *data);
|
||||
static void on_ws_message(struct mg_connection *connection, struct mg_ws_message *message, void *data);
|
||||
static void on_ws_disconnect(struct mg_connection *connection, void *data);
|
||||
static void handle_client(struct mg_connection *connection, int event_type, void *ev_data);
|
||||
static void on_ws_connect(struct mg_connection *connection, struct mg_http_message *message);
|
||||
static void on_ws_message(struct mg_connection *connection, struct mg_ws_message *message);
|
||||
static void on_ws_disconnect(struct mg_connection *connection);
|
||||
|
||||
bool client_is_open(struct client *client, uint16_t channel);
|
||||
static void modem_open(struct client *client, uint16_t request_id, uint16_t channel);
|
||||
|
@ -101,15 +101,15 @@ int main(void) {
|
|||
mg_mgr_free(&manager);
|
||||
}
|
||||
|
||||
static void handle_client(struct mg_connection *connection, int event_type, void *event_data, void *fn_data) {
|
||||
static void handle_client(struct mg_connection *connection, int event_type, void *event_data) {
|
||||
if (event_type == MG_EV_OPEN) {
|
||||
if (connection->rem.port == 0) return;
|
||||
memset(connection->data, 0, 32);
|
||||
} else if (event_type == MG_EV_HTTP_MSG) {
|
||||
struct mg_http_message *http_message = (struct mg_http_message *) event_data;
|
||||
if (mg_http_match_uri(http_message, "/open")) {
|
||||
if (mg_match(http_message->uri, mg_str_s("/open"), 0)) {
|
||||
mg_ws_upgrade(connection, http_message, NULL);
|
||||
} else if (mg_http_match_uri(http_message, "/metrics")) {
|
||||
} else if (mg_match(http_message->uri, mg_str_s("/metrics"), 0)) {
|
||||
mg_printf(connection, "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
|
||||
mg_http_printf_chunk(connection, "# HELP ws_bytes_sent_total Number of bytes sent to clients\n");
|
||||
mg_http_printf_chunk(connection, "# TYPE ws_bytes_sent_total counter\n");
|
||||
|
@ -147,13 +147,13 @@ static void handle_client(struct mg_connection *connection, int event_type, void
|
|||
}
|
||||
} else if (event_type == MG_EV_WS_OPEN) {
|
||||
struct mg_http_message *http_message = (struct mg_http_message *) event_data;
|
||||
on_ws_connect(connection, http_message, fn_data);
|
||||
on_ws_connect(connection, http_message);
|
||||
} else if (event_type == MG_EV_WS_MSG) {
|
||||
struct mg_ws_message *ws_message = (struct mg_ws_message *)event_data;
|
||||
on_ws_message(connection, ws_message, fn_data);
|
||||
on_ws_message(connection, ws_message);
|
||||
} else if (event_type == MG_EV_CLOSE) {
|
||||
if (connection->is_websocket) {
|
||||
on_ws_disconnect(connection, fn_data);
|
||||
on_ws_disconnect(connection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -211,9 +211,8 @@ void ws_respond(struct client *client, uint16_t request_id, void *data, uint32_t
|
|||
mg_ws_send(client->connection, buffer, size + 3, WEBSOCKET_OP_BINARY);
|
||||
}
|
||||
|
||||
static void on_ws_connect(struct mg_connection *connection, struct mg_http_message *message, void *data) {
|
||||
static void on_ws_connect(struct mg_connection *connection, struct mg_http_message *message) {
|
||||
(void)message;
|
||||
(void)data;
|
||||
struct client *client = malloc(sizeof(struct client));
|
||||
memcpy(&connection->data[0], &client, sizeof(struct client *));
|
||||
client->connection = connection;
|
||||
|
@ -226,9 +225,7 @@ static void on_ws_connect(struct mg_connection *connection, struct mg_http_messa
|
|||
mg_ws_send(connection, buffer, 2 + buffer[1], WEBSOCKET_OP_BINARY);
|
||||
}
|
||||
|
||||
static void on_ws_message(struct mg_connection *connection, struct mg_ws_message *message, void *data) {
|
||||
(void)data;
|
||||
|
||||
static void on_ws_message(struct mg_connection *connection, struct mg_ws_message *message) {
|
||||
if ((message->flags & 15) != WEBSOCKET_OP_BINARY) {
|
||||
const char *err_str = "This server only works in binary mode. Sorry!";
|
||||
mg_ws_send(connection, err_str, strlen(err_str), WEBSOCKET_OP_TEXT);
|
||||
|
@ -244,15 +241,15 @@ static void on_ws_message(struct mg_connection *connection, struct mg_ws_message
|
|||
|
||||
if (message->data.len == 0) return;
|
||||
|
||||
uint16_t request_id = ntohs(*(uint16_t*)&message->data.ptr[1]);
|
||||
uint16_t request_id = ntohs(*(uint16_t*)&message->data.buf[1]);
|
||||
|
||||
switch (message->data.ptr[0]) {
|
||||
switch (message->data.buf[0]) {
|
||||
case 'I': // info. We can safely ignore that message
|
||||
break;
|
||||
case 'O': // open
|
||||
{
|
||||
metrics.method_calls[0]++;
|
||||
uint16_t channel = ntohs(*(uint16_t*)&message->data.ptr[3]);
|
||||
uint16_t channel = ntohs(*(uint16_t*)&message->data.buf[3]);
|
||||
printf("%p[%04x] modem.open(%d)\n", (void*)client, request_id, channel);
|
||||
modem_open(client, request_id, channel);
|
||||
}
|
||||
|
@ -260,7 +257,7 @@ static void on_ws_message(struct mg_connection *connection, struct mg_ws_message
|
|||
case 'o': // isOpen
|
||||
{
|
||||
metrics.method_calls[1]++;
|
||||
uint16_t channel = ntohs(*(uint16_t*)&message->data.ptr[3]);
|
||||
uint16_t channel = ntohs(*(uint16_t*)&message->data.buf[3]);
|
||||
printf("%p[%04x] modem.isOpen(%d)\n", (void*)client, request_id, channel);
|
||||
modem_isOpen(client, request_id, channel);
|
||||
}
|
||||
|
@ -268,7 +265,7 @@ static void on_ws_message(struct mg_connection *connection, struct mg_ws_message
|
|||
case 'c': // close
|
||||
{
|
||||
metrics.method_calls[2]++;
|
||||
uint16_t channel = ntohs(*(uint16_t*)&message->data.ptr[3]);
|
||||
uint16_t channel = ntohs(*(uint16_t*)&message->data.buf[3]);
|
||||
printf("%p[%04x] modem.close(%d)\n", (void*)client, request_id, channel);
|
||||
modem_close(client, request_id, channel);
|
||||
}
|
||||
|
@ -283,21 +280,20 @@ static void on_ws_message(struct mg_connection *connection, struct mg_ws_message
|
|||
case 'T': // transmit
|
||||
{
|
||||
metrics.method_calls[4]++;
|
||||
uint16_t channel = ntohs(*(uint16_t*)&message->data.ptr[3]);
|
||||
uint16_t reply_channel = ntohs(*(uint16_t*)&message->data.ptr[5]);
|
||||
uint16_t data_length = ntohs(*(uint16_t*)&message->data.ptr[7]);
|
||||
modem_transmit(client, request_id, channel, reply_channel, (void*)&message->data.ptr[9], data_length);
|
||||
uint16_t channel = ntohs(*(uint16_t*)&message->data.buf[3]);
|
||||
uint16_t reply_channel = ntohs(*(uint16_t*)&message->data.buf[5]);
|
||||
uint16_t data_length = ntohs(*(uint16_t*)&message->data.buf[7]);
|
||||
modem_transmit(client, request_id, channel, reply_channel, (void*)&message->data.buf[9], data_length);
|
||||
}
|
||||
return;
|
||||
default:
|
||||
ws_send_error(client, request_id, "Unknown opcode: 0x%02x", message->data.ptr[0]);
|
||||
ws_send_error(client, request_id, "Unknown opcode: 0x%02x", message->data.buf[0]);
|
||||
connection->is_draining = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void on_ws_disconnect(struct mg_connection *connection, void *data) {
|
||||
(void)data;
|
||||
static void on_ws_disconnect(struct mg_connection *connection) {
|
||||
|
||||
struct client *client = *(struct client **)&connection->data[0];
|
||||
if (client->connection == connection) {
|
||||
|
|
Loading…
Reference in New Issue