diff --git a/CMakeLists.txt b/CMakeLists.txt index a9df2b262..8f59a6265 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -235,9 +235,15 @@ add_dependencies(openomf copy_shaders) # Build tools if requested set(TOOL_TARGET_NAMES) + + # always build languagetool, for BuildLanguages.cmake add_executable(languagetool tools/languagetool/main.c) list(APPEND TOOL_TARGET_NAMES languagetool) +#somehow language tool is not being rebuilt on MSVC correctly, it's missing libpng and the linking fails. +if(WIN32 AND NOT MINGW) + set(CORELIBS languagetool ${CORELIBS}) +endif() if (USE_TOOLS) add_executable(bktool tools/bktool/main.c tools/shared/animation_misc.c diff --git a/src/formats/bk.c b/src/formats/bk.c index 1eceed561..9841287b8 100644 --- a/src/formats/bk.c +++ b/src/formats/bk.c @@ -10,6 +10,7 @@ #include "formats/internal/writer.h" #include "formats/palette.h" #include "formats/pcx.h" +#include "formats/transparent.h" #include "formats/vga_image.h" #include "utils/allocator.h" @@ -134,7 +135,7 @@ int sd_bk_load(sd_bk_file *bk, const char *filename) { // Read background image bk->background = omf_calloc(1, sizeof(sd_vga_image)); - if((ret = sd_vga_image_create(bk->background, img_w, img_h)) != SD_SUCCESS) { + if((ret = sd_vga_image_create(bk->background, img_w, img_h, BACKGROUND_TRANSPARENT_INDEX)) != SD_SUCCESS) { goto exit_0; } int bsize = img_w * img_h; diff --git a/src/formats/fonts.c b/src/formats/fonts.c index 489560c43..0b7a8b8a2 100644 --- a/src/formats/fonts.c +++ b/src/formats/fonts.c @@ -4,6 +4,7 @@ #include "formats/fonts.h" #include "formats/internal/reader.h" #include "formats/internal/writer.h" +#include int sd_font_create(sd_font *font) { if(font == NULL) { @@ -57,18 +58,20 @@ int sd_font_save(const sd_font *font, const char *file) { return SD_SUCCESS; } -int sd_font_decode(const sd_font *font, sd_vga_image *o, uint8_t ch, uint8_t color) { +int sd_font_decode(const sd_font *font, sd_vga_image *o, uint8_t ch, uint8_t color, int transparent) { if(font == NULL || o == NULL || ch >= 224) { return SD_INVALID_INPUT; } + assert((transparent >= 0) && (transparent < 256)); + int t = 0; for(unsigned i = 0; i < font->h; i++) { for(int k = font->h - 1; k >= 0; k--) { if(font->chars[ch].data[i] & (1 << k)) { o->data[t] = color; } else { - o->data[t] = 0; + o->data[t] = (char)transparent; } t++; } diff --git a/src/formats/fonts.h b/src/formats/fonts.h index 0e09f2644..7d66f12a3 100644 --- a/src/formats/fonts.h +++ b/src/formats/fonts.h @@ -93,7 +93,7 @@ int sd_font_save(const sd_font *font, const char *filename); * \param ch Character to load. Must be 0 <= ch <= 224. * \param color Color palette index (0 - 0xFF) */ -int sd_font_decode(const sd_font *font, sd_vga_image *surface, uint8_t ch, uint8_t color); +int sd_font_decode(const sd_font *font, sd_vga_image *surface, uint8_t ch, uint8_t color, int transparent); /** * Same as sd_font_decode, but decodes to an RGBA surface. diff --git a/src/formats/pcx.c b/src/formats/pcx.c index d0625ecbf..5746f0d62 100644 --- a/src/formats/pcx.c +++ b/src/formats/pcx.c @@ -1,7 +1,9 @@ #include "formats/pcx.h" #include "formats/error.h" #include "formats/internal/reader.h" +#include "formats/transparent.h" #include "utils/allocator.h" +#include #include #include #include @@ -69,7 +71,7 @@ int pcx_load(pcx_file *pcx, const char *filename) { } int ret; - if((ret = sd_vga_image_create(&(pcx->image), 320, 200)) != SD_SUCCESS) { + if((ret = sd_vga_image_create(&(pcx->image), 320, 200, FONT_TRANSPARENT_INDEX)) != SD_SUCCESS) { return ret; } @@ -141,11 +143,14 @@ int pcx_load_font(pcx_font *font, const char *filename) { return SD_SUCCESS; } -int pcx_font_decode(const pcx_font *font, sd_vga_image *o, uint8_t ch, int8_t palette_offset) { +int pcx_font_decode(const pcx_font *font, sd_vga_image *o, uint8_t ch, int8_t palette_offset, int transparent) { if(ch >= font->glyph_count || font == NULL || o == NULL) { return SD_INVALID_INPUT; } + // Fonts always need to have a transparent value. + assert((transparent >= 0) && (transparent < 256)); + int k = 0; for(int i = font->glyphs[ch].y; i < font->glyphs[ch].y + font->glyph_height; i++) { int l = 0; @@ -153,7 +158,7 @@ int pcx_font_decode(const pcx_font *font, sd_vga_image *o, uint8_t ch, int8_t pa if(font->pcx.image.data[(i * 320) + j]) { o->data[(k * font->glyphs[ch].width) + l] = palette_offset + (int)font->pcx.image.data[(i * 320) + j]; } else { - o->data[(k * font->glyphs[ch].width) + l] = 0; + o->data[(k * font->glyphs[ch].width) + l] = transparent; } l++; diff --git a/src/formats/pcx.h b/src/formats/pcx.h index a45e6bcc8..a745b1f84 100644 --- a/src/formats/pcx.h +++ b/src/formats/pcx.h @@ -49,7 +49,7 @@ typedef struct { int pcx_load(pcx_file *pcx, const char *filename); int pcx_load_font(pcx_font *font, const char *filename); -int pcx_font_decode(const pcx_font *font, sd_vga_image *o, uint8_t ch, int8_t palette_offset); +int pcx_font_decode(const pcx_font *font, sd_vga_image *o, uint8_t ch, int8_t palette_offset, int transparent); void pcx_free(pcx_file *pcx); void pcx_font_free(pcx_font *font); diff --git a/src/formats/sprite.c b/src/formats/sprite.c index 73d227215..a6864fa47 100644 --- a/src/formats/sprite.c +++ b/src/formats/sprite.c @@ -4,6 +4,7 @@ #include "formats/error.h" #include "formats/palette.h" #include "formats/sprite.h" +#include "formats/transparent.h" #include "utils/allocator.h" int sd_sprite_create(sd_sprite *sprite) { @@ -271,6 +272,7 @@ int sd_sprite_vga_decode(sd_vga_image *dst, const sd_sprite *src) { uint16_t c = 0; uint16_t data = 0; char op = 0; + int transparent = SPRITE_TRANSPARENT_INDEX; // Make sure we aren't being fed BS if(dst == NULL || src == NULL) { @@ -279,9 +281,9 @@ int sd_sprite_vga_decode(sd_vga_image *dst, const sd_sprite *src) { // If image data length is 0, then size should be 1x1 if(src->len > 0) { - sd_vga_image_create(dst, src->width, src->height); + sd_vga_image_create(dst, src->width, src->height, transparent); } else { - sd_vga_image_create(dst, 1, 1); + sd_vga_image_create(dst, 1, 1, transparent); } // XXX CREDITS.BK has a bunch of 0 width sprites, for some unknown reason @@ -310,6 +312,7 @@ int sd_sprite_vga_decode(sd_vga_image *dst, const sd_sprite *src) { uint8_t b = src->data[i]; int pos = ((y * src->width) + x); dst->data[pos] = b; + assert(b != transparent); i++; // we read 1 byte x++; data--; @@ -324,6 +327,8 @@ int sd_sprite_vga_decode(sd_vga_image *dst, const sd_sprite *src) { } } + dst->transparent = transparent; + // All done. dst should now contain a valid vga image. return SD_SUCCESS; } diff --git a/src/formats/transparent.h b/src/formats/transparent.h new file mode 100644 index 000000000..c0c487626 --- /dev/null +++ b/src/formats/transparent.h @@ -0,0 +1,44 @@ +/*! \file + * \brief Transparent VGA pixel values + * \details Describes the transparancy index value for various engine components. + * \copyright MIT license. + * \date 2024 + * \author Andrew Thompson + * \author Tuomas Virtanen + */ + +#ifndef TRANSPARENT_H +#define TRANSPARENT_H + +// Default's. +// Please do not use the default definitions in the code directly. Define a new value below instead. +// This way all different transparency values are stored in one place. +#define DEFAULT_TRANSPARENT_INDEX 0 +#define DEFAULT_NOT_TRANSPARENT -1 + +// All sprites have holes, these holes need to be transparent. +#define SPRITE_TRANSPARENT_INDEX DEFAULT_TRANSPARENT_INDEX + +// Backgrounds have no transparent pixels and need all pixels to be rendered. +#define BACKGROUND_TRANSPARENT_INDEX DEFAULT_NOT_TRANSPARENT + +// Force an opaque menu for now. +#define MENU_TRANSPARENT_INDEX DEFAULT_NOT_TRANSPARENT + +// Portraits have a transparancy index that needs to offset past other items in the global palette. +// TODO: Should really become default. +#define PORTRAIT_TRANSPARENT_INDEX 0xD0 + +// Portrait highlights need a special offset for transparency to not conflict with other entries in the global palette. +// TODO: Should really become default. +#define HIGHLIGHT_TRANSPARENT_INDEX 90 + +// Fonts need a transparent index that does not conflict with the lower 8 colors on the N64 otherwise there will be a +// combinatorial explosion. +#define FONT_TRANSPARENT_INDEX DEFAULT_TRANSPARENT_INDEX +#define PCX_FONT_TRANSPARENT_INDEX DEFAULT_TRANSPARENT_INDEX + +// Gauges in the player select have an opaque background and are not transparent. +#define GAUGE_TRANSPARENT_INDEX DEFAULT_NOT_TRANSPARENT + +#endif diff --git a/src/formats/vga_image.c b/src/formats/vga_image.c index d9e95bb35..0c22f857c 100644 --- a/src/formats/vga_image.c +++ b/src/formats/vga_image.c @@ -1,22 +1,28 @@ +#if !defined(MIN_BUILD) #include +#endif +#include #include #include #include #include #include "formats/error.h" +#include "formats/transparent.h" #include "formats/vga_image.h" #include "utils/allocator.h" #include "utils/png_writer.h" -int sd_vga_image_create(sd_vga_image *img, unsigned int w, unsigned int h) { +int sd_vga_image_create(sd_vga_image *img, unsigned int w, unsigned int h, int transparent) { if(img == NULL) { return SD_INVALID_INPUT; } img->w = w; img->h = h; img->len = w * h; - img->data = omf_calloc(1, w * h); + img->transparent = transparent; + img->data = omf_alloc_with_options(1, img->len, ALLOC_HINT_TEXTURE); + assert((img->data != NULL) || (img->len == 0)); return SD_SUCCESS; } @@ -27,7 +33,8 @@ int sd_vga_image_copy(sd_vga_image *dst, const sd_vga_image *src) { dst->w = src->w; dst->h = src->h; dst->len = src->len; - dst->data = omf_calloc(src->len, 1); + dst->data = omf_malloc(src->len); + dst->transparent = src->transparent; memcpy(dst->data, src->data, src->len); return SD_SUCCESS; } @@ -36,7 +43,7 @@ void sd_vga_image_free(sd_vga_image *img) { if(img == NULL) { return; } - omf_free(img->data); + omf_free_with_options(img->data, ALLOC_HINT_TEXTURE); } int sd_vga_image_decode(sd_rgba_image *dst, const sd_vga_image *src, const vga_palette *pal) { @@ -62,6 +69,9 @@ int sd_vga_image_decode(sd_rgba_image *dst, const sd_vga_image *src, const vga_p } int sd_vga_image_from_png(sd_vga_image *img, const char *filename) { +#if defined(MIN_BUILD) + return 0; +#else png_structp png_ptr; png_infop info_ptr; int ret = SD_SUCCESS; @@ -136,7 +146,7 @@ int sd_vga_image_from_png(sd_vga_image *img, const char *filename) { png_read_image(png_ptr, row_pointers); // Convert - if(sd_vga_image_create(img, w, h) != SD_SUCCESS) { + if(sd_vga_image_create(img, w, h, DEFAULT_NOT_TRANSPARENT) != SD_SUCCESS) { ret = SD_OUT_OF_MEMORY; goto error_3; } @@ -159,6 +169,7 @@ int sd_vga_image_from_png(sd_vga_image *img, const char *filename) { fclose(handle); error_0: return ret; +#endif } int sd_vga_image_to_png(const sd_vga_image *img, const vga_palette *pal, const char *filename) { diff --git a/src/formats/vga_image.h b/src/formats/vga_image.h index 173efd86b..21c001588 100644 --- a/src/formats/vga_image.h +++ b/src/formats/vga_image.h @@ -27,6 +27,7 @@ typedef struct { unsigned int h; ///< Pixel height unsigned int len; ///< Byte length char *data; ///< Palette representation of image data + int transparent; } sd_vga_image; /*! \brief Initialize VGA image structure @@ -41,7 +42,7 @@ typedef struct { * \param w Image width in pixels * \param h Image height in pixels */ -int sd_vga_image_create(sd_vga_image *img, unsigned int w, unsigned int h); +int sd_vga_image_create(sd_vga_image *img, unsigned int w, unsigned int h, int transparent); /*! \brief Copy VGA image structure * diff --git a/src/game/gui/gauge.c b/src/game/gui/gauge.c index e984438d8..0b295d316 100644 --- a/src/game/gui/gauge.c +++ b/src/game/gui/gauge.c @@ -1,4 +1,5 @@ #include "game/gui/gauge.h" +#include "formats/transparent.h" #include "game/gui/widget.h" #include "utils/allocator.h" #include "utils/miscmath.h" @@ -74,7 +75,7 @@ typedef struct { } gauge; static void surface_from_pix_img(surface *sur, const pixel_image *pix) { - surface_create_from_data(sur, pix->width, pix->height, pix->data); + surface_create_from_data(sur, pix->width, pix->height, pix->data, GAUGE_TRANSPARENT_INDEX); } static void gauge_render(component *c) { diff --git a/src/game/gui/menu_background.c b/src/game/gui/menu_background.c index a2f9dbb1c..7594df10c 100644 --- a/src/game/gui/menu_background.c +++ b/src/game/gui/menu_background.c @@ -1,4 +1,5 @@ #include "game/gui/menu_background.h" +#include "formats/transparent.h" #include "video/image.h" #define COLOR_MENU_LINE 252 @@ -9,8 +10,7 @@ #define COLOR_MENU_BG 0 void menu_transparent_bg_create(surface *s, int w, int h) { - surface_create(s, w, h); - surface_set_transparency(s, -1); + surface_create(s, w, h, BACKGROUND_TRANSPARENT_INDEX); } void menu_background_create(surface *s, int w, int h) { @@ -24,8 +24,7 @@ void menu_background_create(surface *s, int w, int h) { image_line(&img, 0, y, w - 1, y, COLOR_MENU_LINE); } image_rect(&img, 0, 0, w - 1, h - 1, COLOR_MENU_BORDER); - surface_create_from_image(s, &img); - surface_set_transparency(s, COLOR_MENU_BG); + surface_create_from_image(s, &img, MENU_TRANSPARENT_INDEX); image_free(&img); } @@ -42,8 +41,7 @@ void menu_background2_create(surface *s, int w, int h) { } image_rect(&img, 1, 1, w - 2, h - 2, COLOR_MENU_BORDER2); image_rect(&img, 0, 0, w - 2, h - 2, COLOR_MENU_BORDER1); - surface_create_from_image(s, &img); - surface_set_transparency(s, COLOR_MENU_BG); + surface_create_from_image(s, &img, MENU_TRANSPARENT_INDEX); image_free(&img); } @@ -53,6 +51,6 @@ void menu_background_border_create(surface *s, int w, int h) { image_create(&img, w, h); image_clear(&img, 0); image_rect(&img, 0, 0, w - 1, h - 1, COLOR_MENU_BORDER); - surface_create_from_image(s, &img); + surface_create_from_image(s, &img, MENU_TRANSPARENT_INDEX); image_free(&img); } diff --git a/src/game/gui/progressbar.c b/src/game/gui/progressbar.c index e685651f0..7d90ef062 100644 --- a/src/game/gui/progressbar.c +++ b/src/game/gui/progressbar.c @@ -1,5 +1,6 @@ #include +#include "formats/transparent.h" #include "game/gui/progressbar.h" #include "game/gui/widget.h" #include "utils/allocator.h" @@ -95,7 +96,7 @@ static void progressbar_render(component *c) { if(bar->block == NULL) { bar->block = omf_calloc(1, sizeof(surface)); } - surface_create_from_image(bar->block, &tmp); + surface_create_from_image(bar->block, &tmp, MENU_TRANSPARENT_INDEX); image_free(&tmp); } else { omf_free(bar->block); @@ -153,14 +154,14 @@ static void progressbar_layout(component *c, int x, int y, int w, int h) { image_clear(&tmp, bar->theme.bg_color); image_rect_bevel(&tmp, 0, 0, w - 1, h - 1, bar->theme.border_topleft_color, bar->theme.border_bottomright_color, bar->theme.border_bottomright_color, bar->theme.border_topleft_color); - surface_create_from_image(bar->background, &tmp); + surface_create_from_image(bar->background, &tmp, MENU_TRANSPARENT_INDEX); image_free(&tmp); image_create(&tmp, w, h); image_clear(&tmp, bar->theme.bg_color_alt); image_rect_bevel(&tmp, 0, 0, w - 1, h - 1, bar->theme.border_topleft_color, bar->theme.border_bottomright_color, bar->theme.border_bottomright_color, bar->theme.border_topleft_color); - surface_create_from_image(bar->background_alt, &tmp); + surface_create_from_image(bar->background_alt, &tmp, MENU_TRANSPARENT_INDEX); image_free(&tmp); } diff --git a/src/game/gui/text_render.c b/src/game/gui/text_render.c index 6bdd2b169..9f34b3a70 100644 --- a/src/game/gui/text_render.c +++ b/src/game/gui/text_render.c @@ -306,6 +306,9 @@ static void text_render_len(const text_settings *settings, text_mode mode, int x surface *sur; // Render characters + int mxstart = mx; + int mystart = my; + int kstart = k; for(; k < line_len; k++) { // Skip line endings. if(text[ptr + k] == '\n') @@ -318,6 +321,29 @@ static void text_render_len(const text_settings *settings, text_mode mode, int x } render_char_shadow_surface(settings, sur, mx + start_x, my + start_y); + + // Render to the right direction + if(settings->direction == TEXT_HORIZONTAL) { + mx += sur->w + settings->cspacing; + } else { + my += char_h; + } + } + + mx = mxstart; + my = mystart; + k = kstart; + for(; k < line_len; k++) { + // Skip line endings. + if(text[ptr + k] == '\n') + continue; + + // Render character + sur = get_font_surface(settings, text[ptr + k]); + if(sur == NULL) { + continue; + } + render_char_surface(settings, mode, sur, mx + start_x, my + start_y); // Render to the right direction diff --git a/src/game/gui/textinput.c b/src/game/gui/textinput.c index 3bd810ce5..dd953e7e3 100644 --- a/src/game/gui/textinput.c +++ b/src/game/gui/textinput.c @@ -3,6 +3,7 @@ #include #include +#include "formats/transparent.h" #include "game/gui/textinput.h" #include "game/gui/widget.h" #include "utils/allocator.h" @@ -244,7 +245,7 @@ component *textinput_create(const text_settings *tconf, int max_chars, const cha image_create(&img, tb->max_chars * tsize + 2, tsize + 3); image_clear(&img, COLOR_MENU_BG); image_rect(&img, 0, 0, tb->max_chars * tsize + 1, tsize + 2, COLOR_MENU_BORDER); - surface_create_from_image(&tb->sur, &img); + surface_create_from_image(&tb->sur, &img, BACKGROUND_TRANSPARENT_INDEX); image_free(&img); // Copy over the initial value diff --git a/src/game/objects/har.c b/src/game/objects/har.c index 81304ce8b..7091a1ef2 100644 --- a/src/game/objects/har.c +++ b/src/game/objects/har.c @@ -6,6 +6,7 @@ #include "audio/audio.h" #include "controller/controller.h" #include "formats/af.h" +#include "formats/transparent.h" #include "game/common_defines.h" #include "game/game_state.h" #include "game/objects/arena_constraints.h" @@ -2226,7 +2227,7 @@ int har_create(object *obj, af *af_data, int dir, int har_id, int pilot_id, int #ifdef DEBUGMODE object_set_debug_cb(obj, har_debug); - surface_create(&local->cd_debug, 320, 200); + surface_create(&local->cd_debug, 320, 200, SPRITE_TRANSPARENT_INDEX); surface_clear(&local->cd_debug); #endif diff --git a/src/game/scenes/melee.c b/src/game/scenes/melee.c index 50103a4e0..b479e6487 100644 --- a/src/game/scenes/melee.c +++ b/src/game/scenes/melee.c @@ -3,6 +3,7 @@ #include "audio/audio.h" #include "formats/pilot.h" +#include "formats/transparent.h" #include "game/game_state.h" #include "game/gui/menu_background.h" #include "game/gui/progressbar.h" @@ -677,7 +678,6 @@ static void load_har_portraits(scene *scene, melee_local *local) { target->x = current->pos.x + 62 * col; target->y = current->pos.y + 42 * row; surface_create_from_surface(&target->enabled, 51, 36, 62 * col, 42 * row, current->data); - surface_set_transparency(&target->enabled, 0xD0); // Copy the enabled image, and compress the colors to grayscale surface_create_from(&target->disabled, &target->enabled); @@ -728,8 +728,7 @@ int melee_create(scene *scene) { // Create a black surface for the highlight box. We modify the palette in renderer. unsigned char *black = omf_calloc(1, 51 * 36); - surface_create_from_data(&local->select_hilight, 51, 36, black); - surface_set_transparency(&local->select_hilight, -1); + surface_create_from_data(&local->select_hilight, 51, 36, black, HIGHLIGHT_TRANSPARENT_INDEX); omf_free(black); // set up the magic controller hooks diff --git a/src/resources/bk.c b/src/resources/bk.c index 60c8dcbdc..56ecf5fbd 100644 --- a/src/resources/bk.c +++ b/src/resources/bk.c @@ -10,7 +10,7 @@ void bk_create(bk *b, void *src) { b->file_id = sdbk->file_id; // Copy VGA image - surface_create_from_vga(&b->background, sdbk->background); + surface_create_from_vga(&b->background, sdbk->background, sdbk->background->transparent); // Copy sound translation table memcpy(b->sound_translation_table, sdbk->soundtable, 30); diff --git a/src/resources/fonts.c b/src/resources/fonts.c index a15d6d3df..5c299aab2 100644 --- a/src/resources/fonts.c +++ b/src/resources/fonts.c @@ -1,6 +1,7 @@ #include "formats/fonts.h" #include "formats/error.h" #include "formats/pcx.h" +#include "formats/transparent.h" #include "resources/fonts.h" #include "resources/ids.h" #include "resources/pathmanager.h" @@ -59,12 +60,12 @@ int font_load(font *font, const char *filename, unsigned int size) { } // Load into textures - sd_vga_image_create(&img, pixsize, pixsize); + sd_vga_image_create(&img, pixsize, pixsize, FONT_TRANSPARENT_INDEX); for(int i = 0; i < 224; i++) { sur = omf_calloc(1, sizeof(surface)); - sd_font_decode(&sdfont, &img, i, 1); - surface_create_from_vga(sur, &img); - surface_set_transparency(sur, 0); + // TODO: why is there a copy needed for this? + sd_font_decode(&sdfont, &img, i, 1, FONT_TRANSPARENT_INDEX); + surface_create_from_vga(sur, &img, FONT_TRANSPARENT_INDEX); vector_append(&font->surfaces, &sur); } @@ -95,11 +96,10 @@ int pcx_font_load(font *font, const char *filename, int8_t palette_offset) { // Load into textures for(int i = 0; i < pcx_font.glyph_count; i++) { - sd_vga_image_create(&img, pcx_font.glyphs[i].width, pixsize); + sd_vga_image_create(&img, pcx_font.glyphs[i].width, pixsize, PCX_FONT_TRANSPARENT_INDEX); sur = omf_calloc(1, sizeof(surface)); - pcx_font_decode(&pcx_font, &img, i, 1); - surface_create_from_vga(sur, &img); - surface_set_transparency(sur, 0); + pcx_font_decode(&pcx_font, &img, i, 1, PCX_FONT_TRANSPARENT_INDEX); + surface_create_from_vga(sur, &img, PCX_FONT_TRANSPARENT_INDEX); vector_append(&font->surfaces, &sur); sd_vga_image_free(&img); } diff --git a/src/resources/sprite.c b/src/resources/sprite.c index 5391dfafd..9747131db 100644 --- a/src/resources/sprite.c +++ b/src/resources/sprite.c @@ -19,7 +19,7 @@ void sprite_create(sprite *sp, void *src, int id) { // Load data sd_vga_image raw; sd_sprite_vga_decode(&raw, sdsprite); - surface_create_from_data(sp->data, raw.w, raw.h, (unsigned char *)raw.data); + surface_create_from_data(sp->data, raw.w, raw.h, (unsigned char *)raw.data, raw.transparent); sd_vga_image_free(&raw); } diff --git a/src/resources/sprite.h b/src/resources/sprite.h index d49a09501..501319c26 100644 --- a/src/resources/sprite.h +++ b/src/resources/sprite.h @@ -9,6 +9,7 @@ typedef struct sprite_t { vec2i pos; surface *data; bool owned; // if we own the surface data + int transparent; } sprite; void sprite_create(sprite *sp, void *src, int id); diff --git a/src/utils/allocator.h b/src/utils/allocator.h index 7d1184650..6c20a4373 100644 --- a/src/utils/allocator.h +++ b/src/utils/allocator.h @@ -8,8 +8,13 @@ extern const char *_text_realloc_error; // Add ifdefs here to include platform-specific allocators. #include "utils/allocator_default.h" +#ifdef N64_BUILD +void free(void *x); +#endif + #define omf_malloc(size) omf_malloc_real((size), __FILE__, __LINE__) #define omf_calloc(nmemb, size) omf_calloc_real((nmemb), (size), __FILE__, __LINE__) #define omf_realloc(ptr, size) omf_realloc_real((ptr), (size), __FILE__, __LINE__) - +#define omf_alloc_with_options(nmemb, size, options) \ + omf_alloc_with_options_real((nmemb), (size), (options), __FILE__, __LINE__) #endif // ALLOCATOR_H diff --git a/src/utils/allocator_default.h b/src/utils/allocator_default.h index 4ae945e3c..de3fad369 100644 --- a/src/utils/allocator_default.h +++ b/src/utils/allocator_default.h @@ -1,10 +1,14 @@ #ifndef ALLOCATOR_DEFAULT_H #define ALLOCATOR_DEFAULT_H +#include #include #include #include +// Allocator options +#define ALLOC_HINT_TEXTURE 0x00000001 + #define omf_free(ptr) \ do { \ free(ptr); \ @@ -35,4 +39,35 @@ static inline void *omf_realloc_real(void *ptr, size_t size, const char *file, i abort(); } +static inline void *omf_alloc_with_options_real(size_t nmemb, size_t size, int options, const char *file, int line) { + void *ret = NULL; + if((options & ALLOC_HINT_TEXTURE) != 0) { +#ifdef N64_BUILD + assertf(size != 0, "texture size was 0"); + ret = malloc_uncached_aligned(64, size); +#else + ret = malloc(nmemb * size); +#endif + } else { + assert(false); // Unknown/unhandled option. + } + + if(ret != NULL) + return ret; + fprintf(stderr, _text_calloc_error, nmemb, size, file, line); + abort(); +} + +static inline void omf_free_with_options(void *ptr, int options) { + if((options & ALLOC_HINT_TEXTURE) != 0) { +#ifdef N64_BUILD + free_uncached(ptr); +#else + omf_free(ptr); +#endif + } else { + assert(false); + } +} + #endif // ALLOCATOR_DEFAULT_H diff --git a/src/utils/png_writer.c b/src/utils/png_writer.c index 8bda22300..5eeb102d9 100644 --- a/src/utils/png_writer.c +++ b/src/utils/png_writer.c @@ -1,10 +1,15 @@ #include "utils/png_writer.h" #include "utils/log.h" #include +#if !defined(MIN_BUILD) #include +#endif #include bool png_write_rgb(const char *filename, int w, int h, const unsigned char *data, bool has_alpha, bool flip) { +#if defined(MIN_BUILD) + return false; +#else FILE *fp = fopen(filename, "wb"); if(fp == NULL) { PERROR("Unable to write PNG file: Could not open file for writing"); @@ -32,9 +37,13 @@ bool png_write_rgb(const char *filename, int w, int h, const unsigned char *data png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp); return true; +#endif } bool png_write_paletted(const char *filename, int w, int h, const vga_palette *pal, const unsigned char *data) { +#if defined(MIN_BUILD) + return true; +#else assert(filename != NULL); assert(data != NULL); assert(w * h > 0); @@ -55,4 +64,5 @@ bool png_write_paletted(const char *filename, int w, int h, const vga_palette *p return false; } return true; +#endif } diff --git a/src/video/surface.c b/src/video/surface.c index 660ea64a3..5d9a60ce4 100644 --- a/src/video/surface.c +++ b/src/video/surface.c @@ -2,47 +2,49 @@ #include "utils/allocator.h" #include "utils/miscmath.h" #include "utils/png_writer.h" +#include #include // Each surface is tagged with a unique key. This is then used for texture atlas. // This keeps track of the last index used. static unsigned int guid = 0; -void surface_create(surface *sur, int w, int h) { - sur->data = omf_calloc(1, w * h); +void surface_create(surface *sur, int w, int h, int transparent) { + sur->video_allocated = false; + sur->data = omf_alloc_with_options(1, w * h, ALLOC_HINT_TEXTURE); sur->guid = guid++; sur->w = w; sur->h = h; - sur->transparent = 0; + sur->transparent = transparent; + if(sur->data != NULL) { + memset(sur->data, 0, w * h); + } } -void surface_create_from_data(surface *sur, int w, int h, const unsigned char *src) { - surface_create(sur, w, h); +void surface_create_from_data(surface *sur, int w, int h, const unsigned char *src, int transparent) { + surface_create(sur, w, h, transparent); memcpy(sur->data, src, w * h); } -void surface_create_from_data_flip(surface *sur, int w, int h, const unsigned char *src) { - surface_create(sur, w, h); +void surface_create_from_data_flip(surface *sur, int w, int h, const unsigned char *src, int transparent) { + surface_create(sur, w, h, transparent); for(int y = 0; y < h; y++) { memcpy(sur->data + (h - y - 1) * w, src + y * w, w); } } -void surface_create_from_vga(surface *sur, const sd_vga_image *src) { - surface_create(sur, src->w, src->h); +void surface_create_from_vga(surface *sur, const sd_vga_image *src, int transparent) { + surface_create(sur, src->w, src->h, transparent); memcpy(sur->data, src->data, src->w * src->h); - sur->transparent = -1; } void surface_create_from_surface(surface *sur, int w, int h, int src_x, int src_y, const surface *src) { - surface_create(sur, w, h); + surface_create(sur, w, h, src->transparent); surface_sub(sur, src, 0, 0, src_x, src_y, w, h, SUB_METHOD_NONE); - sur->transparent = src->transparent; } -void surface_create_from_image(surface *sur, image *img) { - surface_create_from_data(sur, img->w, img->h, img->data); - sur->transparent = -1; +void surface_create_from_image(surface *sur, image *img, int transparent) { + surface_create_from_data(sur, img->w, img->h, img->data, transparent); } int surface_to_image(const surface *sur, image *img) { @@ -52,10 +54,6 @@ int surface_to_image(const surface *sur, image *img) { return 0; } -void surface_set_transparency(surface *sur, int index) { - sur->transparent = index; -} - void surface_free(surface *sur) { omf_free(sur->data); } @@ -66,9 +64,8 @@ void surface_clear(surface *sur) { } void surface_create_from(surface *dst, const surface *src) { - surface_create(dst, src->w, src->h); + surface_create(dst, src->w, src->h, src->transparent); memcpy(dst->data, src->data, src->w * src->h); - dst->transparent = src->transparent; } // Copies a an area of old surface to an entirely new surface diff --git a/src/video/surface.h b/src/video/surface.h index 01149f65e..ed23eec01 100644 --- a/src/video/surface.h +++ b/src/video/surface.h @@ -12,6 +12,7 @@ typedef struct { int h; int transparent; unsigned char *data; + bool video_allocated; } surface; enum @@ -20,19 +21,18 @@ enum SUB_METHOD_MIRROR }; -void surface_create(surface *sur, int w, int h); +void surface_create(surface *sur, int w, int h, int transparent); void surface_create_from(surface *dst, const surface *src); -void surface_create_from_vga(surface *sur, const sd_vga_image *src); -void surface_create_from_image(surface *sur, image *img); -void surface_create_from_data(surface *sur, int w, int h, const unsigned char *src); -void surface_create_from_data_flip(surface *sur, int w, int h, const unsigned char *src); +void surface_create_from_vga(surface *sur, const sd_vga_image *src, int transparent); +void surface_create_from_image(surface *sur, image *img, int transparent); +void surface_create_from_data(surface *sur, int w, int h, const unsigned char *src, int transparent); +void surface_create_from_data_flip(surface *sur, int w, int h, const unsigned char *src, int transparent); void surface_create_from_surface(surface *sur, int w, int h, int src_x, int src_y, const surface *src); int surface_to_image(const surface *sur, image *img); void surface_free(surface *sur); void surface_clear(surface *sur); void surface_sub(surface *dst, const surface *src, int dst_x, int dst_y, int src_x, int src_y, int w, int h, int method); -void surface_set_transparency(surface *dst, int index); /** Flatten surface to a mask * diff --git a/src/video/video.c b/src/video/video.c index 35022d9b2..efe5716eb 100644 --- a/src/video/video.c +++ b/src/video/video.c @@ -2,6 +2,7 @@ #include #include +#include "formats/transparent.h" #include "utils/allocator.h" #include "utils/log.h" #include "video/opengl/object_array.h" @@ -173,8 +174,7 @@ void video_area_capture(surface *sur, int x, int y, int w, int h) { unsigned char *buffer = omf_calloc(1, w * h); glPixelStorei(GL_PACK_ALIGNMENT, 1); glReadPixels(x, y, w, h, GL_RED, GL_UNSIGNED_BYTE, buffer); - surface_create_from_data_flip(sur, w, h, buffer); - surface_set_transparency(sur, -1); + surface_create_from_data_flip(sur, w, h, buffer, BACKGROUND_TRANSPARENT_INDEX); omf_free(buffer); }