Skip to content

Commit 4bcaa89

Browse files
committed
Add transparent index and optimize font rendering with shadows.
1 parent dea58c0 commit 4bcaa89

File tree

24 files changed

+184
-53
lines changed

24 files changed

+184
-53
lines changed

src/formats/bk.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "formats/internal/writer.h"
1111
#include "formats/palette.h"
1212
#include "formats/pcx.h"
13+
#include "formats/transparent.h"
1314
#include "formats/vga_image.h"
1415
#include "utils/allocator.h"
1516

src/formats/fonts.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "formats/fonts.h"
55
#include "formats/internal/reader.h"
66
#include "formats/internal/writer.h"
7+
#include <assert.h>
78

89
int sd_font_create(sd_font *font) {
910
if(font == NULL) {
@@ -57,18 +58,20 @@ int sd_font_save(const sd_font *font, const char *file) {
5758
return SD_SUCCESS;
5859
}
5960

60-
int sd_font_decode(const sd_font *font, sd_vga_image *o, uint8_t ch, uint8_t color) {
61+
int sd_font_decode(const sd_font *font, sd_vga_image *o, uint8_t ch, uint8_t color, int transparent) {
6162
if(font == NULL || o == NULL || ch >= 224) {
6263
return SD_INVALID_INPUT;
6364
}
6465

66+
assert((transparent >= 0) && (transparent < 256));
67+
6568
int t = 0;
6669
for(unsigned i = 0; i < font->h; i++) {
6770
for(int k = font->h - 1; k >= 0; k--) {
6871
if(font->chars[ch].data[i] & (1 << k)) {
6972
o->data[t] = color;
7073
} else {
71-
o->data[t] = 0;
74+
o->data[t] = (char)transparent;
7275
}
7376
t++;
7477
}

src/formats/fonts.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ int sd_font_save(const sd_font *font, const char *filename);
9393
* \param ch Character to load. Must be 0 <= ch <= 224.
9494
* \param color Color palette index (0 - 0xFF)
9595
*/
96-
int sd_font_decode(const sd_font *font, sd_vga_image *surface, uint8_t ch, uint8_t color);
96+
int sd_font_decode(const sd_font *font, sd_vga_image *surface, uint8_t ch, uint8_t color, int transparent);
9797

9898
/**
9999
* Same as sd_font_decode, but decodes to an RGBA surface.

src/formats/pcx.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
#include "formats/pcx.h"
22
#include "formats/error.h"
33
#include "formats/internal/reader.h"
4+
#include "formats/transparent.h"
45
#include "utils/allocator.h"
6+
#include <assert.h>
57
#include <inttypes.h>
68
#include <stdio.h>
79
#include <string.h>
@@ -73,6 +75,7 @@ int pcx_load(pcx_file *pcx, const char *filename) {
7375
return ret;
7476
}
7577

78+
pcx->image.transparent = FONT_TRANSPARENT_INDEX;
7679
for(unsigned j = 0; j < 200; ++j) {
7780
for(unsigned i = 0; i < 320;) {
7881
i += decode_next_bytes(&(pcx->image.data)[(320 * j) + i], reader);
@@ -141,19 +144,22 @@ int pcx_load_font(pcx_font *font, const char *filename) {
141144
return SD_SUCCESS;
142145
}
143146

144-
int pcx_font_decode(const pcx_font *font, sd_vga_image *o, uint8_t ch, int8_t palette_offset) {
147+
int pcx_font_decode(const pcx_font *font, sd_vga_image *o, uint8_t ch, int8_t palette_offset, int transparent) {
145148
if(ch >= font->glyph_count || font == NULL || o == NULL) {
146149
return SD_INVALID_INPUT;
147150
}
148151

152+
// Fonts always need to have a transparent value.
153+
assert((transparent >= 0) && (transparent < 256));
154+
149155
int k = 0;
150156
for(int i = font->glyphs[ch].y; i < font->glyphs[ch].y + font->glyph_height; i++) {
151157
int l = 0;
152158
for(int j = font->glyphs[ch].x; j < font->glyphs[ch].x + font->glyphs[ch].width; j++) {
153159
if(font->pcx.image.data[(i * 320) + j]) {
154160
o->data[(k * font->glyphs[ch].width) + l] = palette_offset + (int)font->pcx.image.data[(i * 320) + j];
155161
} else {
156-
o->data[(k * font->glyphs[ch].width) + l] = 0;
162+
o->data[(k * font->glyphs[ch].width) + l] = transparent;
157163
}
158164

159165
l++;

src/formats/pcx.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ typedef struct {
4949

5050
int pcx_load(pcx_file *pcx, const char *filename);
5151
int pcx_load_font(pcx_font *font, const char *filename);
52-
int pcx_font_decode(const pcx_font *font, sd_vga_image *o, uint8_t ch, int8_t palette_offset);
52+
int pcx_font_decode(const pcx_font *font, sd_vga_image *o, uint8_t ch, int8_t palette_offset, int transparent);
5353
void pcx_free(pcx_file *pcx);
5454
void pcx_font_free(pcx_font *font);
5555

src/formats/sprite.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "formats/error.h"
55
#include "formats/palette.h"
66
#include "formats/sprite.h"
7+
#include "formats/transparent.h"
78
#include "utils/allocator.h"
89

910
int sd_sprite_create(sd_sprite *sprite) {
@@ -271,6 +272,7 @@ int sd_sprite_vga_decode(sd_vga_image *dst, const sd_sprite *src) {
271272
uint16_t c = 0;
272273
uint16_t data = 0;
273274
char op = 0;
275+
int transparent = SPRITE_TRANSPARENT_INDEX;
274276

275277
// Make sure we aren't being fed BS
276278
if(dst == NULL || src == NULL) {
@@ -284,6 +286,8 @@ int sd_sprite_vga_decode(sd_vga_image *dst, const sd_sprite *src) {
284286
sd_vga_image_create(dst, 1, 1);
285287
}
286288

289+
dst->transparent = SPRITE_TRANSPARENT_INDEX;
290+
287291
// XXX CREDITS.BK has a bunch of 0 width sprites, for some unknown reason
288292
if(src->width == 0 || src->height == 0 || src->len == 0) {
289293
return SD_SUCCESS;
@@ -310,6 +314,7 @@ int sd_sprite_vga_decode(sd_vga_image *dst, const sd_sprite *src) {
310314
uint8_t b = src->data[i];
311315
int pos = ((y * src->width) + x);
312316
dst->data[pos] = b;
317+
assert(b != transparent);
313318
i++; // we read 1 byte
314319
x++;
315320
data--;
@@ -324,6 +329,8 @@ int sd_sprite_vga_decode(sd_vga_image *dst, const sd_sprite *src) {
324329
}
325330
}
326331

332+
dst->transparent = transparent;
333+
327334
// All done. dst should now contain a valid vga image.
328335
return SD_SUCCESS;
329336
}

src/formats/transparent.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*! \file
2+
* \brief Transparent VGA pixel values
3+
* \details Describes the transparancy index value for various engine components.
4+
* \copyright MIT license.
5+
* \date 2024
6+
* \author Andrew Thompson
7+
* \author Tuomas Virtanen
8+
*/
9+
10+
#ifndef TRANSPARENT_H
11+
#define TRANSPARENT_H
12+
13+
// Default's.
14+
// Please do not use the default definitions in the code directly. Define a new value below instead.
15+
// This way all different transparency values are stored in one place.
16+
#define DEFAULT_TRANSPARENT_INDEX 0
17+
#define DEFAULT_NOT_TRANSPARENT -1
18+
19+
// All sprites have holes, these holes need to be transparent.
20+
#define SPRITE_TRANSPARENT_INDEX DEFAULT_TRANSPARENT_INDEX
21+
22+
// Backgrounds have no transparent pixels and need all pixels to be rendered.
23+
#define BACKGROUND_TRANSPARENT_INDEX DEFAULT_NOT_TRANSPARENT
24+
25+
// Force an opaque menu for now.
26+
#define MENU_TRANSPARENT_INDEX DEFAULT_NOT_TRANSPARENT
27+
28+
// Portraits have a transparancy index that needs to offset past other items in the global palette.
29+
// TODO: Should really become default.
30+
#define PORTRAIT_TRANSPARENT_INDEX 0xD0
31+
32+
// Portrait highlights need a special offset for transparency to not conflict with other entries in the global palette.
33+
// TODO: Should really become default.
34+
#define HIGHLIGHT_TRANSPARENT_INDEX 90
35+
36+
// Fonts need a transparent index that does not conflict with the lower 8 colors on the N64 otherwise there will be a
37+
// combinatorial explosion.
38+
#define FONT_TRANSPARENT_INDEX DEFAULT_TRANSPARENT_INDEX
39+
#define PCX_FONT_TRANSPARENT_INDEX DEFAULT_TRANSPARENT_INDEX
40+
41+
// Gauges in the player select have an opaque background and are not transparent.
42+
#define GAUGE_TRANSPARENT_INDEX DEFAULT_NOT_TRANSPARENT
43+
44+
#endif

src/formats/vga_image.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
1+
#if !defined(N64_BUILD) && !defined(MIN_BUILD)
12
#include <png.h>
3+
#endif
24
#include <stdint.h>
35
#include <stdio.h>
46
#include <stdlib.h>
57
#include <string.h>
8+
#ifdef N64_BUILD
9+
#include <libdragon.h>
10+
#else
11+
#include <assert.h>
12+
#endif
613

714
#include "formats/error.h"
15+
#include "formats/transparent.h"
816
#include "formats/vga_image.h"
917
#include "utils/allocator.h"
1018
#include "utils/png_writer.h"
@@ -16,7 +24,15 @@ int sd_vga_image_create(sd_vga_image *img, unsigned int w, unsigned int h) {
1624
img->w = w;
1725
img->h = h;
1826
img->len = w * h;
27+
img->transparent = BACKGROUND_TRANSPARENT_INDEX;
28+
#ifdef N64_BUILD
29+
assertf(w <= 320 && h <= 240, "w:%X h:%X", w, h);
30+
img->data = malloc_uncached_aligned(64, w * h);
31+
assert(img->data != NULL);
32+
memset(img->data, 0, w * h);
33+
#else
1934
img->data = omf_calloc(1, w * h);
35+
#endif
2036
return SD_SUCCESS;
2137
}
2238

@@ -28,6 +44,7 @@ int sd_vga_image_copy(sd_vga_image *dst, const sd_vga_image *src) {
2844
dst->h = src->h;
2945
dst->len = src->len;
3046
dst->data = omf_calloc(src->len, 1);
47+
dst->transparent = src->transparent;
3148
memcpy(dst->data, src->data, src->len);
3249
return SD_SUCCESS;
3350
}
@@ -36,7 +53,11 @@ void sd_vga_image_free(sd_vga_image *img) {
3653
if(img == NULL) {
3754
return;
3855
}
56+
#ifdef N64_BUILD
57+
free_uncached(img->data);
58+
#else
3959
omf_free(img->data);
60+
#endif
4061
}
4162

4263
int sd_vga_image_decode(sd_rgba_image *dst, const sd_vga_image *src, const vga_palette *pal) {
@@ -62,6 +83,7 @@ int sd_vga_image_decode(sd_rgba_image *dst, const sd_vga_image *src, const vga_p
6283
}
6384

6485
int sd_vga_image_from_png(sd_vga_image *img, const char *filename) {
86+
#if !defined(N64_BUILD) && !defined(MIN_BUILD)
6587
png_structp png_ptr;
6688
png_infop info_ptr;
6789
int ret = SD_SUCCESS;
@@ -159,14 +181,21 @@ int sd_vga_image_from_png(sd_vga_image *img, const char *filename) {
159181
fclose(handle);
160182
error_0:
161183
return ret;
184+
#else
185+
return 0;
186+
#endif
162187
}
163188

164189
int sd_vga_image_to_png(const sd_vga_image *img, const vga_palette *pal, const char *filename) {
190+
#if !defined(N64_BUILD) && !defined(MIN_BUILD)
165191
if(img == NULL || filename == NULL) {
166192
return SD_INVALID_INPUT;
167193
}
168194
if(!png_write_paletted(filename, img->w, img->h, pal, (unsigned char *)img->data)) {
169195
return SD_FILE_OPEN_ERROR;
170196
}
171197
return SD_SUCCESS;
198+
#else
199+
return 0;
200+
#endif
172201
}

src/formats/vga_image.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ typedef struct {
2727
unsigned int h; ///< Pixel height
2828
unsigned int len; ///< Byte length
2929
char *data; ///< Palette representation of image data
30+
int transparent;
3031
} sd_vga_image;
3132

3233
/*! \brief Initialize VGA image structure

src/game/gui/gauge.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "game/gui/gauge.h"
2+
#include "formats/transparent.h"
23
#include "game/gui/widget.h"
34
#include "utils/allocator.h"
45
#include "utils/miscmath.h"
@@ -74,7 +75,7 @@ typedef struct {
7475
} gauge;
7576

7677
static void surface_from_pix_img(surface *sur, const pixel_image *pix) {
77-
surface_create_from_data(sur, pix->width, pix->height, pix->data);
78+
surface_create_from_data(sur, pix->width, pix->height, pix->data, GAUGE_TRANSPARENT_INDEX);
7879
}
7980

8081
static void gauge_render(component *c) {

0 commit comments

Comments
 (0)