Make GRAPHIC select the text plane
Some checks failed
akbasic CI Build / cmake_build (push) Failing after 3m22s
akbasic CI Build / sanitizers (push) Failing after 4m43s
akbasic CI Build / coverage (push) Failing after 3m43s
akbasic CI Build / akgl_build (push) Failing after 4m48s
akbasic CI Build / mutation_test (push) Failing after 3m31s

Co-authored-by: Andrew Kesterson <andrew@aklabs.net>
This commit is contained in:
2026-08-03 08:08:34 -04:00
parent c5d13f00f6
commit 3342f2b569
13 changed files with 345 additions and 79 deletions

View File

@@ -475,7 +475,7 @@ static akerr_ErrorContext *sink_window(akbasic_TextSink *self, int left, int top
"The sink has no character grid to window");
maxcols = state->fullwidth / state->cellw;
maxrows = state->fullheight / state->cellh;
maxrows = (state->fullheight / state->cellh) - state->texttop;
if ( left < 0 ) { left = 0; }
if ( top < 0 ) { top = 0; }
if ( right >= maxcols ) { right = maxcols - 1; }
@@ -484,7 +484,7 @@ static akerr_ErrorContext *sink_window(akbasic_TextSink *self, int left, int top
"WINDOW asks for no cells at all");
state->x = state->fullx + (left * state->cellw);
state->y = state->fully + (top * state->cellh);
state->y = state->fully + ((state->texttop + top) * state->cellh);
state->columns = (right - left) + 1;
state->rows = (bottom - top) + 1;
state->width = state->columns * state->cellw;
@@ -494,6 +494,78 @@ static akerr_ErrorContext *sink_window(akbasic_TextSink *self, int left, int top
SUCCEED_RETURN(errctx);
}
/**
* @brief Apply GRAPHIC's text-plane half without teaching the runtime about SDL.
*
* Modes 1 and 3 are full bitmaps, so the retained text grid is hidden. Modes 2
* and 4 have a bitmap above and text below. A C128 gives an omitted split its
* bottom six rows; an explicit zero means all text, and the host clamps a C128
* row number to however many measured cells its own window has.
*/
static akerr_ErrorContext *sink_graphic(akbasic_TextSink *self, int mode, int split)
{
PREPARE_ERROR(errctx);
akbasic_AkglSink *state = NULL;
int maxcols = 0;
int maxrows = 0;
FAIL_ZERO_RETURN(errctx, (self != NULL), AKERR_NULLPOINTER, "NULL sink in graphic");
state = (akbasic_AkglSink *)self->self;
FAIL_ZERO_RETURN(errctx, (state != NULL), AKERR_NULLPOINTER, "akgl sink has no state");
maxcols = state->fullwidth / state->cellw;
maxrows = state->fullheight / state->cellh;
state->graphicmode = mode;
if ( mode == 0 ) {
/* Text mode owns the whole screen again, not the last split's rows. */
state->texttop = 0;
state->x = state->fullx;
state->y = state->fully;
state->width = state->fullwidth;
state->height = state->fullheight;
state->columns = maxcols;
state->rows = maxrows;
if ( state->columns > SINK_MAX_COLUMNS - 1 ) {
state->columns = SINK_MAX_COLUMNS - 1;
}
if ( state->rows > SINK_MAX_ROWS ) {
state->rows = SINK_MAX_ROWS;
}
state->cursorcol = 0;
state->cursorrow = 0;
SUCCEED_RETURN(errctx);
}
if ( mode != 2 && mode != 4 ) {
SUCCEED_RETURN(errctx);
}
if ( split < 0 ) {
split = maxrows - 6;
}
if ( split < 0 ) { split = 0; }
if ( split >= maxrows ) {
/* A split below the final row is C128 all-bitmap mode, not a zero-row grid. */
state->graphicmode = 1;
SUCCEED_RETURN(errctx);
}
state->texttop = split;
state->x = state->fullx;
state->y = state->fully + (split * state->cellh);
state->width = state->fullwidth;
state->height = (maxrows - split) * state->cellh;
state->columns = maxcols;
state->rows = maxrows - split;
if ( state->columns > SINK_MAX_COLUMNS - 1 ) {
state->columns = SINK_MAX_COLUMNS - 1;
}
if ( state->rows > SINK_MAX_ROWS ) {
state->rows = SINK_MAX_ROWS;
}
state->cursorcol = 0;
state->cursorrow = 0;
SUCCEED_RETURN(errctx);
}
akerr_ErrorContext *akbasic_sink_init_akgl(akbasic_TextSink *obj, akbasic_AkglSink *state, akgl_RenderBackend *renderer, TTF_Font *font, int w, int h)
{
PREPARE_ERROR(errctx);
@@ -554,6 +626,8 @@ akerr_ErrorContext *akbasic_sink_init_akgl(akbasic_TextSink *obj, akbasic_AkglSi
state->cellh = cellh;
state->columns = w / cellw;
state->rows = h / cellh;
state->graphicmode = 0;
state->texttop = 0;
if ( state->columns > SINK_MAX_COLUMNS - 1 ) {
state->columns = SINK_MAX_COLUMNS - 1;
}
@@ -569,6 +643,7 @@ akerr_ErrorContext *akbasic_sink_init_akgl(akbasic_TextSink *obj, akbasic_AkglSi
obj->moveto = sink_moveto;
obj->window = sink_window;
obj->grid = sink_grid;
obj->graphic = sink_graphic;
SUCCEED_RETURN(errctx);
}
@@ -584,6 +659,11 @@ akerr_ErrorContext *akbasic_sink_akgl_render(akbasic_TextSink *obj)
FAIL_ZERO_RETURN(errctx, (state != NULL), AKERR_NULLPOINTER,
"akgl sink has no state");
/* A full bitmap owns every display row; the text buffer remains intact. */
if ( state->graphicmode == 1 || state->graphicmode == 3 ) {
SUCCEED_RETURN(errctx);
}
/*
* **Repaint every row of the text area, every frame.** Not just the rows
* that changed -- that was tried, with a `drawn[]` array marking which rows