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); BOOL Backend_SupportsSubpixelGlyphs(void);
Backend_Glyph* Backend_LoadGlyph(const unsigned char *pixels, unsigned int width, unsigned int height, int pitch, FontPixelMode pixel_mode); 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_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_HandleRenderTargetLoss(void);
void Backend_HandleWindowResize(void); void Backend_HandleWindowResize(void);

View file

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

View file

@ -24,6 +24,9 @@ static SDL_Surface *window_sdlsurface;
static Backend_Surface framebuffer; 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) static void RectToSDLRect(const RECT *rect, SDL_Rect *sdl_rect)
{ {
sdl_rect->x = (int)rect->left; sdl_rect->x = (int)rect->left;
@ -243,9 +246,19 @@ void Backend_UnloadGlyph(Backend_Glyph *glyph)
free(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; return;
SDL_Rect rect; 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.w = glyph->sdlsurface->w;
rect.h = glyph->sdlsurface->h; 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) void Backend_HandleRenderTargetLoss(void)

View file

@ -42,6 +42,8 @@ static Backend_Surface framebuffer;
static Backend_Surface *surface_list_head; static Backend_Surface *surface_list_head;
static unsigned char glyph_colour_channels[3];
static void RectToSDLRect(const RECT *rect, SDL_Rect *sdl_rect) static void RectToSDLRect(const RECT *rect, SDL_Rect *sdl_rect)
{ {
sdl_rect->x = (int)rect->left; sdl_rect->x = (int)rect->left;
@ -376,20 +378,29 @@ void Backend_UnloadGlyph(Backend_Glyph *glyph)
free(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 // 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. // with the colour key doesn't occur.
if (glyph == NULL || surface == NULL) if (glyph == NULL)
return; return;
SDL_Rect destination_rect = {(int)x, (int)y, (int)glyph->width, (int)glyph->height}; SDL_Rect destination_rect = {(int)x, (int)y, (int)glyph->width, (int)glyph->height};
// Blit the texture // 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_SetTextureBlendMode(glyph->texture, SDL_BLENDMODE_BLEND);
SDL_SetRenderTarget(renderer, surface->texture);
SDL_RenderCopy(renderer, glyph->texture, NULL, &destination_rect); 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 SDL_Surface *framebuffer_sdlsurface;
static Backend_Surface framebuffer; 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) 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); 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); 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; return;
switch (glyph->pixel_mode) switch (glyph->pixel_mode)
{ {
case FONT_PIXEL_MODE_LCD: 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; const float *font_pixel = (float*)glyph->pixels + (iy * glyph->width + ix) * 3;
if (font_pixel[0] || font_pixel[1] || font_pixel[2]) 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) for (unsigned int j = 0; j < 3; ++j)
{ {
const float alpha = font_pixel[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; break;
case FONT_PIXEL_MODE_GRAY: 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]; const float alpha = ((float*)glyph->pixels)[iy * glyph->width + ix];
if (alpha) 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) 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; break;
case FONT_PIXEL_MODE_MONO: 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]) 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) 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) 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; 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; const int letter_y = y + glyph->y;
if (glyph->backend != NULL) 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; pen_x += glyph->x_advance;
} }