Allow font atlases to be non-square

Saves a little memory in some cases. It's the backend's job to decide
if this is a problem or not, and pad it if it has to.
This commit is contained in:
Clownacy 2020-09-14 12:07:52 +01:00
parent 17da39fa14
commit daa55b1a3c
7 changed files with 28 additions and 26 deletions

View file

@ -24,7 +24,7 @@ unsigned char* RenderBackend_LockSurface(RenderBackend_Surface *surface, size_t
void RenderBackend_UnlockSurface(RenderBackend_Surface *surface, size_t width, size_t height);
void RenderBackend_Blit(RenderBackend_Surface *source_surface, const RenderBackend_Rect *rect, RenderBackend_Surface *destination_surface, long x, long y, bool colour_key);
void RenderBackend_ColourFill(RenderBackend_Surface *surface, const RenderBackend_Rect *rect, unsigned char red, unsigned char green, unsigned char blue);
RenderBackend_GlyphAtlas* RenderBackend_CreateGlyphAtlas(size_t size);
RenderBackend_GlyphAtlas* RenderBackend_CreateGlyphAtlas(size_t width, size_t height);
void RenderBackend_DestroyGlyphAtlas(RenderBackend_GlyphAtlas *atlas);
void RenderBackend_UploadGlyph(RenderBackend_GlyphAtlas *atlas, size_t x, size_t y, const unsigned char *pixels, size_t width, size_t height);
void RenderBackend_PrepareToDrawGlyphs(RenderBackend_GlyphAtlas *atlas, RenderBackend_Surface *destination_surface, unsigned char red, unsigned char green, unsigned char blue);

View file

@ -40,7 +40,8 @@ typedef struct RenderBackend_Surface
typedef struct RenderBackend_GlyphAtlas
{
GLuint texture_id;
size_t size;
size_t width;
size_t height;
} RenderBackend_GlyphAtlas;
typedef struct Coordinate2D
@ -866,21 +867,22 @@ void RenderBackend_ColourFill(RenderBackend_Surface *surface, const RenderBacken
// Glyph management //
//////////////////////
RenderBackend_GlyphAtlas* RenderBackend_CreateGlyphAtlas(size_t size)
RenderBackend_GlyphAtlas* RenderBackend_CreateGlyphAtlas(size_t width, size_t height)
{
RenderBackend_GlyphAtlas *atlas = (RenderBackend_GlyphAtlas*)malloc(sizeof(RenderBackend_GlyphAtlas));
if (atlas != NULL)
{
atlas->size = size;
atlas->width = width;
atlas->height = height;
glGenTextures(1, &atlas->texture_id);
glBindTexture(GL_TEXTURE_2D, atlas->texture_id);
#ifdef USE_OPENGLES2
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, size, size, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL);
#else
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, size, size, 0, GL_RED, GL_UNSIGNED_BYTE, NULL);
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, NULL);
#endif
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
@ -986,10 +988,10 @@ void RenderBackend_DrawGlyph(RenderBackend_GlyphAtlas *atlas, long x, long y, si
vertex_buffer_slot->vertices[1][2].position.x = vertex_left;
vertex_buffer_slot->vertices[1][2].position.y = vertex_bottom;
const GLfloat texture_left = glyph_x / (GLfloat)atlas->size;
const GLfloat texture_top = glyph_y / (GLfloat)atlas->size;
const GLfloat texture_right = (glyph_x + glyph_width) / (GLfloat)atlas->size;
const GLfloat texture_bottom = (glyph_y + glyph_height) / (GLfloat)atlas->size;
const GLfloat texture_left = glyph_x / (GLfloat)atlas->width;
const GLfloat texture_top = glyph_y / (GLfloat)atlas->height;
const GLfloat texture_right = (glyph_x + glyph_width) / (GLfloat)atlas->width;
const GLfloat texture_bottom = (glyph_y + glyph_height) / (GLfloat)atlas->height;
vertex_buffer_slot->vertices[0][0].texture.x = texture_left;
vertex_buffer_slot->vertices[0][0].texture.y = texture_top;

View file

@ -197,13 +197,13 @@ void RenderBackend_ColourFill(RenderBackend_Surface *surface, const RenderBacken
Backend_PrintError("Couldn't fill rectangle with color: %s", SDL_GetError());
}
RenderBackend_GlyphAtlas* RenderBackend_CreateGlyphAtlas(size_t size)
RenderBackend_GlyphAtlas* RenderBackend_CreateGlyphAtlas(size_t width, size_t height)
{
RenderBackend_GlyphAtlas *atlas = (RenderBackend_GlyphAtlas*)malloc(sizeof(RenderBackend_GlyphAtlas));
if (atlas != NULL)
{
atlas->sdlsurface = SDL_CreateRGBSurfaceWithFormat(0, size, size, 0, SDL_PIXELFORMAT_RGBA32);
atlas->sdlsurface = SDL_CreateRGBSurfaceWithFormat(0, width, height, 0, SDL_PIXELFORMAT_RGBA32);
if (atlas->sdlsurface != NULL)
{

View file

@ -335,13 +335,13 @@ void RenderBackend_ColourFill(RenderBackend_Surface *surface, const RenderBacken
Backend_PrintError("Couldn't enable alpha blending for drawing operations: %s", SDL_GetError());
}
RenderBackend_GlyphAtlas* RenderBackend_CreateGlyphAtlas(size_t size)
RenderBackend_GlyphAtlas* RenderBackend_CreateGlyphAtlas(size_t width, size_t height)
{
RenderBackend_GlyphAtlas *atlas = (RenderBackend_GlyphAtlas*)malloc(sizeof(RenderBackend_GlyphAtlas));
if (atlas != NULL)
{
atlas->texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STATIC, size, size);
atlas->texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STATIC, width, height);
if (atlas->texture != NULL)
{

View file

@ -22,7 +22,8 @@ typedef struct RenderBackend_Surface
typedef struct RenderBackend_GlyphAtlas
{
unsigned char *pixels;
size_t size;
size_t width;
size_t height;
} RenderBackend_GlyphAtlas;
static RenderBackend_Surface framebuffer;
@ -258,17 +259,18 @@ ATTRIBUTE_HOT void RenderBackend_ColourFill(RenderBackend_Surface *surface, cons
}
}
RenderBackend_GlyphAtlas* RenderBackend_CreateGlyphAtlas(size_t size)
RenderBackend_GlyphAtlas* RenderBackend_CreateGlyphAtlas(size_t width, size_t height)
{
RenderBackend_GlyphAtlas *atlas = (RenderBackend_GlyphAtlas*)malloc(sizeof(RenderBackend_GlyphAtlas));
if (atlas != NULL)
{
atlas->pixels = (unsigned char*)malloc(size * size);
atlas->pixels = (unsigned char*)malloc(width * height);
if (atlas->pixels != NULL)
{
atlas->size = size;
atlas->width = width;
atlas->height = height;
return atlas;
}
@ -288,7 +290,7 @@ void RenderBackend_DestroyGlyphAtlas(RenderBackend_GlyphAtlas *atlas)
void RenderBackend_UploadGlyph(RenderBackend_GlyphAtlas *atlas, size_t x, size_t y, const unsigned char *pixels, size_t width, size_t height)
{
for (size_t i = 0; i < height; ++i)
memcpy(&atlas->pixels[(y + i) * atlas->size + x], &pixels[i * width], width);
memcpy(&atlas->pixels[(y + i) * atlas->width + x], &pixels[i * width], width);
}
void RenderBackend_PrepareToDrawGlyphs(RenderBackend_GlyphAtlas *atlas, RenderBackend_Surface *destination_surface, unsigned char red, unsigned char green, unsigned char blue)
@ -311,7 +313,7 @@ void RenderBackend_DrawGlyph(RenderBackend_GlyphAtlas *atlas, long x, long y, si
{
for (unsigned int ix = MAX(-x, 0); x + ix < MIN(x + glyph_width, glyph_destination_surface->width); ++ix)
{
const unsigned char alpha_int = atlas->pixels[(glyph_y + iy) * atlas->size + (glyph_x + ix)];
const unsigned char alpha_int = atlas->pixels[(glyph_y + iy) * atlas->width + (glyph_x + ix)];
if (alpha_int != 0)
{

View file

@ -722,7 +722,7 @@ void RenderBackend_ColourFill(RenderBackend_Surface *surface, const RenderBacken
}
}
RenderBackend_GlyphAtlas* RenderBackend_CreateGlyphAtlas(size_t size)
RenderBackend_GlyphAtlas* RenderBackend_CreateGlyphAtlas(size_t width, size_t height)
{
RenderBackend_GlyphAtlas *atlas = (RenderBackend_GlyphAtlas*)malloc(sizeof(RenderBackend_GlyphAtlas));
@ -730,8 +730,8 @@ RenderBackend_GlyphAtlas* RenderBackend_CreateGlyphAtlas(size_t size)
{
// Initialise texture
memset(&atlas->texture, 0, sizeof(atlas->texture));
atlas->texture.surface.width = size;
atlas->texture.surface.height = size;
atlas->texture.surface.width = width;
atlas->texture.surface.height = height;
atlas->texture.surface.format = GX2_SURFACE_FORMAT_UNORM_R8;
atlas->texture.surface.depth = 1;
atlas->texture.surface.dim = GX2_SURFACE_DIM_TEXTURE_2D;

View file

@ -12,8 +12,6 @@
#include "File.h"
#include "Backends/Rendering.h"
#define MAX(a,b) ((a) > (b) ? (a) : (b))
// Cave Story wasn't intended to use font anti-aliasing. It's only because Microsoft enabled it
// by default from Windows Vista onwards that the game started using it.
// Font anti-aliasing conflicts with the game's colour-keying, causing ugly artifacting around
@ -1087,7 +1085,7 @@ Font* LoadFontFromData(const unsigned char *data, size_t data_size, size_t cell_
font->atlas_row_length = atlas_columns;
font->atlas = RenderBackend_CreateGlyphAtlas(MAX(atlas_columns * atlas_entry_width, atlas_rows * atlas_entry_height));
font->atlas = RenderBackend_CreateGlyphAtlas(atlas_columns * atlas_entry_width, atlas_rows * atlas_entry_height);
if (font->atlas != NULL)
{