Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 54 additions & 25 deletions examples/demos/stars/Makefile
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
# Makefile for building the random pixel demo
# Compiles random_pixels.has -> random_pixels.s -> random_pixels.o
# Makefile for building demos in examples/demos/stars
# Compiles each .has file to build/<name>.s -> build/<name>.o -> build/<name>.exe
# Links with library object files from build/

.SUFFIXES:

MAKEFILE_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
PROJ_ROOT := $(abspath $(MAKEFILE_DIR)../../..)
PROJ_ROOT := ../../..

HASC := cd $(PROJ_ROOT) && .venv/bin/python -m hasc.cli
# Resolve compiler runner from project root.
# Prefer `venv`, then `.venv`, then fallback to system python3.
PYTHON_BIN := $(if $(wildcard $(PROJ_ROOT)/venv/bin/python),venv/bin/python,$(if $(wildcard $(PROJ_ROOT)/.venv/bin/python),.venv/bin/python,python3))
HASC := cd "$(PROJ_ROOT)" && "$(PYTHON_BIN)" -m hasc.cli
VASM := vasmm68k_mot
VLINK := vlink

LIB_DIR := ../../../lib
BUILD_DIR := ../../../build
SRC_DIR := .

HAS_SOURCE := random_pixels.has
ASM_SOURCE := $(BUILD_DIR)/random_pixels.s
MAIN_OBJ := $(BUILD_DIR)/random_pixels.o
EXE_FILE := $(BUILD_DIR)/random_pixels.exe
HAS_SOURCES := $(wildcard $(SRC_DIR)/*.has)
DEMO_NAMES := $(basename $(notdir $(HAS_SOURCES)))
ASM_SOURCES := $(addprefix $(BUILD_DIR)/,$(addsuffix .s,$(DEMO_NAMES)))
MAIN_OBJS := $(addprefix $(BUILD_DIR)/,$(addsuffix .o,$(DEMO_NAMES)))
EXE_FILES := $(addprefix $(BUILD_DIR)/,$(addsuffix .exe,$(DEMO_NAMES)))

LIB_OBJS := $(BUILD_DIR)/graphics.o \
$(BUILD_DIR)/helpers.o \
Expand All @@ -27,27 +30,31 @@ LIB_OBJS := $(BUILD_DIR)/graphics.o \
$(BUILD_DIR)/input.o \
$(BUILD_DIR)/heap.o \
$(BUILD_DIR)/bob.o \
$(BUILD_DIR)/font8x8.o \
$(BUILD_DIR)/takeover.o

VASM_FLAGS := -m68000 -Fhunk -kick1hunks -I$(LIB_DIR)
VLINK_FLAGS := -bamigahunk -Bstatic

.PHONY: all clean run compile assemble link
.PHONY: all clean run compile assemble link list amiga run-vamos

all: $(EXE_FILE)
all: $(EXE_FILES)

list:
@echo "Demos in $(SRC_DIR): $(DEMO_NAMES)"

$(BUILD_DIR):
@mkdir -p $(BUILD_DIR)

$(EXE_FILE): $(MAIN_OBJ) $(LIB_OBJS)
@echo "Linking demo + libraries -> $(notdir $(EXE_FILE))"
$(BUILD_DIR)/%.exe: $(BUILD_DIR)/%.o $(LIB_OBJS)
@echo "Linking demo + libraries -> $(notdir $@)"
@which $(VLINK) > /dev/null || (echo "Error: $(VLINK) not found in PATH"; exit 1)
$(VLINK) $(VLINK_FLAGS) $^ -o $@

$(MAIN_OBJ): $(ASM_SOURCE) | $(BUILD_DIR)
$(BUILD_DIR)/%.o: $(BUILD_DIR)/%.s | $(BUILD_DIR)
@echo "Assembling $(notdir $<) -> $(notdir $@)"
@which $(VASM) > /dev/null || (echo "Error: $(VASM) not found in PATH"; exit 1)
$(VASM) $(VASM_FLAGS) -L $(BUILD_DIR)/random_pixels.lst -o $@ $<
$(VASM) $(VASM_FLAGS) -L $(BUILD_DIR)/$*.lst -o $@ $<

$(BUILD_DIR)/graphics.o: $(LIB_DIR)/graphics.s | $(BUILD_DIR)
@echo "Assembling graphics.s -> $(notdir $@)"
Expand Down Expand Up @@ -81,17 +88,39 @@ $(BUILD_DIR)/bob.o: $(LIB_DIR)/bob.s | $(BUILD_DIR)
@echo "Assembling bob.s -> $(notdir $@)"
$(VASM) $(VASM_FLAGS) -L $(BUILD_DIR)/bob.lst -o $@ $<

$(ASM_SOURCE): $(HAS_SOURCE) | $(BUILD_DIR)
@echo "Compiling $(HAS_SOURCE) -> $(notdir $@)"
$(BUILD_DIR)/font8x8.o: $(LIB_DIR)/font8x8.s | $(BUILD_DIR)
@echo "Assembling font8x8.s -> $(notdir $@)"
$(VASM) $(VASM_FLAGS) -L $(BUILD_DIR)/font8x8.lst -o $@ $<


$(BUILD_DIR)/%.s: %.has | $(BUILD_DIR)
@echo "Compiling $< -> $(notdir $@)"
@mkdir -p $(dir $@)
$(HASC) examples/demos/stars/$< -o build/random_pixels.s
$(HASC) examples/demos/stars/$< -o build/$*.s

compile: $(ASM_SOURCE)
assemble: $(MAIN_OBJ)
link: $(EXE_FILE)
compile: $(ASM_SOURCES)
assemble: $(MAIN_OBJS)
link: $(EXE_FILES)

clean:
rm -rf $(BUILD_DIR)/random_pixels.o $(BUILD_DIR)/random_pixels.s $(BUILD_DIR)/random_pixels.exe $(BUILD_DIR)/random_pixels.lst

run: $(EXE_FILE)
./$(EXE_FILE)
rm -rf $(ASM_SOURCES) $(MAIN_OBJS) $(EXE_FILES) $(addprefix $(BUILD_DIR)/,$(addsuffix .lst,$(DEMO_NAMES)))

DEMO ?= random_pixels
TARGET_EXE := $(BUILD_DIR)/$(DEMO).exe

# Build one selected Amiga executable (e.g. `make amiga DEMO=Texts`).
amiga: $(TARGET_EXE)
@echo "Amiga executable ready: $(TARGET_EXE)"

# Run the Amiga executable via vamos when available.
run-vamos: $(TARGET_EXE)
@if which vamos > /dev/null; then \
echo "Running $(TARGET_EXE) with vamos"; \
vamos $(TARGET_EXE); \
else \
echo "vamos not found. Built Amiga executable: $(TARGET_EXE)"; \
echo "Run it on Amiga/emulator manually."; \
fi

# Keep `run` as alias for Amiga-oriented execution.
run: run-vamos
126 changes: 126 additions & 0 deletions examples/demos/stars/Texts.has
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
#pragma lockreg(a5);

// Visual regression demo for Text/Print in 320x256x32 mode.
// Stresses cursor handling, newline behavior, wrapping, colors, and font attachment.

extern var fonts: int;
const KEY_ESC = 69;

code main:
extern func SetGraphicsMode(mode: int) -> int;
extern func ClearScreen() -> int;
extern func SetColor(id: int, col: int) -> int;
extern func SetFont(ptr: int) -> int;
extern func Text(x: int, y: int, msg: int, color: int) -> int;
extern func Print(msg: int, color: int) -> int;
extern func UpdateCopperList() -> int;
extern func WaitVBlank() -> int;
extern func InitKeyboard() -> void;
extern func GetKey() -> byte;
extern func TakeSystem() -> void;
extern func ReleaseSystem() -> void;

public main;

asm {
jsr TakeSystem
jsr main
jmp ReleaseSystem
}

proc main() -> int {
var running: int = 1;
var key: byte;
var frame: int = 0;
var blink: int = 0;

if (SetGraphicsMode(0) == -1) {
return -1;
}

call InitKeyboard();
call SetFont(&fonts);
call ClearScreen();

// Keep palette explicit so color bugs are easy to spot.
call SetColor(0, $000);
call SetColor(1, $FFF);
call SetColor(2, $F80);
call SetColor(3, $0F0);
call SetColor(4, $08F);
call SetColor(5, $FF0);
call SetColor(6, $F0F);
call SetColor(7, $0FF);

call Text(1, 1, &title_txt, 2);
call Text(1, 2, &info_txt, 3);
call Text(1, 4, &phase1_hdr, 5);
call Text(1, 5, &phase1_hint, 1);

// Phase 1: deterministic Print-only block.
call Print(&baseline_block, 2);

call Text(1, 12, &phase2_hdr, 6);
call Text(1, 13, &phase2_hint, 1);

// Phase 2: mixed Print/Text interactions.
call Print(&stress_seq_a, 4);
call Print(&stress_seq_lf, 6);
call Print(&stress_seq_cr, 7);
call Text(2, 17, &text_anchor_a, 5);
call Text(2, 19, &text_anchor_b, 7);
call Print(&post_text_seq, 2);
call Print(&wrap_test_seq, 3);

call Text(1, 30, &exit_hint_txt, 1);
call UpdateCopperList();

while (running == 1) {
call WaitVBlank();

// Small periodic update to keep exercising Text on same line.
frame = frame + 1;
if (frame == 25) {
frame = 0;
if (blink == 0) {
blink = 1;
call Text(1, 28, &pulse_a_txt, 4);
} else {
blink = 0;
call Text(1, 28, &pulse_b_txt, 6);
}
call UpdateCopperList();
}

key = GetKey();
if (key == KEY_ESC) {
running = 0;
}
}

return 0;
}

data text_data:
title_txt.b = "Texts.has - Print/Text Regression Demo", 0
info_txt.b = "Mode: 320x256x32 | font: lib/font8x8.s", 0

phase1_hdr.b = "PHASE 1: BASELINE (PRINT ONLY)", 0
phase1_hint.b = "Expected: full labels, stable left edge, no missing first chars.", 0
baseline_block.b = 10, "BASE-A: 0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ", 10, "BASE-B: AAAA BBBB CCCC DDDD", 10, "BASE-C: left edge marker -> [#]", 0

phase2_hdr.b = "PHASE 2: STRESS (PRINT + TEXT MIX)", 0
phase2_hint.b = "Expected: Text() anchors do not permanently move Print cursor.", 0
stress_seq_a.b = 10, "STRESS-A: mixed cursor test start", 0
stress_seq_lf.b = 10, "STRESS-B after LF should start on next line.", 0
stress_seq_cr.b = 13, "STRESS-C after CR should also start on next line.", 0

text_anchor_a.b = "TEXT anchor A at (2,17)", 0
text_anchor_b.b = "TEXT anchor B at (2,19)", 0
post_text_seq.b = "STRESS-D cursor should continue from STRESS-C, not Text anchors.", 0

wrap_test_seq.b = "WRAP: 0123456789012345678901234567890123456789 <- end", 0

pulse_a_txt.b = "Pulse line via Text(): state A", 0
pulse_b_txt.b = "Pulse line via Text(): state B", 0
exit_hint_txt.b = "Press ESC to exit demo.", 0
Loading