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.
|
CrocParty: a tiny platformer.
|
||||||
# Please consider migrating your external dependencies from WORKSPACE to MODULE.bazel.
|
"""
|
||||||
#
|
module(
|
||||||
# For more details, please check https://github.com/bazelbuild/bazel/issues/18958
|
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
1603
MODULE.bazel.lock
File diff suppressed because it is too large
Load Diff
@ -4,9 +4,9 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
// 240 x 135 is also cool
|
// 256 x 144 is also cool
|
||||||
#define DEVICE_W 128
|
#define DEVICE_W 256
|
||||||
#define DEVICE_H 128
|
#define DEVICE_H 144
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
DEVICE_BUTTON_L=0,
|
DEVICE_BUTTON_L=0,
|
||||||
|
@ -49,10 +49,10 @@ void game_update() {
|
|||||||
ellipse_x0 += ellipse_dx0;
|
ellipse_x0 += ellipse_dx0;
|
||||||
if (ellipse_x0 < 0 || ellipse_x0 > DEVICE_W * 4) { ellipse_dx0 *= -1; }
|
if (ellipse_x0 < 0 || ellipse_x0 > DEVICE_W * 4) { ellipse_dx0 *= -1; }
|
||||||
ellipse_y0 += ellipse_dy0;
|
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;
|
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;
|
ellipse_y1 += ellipse_dy1;
|
||||||
if (ellipse_y1 < 0 || ellipse_y1 > DEVICE_H * 4) { ellipse_dy1 *= -1; }
|
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, 6, 248, false);
|
||||||
sys_circ_draw_ext(x0, y0, 8, 244, false);
|
sys_circ_draw_ext(x0, y0, 8, 244, false);
|
||||||
sys_line_draw(x0, y0, x1, y1, 254);
|
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(
|
cc_library(
|
||||||
name = "sys",
|
name = "sys",
|
||||||
srcs = glob(["*.c"]),
|
srcs = glob(["*.c"]) + [":fonts/sys_font_small.c"],
|
||||||
hdrs = glob(["*.h"]),
|
hdrs = glob(["*.h"]) + [":fonts/sys_font_small.h"],
|
||||||
visibility = ["//visibility:public"],
|
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_data.h"
|
||||||
#include "sys_graphics.h"
|
#include "sys_graphics.h"
|
||||||
|
#include "fonts/sys_font_small.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize sys.
|
* Initialize sys.
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
typedef int32_t sys_i32;
|
typedef int32_t sys_i32;
|
||||||
typedef uint8_t sys_color;
|
typedef uint8_t sys_color;
|
||||||
typedef uint32_t sys_screen_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);
|
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(
|
void sys_scanline_internal_set(
|
||||||
sys_i32 x0, sys_i32 x1, sys_i32 y, sys_color c, bool fill
|
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 ==
|
// == public ==
|
||||||
void sys_clip_set(sys_i32 x0, sys_i32 y0, sys_i32 x1, sys_i32 y1) {
|
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];
|
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) {
|
void sys_cls(sys_color c) {
|
||||||
assert(sys_get_initialized());
|
assert(sys_get_initialized());
|
||||||
|
|
||||||
@ -250,4 +263,17 @@ void sys_scanline_internal_set(
|
|||||||
sys_pixel_internal_set(x0, y, c);
|
sys_pixel_internal_set(x0, y, c);
|
||||||
sys_pixel_internal_set(x1, y, c);
|
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: SSET/SGET
|
||||||
// TODO: FGET/FSET
|
// 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?
|
// TODO: CURSOR? COLOR?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -83,7 +86,7 @@ void sys_camera_reset();
|
|||||||
* This is a special case of sys_circ_oval_draw_ext.
|
* 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_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);
|
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