Skip to content

Commit

Permalink
Add transparent index and optimize font rendering with shadows.
Browse files Browse the repository at this point in the history
  • Loading branch information
nopjne committed Nov 17, 2024
1 parent 96fdc35 commit 780bf67
Show file tree
Hide file tree
Showing 27 changed files with 223 additions and 72 deletions.
6 changes: 6 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion src/formats/bk.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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;
Expand Down
7 changes: 5 additions & 2 deletions src/formats/fonts.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "formats/fonts.h"
#include "formats/internal/reader.h"
#include "formats/internal/writer.h"
#include <assert.h>

int sd_font_create(sd_font *font) {
if(font == NULL) {
Expand Down Expand Up @@ -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++;
}
Expand Down
2 changes: 1 addition & 1 deletion src/formats/fonts.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
11 changes: 8 additions & 3 deletions src/formats/pcx.c
Original file line number Diff line number Diff line change
@@ -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 <assert.h>
#include <inttypes.h>
#include <stdio.h>
#include <string.h>
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -141,19 +143,22 @@ 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;
for(int j = font->glyphs[ch].x; j < font->glyphs[ch].x + font->glyphs[ch].width; j++) {
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++;
Expand Down
2 changes: 1 addition & 1 deletion src/formats/pcx.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
9 changes: 7 additions & 2 deletions src/formats/sprite.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand All @@ -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
Expand Down Expand Up @@ -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--;
Expand All @@ -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;
}
Expand Down
44 changes: 44 additions & 0 deletions src/formats/transparent.h
Original file line number Diff line number Diff line change
@@ -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
21 changes: 16 additions & 5 deletions src/formats/vga_image.c
Original file line number Diff line number Diff line change
@@ -1,22 +1,28 @@
#if !defined(MIN_BUILD)
#include <png.h>
#endif
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#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;
}

Expand All @@ -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;
}
Expand All @@ -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) {
Expand All @@ -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;
Expand Down Expand Up @@ -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;
}
Expand All @@ -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) {
Expand Down
3 changes: 2 additions & 1 deletion src/formats/vga_image.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
*
Expand Down
3 changes: 2 additions & 1 deletion src/game/gui/gauge.c
Original file line number Diff line number Diff line change
@@ -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"
Expand Down Expand Up @@ -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) {
Expand Down
12 changes: 5 additions & 7 deletions src/game/gui/menu_background.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "game/gui/menu_background.h"
#include "formats/transparent.h"
#include "video/image.h"

#define COLOR_MENU_LINE 252
Expand All @@ -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) {
Expand All @@ -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);
}

Expand All @@ -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);
}

Expand All @@ -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);
}
Loading

0 comments on commit 780bf67

Please sign in to comment.