Add font loader
This commit is contained in:
parent
e05f050e7d
commit
cb44cab4f8
30
MODULE.bazel
30
MODULE.bazel
@ -1,6 +1,24 @@
|
||||
###############################################################################
|
||||
# Bazel now uses Bzlmod by default to manage external dependencies.
|
||||
# Please consider migrating your external dependencies from WORKSPACE to MODULE.bazel.
|
||||
#
|
||||
# For more details, please check https://github.com/bazelbuild/bazel/issues/18958
|
||||
###############################################################################
|
||||
"""
|
||||
CrocParty: a tiny platformer.
|
||||
"""
|
||||
module(
|
||||
name="crocparty",
|
||||
version="0.0",
|
||||
)
|
||||
|
||||
bazel_dep(name="rules_python", version="0.31.0")
|
||||
|
||||
# Set up Python
|
||||
python = use_extension("@rules_python//python/extensions:python.bzl", "python")
|
||||
python.toolchain(
|
||||
python_version = "3.10",
|
||||
is_default = True,
|
||||
)
|
||||
|
||||
pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip")
|
||||
pip.parse(
|
||||
hub_name = "pytools_deps",
|
||||
python_version = "3.10",
|
||||
requirements_lock = "//pytools:requirements.txt",
|
||||
)
|
||||
use_repo(pip, "pytools_deps")
|
1603
MODULE.bazel.lock
generated
1603
MODULE.bazel.lock
generated
File diff suppressed because it is too large
Load Diff
@ -4,9 +4,9 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
// 240 x 135 is also cool
|
||||
#define DEVICE_W 128
|
||||
#define DEVICE_H 128
|
||||
// 256 x 144 is also cool
|
||||
#define DEVICE_W 256
|
||||
#define DEVICE_H 144
|
||||
|
||||
typedef enum {
|
||||
DEVICE_BUTTON_L=0,
|
||||
|
@ -49,10 +49,10 @@ void game_update() {
|
||||
ellipse_x0 += ellipse_dx0;
|
||||
if (ellipse_x0 < 0 || ellipse_x0 > DEVICE_W * 4) { ellipse_dx0 *= -1; }
|
||||
ellipse_y0 += ellipse_dy0;
|
||||
if (ellipse_y0 < 0 || ellipse_y0 > DEVICE_W * 4) { ellipse_dy0 *= -1; }
|
||||
if (ellipse_y0 < 0 || ellipse_y0 > DEVICE_H * 4) { ellipse_dy0 *= -1; }
|
||||
|
||||
ellipse_x1 += ellipse_dx1;
|
||||
if (ellipse_x1 < 0 || ellipse_x1 > DEVICE_H * 4) { ellipse_dx1 *= -1; }
|
||||
if (ellipse_x1 < 0 || ellipse_x1 > DEVICE_W * 4) { ellipse_dx1 *= -1; }
|
||||
ellipse_y1 += ellipse_dy1;
|
||||
if (ellipse_y1 < 0 || ellipse_y1 > DEVICE_H * 4) { ellipse_dy1 *= -1; }
|
||||
}
|
||||
@ -89,4 +89,6 @@ void game_draw() {
|
||||
sys_circ_draw_ext(x0, y0, 6, 248, false);
|
||||
sys_circ_draw_ext(x0, y0, 8, 244, false);
|
||||
sys_line_draw(x0, y0, x1, y1, 254);
|
||||
|
||||
sys_print("Hello, blood\nsources!", x1, y1, 224);
|
||||
}
|
||||
|
1
pytools/.gitignore
vendored
Normal file
1
pytools/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
venv/
|
10
pytools/BUILD
Normal file
10
pytools/BUILD
Normal file
@ -0,0 +1,10 @@
|
||||
load("@pytools_deps//:requirements.bzl", "requirement")
|
||||
|
||||
py_binary(
|
||||
name = "font",
|
||||
srcs = ["font.py"],
|
||||
deps = [
|
||||
requirement("pillow"),
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
53
pytools/font.py
Normal file
53
pytools/font.py
Normal file
@ -0,0 +1,53 @@
|
||||
from typing import Tuple
|
||||
from PIL import Image
|
||||
import sys
|
||||
|
||||
|
||||
def main(font_name, n_glyphs, fname_png, fname_c):
|
||||
glyphs = load_glyphs(fname_png)
|
||||
assert(len(glyphs) == n_glyphs), f"must be exactly {n_glyphs} glyphs"
|
||||
|
||||
with open(fname_c, "wt") as output:
|
||||
output.writelines([
|
||||
"// generated code! be nice!\n",
|
||||
"#include \"sys/sys.h\";\n",
|
||||
f"sys_glyph {font_name}[{n_glyphs}] = {{{', '.join(str(g) for g in glyphs)}}};\n"
|
||||
])
|
||||
|
||||
|
||||
def load_glyphs(fname_png: str):
|
||||
with Image.open(fname_png) as im:
|
||||
width = im.width
|
||||
height = im.height
|
||||
|
||||
assert width % 8 == 0, "width must be a multiple of 8"
|
||||
assert height % 8 == 0, "height must be a multiple of 8"
|
||||
|
||||
data = list(im.convert("RGBA").getdata())
|
||||
monochrome = [pixel_to_monochrome(p) for p in data]
|
||||
|
||||
glyphs = []
|
||||
for gy in range(0, height, 8):
|
||||
for gx in range(0, width, 8):
|
||||
glyph = 0
|
||||
for py in range(0, 8):
|
||||
for px in range(0, 8):
|
||||
x = gx + px
|
||||
y = gy + py
|
||||
if monochrome[y * width + x]:
|
||||
glyph |= 1 << (py * 8 + px)
|
||||
glyphs.append(glyph)
|
||||
|
||||
return glyphs
|
||||
|
||||
|
||||
def pixel_to_monochrome(rgba: Tuple[int, int, int, int]):
|
||||
if rgba[3] < 128: return False
|
||||
if (rgba[0] + rgba[1] + rgba[2])/3 < 128: return False
|
||||
return True
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
assert len(sys.argv) == 5, \
|
||||
"there must be four args (font name, n glyphs, src png, out c)"
|
||||
main(sys.argv[1], int(sys.argv[2]), sys.argv[3], sys.argv[4])
|
1
pytools/requirements.txt
Normal file
1
pytools/requirements.txt
Normal file
@ -0,0 +1 @@
|
||||
pillow==10.2.0
|
21
sys/BUILD
21
sys/BUILD
@ -1,7 +1,22 @@
|
||||
load("@bazel_skylib//rules:run_binary.bzl", "run_binary")
|
||||
|
||||
cc_library(
|
||||
name = "sys",
|
||||
srcs = glob(["*.c"]),
|
||||
hdrs = glob(["*.h"]),
|
||||
srcs = glob(["*.c"]) + [":fonts/sys_font_small.c"],
|
||||
hdrs = glob(["*.h"]) + [":fonts/sys_font_small.h"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = ["//device:device"]
|
||||
deps = ["//device:device"],
|
||||
)
|
||||
|
||||
run_binary(
|
||||
name = "sys_font_small",
|
||||
args = [
|
||||
"sys_font_small",
|
||||
"256",
|
||||
"$(location :fonts/sys_font_small.png)",
|
||||
"$(location :fonts/sys_font_small.c)"
|
||||
],
|
||||
srcs = [":fonts/sys_font_small.png"],
|
||||
outs = [":fonts/sys_font_small.c"],
|
||||
tool = "//pytools:font",
|
||||
)
|
BIN
sys/fonts/sys_font_normal.png
Normal file
BIN
sys/fonts/sys_font_normal.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
8
sys/fonts/sys_font_small.h
Normal file
8
sys/fonts/sys_font_small.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef CROCPARTY_SYS_FONT_SMALL_H
|
||||
#define CROCPARTY_SYS_FONT_SMALL_H
|
||||
|
||||
#include "sys/sys.h"
|
||||
|
||||
extern sys_glyph sys_font_small[256];
|
||||
|
||||
#endif // CROCPARTY_SYS_FONT_SMALL_H
|
BIN
sys/fonts/sys_font_small.png
Normal file
BIN
sys/fonts/sys_font_small.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 33 KiB |
@ -3,6 +3,7 @@
|
||||
|
||||
#include "sys_data.h"
|
||||
#include "sys_graphics.h"
|
||||
#include "fonts/sys_font_small.h"
|
||||
|
||||
/**
|
||||
* Initialize sys.
|
||||
|
@ -6,6 +6,7 @@
|
||||
typedef int32_t sys_i32;
|
||||
typedef uint8_t sys_color;
|
||||
typedef uint32_t sys_screen_color;
|
||||
typedef uint64_t sys_glyph;
|
||||
|
||||
sys_screen_color sys_make_screen_color(uint8_t r, uint8_t g, uint8_t b);
|
||||
|
||||
|
@ -11,6 +11,7 @@ void sys_pixel_internal_set(sys_i32 x, sys_i32 y, sys_color c);
|
||||
void sys_scanline_internal_set(
|
||||
sys_i32 x0, sys_i32 x1, sys_i32 y, sys_color c, bool fill
|
||||
);
|
||||
void sys_glyph_draw(sys_i32 x, sys_i32 y, sys_glyph g, sys_color c);
|
||||
|
||||
// == public ==
|
||||
void sys_clip_set(sys_i32 x0, sys_i32 y0, sys_i32 x1, sys_i32 y1) {
|
||||
@ -55,6 +56,18 @@ sys_color sys_pixel_get(sys_i32 x, sys_i32 y) {
|
||||
return device_pixels[y][x];
|
||||
}
|
||||
|
||||
void sys_print(char* str, sys_i32 x, sys_i32 y, sys_color col) {
|
||||
sys_i32 x_orig = x;
|
||||
for (sys_i32 i = 0;; i++) {
|
||||
uint8_t c = str[i];
|
||||
if (c == 0) { break; }
|
||||
if (c == '\n') { x = x_orig; y += 8; continue; }
|
||||
if (c == '\r') { x = x_orig; continue; }
|
||||
sys_glyph_draw(x, y, sys_font_small[c], col);
|
||||
x += 8;
|
||||
}
|
||||
}
|
||||
|
||||
void sys_cls(sys_color c) {
|
||||
assert(sys_get_initialized());
|
||||
|
||||
@ -251,3 +264,16 @@ void sys_scanline_internal_set(
|
||||
sys_pixel_internal_set(x1, y, c);
|
||||
}
|
||||
}
|
||||
|
||||
void sys_glyph_draw(sys_i32 x, sys_i32 y, sys_glyph g, sys_color c) {
|
||||
// iterate through the bits of the glyph, and draw the character
|
||||
// if that bit is set
|
||||
for (int py = 0; py < 8; py++) {
|
||||
for (int px = 0; px < 8; px++) {
|
||||
uint64_t mask = ((uint64_t) 1) << (uint64_t) (py * 8 + px);
|
||||
if ((g & mask) != 0) {
|
||||
sys_pixel_internal_set(x + px, y + py, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -54,7 +54,10 @@ sys_color sys_pixel_get(
|
||||
|
||||
// TODO: SSET/SGET
|
||||
// TODO: FGET/FSET
|
||||
// TODO: PRINT
|
||||
/**
|
||||
* Print a string `str` in the color `col`
|
||||
*/
|
||||
void sys_print(char* str, sys_i32 x, sys_i32 y, sys_color col);
|
||||
// TODO: CURSOR? COLOR?
|
||||
|
||||
/**
|
||||
@ -83,7 +86,7 @@ void sys_camera_reset();
|
||||
* This is a special case of sys_circ_oval_draw_ext.
|
||||
*/
|
||||
void sys_circ_draw(sys_i32 x, sys_i32 y, sys_i32 r, sys_color c);
|
||||
void sys_circ_fill(sys_i32 x, sys_i32 y, sys_i32 r);
|
||||
void sys_circ_fill(sys_i32 x, sys_i32 y, sys_i32 r, sys_color c);
|
||||
void sys_circ_draw_ext(sys_i32 x, sys_i32 y, sys_i32 r, sys_color c, bool fill);
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user