tuxanci2-engine
Game engine for tuxanci2
Log | Files | Refs | README | LICENSE
commit e9acd21cb6b5b86ae832f48a114eec3e4faec6fa
parent 909057f87ecc9c564f8440baf8079e53a17adc0a
Author: Connor Thomson <connor@gnufault.org>
Date:   Wed, 28 Oct 2026 18:36:52 -0700

Optimizations

Diffstat:
Minclude/ta_display.h | 3++-
Minclude/ta_image.h | 2+-
Mplatforms/dreamcast/dreamcast.c | 8++++----
Mplatforms/n64/n64.c | 7++++++-
Mplatforms/ps1/ps1.c | 16++++++++++------
Mplatforms/saturn/saturn.c | 30+++++++++++++++++-------------
Msrc/screens/ta_screen_loading.c | 7-------
Msrc/ta_display.c | 28++++++++++++++++++++++++++++
Msrc/ta_image.c | 133+++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/ta_text.c | 15++-------------
10 files changed, 135 insertions(+), 114 deletions(-)

diff --git a/include/ta_display.h b/include/ta_display.h @@ -21,8 +21,8 @@ typedef struct { typedef struct { ta_uint16 x, y; ta_uint16 width, height; + ta_uint16 draw_width, draw_height; ta_display_pixel_format format; - ta_uint32 _pad; ta_uint8 pixels[]; } ta_display_sprite; @@ -37,6 +37,7 @@ extern ta_display_sprites_t *ta_display_sprites; ta_bool ta_display_init(void); void ta_display_deinit(void); +ta_display_sprite *ta_display_sprite_create(ta_uint16 width, ta_uint16 height); ta_bool ta_display_sprite_add(ta_display_sprite *sprite); void ta_display_sprite_free(ta_display_sprite *sprite); void ta_display_sprites_clear(void); diff --git a/include/ta_image.h b/include/ta_image.h @@ -4,7 +4,7 @@ #include "ta_types.h" ta_bool ta_image_draw(const ta_uint8 *data, ta_uint32 length, ta_fixed x, ta_fixed y, ta_fixed width, ta_fixed height, ta_uint16 frame); -ta_bool ta_image_prepare(const ta_uint8 *data, ta_uint32 length, ta_fixed width, ta_fixed height, ta_uint16 frame); +ta_bool ta_image_render(const ta_uint8 *data, ta_uint32 length, ta_uint16 frame, ta_uint32 width, ta_uint32 height, ta_uint32 *pixels); ta_bool ta_image_init(const ta_uint8 *data, ta_uint32 length); ta_bool ta_image_get_size(const ta_uint8 *data, ta_uint32 length, ta_uint32 *width, ta_uint32 *height); void ta_image_release(void); diff --git a/platforms/dreamcast/dreamcast.c b/platforms/dreamcast/dreamcast.c @@ -105,16 +105,16 @@ static void render_sprites(void) { pvr_sprite_txr_t quad = { .flags = PVR_CMD_VERTEX_EOL, .ax = (float)sprite->x, - .ay = (float)(sprite->y + sprite->height), + .ay = (float)(sprite->y + sprite->draw_height), .az = 1.0f, .bx = (float)sprite->x, .by = (float)sprite->y, .bz = 1.0f, - .cx = (float)(sprite->x + sprite->width), + .cx = (float)(sprite->x + sprite->draw_width), .cy = (float)sprite->y, .cz = 1.0f, - .dx = (float)(sprite->x + sprite->width), - .dy = (float)(sprite->y + sprite->height), + .dx = (float)(sprite->x + sprite->draw_width), + .dy = (float)(sprite->y + sprite->draw_height), .dummy = 0, .auv = PVR_PACK_16BIT_UV(0.0f, (float)sprite->height / texture_height), .buv = PVR_PACK_16BIT_UV(0.0f, 0.0f), diff --git a/platforms/n64/n64.c b/platforms/n64/n64.c @@ -80,7 +80,12 @@ int main(void) { ta_display_sprite *sprite = ta_display_sprites->sprites[i]; surface_t texture = surface_make_linear(sprite->pixels, FMT_RGBA32, sprite->width, sprite->height); data_cache_hit_writeback(sprite->pixels, (uint32_t)sprite->width * sprite->height * sizeof(uint32_t)); - rdpq_tex_blit(&texture, sprite->x, sprite->y, NULL); + rdpq_blitparms_t parameters = { + .scale_x = (float)sprite->draw_width / sprite->width, + .scale_y = (float)sprite->draw_height / sprite->height + }; + rdpq_mode_filter(sprite->draw_width != sprite->width || sprite->draw_height != sprite->height ? FILTER_BILINEAR : FILTER_POINT); + rdpq_tex_blit(&texture, sprite->x, sprite->y, &parameters); } rdpq_detach_show(); diff --git a/platforms/ps1/ps1.c b/platforms/ps1/ps1.c @@ -6,7 +6,7 @@ #define SCREEN_WIDTH 320 #define SCREEN_HEIGHT 240 -#define WINDOW_BPP 32 +#define WINDOW_BPP 15 #define STACK_RESERVE 0x20000u @@ -276,15 +276,19 @@ static void compose(void) { } source = (const ta_uint32 *)sprite->pixels; - width = sprite->width; - height = sprite->height; + width = sprite->draw_width; + height = sprite->draw_height; + + const ta_uint32 step_x = ((ta_uint32)sprite->width << 16) / width; + const ta_uint32 step_y = ((ta_uint32)sprite->height << 16) / height; for (ta_uint32 y = 0; y < height && sprite->y + y < SCREEN_HEIGHT; y++) { - const ta_uint32 *row = source + y * width; + const ta_uint32 *row = source + ((y * step_y) >> 16) * sprite->width; ta_uint16 *destination = framebuffer + (sprite->y + y) * SCREEN_WIDTH + sprite->x; + ta_uint32 source_x = 0; - for (ta_uint32 x = 0; x < width && sprite->x + x < SCREEN_WIDTH; x++) { - const ta_uint32 pixel = row[x]; + for (ta_uint32 x = 0; x < width && sprite->x + x < SCREEN_WIDTH; x++, source_x += step_x) { + const ta_uint32 pixel = row[source_x >> 16]; const ta_uint32 alpha = pixel & 0xffu; if (alpha == 0) { diff --git a/platforms/saturn/saturn.c b/platforms/saturn/saturn.c @@ -16,7 +16,7 @@ typedef struct { const ta_display_sprite *source; - ta_uint16 x, y, width, height; + ta_uint16 x, y, draw_width, draw_height; ta_uint32 checksum; unsigned int vram_bytes; } slot_t; @@ -79,31 +79,35 @@ static ta_uint32 sprite_checksum(const ta_display_sprite *sprite) { } static ta_bool slot_matches(const slot_t *slot, const ta_display_sprite *sprite) { - return (ta_bool)(slot->source == sprite && slot->x == sprite->x && slot->y == sprite->y && slot->width == sprite->width && slot->height == sprite->height && slot->checksum == sprite_checksum(sprite)); + return (ta_bool)(slot->source == sprite && slot->x == sprite->x && slot->y == sprite->y && slot->draw_width == sprite->draw_width && slot->draw_height == sprite->draw_height && slot->checksum == sprite_checksum(sprite)); } static ta_bool upload_sprite(const ta_display_sprite *sprite) { - if (slot_count >= MAX_SLOTS || sprite->format != TA_DISPLAY_PIXEL_FORMAT_32 || sprite->width == 0 || sprite->height == 0 || sprite->width > VDP1_MAX_WIDTH || sprite->height > VDP1_MAX_HEIGHT) { + if (slot_count >= MAX_SLOTS || sprite->format != TA_DISPLAY_PIXEL_FORMAT_32 || sprite->draw_width == 0 || sprite->draw_height == 0 || sprite->draw_width > VDP1_MAX_WIDTH || sprite->draw_height > VDP1_MAX_HEIGHT) { return ta_false; } - const unsigned int padded_width = ((unsigned int)sprite->width + 7) & ~7u; - const unsigned int bytes = padded_width * sprite->height * (unsigned int)sizeof(jo_color); + const unsigned int padded_width = ((unsigned int)sprite->draw_width + 7) & ~7u; + const unsigned int bytes = padded_width * sprite->draw_height * (unsigned int)sizeof(jo_color); - if (padded_width * sprite->height > sizeof(upload_buffer) / sizeof(upload_buffer[0]) || + if (padded_width * sprite->draw_height > sizeof(upload_buffer) / sizeof(upload_buffer[0]) || vram_used + bytes > VRAM_BUDGET) { return ta_false; } const ta_uint32 *source = (const ta_uint32 *)sprite->pixels; - for (unsigned int y = 0; y < sprite->height; y++) { - const ta_uint32 *row = source + (unsigned int)y * sprite->width; + const ta_uint32 step_x = ((ta_uint32)sprite->width << 16) / sprite->draw_width; + const ta_uint32 step_y = ((ta_uint32)sprite->height << 16) / sprite->draw_height; + + for (unsigned int y = 0; y < sprite->draw_height; y++) { + const ta_uint32 *row = source + ((y * step_y) >> 16) * sprite->width; jo_color *destination = upload_buffer + (unsigned int)y * padded_width; + ta_uint32 source_x = 0; unsigned int x = 0; - for (; x < sprite->width; x++) { - const ta_uint32 pixel = row[x]; + for (; x < sprite->draw_width; x++, source_x += step_x) { + const ta_uint32 pixel = row[source_x >> 16]; if ((pixel & 0xff) < ALPHA_THRESHOLD) { destination[x] = 0; @@ -118,7 +122,7 @@ static ta_bool upload_sprite(const ta_display_sprite *sprite) { } jo_img image = { - (unsigned short)padded_width, sprite->height, + (unsigned short)padded_width, sprite->draw_height, upload_buffer }; @@ -132,8 +136,8 @@ static ta_bool upload_sprite(const ta_display_sprite *sprite) { slot->source = sprite; slot->x = sprite->x; slot->y = sprite->y; - slot->width = sprite->width; - slot->height = sprite->height; + slot->draw_width = sprite->draw_width; + slot->draw_height = sprite->draw_height; slot->checksum = sprite_checksum(sprite); slot->vram_bytes = bytes; vram_used += bytes; diff --git a/src/screens/ta_screen_loading.c b/src/screens/ta_screen_loading.c @@ -9,7 +9,6 @@ static ta_bool logo_loaded; static ta_bool logo_shown; static ta_bool background_loaded; -static ta_bool background_scaled; static void draw_loading_logo(void) { ta_uint32 width; @@ -42,7 +41,6 @@ void ta_screen_loading_init(void) { logo_loaded = ta_false; logo_shown = ta_false; background_loaded = ta_false; - background_scaled = ta_false; } ta_bool ta_screen_loading_update(void) { @@ -65,11 +63,6 @@ ta_bool ta_screen_loading_update(void) { return ta_true; } - if (!background_scaled) { - background_scaled = ta_image_prepare(ta_file_bg, ta_file_bg_len, TA_FIXED_ONE, TA_FIXED_ONE, 0); - return ta_true; - } - ta_screen_current = TA_SCEEEN_MAIN_MENU; return ta_true; diff --git a/src/ta_display.c b/src/ta_display.c @@ -40,6 +40,34 @@ void ta_display_deinit(void) { ta_display->size = 0; } +ta_display_sprite *ta_display_sprite_create(ta_uint16 width, ta_uint16 height) { + if (width == 0 || height == 0) { + return TA_NULL; + } + + ta_size max_size = (ta_size)-1; + ta_size pixel_count = (ta_size)width * height; + + if (pixel_count > (max_size - sizeof(ta_display_sprite)) / sizeof(ta_uint32)) { + return TA_NULL; + } + + ta_display_sprite *sprite = ta_malloc(sizeof(*sprite) + pixel_count * sizeof(ta_uint32)); + if (!sprite) { + return TA_NULL; + } + + sprite->x = 0; + sprite->y = 0; + sprite->width = width; + sprite->height = height; + sprite->draw_width = width; + sprite->draw_height = height; + sprite->format = TA_DISPLAY_PIXEL_FORMAT_32; + + return sprite; +} + ta_bool ta_display_sprite_add(ta_display_sprite *sprite) { if (!sprite || !ta_display_sprites) { return ta_false; diff --git a/src/ta_image.c b/src/ta_image.c @@ -482,30 +482,6 @@ static ta_bool prepare_scaled(ta_image_cache *image, ta_uint32 width, ta_uint32 return ta_true; } -ta_bool ta_image_prepare(const ta_uint8 *data, ta_uint32 length, ta_fixed width, ta_fixed height, ta_uint16 frame) { - if (data == 0 || length == 0 || width == 0 || height == 0 || width > TA_FIXED_ONE || height > TA_FIXED_ONE || (!ta_display->sprite_mode && ta_display->buffers[1] == 0) || (ta_display->bpp != 8 && ta_display->bpp != 32)) { - return ta_false; - } - - ta_uint32 pixel_width = (ta_uint32)(((ta_uint64)width * ta_display->width) >> 16); - ta_uint32 pixel_height = (ta_uint32)(((ta_uint64)height * ta_display->height) >> 16); - - if (pixel_width == 0 || pixel_height == 0) { - return ta_false; - } - - ta_image_cache *image = get_image(data, length, frame); - if (image == 0) { - return ta_false; - } - - if ((image->flags & TAIF_FLAG_TRANSPARENT) != 0) { - return ta_true; - } - - return prepare_scaled(image, pixel_width, pixel_height); -} - ta_bool ta_image_draw(const ta_uint8 *data, ta_uint32 length, ta_fixed x, ta_fixed y, ta_fixed width, ta_fixed height, ta_uint16 frame) { if (data == 0 || length == 0 || x > TA_FIXED_ONE || y > TA_FIXED_ONE || width == 0 || height == 0 || width > TA_FIXED_ONE || height > TA_FIXED_ONE || (!ta_display->sprite_mode && ta_display->buffers[1] == 0) || (ta_display->sprite_mode && (!ta_display_sprites || ta_display->bpp != 32)) || (ta_display->bpp != 8 && ta_display->bpp != 32)) { return ta_false; @@ -543,64 +519,43 @@ ta_bool ta_image_draw(const ta_uint8 *data, ta_uint32 length, ta_fixed x, ta_fix ta_bool transparent = (image->flags & TAIF_FLAG_TRANSPARENT) != 0; if (ta_display->sprite_mode) { - ta_size max_size = (ta_size)-1; - if (visible_width > max_size / sizeof(ta_uint32) / visible_height) { - return ta_false; + ta_uint32 source_width = image->width; + ta_uint32 source_height = image->height; + + if (visible_width < pixel_width) { + source_width = (ta_uint32)(((ta_uint64)visible_width * image->width + pixel_width - 1) / pixel_width); } - ta_size pixel_count = (ta_size)visible_width * visible_height; - ta_display_sprite *sprite = (ta_display_sprite *)ta_malloc(sizeof(*sprite) + pixel_count * sizeof(ta_uint32)); + if (visible_height < pixel_height) { + source_height = (ta_uint32)(((ta_uint64)visible_height * image->height + pixel_height - 1) / pixel_height); + } + + ta_display_sprite *sprite = ta_display_sprite_create((ta_uint16)source_width, (ta_uint16)source_height); if (!sprite) { return ta_false; } sprite->x = (ta_uint16)pixel_x; sprite->y = (ta_uint16)pixel_y; - sprite->width = (ta_uint16)visible_width; - sprite->height = (ta_uint16)visible_height; - sprite->format = TA_DISPLAY_PIXEL_FORMAT_32; + sprite->draw_width = (ta_uint16)visible_width; + sprite->draw_height = (ta_uint16)visible_height; + ta_uint32 *pixels = (ta_uint32 *)sprite->pixels; + ta_uint32 palette_offset = transparent ? 1 : 0; - if (!transparent && prepare_scaled(image, pixel_width, pixel_height)) { - const ta_uint32 *source = (const ta_uint32 *)image->scaled; - for (ta_uint32 image_y = 0; image_y < visible_height; image_y++) { - for (ta_uint32 image_x = 0; image_x < visible_width; image_x++) { - ta_uint32 color = source[(ta_size)image_y * pixel_width + image_x]; - pixels[(ta_size)image_y * visible_width + image_x] = (color << 8) | 0xff; - } - } - } else { - ta_image_axis *columns = (ta_image_axis *)ta_malloc((ta_size)visible_width * sizeof(*columns)); - if (!columns) { - ta_free(sprite); - return ta_false; - } + for (ta_uint32 image_y = 0; image_y < source_height; image_y++) { + for (ta_uint32 image_x = 0; image_x < source_width; image_x++) { + ta_uint8 index = get_pixel_index(image, image_x, image_y); + ta_uint32 *pixel = &pixels[(ta_size)image_y * source_width + image_x]; - for (ta_uint32 image_x = 0; image_x < visible_width; image_x++) { - columns[image_x] = axis_position(image_x, pixel_width, image->width); - } + if (transparent && index == 0) { + *pixel = 0; + } else { + const ta_uint8 *color = image->palette[index - palette_offset]; - for (ta_uint32 image_y = 0; image_y < visible_height; image_y++) { - ta_image_axis row = axis_position(image_y, pixel_height, image->height); - for (ta_uint32 image_x = 0; image_x < visible_width; image_x++) { - ta_uint32 red; - ta_uint32 green; - ta_uint32 blue; - ta_uint32 alpha = sample_image(image, columns[image_x], row, &red, &green, &blue); - - if (alpha == 0) { - pixels[(ta_size)image_y * visible_width + image_x] = 0; - } else { - red = (red + alpha / 2) / alpha; - green = (green + alpha / 2) / alpha; - blue = (blue + alpha / 2) / alpha; - ta_uint32 output_alpha = (alpha * 255 + 32768) >> 16; - pixels[(ta_size)image_y * visible_width + image_x] = (red << 24) | (green << 16) | (blue << 8) | output_alpha; - } + *pixel = ((ta_uint32)color[0] << 24) | ((ta_uint32)color[1] << 16) | ((ta_uint32)color[2] << 8) | 0xff; } } - - ta_free(columns); } if (!ta_display_sprite_add(sprite)) { @@ -686,6 +641,48 @@ ta_bool ta_image_draw(const ta_uint8 *data, ta_uint32 length, ta_fixed x, ta_fix return ta_true; } +ta_bool ta_image_render(const ta_uint8 *data, ta_uint32 length, ta_uint16 frame, ta_uint32 width, ta_uint32 height, ta_uint32 *pixels) { + if (pixels == 0 || width == 0 || height == 0) { + return ta_false; + } + + ta_image_cache *image = get_image(data, length, frame); + if (image == 0) { + return ta_false; + } + + ta_image_axis *columns = (ta_image_axis *)ta_malloc((ta_size)width * sizeof(*columns)); + if (columns == 0) { + return ta_false; + } + + for (ta_uint32 x = 0; x < width; x++) { + columns[x] = axis_position(x, width, image->width); + } + + for (ta_uint32 y = 0; y < height; y++) { + ta_image_axis row = axis_position(y, height, image->height); + + for (ta_uint32 x = 0; x < width; x++) { + ta_uint32 red; + ta_uint32 green; + ta_uint32 blue; + + sample_image(image, columns[x], row, &red, &green, &blue); + + red = (red + 32768) >> 16; + green = (green + 32768) >> 16; + blue = (blue + 32768) >> 16; + + pixels[(ta_size)y * width + x] = (red << 16) | (green << 8) | blue; + } + } + + ta_free(columns); + + return ta_true; +} + void ta_image_release(void) { while (image_cache != 0) { ta_image_cache *image = image_cache; diff --git a/src/ta_text.c b/src/ta_text.c @@ -941,19 +941,12 @@ void ta_text_rasterize(ta_text *text) { } ta_size pixel_count = (ta_size)sprite_width * (ta_size)sprite_height; - ta_display_sprite *sprite = (ta_display_sprite *)ta_malloc(sizeof(*sprite) + pixel_count * sizeof(ta_uint32)); + ta_display_sprite *sprite = ta_display_sprite_create((ta_uint16)sprite_width, (ta_uint16)sprite_height); if (!sprite) { return; } - sprite->x = 0; - sprite->y = 0; - sprite->width = (ta_uint16)sprite_width; - sprite->height = (ta_uint16)sprite_height; - sprite->format = TA_DISPLAY_PIXEL_FORMAT_32; - sprite->_pad = 0; - ta_uint32 *pixels = (ta_uint32 *)sprite->pixels; for (ta_size i = 0; i < pixel_count; i++) { @@ -1020,7 +1013,7 @@ void ta_text_draw(ta_text *text) { ta_uint32 visible_width = (ta_uint32)(column_end - column_start); ta_uint32 visible_height = (ta_uint32)(row_end - row_start); - ta_display_sprite *copy = (ta_display_sprite *)ta_malloc(sizeof(*copy) + (ta_size)visible_width * visible_height * sizeof(ta_uint32)); + ta_display_sprite *copy = ta_display_sprite_create((ta_uint16)visible_width, (ta_uint16)visible_height); if (!copy) { return; @@ -1028,10 +1021,6 @@ void ta_text_draw(ta_text *text) { copy->x = (ta_uint16)(destination_x + column_start); copy->y = (ta_uint16)(destination_y + row_start); - copy->width = (ta_uint16)visible_width; - copy->height = (ta_uint16)visible_height; - copy->format = TA_DISPLAY_PIXEL_FORMAT_32; - copy->_pad = 0; ta_uint32 *copy_pixels = (ta_uint32 *)copy->pixels;