diff --git a/MAINTENANCE.md b/MAINTENANCE.md index bb54538..222c7f8 100644 --- a/MAINTENANCE.md +++ b/MAINTENANCE.md @@ -166,7 +166,7 @@ a mixed build leaks pool slots or frees one twice rather than failing to link. |---|---|---|---|---| | `deps/libakerror` | 2.0.1 | `libakerror.so.2` | major only | **none** — no version macro; `include/akbasic/error.h` feature-tests `AKERR_THREAD_SAFE` and `AKERR_EXIT_STATUS_UNREPRESENTABLE` instead | | `deps/libakstdlib` | 0.2.0 | `libakstdlib.so.0.2` | **`MAJOR.MINOR` while major is 0** | `AKSL_VERSION_*`, `aksl_version()`, `AKSL_VERSION_CHECK()` | -| `deps/libakgl` | 0.4.0 | `libakgl.so.0.4` | **`MAJOR.MINOR` while major is 0** | `AKGL_VERSION*`, `akgl_version()`, `AKGL_VERSION_AT_LEAST()` | +| `deps/libakgl` | 0.5.0 | `libakgl.so.0.5` | **`MAJOR.MINOR` while major is 0** | `AKGL_VERSION*`, `akgl_version()`, `AKGL_VERSION_AT_LEAST()` | For both 0.x libraries the soname carries `MAJOR.MINOR` deliberately: 0.1 and 0.2 are *different* ABIs, and both become major-only at 1.0. Do not read `0.1 → 0.2` as a compatible diff --git a/README.md b/README.md index 48eb40c..b0f9944 100644 --- a/README.md +++ b/README.md @@ -144,7 +144,7 @@ nothing to install first. * [libakstdlib](https://source.starfort.tech/andrew/libakstdlib) 0.2.0 — libc wrappers that report through `libakerror`. String-to-number conversion goes straight to it, which is why `VAL("garbage")` is an error rather than a silent `0`. -* [libakgl](https://source.starfort.tech/andrew/libakgl) 0.4.0 — **optional**, only for +* [libakgl](https://source.starfort.tech/andrew/libakgl) 0.5.0 — **optional**, only for `-DAKBASIC_WITH_AKGL=ON`. Pulls in SDL3. Its soname carries `MAJOR.MINOR` while the major is 0, so rebuild rather than relink. * [basicinterpret](https://source.starfort.tech/andrew/basicinterpret) — the Go original. diff --git a/TODO.md b/TODO.md index a2556bd..59eb1b7 100644 --- a/TODO.md +++ b/TODO.md @@ -1291,11 +1291,23 @@ deviations from the reference's *program*: `main.go` and the SDL half of 40. **A sprite is a real `libakgl` actor, and it is drawn by a renderfunc of ours.** Each of the eight becomes a `SpriteSheet` + `Sprite` + `Character` + `Actor` registered in `AKGL_REGISTRY_ACTOR`, so an embedding game sees BASIC's sprites alongside its own (goal 3). - But `akgl_actor_render()` is not what draws them: it computes its destination *height* from - the sprite's **width**, which would draw a 24×21 Commodore sprite as a 24×24 square, and an - actor carries a single scalar `scale` that cannot express `SPRITE`'s separate x- and - y-expand bits. `src/sprite_akgl.c` installs its own `renderfunc`, which is libakgl's own - extension point for exactly this. Both defects are filed upstream. + But `akgl_actor_render()` is not what draws them. There were two reasons and **libakgl + 0.5.0 fixed one**: the default used to compute its destination *height* from the sprite's + **width**, drawing a 24×21 Commodore sprite as a 24×24 square, and it now uses the height + — libakgl defect 26, filed from here and closed there. + + **The reason that remains is the one that keeps this file.** An actor carries a single + scalar `scale` applied to both axes, which cannot express `SPRITE`'s separate x- and + y-expand bits, so `MOVSPR`'s twice-as-wide-same-height is unrepresentable. libakgl records + it as open and names this interpreter as the caller that needs it; the fix is a design + choice over there — `scale_x`/`scale_y` beside `scale`, or replacing `scale` and taking + the ABI break while the major is still 0 — rather than a patch. Until then + `src/sprite_akgl.c` installs its own `renderfunc`, which is libakgl's own extension point + for exactly this. + + Worth keeping as a pattern: both defects were found by *using* the library for something + it had not been used for, and both were filed rather than worked around silently. One came + back fixed. --- @@ -1708,7 +1720,7 @@ Dependency baseline: |---|---|---| | `deps/libakerror` | 2.0.1 | Private ownership-enforced status registry. akbasic reserves 512–767 in `akbasic_error_register()`. Does not namespace its `coverage` target when embedded — worked around in our `CMakeLists.txt`. **2.0.0 is thread safe and an ABI break** (`libakerror.so.2`): `__akerr_last_ignored` is thread-local and `akerr_next_error()` returns an owned reference, neither of which fails to link when mismatched. **2.0.1 fixes an exit status that mattered more to this band than to any other** — see below. | | `deps/libakstdlib` | 0.2.0 | soname `libakstdlib.so.0.2`. `AKSL_VERSION_CHECK()` asserted in `tests/version_check.c`. This release fixed all six confirmed defects the port was working around — see §1.9, where the bans are now lifted. | -| `deps/libakgl` | 0.4.0 | soname `libakgl.so.0.4`. Owns status codes 256–260. Linked and tested under `-DAKBASIC_WITH_AKGL=ON`, which still defaults OFF so the core library and its whole suite build on a machine with no SDL. **0.3.0 closed every API gap this port had filed** — see §7 — so the four workarounds §3 used to list are gone. 0.4.0 is a leak-and-overread release that changed no public struct, but the soname carries `MAJOR.MINOR` while the major is 0, so rebuild rather than relink. | +| `deps/libakgl` | 0.5.0 | soname `libakgl.so.0.5`. Owns status codes 256–260. Linked and tested under `-DAKBASIC_WITH_AKGL=ON`, which still defaults OFF so the core library and its whole suite build on a machine with no SDL. **0.3.0 closed every API gap this port had filed** — see §7 — so the four workarounds §3 used to list are gone. 0.4.0 was a leak-and-overread release that changed no public struct. **0.5.0 is the first that broke our source as well as our ABI**: it namespaced every exported symbol, so `akgl_render_bind2d` is `akgl_render_2d_bind`, `akgl_sprite_sheet_coords_for_frame` is `akgl_spritesheet_coords_for_frame`, the `renderer`/`camera`/`window` globals carry the prefix, and `_akgl_renderer`/`_akgl_camera` are `akgl_default_renderer`/`akgl_default_camera`. `include/akbasic/akgl.h` asserts the 0.5.0 floor. | **An unhandled error in this band used to exit zero, and 512 is the worst possible base for that.** `libakerror`'s default unhandled-error handler ended in `exit(errctx->status)`, and a diff --git a/deps/libakgl b/deps/libakgl index 93e8e4a..b899f09 160000 --- a/deps/libakgl +++ b/deps/libakgl @@ -1 +1 @@ -Subproject commit 93e8e4afa4fff5778606d50f92107141f4ada180 +Subproject commit b899f09fc8b54802c3f64ba1473c657bd3feaaeb diff --git a/include/akbasic/akgl.h b/include/akbasic/akgl.h index 15e8079..6a56963 100644 --- a/include/akbasic/akgl.h +++ b/include/akbasic/akgl.h @@ -36,26 +36,34 @@ #include /* - * The API floor is 0.3.0: akgl_render_bind2d(), akgl_audio_sweep(), and - * akgl_Keystroke with akgl_controller_poll_keystroke() all arrived there, and - * nothing in this target uses anything newer. The floor asserted below is - * 0.4.0 anyway, and the difference is ABI rather than API. + * **0.5.0 is a hard floor, API as well as ABI**, which is new: every release + * before it moved this line for ABI reasons alone. 0.5.0 namespaced every + * exported symbol, so the spellings this target compiles against do not exist in + * 0.4.0 and the ones 0.4.0 had do not exist here. `akgl_render_bind2d` is + * `akgl_render_2d_bind`, `akgl_sprite_sheet_coords_for_frame` is + * `akgl_spritesheet_coords_for_frame`, and the `renderer`, `camera` and `window` + * globals carry the prefix -- with `_akgl_renderer` and `_akgl_camera` now + * `akgl_default_renderer` and `akgl_default_camera`. * - * The soname carries MAJOR.MINOR while the major is 0, so 0.3 and 0.4 are - * different ABIs *by declaration* -- libakgl's versioning policy says a 0.x - * minor bump may break, and the soname is built to match. 0.4.0 in fact changed - * no public struct: it is leak and overread fixes inside src/. The floor moves - * anyway, because the alternative is deciding for ourselves which of libakgl's - * minor releases were really compatible, and that is exactly the judgement the - * soname exists to take away from us. + * That rename was not cosmetic and libakgl's TODO.md says why at length: an + * exported global called `renderer` collided with a test's own variable of the + * same name, the executable's definition preempted the library's, and every + * texture load in that suite failed while the suite reported success. * - * What it catches is the case the soname cannot: a build against 0.3 headers - * that happens to find a 0.4 library, or the reverse. Refused here rather than + * The soname carries MAJOR.MINOR while the major is 0, so 0.4 and 0.5 are + * different ABIs *by declaration* -- libakgl's versioning policy says a 0.x minor + * bump may break, and the soname is built to match. The floor moves with every + * one of them, because the alternative is deciding for ourselves which of + * libakgl's minor releases were really compatible, and that is exactly the + * judgement the soname exists to take away from us. + * + * What it catches is the case the soname cannot: a build against 0.4 headers + * that happens to find a 0.5 library, or the reverse. Refused here rather than * at link time, because a missing symbol names a function and this names the * release. */ -#if !AKGL_VERSION_AT_LEAST(0, 4, 0) -#error "akbasic's libakgl adaptors require libakgl 0.4.0 or later" +#if !AKGL_VERSION_AT_LEAST(0, 5, 0) +#error "akbasic's libakgl adaptors require libakgl 0.5.0 or later" #endif #include diff --git a/src/frontend_akgl.c b/src/frontend_akgl.c index 762cb54..16a1ed7 100644 --- a/src/frontend_akgl.c +++ b/src/frontend_akgl.c @@ -30,7 +30,8 @@ #include #include /* - * game.h purely for the `renderer` global and its `_akgl_renderer` storage. + * game.h purely for the `akgl_renderer` global and its `akgl_default_renderer` + * storage. * akgl_text_rendertextat() takes no renderer argument and reads that global, so * a host that never calls akgl_game_init() -- which is every host embedding this * interpreter, since owning the game loop is exactly what goal 3 forbids -- has @@ -72,13 +73,13 @@ akerr_ErrorContext *akbasic_frontend_akgl_init(akbasic_AkglFrontend *obj, const FAIL_ZERO_RETURN(errctx, TTF_Init(), AKGL_ERR_SDL, "Couldn't initialize SDL_ttf: %s", SDL_GetError()); - obj->renderer = &_akgl_renderer; - renderer = obj->renderer; + obj->renderer = &akgl_default_renderer; + akgl_renderer = obj->renderer; FAIL_ZERO_RETURN(errctx, SDL_CreateWindowAndRenderer(title, w, h, 0, &obj->window, &obj->renderer->sdl_renderer), AKGL_ERR_SDL, "Couldn't create the window: %s", SDL_GetError()); - window = obj->window; + akgl_window = obj->window; /* * Without this SDL sends no SDL_EVENT_TEXT_INPUT at all, every keystroke @@ -95,14 +96,14 @@ akerr_ErrorContext *akbasic_frontend_akgl_init(akbasic_AkglFrontend *obj, const SDL_GetError()); } /* - * Bind the 2D methods onto the renderer we just made. akgl_render_init2d() + * Bind the 2D methods onto the renderer we just made. akgl_render_2d_init() * would do this too, but it creates its own window from the game properties * first, which is the akgl_game_init() path a host with its own window is * not on. libakgl 0.3.0 split the vtable half out for exactly this caller -- * it was API-gap item 7, and until it landed these six pointers were * assigned by hand here and in tests/akgl_backends.c. */ - PASS(errctx, akgl_render_bind2d(obj->renderer)); + PASS(errctx, akgl_render_2d_bind(obj->renderer)); /* * The object pools and the name registries. Every akgl_*_initialize ends in @@ -133,11 +134,11 @@ akerr_ErrorContext *akbasic_frontend_akgl_init(akbasic_AkglFrontend *obj, const * anybody could act on. One screen's worth at the origin: BASIC has no verb * that scrolls a view, so the world and the screen are the same thing here. */ - camera = &_akgl_camera; - camera->x = 0.0f; - camera->y = 0.0f; - camera->w = (float)w; - camera->h = (float)h; + akgl_camera = &akgl_default_camera; + akgl_camera->x = 0.0f; + akgl_camera->y = 0.0f; + akgl_camera->w = (float)w; + akgl_camera->h = (float)h; obj->font = TTF_OpenFont(fontpath, (float)fontsize); FAIL_ZERO_RETURN(errctx, (obj->font != NULL), AKGL_ERR_SDL, @@ -331,7 +332,7 @@ void akbasic_frontend_akgl_shutdown(akbasic_AkglFrontend *obj) SDL_StopTextInput(obj->window); SDL_DestroyWindow(obj->window); obj->window = NULL; - window = NULL; + akgl_window = NULL; } TTF_Quit(); if ( obj->ownssdl ) { diff --git a/src/sprite_akgl.c b/src/sprite_akgl.c index 207b506..caeac4f 100644 --- a/src/sprite_akgl.c +++ b/src/sprite_akgl.c @@ -17,12 +17,20 @@ * loads through akgl_spritesheet_initialize(), the same two calls * akgl_sprite_load_json_spritesheet() makes. * - * Every actor gets a renderfunc of its own rather than akgl_actor_render(). Two - * reasons, both defects filed upstream: the default computes its destination - * height from the sprite's *width*, which draws a 24x21 Commodore sprite as a - * 24x24 square; and an actor carries one scalar `scale`, which cannot express - * SPRITE's separate x- and y-expand bits. Installing a function pointer is - * libakgl's own extension point for exactly this, so nothing is forked. + * Every actor gets a renderfunc of its own rather than akgl_actor_render(). It + * was two reasons, both filed upstream, and **libakgl 0.5.0 fixed one of them**: + * the default used to compute its destination height from the sprite's *width*, + * drawing a 24x21 Commodore sprite as a 24x24 square, and it now uses the + * height. That was libakgl defect 26. + * + * The remaining reason is the one that still requires this file: an akgl_Actor + * carries a single scalar `scale` applied to both axes, which cannot express + * SPRITE's separate x- and y-expand bits. libakgl records that as an open item + * and names this interpreter as the caller that needs it; the shape it takes -- + * scale_x/scale_y beside scale, or replacing scale outright -- is a design + * decision over there rather than a patch. Until it lands, installing a function + * pointer is libakgl's own extension point for exactly this, so nothing is + * forked. */ #include @@ -82,9 +90,11 @@ static akerr_ErrorContext *slot_of(akbasic_SpriteBackend *self, int n, akbasic_A /** * @brief Draw one BASIC sprite, in place of akgl_actor_render(). * - * Differs from the default in exactly two ways, both noted at the top of this - * file: the destination height comes from the sprite's height rather than its - * width, and the two expansion bits scale the axes independently. + * Differs from the default in exactly one way now, noted at the top of this file: + * the two expansion bits scale the axes independently, where an actor's single + * `scale` cannot. Taking the destination height from the sprite's height used to + * be the second difference and is the default's behaviour as of libakgl 0.5.0 -- + * the line below is no longer a correction, only agreement. * * Like the default, it skips rather than reports: an actor with no image, one * that is hidden, one whose slot has been reused. A frame is not the place to @@ -121,9 +131,9 @@ static akerr_ErrorContext *spr_render_actor(akgl_Actor *obj) SUCCEED_RETURN(errctx); } - PASS(errctx, akgl_sprite_sheet_coords_for_frame(sprite, &src, 0)); - dest.x = obj->x - (camera != NULL ? camera->x : 0.0f); - dest.y = obj->y - (camera != NULL ? camera->y : 0.0f); + PASS(errctx, akgl_spritesheet_coords_for_frame(sprite, &src, 0)); + dest.x = obj->x - (akgl_camera != NULL ? akgl_camera->x : 0.0f); + dest.y = obj->y - (akgl_camera != NULL ? akgl_camera->y : 0.0f); dest.w = (float32_t)sprite->width * (state->xexpand[found] ? 2.0f : 1.0f); dest.h = (float32_t)sprite->height * (state->yexpand[found] ? 2.0f : 1.0f); diff --git a/tests/akgl_backends.c b/tests/akgl_backends.c index cb1df0b..6ca0bcf 100644 --- a/tests/akgl_backends.c +++ b/tests/akgl_backends.c @@ -25,7 +25,7 @@ #include #include /* - * game.h purely for the `renderer` global and its `_akgl_renderer` storage. The + * game.h purely for the `akgl_renderer` global and its `akgl_default_renderer` storage. The * interpreter never calls akgl_game_init() -- it drives subsystems directly, and * owning the game loop is exactly what goal 3 forbids -- but the draw calls read * that global, so a test standing in for a host has to populate it the same way @@ -85,9 +85,9 @@ static akerr_ErrorContext AKERR_NOIGNORE *clear_target(void) { PREPARE_ERROR(errctx); - FAIL_ZERO_RETURN(errctx, SDL_SetRenderDrawColor(renderer->sdl_renderer, 0, 0, 0, 0xff), + FAIL_ZERO_RETURN(errctx, SDL_SetRenderDrawColor(akgl_renderer->sdl_renderer, 0, 0, 0, 0xff), AKGL_ERR_SDL, "%s", SDL_GetError()); - FAIL_ZERO_RETURN(errctx, SDL_RenderClear(renderer->sdl_renderer), + FAIL_ZERO_RETURN(errctx, SDL_RenderClear(akgl_renderer->sdl_renderer), AKGL_ERR_SDL, "%s", SDL_GetError()); SUCCEED_RETURN(errctx); } @@ -104,8 +104,8 @@ static akerr_ErrorContext AKERR_NOIGNORE *start_runtime(const char *source) PASS(errctx, akbasic_sink_init_stdio(&SINK, &SINKSTATE, OUT, NULL)); PASS(errctx, akbasic_runtime_init(&RUNTIME, &SINK)); - PASS(errctx, akbasic_graphics_init_akgl(&GRAPHICS, &GRAPHICSSTATE, renderer)); - PASS(errctx, akbasic_sprite_init_akgl(&SPRITES, &SPRITESSTATE, renderer, &GRAPHICSSTATE)); + PASS(errctx, akbasic_graphics_init_akgl(&GRAPHICS, &GRAPHICSSTATE, akgl_renderer)); + PASS(errctx, akbasic_sprite_init_akgl(&SPRITES, &SPRITESSTATE, akgl_renderer, &GRAPHICSSTATE)); PASS(errctx, akbasic_runtime_set_devices(&RUNTIME, &GRAPHICS, NULL, NULL, &SPRITES)); PASS(errctx, akbasic_runtime_load(&RUNTIME, source)); PASS(errctx, akbasic_runtime_start(&RUNTIME, AKBASIC_MODE_RUN)); @@ -136,7 +136,7 @@ static akerr_ErrorContext AKERR_NOIGNORE *test_draw_reaches_pixels(void) PASS(errctx, start_runtime("10 COLOR 1, 3\n20 DRAW 1, 10, 20\n")); TEST_REQUIRE_STR(OUTPUT, ""); - shot = SDL_RenderReadPixels(renderer->sdl_renderer, NULL); + shot = SDL_RenderReadPixels(akgl_renderer->sdl_renderer, NULL); TEST_REQUIRE(shot != NULL, "could not read the render target back"); /* Palette index 3 is red: 0x88, 0x39, 0x32 in src/graphics_tables.c. */ TEST_REQUIRE(pixel_is(shot, 10, 20, 0x88, 0x39, 0x32), @@ -171,7 +171,7 @@ static akerr_ErrorContext AKERR_NOIGNORE *test_size_is_the_renderer(void) "20 DRAW 1, 1000, 1000\n")); TEST_REQUIRE_STR(OUTPUT, ""); - shot = SDL_RenderReadPixels(renderer->sdl_renderer, NULL); + shot = SDL_RenderReadPixels(akgl_renderer->sdl_renderer, NULL); TEST_REQUIRE(shot != NULL, "could not read the render target back"); /* * The far corner of the user space lands on the far corner of the target. @@ -195,7 +195,7 @@ static akerr_ErrorContext AKERR_NOIGNORE *test_box_outlines(void) PASS(errctx, start_runtime("10 BOX 1, 10, 10, 40, 40\n")); TEST_REQUIRE_STR(OUTPUT, ""); - shot = SDL_RenderReadPixels(renderer->sdl_renderer, NULL); + shot = SDL_RenderReadPixels(akgl_renderer->sdl_renderer, NULL); TEST_REQUIRE(shot != NULL, "could not read the render target back"); TEST_REQUIRE(pixel_is(shot, 10, 10, 0xff, 0xff, 0xff), "the box's corner should be lit"); TEST_REQUIRE(pixel_is(shot, 25, 10, 0xff, 0xff, 0xff), "the box's top edge should be lit"); @@ -223,7 +223,7 @@ static akerr_ErrorContext AKERR_NOIGNORE *test_paint_fills_region(void) "30 PAINT 2, 25, 25\n")); TEST_REQUIRE_STR(OUTPUT, ""); - shot = SDL_RenderReadPixels(renderer->sdl_renderer, NULL); + shot = SDL_RenderReadPixels(akgl_renderer->sdl_renderer, NULL); TEST_REQUIRE(shot != NULL, "could not read the render target back"); /* Palette index 6 is green: 0x55, 0xa0, 0x49. */ TEST_REQUIRE(pixel_is(shot, 25, 25, 0x55, 0xa0, 0x49), @@ -247,7 +247,7 @@ static akerr_ErrorContext AKERR_NOIGNORE *test_shape_roundtrip(void) "30 GSHAPE A$, 64, 64\n")); TEST_REQUIRE_STR(OUTPUT, ""); - shot = SDL_RenderReadPixels(renderer->sdl_renderer, NULL); + shot = SDL_RenderReadPixels(akgl_renderer->sdl_renderer, NULL); TEST_REQUIRE(shot != NULL, "could not read the render target back"); /* The saved corner was at (4,4); pasted at (64,64) it lands at (68,68). */ TEST_REQUIRE(pixel_is(shot, 68, 68, 0xff, 0xff, 0xff), @@ -273,7 +273,7 @@ static akerr_ErrorContext AKERR_NOIGNORE *test_sink_grid_and_wrap(void) PASS(errctx, akgl_text_measure(font, "A", &cellw, &cellh)); TEST_REQUIRE(cellw > 0 && cellh > 0, "the fixture font should measure a real cell"); - PASS(errctx, akbasic_sink_init_akgl(&AKGLSINK, &AKGLSINKSTATE, renderer, font, + PASS(errctx, akbasic_sink_init_akgl(&AKGLSINK, &AKGLSINKSTATE, akgl_renderer, font, TARGET_SIZE, TARGET_SIZE)); TEST_REQUIRE_INT(AKGLSINKSTATE.cellw, cellw); TEST_REQUIRE_INT(AKGLSINKSTATE.columns, TARGET_SIZE / cellw); @@ -297,7 +297,7 @@ static akerr_ErrorContext AKERR_NOIGNORE *test_sink_grid_and_wrap(void) * producing a zero-column grid, which would divide by zero on the first * wrap. */ - TEST_REQUIRE_STATUS(akbasic_sink_init_akgl(&AKGLSINK, &AKGLSINKSTATE, renderer, font, 1, 1), + TEST_REQUIRE_STATUS(akbasic_sink_init_akgl(&AKGLSINK, &AKGLSINKSTATE, akgl_renderer, font, 1, 1), AKBASIC_ERR_BOUNDS); TEST_REQUIRE_STATUS(akbasic_sink_init_akgl(&AKGLSINK, &AKGLSINKSTATE, NULL, font, TARGET_SIZE, TARGET_SIZE), @@ -315,7 +315,7 @@ static akerr_ErrorContext AKERR_NOIGNORE *test_sink_renders(void) bool lit = false; PASS(errctx, clear_target()); - PASS(errctx, akbasic_sink_init_akgl(&AKGLSINK, &AKGLSINKSTATE, renderer, font, + PASS(errctx, akbasic_sink_init_akgl(&AKGLSINK, &AKGLSINKSTATE, akgl_renderer, font, TARGET_SIZE, TARGET_SIZE)); PASS(errctx, AKGLSINK.write(&AKGLSINK, "X")); PASS(errctx, akbasic_sink_akgl_render(&AKGLSINK)); @@ -326,7 +326,7 @@ static akerr_ErrorContext AKERR_NOIGNORE *test_sink_renders(void) * is free to hint them differently. The seam being tested is that the text * reached the renderer at the cursor's cell at all. */ - shot = SDL_RenderReadPixels(renderer->sdl_renderer, NULL); + shot = SDL_RenderReadPixels(akgl_renderer->sdl_renderer, NULL); TEST_REQUIRE(shot != NULL, "could not read the render target back"); for ( y = 0; y < AKGLSINKSTATE.cellh && !lit; y++ ) { for ( x = 0; x < AKGLSINKSTATE.cellw && !lit; x++ ) { @@ -402,7 +402,7 @@ static akerr_ErrorContext AKERR_NOIGNORE *test_sprite_from_file(void) TEST_REQUIRE_STR(OUTPUT, ""); PASS(errctx, akbasic_sprite_akgl_render(&SPRITES)); - shot = SDL_RenderReadPixels(renderer->sdl_renderer, NULL); + shot = SDL_RenderReadPixels(akgl_renderer->sdl_renderer, NULL); TEST_REQUIRE(shot != NULL, "could not read the render target back"); /* * Magenta, not white: SPRITE's colour argument modulates the texture and @@ -448,7 +448,7 @@ static akerr_ErrorContext AKERR_NOIGNORE *test_sprite_from_pattern(void) TEST_REQUIRE_STR(OUTPUT, ""); PASS(errctx, akbasic_sprite_akgl_render(&SPRITES)); - shot = SDL_RenderReadPixels(renderer->sdl_renderer, NULL); + shot = SDL_RenderReadPixels(akgl_renderer->sdl_renderer, NULL); TEST_REQUIRE(shot != NULL, "could not read the render target back"); /* Palette index 6 is green: 0x55, 0xa0, 0x49. */ TEST_REQUIRE(pixel_is(shot, 20, 20, 0x55, 0xa0, 0x49), @@ -485,7 +485,7 @@ static akerr_ErrorContext AKERR_NOIGNORE *test_sprite_from_shape(void) TEST_REQUIRE_STR(OUTPUT, ""); PASS(errctx, akbasic_sprite_akgl_render(&SPRITES)); - shot = SDL_RenderReadPixels(renderer->sdl_renderer, NULL); + shot = SDL_RenderReadPixels(akgl_renderer->sdl_renderer, NULL); TEST_REQUIRE(shot != NULL, "could not read the render target back"); /* * Palette index 3 is red, which is what the BOX was outlined in. The corner @@ -512,7 +512,7 @@ int main(void) ATTEMPT { CATCH(errctx, akgl_error_init()); - renderer = &_akgl_renderer; + akgl_renderer = &akgl_default_renderer; FAIL_ZERO_BREAK(errctx, SDL_Init(SDL_INIT_VIDEO), AKGL_ERR_SDL, "Couldn't initialize SDL: %s", SDL_GetError()); @@ -521,17 +521,18 @@ int main(void) FAIL_ZERO_BREAK(errctx, SDL_CreateWindowAndRenderer("net/aklabs/akbasic/test_akgl_backends", TARGET_SIZE, TARGET_SIZE, 0, - &window, &renderer->sdl_renderer), + &akgl_window, &akgl_renderer->sdl_renderer), AKGL_ERR_SDL, "Couldn't create window/renderer: %s", SDL_GetError()); /* * Bind the 2D methods. akgl_text_rendertextat() reaches through - * renderer->draw_texture and an SDL_Renderer alone does not fill that in; + * akgl_renderer->draw_texture and an SDL_Renderer alone does not fill that in; * deps/libakgl/tests/draw.c gets away without it because the draw * primitives take the SDL_Renderer directly. These six pointers were - * assigned by hand here until libakgl 0.3.0 split akgl_render_bind2d out - * of akgl_render_init2d -- API-gap item 7, filed from this file. + * assigned by hand here until libakgl 0.3.0 split the bind half out of the + * init half -- API-gap item 7, filed from this file. Both were renamed in + * 0.5.0, from akgl_render_bind2d and akgl_render_init2d. */ - CATCH(errctx, akgl_render_bind2d(renderer)); + CATCH(errctx, akgl_render_2d_bind(akgl_renderer)); /* * The three things akgl_game_init() would have done and this file, being @@ -541,11 +542,11 @@ int main(void) */ CATCH(errctx, akgl_heap_init()); CATCH(errctx, akgl_registry_init()); - camera = &_akgl_camera; - camera->x = 0.0f; - camera->y = 0.0f; - camera->w = (float)TARGET_SIZE; - camera->h = (float)TARGET_SIZE; + akgl_camera = &akgl_default_camera; + akgl_camera->x = 0.0f; + akgl_camera->y = 0.0f; + akgl_camera->w = (float)TARGET_SIZE; + akgl_camera->h = (float)TARGET_SIZE; /* * libakgl's own monospaced fixture, borrowed rather than copied. Being diff --git a/tests/akgl_frontend.c b/tests/akgl_frontend.c index 01cbc70..75551c1 100644 --- a/tests/akgl_frontend.c +++ b/tests/akgl_frontend.c @@ -33,7 +33,7 @@ #include #include #include -/* game.h for the `camera` global, which akgl_actor_render() reads. */ +/* game.h for the `akgl_camera` global, which akgl_actor_render() reads. */ #include #include #include @@ -875,9 +875,9 @@ static akerr_ErrorContext AKERR_NOIGNORE *test_host_can_draw_an_actor(void) PASS(errctx, start_frontend(NULL)); - TEST_REQUIRE(camera != NULL, "the frontend should have pointed the camera somewhere"); - TEST_REQUIRE_INT((int)camera->w, WINDOW_W); - TEST_REQUIRE_INT((int)camera->h, WINDOW_H); + TEST_REQUIRE(akgl_camera != NULL, "the frontend should have pointed the camera somewhere"); + TEST_REQUIRE_INT((int)akgl_camera->w, WINDOW_W); + TEST_REQUIRE_INT((int)akgl_camera->h, WINDOW_H); TEST_REQUIRE(AKGL_REGISTRY_ACTOR != 0, "the frontend should have created the registries"); memset(sheetname, 0, sizeof(sheetname)); diff --git a/tools/screenshot.c b/tools/screenshot.c index 6fd2451..3b81136 100644 --- a/tools/screenshot.c +++ b/tools/screenshot.c @@ -104,22 +104,22 @@ static akerr_ErrorContext AKERR_NOIGNORE *draw_program(const char *outpath, int SDL_Surface *shot = NULL; PASS(errctx, akgl_error_init()); - renderer = &_akgl_renderer; + akgl_renderer = &akgl_default_renderer; FAIL_ZERO_RETURN(errctx, SDL_Init(SDL_INIT_VIDEO), AKGL_ERR_SDL, "Couldn't initialize SDL: %s", SDL_GetError()); FAIL_ZERO_RETURN(errctx, SDL_CreateWindowAndRenderer("net/aklabs/akbasic/screenshot", w, h, 0, - &window, &renderer->sdl_renderer), + &akgl_window, &akgl_renderer->sdl_renderer), AKGL_ERR_SDL, "Couldn't create window/renderer: %s", SDL_GetError()); - PASS(errctx, akgl_render_bind2d(renderer)); + PASS(errctx, akgl_render_2d_bind(akgl_renderer)); PASS(errctx, akgl_heap_init()); PASS(errctx, akgl_registry_init()); - camera = &_akgl_camera; - camera->x = 0.0f; - camera->y = 0.0f; - camera->w = (float32_t)w; - camera->h = (float32_t)h; + akgl_camera = &akgl_default_camera; + akgl_camera->x = 0.0f; + akgl_camera->y = 0.0f; + akgl_camera->w = (float32_t)w; + akgl_camera->h = (float32_t)h; /* * Opaque black, so a figure has a defined background rather than whatever @@ -127,17 +127,17 @@ static akerr_ErrorContext AKERR_NOIGNORE *draw_program(const char *outpath, int * over the output for a reason src/graphics_akgl.c explains -- clearing is * the host's prerogative -- and this is the host doing it. */ - FAIL_ZERO_RETURN(errctx, SDL_SetRenderDrawColor(renderer->sdl_renderer, 0, 0, 0, 0xff), + FAIL_ZERO_RETURN(errctx, SDL_SetRenderDrawColor(akgl_renderer->sdl_renderer, 0, 0, 0, 0xff), AKGL_ERR_SDL, "%s", SDL_GetError()); - FAIL_ZERO_RETURN(errctx, SDL_RenderClear(renderer->sdl_renderer), + FAIL_ZERO_RETURN(errctx, SDL_RenderClear(akgl_renderer->sdl_renderer), AKGL_ERR_SDL, "%s", SDL_GetError()); /* stdout: a program that errors puts its "? line : CLASS message" there, which is what the caller shows when a figure comes out wrong. */ PASS(errctx, akbasic_sink_init_stdio(&SINK, &SINKSTATE, stdout, NULL)); PASS(errctx, akbasic_runtime_init(&RUNTIME, &SINK)); - PASS(errctx, akbasic_graphics_init_akgl(&GRAPHICS, &GRAPHICSSTATE, renderer)); - PASS(errctx, akbasic_sprite_init_akgl(&SPRITES, &SPRITESSTATE, renderer, &GRAPHICSSTATE)); + PASS(errctx, akbasic_graphics_init_akgl(&GRAPHICS, &GRAPHICSSTATE, akgl_renderer)); + PASS(errctx, akbasic_sprite_init_akgl(&SPRITES, &SPRITESSTATE, akgl_renderer, &GRAPHICSSTATE)); PASS(errctx, akbasic_runtime_set_devices(&RUNTIME, &GRAPHICS, NULL, NULL, &SPRITES)); PASS(errctx, akbasic_runtime_load(&RUNTIME, SOURCE)); PASS(errctx, akbasic_runtime_start(&RUNTIME, AKBASIC_MODE_RUN)); @@ -151,7 +151,7 @@ static akerr_ErrorContext AKERR_NOIGNORE *draw_program(const char *outpath, int */ PASS(errctx, akbasic_sprite_akgl_render(&SPRITES)); - shot = SDL_RenderReadPixels(renderer->sdl_renderer, NULL); + shot = SDL_RenderReadPixels(akgl_renderer->sdl_renderer, NULL); FAIL_ZERO_RETURN(errctx, (shot != NULL), AKGL_ERR_SDL, "Couldn't read the target back: %s", SDL_GetError()); if ( !IMG_SavePNG(shot, outpath) ) { @@ -196,9 +196,9 @@ int main(int argc, char **argv) CATCH(errctx, read_program(argv[1])); CATCH(errctx, draw_program(argv[2], w, h)); } CLEANUP { - if ( window != NULL ) { - SDL_DestroyWindow(window); - window = NULL; + if ( akgl_window != NULL ) { + SDL_DestroyWindow(akgl_window); + akgl_window = NULL; } SDL_Quit(); } PROCESS(errctx) {