From e6e59665e6893d4c4a41a85b224de1789439837f Mon Sep 17 00:00:00 2001 From: klemek Date: Thu, 5 Nov 2026 22:28:07 +0100 Subject: [PATCH] refactor: better sentence generator --- .gitignore | 2 + Makefile.dev | 11 +++-- project/inc_sentences.glsl | 21 --------- sentences.example.txt | 17 ++++++++ src/forge_invar/__init__.py | 6 ++- src/forge_invar/tools/__init__.py | 3 +- src/forge_invar/tools/sentences.py | 70 ++++++++++++++++++++++++++++++ 7 files changed, 102 insertions(+), 28 deletions(-) delete mode 100644 project/inc_sentences.glsl create mode 100644 sentences.example.txt create mode 100644 src/forge_invar/tools/sentences.py diff --git a/.gitignore b/.gitignore index 29cdb72..0d278fc 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,6 @@ build debug.png error.glsl forge_default_save.* +project/inc_sentences.glsl +sentences.txt tmp* diff --git a/Makefile.dev b/Makefile.dev index 512c2cf..7632d56 100644 --- a/Makefile.dev +++ b/Makefile.dev @@ -43,7 +43,7 @@ print-%: # ACTIONS .PHONY: init -init: uv-sync git-submodule-init git-submodule-update ## install project +init: uv-sync git-submodule-init git-submodule-update sentences ## install project .PHONY: update update: uv-upgrade ## update project dependencies @@ -55,10 +55,13 @@ format: ruff-fix ruff-format ## format project lint: ruff ruff-format-check ty ## lint project .PHONY: gen-img -gen-img: uv-run-invar-mode-gen-img +gen-img: uv-run-invar-mode-gen-img ## generate resources/*.png .PHONY: debug-img -debug-img: uv-run-invar-mode-debug-img +debug-img: uv-run-invar-mode-debug-img ## debug i2c screen with mock data + +.PHONY: sentences +sentences: uv-run-invar-mode-sentences ## generate project/inc_sentences.glsl .PHONY: rasp-init rasp-init: rasp-chmod-opt rasp-rsync rasp-unmount ## init raspberry @@ -68,7 +71,7 @@ rasp-install: rasp-install-pal ## setup raspberry .PHONY: rasp-install-% rasp-install-%: ## setup raspberry (PAL/NTSC/HDMI) - $(MAKE) git-submodule-update rasp-rsync rasp-setup-config-$* rasp-setup-cmdline-$* rasp-setup-start-$* rasp-unmount + $(MAKE) git-submodule-update sentences rasp-rsync rasp-setup-config-$* rasp-setup-cmdline-$* rasp-setup-start-$* rasp-unmount .PHONY: rasp-reset rasp-reset: rasp-rsync rasp-setup-config-hdmi rasp-reset-cmdline rasp-reset-start rasp-unmount ## reset raspberry to console mode diff --git a/project/inc_sentences.glsl b/project/inc_sentences.glsl deleted file mode 100644 index e905516..0000000 --- a/project/inc_sentences.glsl +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef INC_SENTENCES -#define INC_SENTENCES - -#define SENTENCE_COUNT 8 -#define SENTENCE_MAX_LENGTH 20 - -const int sentences[] = int[SENTENCE_COUNT * SENTENCE_MAX_LENGTH]( - 0x46, 0x6F, 0x6C, 0x6C, 0x65, 0x20, 0x4E, 0x75, 0x69, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x44, 0x75, 0x20, 0x51, 0x75, 0x61, 0x72, 0x61, 0x6E, 0x74, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x4C, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x46, 0x6F, 0x6C, 0x6C, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x4E, 0x75, 0x69, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x44, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x51, 0x75, 0x61, 0x72, 0x61, 0x6E, 0x74, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x35, 0x33, 0xF8, 0x20, 0x4D, 0x69, 0x65, 0x74, 0x74, 0x65, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -); - -const int lengths[] = int[SENTENCE_COUNT]( - 10, 11, 2, 5, 4, 2, 8, 11 -); -#endif diff --git a/sentences.example.txt b/sentences.example.txt new file mode 100644 index 0000000..351e01d --- /dev/null +++ b/sentences.example.txt @@ -0,0 +1,17 @@ +forge +FORGE +F.O.R.G.E. +Fusion +Of +Real-time +Generative +Effects +Everything you see +Pixel by pixel +Live +Generated +Controlled +π +Kleπek +Code as art +Art as code diff --git a/src/forge_invar/__init__.py b/src/forge_invar/__init__.py index a151593..879f9e7 100644 --- a/src/forge_invar/__init__.py +++ b/src/forge_invar/__init__.py @@ -5,7 +5,7 @@ import time from .display import get_display from .forge_data import ForgeData from .i2c import I2C -from .tools import debug_img, gen_img +from .tools import debug_img, gen_img, sentences def main_loop() -> None: @@ -26,7 +26,7 @@ def main() -> None: parser = argparse.ArgumentParser() parser.add_argument( - "--mode", default="default", choices=["default", "gen-img", "debug-img"] + "--mode", default="default", choices=["default", "gen-img", "debug-img", "sentences"] ) args = parser.parse_args() @@ -34,5 +34,7 @@ def main() -> None: gen_img() elif args.mode == "debug-img": debug_img() + elif args.mode == "sentences": + sentences() else: main_loop() diff --git a/src/forge_invar/tools/__init__.py b/src/forge_invar/tools/__init__.py index 164f03c..3864ece 100644 --- a/src/forge_invar/tools/__init__.py +++ b/src/forge_invar/tools/__init__.py @@ -1,4 +1,5 @@ from .debug_img import main as debug_img from .gen_img import main as gen_img +from .sentences import main as sentences -__all__ = ["debug_img", "gen_img"] +__all__ = ["debug_img", "gen_img", "sentences"] diff --git a/src/forge_invar/tools/sentences.py b/src/forge_invar/tools/sentences.py new file mode 100644 index 0000000..6f66817 --- /dev/null +++ b/src/forge_invar/tools/sentences.py @@ -0,0 +1,70 @@ +import logging +import re + +from ..constants import PROJECT_PATH + +TARGET_FILE = PROJECT_PATH / "project" / "inc_sentences.glsl" + +CP437_FILE = PROJECT_PATH / "project" / "inc_cp437.glsl" + +SENTENCES_FILE = PROJECT_PATH / "sentences.txt" +BACKUP_SENTENCES_FILE = PROJECT_PATH / "sentences.example.txt" + +log = logging.getLogger(__name__) + +def read_mapping() -> dict[str, str]: + mapping = {' ': '0x20'} + with CP437_FILE.open() as cp437: + for line in cp437: + if (match := re.match(r'.*// (0x\w\w), (.)$', line)): + mapping[match.group(2)] = match.group(1) + return mapping + +def read_sentences() -> list[str]: + if SENTENCES_FILE.exists(): + return SENTENCES_FILE.read_text().splitlines() + log.warning("sentences.txt not found, using backup") + return BACKUP_SENTENCES_FILE.read_text().splitlines() + +def convert(sentence: str, mapping: dict[str, str], max_len: int) -> str: + out = [] + for i in range(max_len): + if i >= len(sentence): + out += ["0x00"] + elif sentence[i] not in mapping: + log.warning(f"Char '{sentence[i]}' not in CP437") + out += ["0x20"] + else: + out += [mapping[sentence[i]]] + return ", ".join(out) + +def main(): + mapping = read_mapping() + sentences = read_sentences() + + max_len = max(len(sentence) for sentence in sentences) + + with TARGET_FILE.open("w") as file: + file.write("#ifndef INC_SENTENCES\n") + file.write("#define INC_SENTENCES\n\n") + file.write(f"#define SENTENCE_COUNT {len(sentences)}\n") + file.write(f"#define SENTENCE_MAX_LENGTH {max_len}\n\n") + file.write( + "const int sentences[] = int[SENTENCE_COUNT * SENTENCE_MAX_LENGTH](\n" + ) + file.writelines( + " " + convert(sentence, mapping, max_len) + ("," if i < len(sentences) - 1 else " ") + f" // {sentence}\n" + for i, sentence in enumerate(sentences) + ) + file.write(");\n\n") + file.write("const int lengths[] = int[SENTENCE_COUNT](\n") + file.write( + " " + ", ".join(str(len(sentence)) for sentence in sentences) + "\n" + ) + file.write(");\n") + file.write("#endif") + + + +if __name__ == "__main__": + main()