Added Backend_PrepareToDrawGlyphs

This is to reduce OpenGL context changes, and help pave the way for
glyph-batching
This commit is contained in:
Clownacy 2020-02-01 16:40:23 +00:00
parent fa8ab56e93
commit 639039ce3a
6 changed files with 93 additions and 40 deletions

View file

@ -28,6 +28,7 @@ void Backend_ColourFill(Backend_Surface *surface, const RECT *rect, unsigned cha
BOOL Backend_SupportsSubpixelGlyphs(void);
Backend_Glyph* Backend_LoadGlyph(const unsigned char *pixels, unsigned int width, unsigned int height, int pitch, FontPixelMode pixel_mode);
void Backend_UnloadGlyph(Backend_Glyph *glyph);
void Backend_DrawGlyph(Backend_Surface *surface, Backend_Glyph *glyph, long x, long y, const unsigned char *colours);
void Backend_PrepareToDrawGlyphs(Backend_Surface *destination_surface, const unsigned char *colour_channels);
void Backend_DrawGlyph(Backend_Glyph *glyph, long x, long y);
void Backend_HandleRenderTargetLoss(void);
void Backend_HandleWindowResize(void);

View file

@ -95,6 +95,9 @@ static RenderMode last_render_mode;
static Backend_Surface framebuffer;
static unsigned char glyph_colour_channels[3];
static Backend_Surface *glyph_destination_surface;
#ifdef USE_OPENGLES2
static const GLchar *vertex_shader_plain = " \
#version 100\n \
@ -976,7 +979,17 @@ void Backend_UnloadGlyph(Backend_Glyph *glyph)
free(glyph);
}
void Backend_DrawGlyph(Backend_Surface *surface, Backend_Glyph *glyph, long x, long y, const unsigned char *colours)
void Backend_PrepareToDrawGlyphs(Backend_Surface *destination_surface, const unsigned char *colour_channels)
{
if (destination_surface == NULL)
return;
glyph_destination_surface = destination_surface;
memcpy(glyph_colour_channels, colour_channels, sizeof(glyph_colour_channels));
}
void Backend_DrawGlyph(Backend_Glyph *glyph, long x, long y)
{
static Backend_Surface *last_surface;
static Backend_Glyph *last_glyph;
@ -984,36 +997,36 @@ void Backend_DrawGlyph(Backend_Surface *surface, Backend_Glyph *glyph, long x, l
static unsigned char last_green;
static unsigned char last_blue;
if (glyph == NULL || surface == NULL)
if (glyph == NULL || glyph_destination_surface == NULL)
return;
const RenderMode render_mode = (glyph->pixel_mode == FONT_PIXEL_MODE_LCD ? MODE_DRAW_GLYPH_LCD : MODE_DRAW_GLYPH);
if (last_render_mode != render_mode || last_surface != surface || last_glyph != glyph || last_red != colours[0] || last_green != colours[1] || last_blue != colours[2])
if (last_render_mode != render_mode || last_surface != glyph_destination_surface || last_glyph != glyph || last_red != glyph_colour_channels[0] || last_green != glyph_colour_channels[1] || last_blue != glyph_colour_channels[2])
{
FlushVertexBuffer();
last_render_mode = render_mode;
last_surface = surface;
last_surface = glyph_destination_surface;
last_glyph = glyph;
last_red = colours[0];
last_green = colours[1];
last_blue = colours[2];
last_red = glyph_colour_channels[0];
last_green = glyph_colour_channels[1];
last_blue = glyph_colour_channels[2];
if (glyph->pixel_mode == FONT_PIXEL_MODE_LCD)
{
glUseProgram(program_glyph_subpixel_part2);
glUniform4f(program_glyph_subpixel_part2_uniform_colour, colours[0] / 255.0f, colours[1] / 255.0f, colours[2] / 255.0f, 1.0f);
glUniform4f(program_glyph_subpixel_part2_uniform_colour, glyph_colour_channels[0] / 255.0f, glyph_colour_channels[1] / 255.0f, glyph_colour_channels[2] / 255.0f, 1.0f);
}
else
{
glUseProgram(program_glyph_normal);
glUniform4f(program_glyph_normal_uniform_colour, colours[0] / 255.0f, colours[1] / 255.0f, colours[2] / 255.0f, 1.0f);
glUniform4f(program_glyph_normal_uniform_colour, glyph_colour_channels[0] / 255.0f, glyph_colour_channels[1] / 255.0f, glyph_colour_channels[2] / 255.0f, 1.0f);
}
// Point our framebuffer to the destination texture
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, surface->texture_id, 0);
glViewport(0, 0, surface->width, surface->height);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glyph_destination_surface->texture_id, 0);
glViewport(0, 0, glyph_destination_surface->width, glyph_destination_surface->height);
glEnable(GL_BLEND);
@ -1023,10 +1036,10 @@ void Backend_DrawGlyph(Backend_Surface *surface, Backend_Glyph *glyph, long x, l
glBindTexture(GL_TEXTURE_2D, glyph->texture_id);
}
const GLfloat vertex_left = (x * (2.0f / surface->width)) - 1.0f;
const GLfloat vertex_right = ((x + glyph->width) * (2.0f / surface->width)) - 1.0f;
const GLfloat vertex_top = (y * (2.0f / surface->height)) - 1.0f;
const GLfloat vertex_bottom = ((y + glyph->height) * (2.0f / surface->height)) - 1.0f;
const GLfloat vertex_left = (x * (2.0f / glyph_destination_surface->width)) - 1.0f;
const GLfloat vertex_right = ((x + glyph->width) * (2.0f / glyph_destination_surface->width)) - 1.0f;
const GLfloat vertex_top = (y * (2.0f / glyph_destination_surface->height)) - 1.0f;
const GLfloat vertex_bottom = ((y + glyph->height) * (2.0f / glyph_destination_surface->height)) - 1.0f;
VertexBufferSlot *vertex_buffer_slot = GetVertexBufferSlot();

View file

@ -24,6 +24,9 @@ static SDL_Surface *window_sdlsurface;
static Backend_Surface framebuffer;
static unsigned char glyph_colour_channels[3];
static SDL_Surface *glyph_destination_sdlsurface;
static void RectToSDLRect(const RECT *rect, SDL_Rect *sdl_rect)
{
sdl_rect->x = (int)rect->left;
@ -243,9 +246,19 @@ void Backend_UnloadGlyph(Backend_Glyph *glyph)
free(glyph);
}
void Backend_DrawGlyph(Backend_Surface *surface, Backend_Glyph *glyph, long x, long y, const unsigned char *colours)
void Backend_PrepareToDrawGlyphs(Backend_Surface *destination_surface, const unsigned char *colour_channels)
{
if (glyph == NULL || surface == NULL)
if (destination_surface == NULL)
return;
glyph_destination_sdlsurface = destination_surface->sdlsurface;
memcpy(glyph_colour_channels, colour_channels, sizeof(glyph_colour_channels));
}
void Backend_DrawGlyph(Backend_Glyph *glyph, long x, long y)
{
if (glyph == NULL)
return;
SDL_Rect rect;
@ -254,9 +267,9 @@ void Backend_DrawGlyph(Backend_Surface *surface, Backend_Glyph *glyph, long x, l
rect.w = glyph->sdlsurface->w;
rect.h = glyph->sdlsurface->h;
SDL_SetSurfaceColorMod(glyph->sdlsurface, colours[0], colours[1], colours[2]);
SDL_SetSurfaceColorMod(glyph->sdlsurface, glyph_colour_channels[0], glyph_colour_channels[1], glyph_colour_channels[2]);
SDL_BlitSurface(glyph->sdlsurface, NULL, surface->sdlsurface, &rect);
SDL_BlitSurface(glyph->sdlsurface, NULL, glyph_destination_sdlsurface, &rect);
}
void Backend_HandleRenderTargetLoss(void)

View file

@ -42,6 +42,8 @@ static Backend_Surface framebuffer;
static Backend_Surface *surface_list_head;
static unsigned char glyph_colour_channels[3];
static void RectToSDLRect(const RECT *rect, SDL_Rect *sdl_rect)
{
sdl_rect->x = (int)rect->left;
@ -376,20 +378,29 @@ void Backend_UnloadGlyph(Backend_Glyph *glyph)
free(glyph);
}
void Backend_DrawGlyph(Backend_Surface *surface, Backend_Glyph *glyph, long x, long y, const unsigned char *colours)
void Backend_PrepareToDrawGlyphs(Backend_Surface *destination_surface, const unsigned char *colour_channels)
{
if (destination_surface == NULL)
return;
SDL_SetRenderTarget(renderer, destination_surface->texture);
memcpy(glyph_colour_channels, colour_channels, sizeof(glyph_colour_channels));
}
void Backend_DrawGlyph(Backend_Glyph *glyph, long x, long y)
{
// The SDL_Texture side of things uses alpha, not a colour-key, so the bug where the font is blended
// with the colour key doesn't occur.
if (glyph == NULL || surface == NULL)
if (glyph == NULL)
return;
SDL_Rect destination_rect = {(int)x, (int)y, (int)glyph->width, (int)glyph->height};
// Blit the texture
SDL_SetTextureColorMod(glyph->texture, colours[0], colours[1], colours[2]);
SDL_SetTextureColorMod(glyph->texture, glyph_colour_channels[0], glyph_colour_channels[1], glyph_colour_channels[2]);
SDL_SetTextureBlendMode(glyph->texture, SDL_BLENDMODE_BLEND);
SDL_SetRenderTarget(renderer, surface->texture);
SDL_RenderCopy(renderer, glyph->texture, NULL, &destination_rect);
}

View file

@ -34,6 +34,9 @@ static SDL_Surface *window_sdlsurface;
static SDL_Surface *framebuffer_sdlsurface;
static Backend_Surface framebuffer;
static unsigned char glyph_colour_channels[3];
static Backend_Surface *glyph_destination_surface;
Backend_Surface* Backend_Init(const char *title, int width, int height, BOOL fullscreen)
{
window = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, 0);
@ -371,28 +374,38 @@ void Backend_UnloadGlyph(Backend_Glyph *glyph)
free(glyph);
}
void Backend_DrawGlyph(Backend_Surface *surface, Backend_Glyph *glyph, long x, long y, const unsigned char *colours)
void Backend_PrepareToDrawGlyphs(Backend_Surface *destination_surface, const unsigned char *colour_channels)
{
if (glyph == NULL || surface == NULL)
if (destination_surface == NULL)
return;
glyph_destination_surface = destination_surface;
memcpy(glyph_colour_channels, colour_channels, sizeof(glyph_colour_channels));
}
void Backend_DrawGlyph(Backend_Glyph *glyph, long x, long y)
{
if (glyph == NULL)
return;
switch (glyph->pixel_mode)
{
case FONT_PIXEL_MODE_LCD:
for (unsigned int iy = MAX(-y, 0); y + iy < MIN(y + glyph->height, surface->height); ++iy)
for (unsigned int iy = MAX(-y, 0); y + iy < MIN(y + glyph->height, glyph_destination_surface->height); ++iy)
{
for (unsigned int ix = MAX(-x, 0); x + ix < MIN(x + glyph->width, surface->width); ++ix)
for (unsigned int ix = MAX(-x, 0); x + ix < MIN(x + glyph->width, glyph_destination_surface->width); ++ix)
{
const float *font_pixel = (float*)glyph->pixels + (iy * glyph->width + ix) * 3;
if (font_pixel[0] || font_pixel[1] || font_pixel[2])
{
unsigned char *bitmap_pixel = surface->pixels + (y + iy) * surface->pitch + (x + ix) * 3;
unsigned char *bitmap_pixel = glyph_destination_surface->pixels + (y + iy) * glyph_destination_surface->pitch + (x + ix) * 3;
for (unsigned int j = 0; j < 3; ++j)
{
const float alpha = font_pixel[j];
bitmap_pixel[j] = (unsigned char)((colours[j] * alpha) + (bitmap_pixel[j] * (1.0f - alpha))); // Alpha blending
bitmap_pixel[j] = (unsigned char)((glyph_colour_channels[j] * alpha) + (bitmap_pixel[j] * (1.0f - alpha))); // Alpha blending
}
}
}
@ -401,18 +414,18 @@ void Backend_DrawGlyph(Backend_Surface *surface, Backend_Glyph *glyph, long x, l
break;
case FONT_PIXEL_MODE_GRAY:
for (unsigned int iy = MAX(-y, 0); y + iy < MIN(y + glyph->height, surface->height); ++iy)
for (unsigned int iy = MAX(-y, 0); y + iy < MIN(y + glyph->height, glyph_destination_surface->height); ++iy)
{
for (unsigned int ix = MAX(-x, 0); x + ix < MIN(x + glyph->width, surface->width); ++ix)
for (unsigned int ix = MAX(-x, 0); x + ix < MIN(x + glyph->width, glyph_destination_surface->width); ++ix)
{
const float alpha = ((float*)glyph->pixels)[iy * glyph->width + ix];
if (alpha)
{
unsigned char *bitmap_pixel = surface->pixels + (y + iy) * surface->pitch + (x + ix) * 3;
unsigned char *bitmap_pixel = glyph_destination_surface->pixels + (y + iy) * glyph_destination_surface->pitch + (x + ix) * 3;
for (unsigned int j = 0; j < 3; ++j)
bitmap_pixel[j] = (unsigned char)((colours[j] * alpha) + (bitmap_pixel[j] * (1.0f - alpha))); // Alpha blending
bitmap_pixel[j] = (unsigned char)((glyph_colour_channels[j] * alpha) + (bitmap_pixel[j] * (1.0f - alpha))); // Alpha blending
}
}
}
@ -420,16 +433,16 @@ void Backend_DrawGlyph(Backend_Surface *surface, Backend_Glyph *glyph, long x, l
break;
case FONT_PIXEL_MODE_MONO:
for (unsigned int iy = MAX(-y, 0); y + iy < MIN(y + glyph->height, surface->height); ++iy)
for (unsigned int iy = MAX(-y, 0); y + iy < MIN(y + glyph->height, glyph_destination_surface->height); ++iy)
{
for (unsigned int ix = MAX(-x, 0); x + ix < MIN(x + glyph->width, surface->width); ++ix)
for (unsigned int ix = MAX(-x, 0); x + ix < MIN(x + glyph->width, glyph_destination_surface->width); ++ix)
{
if (((unsigned char*)glyph->pixels)[iy * glyph->width + ix])
{
unsigned char *bitmap_pixel = surface->pixels + (y + iy) * surface->pitch + (x + ix) * 3;
unsigned char *bitmap_pixel = glyph_destination_surface->pixels + (y + iy) * glyph_destination_surface->pitch + (x + ix) * 3;
for (unsigned int j = 0; j < 3; ++j)
bitmap_pixel[j] = colours[j];
bitmap_pixel[j] = glyph_colour_channels[j];
}
}
}

View file

@ -1114,7 +1114,9 @@ void DrawText(FontObject *font_object, Backend_Surface *surface, int x, int y, u
{
if (font_object != NULL)
{
const unsigned char colours[3] = {(unsigned char)colour, (unsigned char)(colour >> 8), (unsigned char)(colour >> 16)};
const unsigned char colour_channels[3] = {(unsigned char)colour, (unsigned char)(colour >> 8), (unsigned char)(colour >> 16)};
Backend_PrepareToDrawGlyphs(surface, colour_channels);
unsigned int pen_x = 0;
@ -1139,7 +1141,7 @@ void DrawText(FontObject *font_object, Backend_Surface *surface, int x, int y, u
const int letter_y = y + glyph->y;
if (glyph->backend != NULL)
Backend_DrawGlyph(surface, glyph->backend, letter_x, letter_y, colours);
Backend_DrawGlyph(glyph->backend, letter_x, letter_y);
pen_x += glyph->x_advance;
}