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:
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, ¶meters);
}
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;