Draw into the whole window, not its top-left 320x200
The graphics verbs documented a coordinate transform that did not exist. With SCALE off a coordinate went straight to akgl_draw_* as a pixel address, so an 800x600 window drew a C128 listing into its corner and left the rest unused -- while the chapter said coordinates were 320x200 and stretching to fit was the host's business. akbasic_GraphicsBackend gains a size entry point, require_graphics() asks it before every verb that draws so a resized window is honoured between two statements, and 320x200 becomes the fallback for a backend that leaves it NULL. It is the record's one optional member, so a host written against the old header keeps the behaviour it had. SCALE now maps onto the device, and RGR(1)/RGR(2) report the drawing surface so a program can use a window whose size it did not choose. RGR(0) is BASIC 7.0's own field, the GRAPHIC mode. SCALE also mapped xmax onto the width rather than onto the last pixel, so SCALE 1, 319, 199 followed by DRAW 1, 319, 199 drew nothing at all -- one pixel past the surface. Fixed in the same line, because it is what makes "SCALE gives a C128 listing the whole window" true rather than nearly true. The akgl test renders against a 128x128 target, deliberately smaller than the old constants: a SCALE still dividing by them misses it entirely rather than landing somewhere plausible. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -43,6 +43,8 @@ typedef struct
|
||||
/* Graphics */
|
||||
int shapes; /* handles handed out so far */
|
||||
bool paint_exhausts; /* when true, paint reports a partial fill */
|
||||
int devwidth; /* what size() reports; see mock_devices_init */
|
||||
int devheight;
|
||||
|
||||
/* Audio */
|
||||
bool voice_active[AKBASIC_AUDIO_VOICES];
|
||||
@@ -94,6 +96,24 @@ static void mock_log(const char *format, ...)
|
||||
|
||||
/* --------------------------------------------------------------- graphics -- */
|
||||
|
||||
/**
|
||||
* @brief Report the recorded surface size, and log that it was asked.
|
||||
*
|
||||
* Logged like every other call because *when* the interpreter asks matters: it
|
||||
* re-asks before each verb that draws, deliberately, so a resized window is not
|
||||
* drawn to at its old size.
|
||||
*/
|
||||
static akerr_ErrorContext *mock_size(akbasic_GraphicsBackend *self, int *width, int *height)
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
(void)self;
|
||||
FAIL_ZERO_RETURN(errctx, (width != NULL && height != NULL), AKERR_NULLPOINTER,
|
||||
"NULL destination in mock_size");
|
||||
*width = MOCK.devwidth;
|
||||
*height = MOCK.devheight;
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
static akerr_ErrorContext *mock_point(akbasic_GraphicsBackend *self, double x, double y, akbasic_Color color)
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
@@ -415,8 +435,18 @@ __attribute__((unused))
|
||||
static void mock_devices_init(void)
|
||||
{
|
||||
memset(&MOCK, 0, sizeof(MOCK));
|
||||
/*
|
||||
* 640x400 rather than 320x200, on purpose: it is exactly twice the fallback,
|
||||
* so a scaled coordinate that came out right by accident -- because nothing
|
||||
* consulted the device at all -- is off by a factor of two rather than
|
||||
* indistinguishable. A test that wants the fallback clears MOCK_GRAPHICS.size,
|
||||
* the way the SOUND test clears MOCK_AUDIO.sweep.
|
||||
*/
|
||||
MOCK.devwidth = 640;
|
||||
MOCK.devheight = 400;
|
||||
|
||||
MOCK_GRAPHICS.self = &MOCK;
|
||||
MOCK_GRAPHICS.size = mock_size;
|
||||
MOCK_GRAPHICS.point = mock_point;
|
||||
MOCK_GRAPHICS.line = mock_line;
|
||||
MOCK_GRAPHICS.rect = mock_rect;
|
||||
|
||||
Reference in New Issue
Block a user