From 8aad8a662851860ee6aa157ccaf45283fa261cec Mon Sep 17 00:00:00 2001 From: Clownacy Date: Tue, 23 Jul 2019 20:05:38 +0100 Subject: [PATCH] Font refactor part 4: Thy Flesh Co- I mean, OpenGL Hard mode. Wound up debugging a weird issue for about half an hour. Turns out you don't need to reset the matrix when you switch framebuffer target? I don't really know how that works. Anyway, yay font rendering is in the OpenGL backend now. --- src/Backends/Rendering/OpenGL2.cpp | 137 +++++++++++++++++++++++------ 1 file changed, 112 insertions(+), 25 deletions(-) diff --git a/src/Backends/Rendering/OpenGL2.cpp b/src/Backends/Rendering/OpenGL2.cpp index c77688be..49439f6f 100644 --- a/src/Backends/Rendering/OpenGL2.cpp +++ b/src/Backends/Rendering/OpenGL2.cpp @@ -18,6 +18,13 @@ typedef struct Backend_Surface unsigned char *pixels; } Backend_Surface; +typedef struct Backend_Glyph +{ + GLuint texture_id; + unsigned int width; + unsigned int height; +} Backend_Glyph; + static SDL_Window *window; static SDL_GLContext context; static GLuint colour_key_program_id; @@ -88,6 +95,8 @@ BOOL Backend_Init(SDL_Window *p_window) // glLoadIdentity(); glEnable(GL_TEXTURE_2D); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); @@ -228,14 +237,7 @@ void Backend_Blit(Backend_Surface *source_surface, const RECT *rect, Backend_Sur // Point our framebuffer to the destination texture glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, destination_surface->texture_id, 0); - // The matrix needs resetting to fit the dimensions of the destination texture - glPushMatrix(); - glLoadIdentity(); - glOrtho(0.0, destination_surface->width, 0.0, destination_surface->height, 1.0, -1.0); - BlitCommon(source_surface, rect, x, y, colour_key); - - glPopMatrix(); } void Backend_BlitToScreen(Backend_Surface *source_surface, const RECT *rect, long x, long y, BOOL colour_key) @@ -268,14 +270,7 @@ void Backend_ColourFill(Backend_Surface *surface, const RECT *rect, unsigned cha // Point our framebuffer to the destination texture glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, surface->texture_id, 0); - // The matrix needs resetting to fit the dimensions of the destination texture - glPushMatrix(); - glLoadIdentity(); - glOrtho(0.0, surface->width, 0.0, surface->height, 1.0, -1.0); - ColourFillCommon(rect, red, green, blue); - - glPopMatrix(); } void Backend_ColourFillToScreen(const RECT *rect, unsigned char red, unsigned char green, unsigned char blue) @@ -291,24 +286,116 @@ void Backend_ScreenToSurface(Backend_Surface *surface, const RECT *rect) // Point our framebuffer to the destination texture glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, surface->texture_id, 0); - // The matrix needs resetting to fit the dimensions of the destination texture - glPushMatrix(); - glLoadIdentity(); - glOrtho(0.0, surface->width, 0.0, surface->height, 1.0, -1.0); - BlitCommon(&framebuffer_surface, rect, rect->left, rect->top, FALSE); - - glPopMatrix(); } -void Backend_DrawText(Backend_Surface *surface, FontObject *font, int x, int y, const char *text, unsigned long colour) +BOOL Backend_SupportsSubpixelGlyph(void) { - // Soon + return FALSE; // Per-component alpha is available as an extension, but I haven't looked into it yet } -void Backend_DrawTextToScreen(FontObject *font, int x, int y, const char *text, unsigned long colour) +Backend_Glyph* Backend_LoadGlyph(const unsigned char *pixels, unsigned int width, unsigned int height, int pitch, unsigned short total_greys, unsigned char pixel_mode) { - // Soon + Backend_Glyph *glyph = (Backend_Glyph*)malloc(sizeof(Backend_Glyph)); + + if (glyph == NULL) + return NULL; + + unsigned char *buffer = (unsigned char*)malloc(width * height * 4); + + switch (pixel_mode) + { + // FONT_PIXEL_MODE_LCD is unsupported + + case FONT_PIXEL_MODE_GRAY: + for (unsigned int y = 0; y < height; ++y) + { + const unsigned char *source_pointer = pixels + y * pitch; + unsigned char *destination_pointer = buffer + y * width * 4; + + for (unsigned int x = 0; x < width; ++x) + { + *destination_pointer++ = 0xFF; + *destination_pointer++ = 0xFF; + *destination_pointer++ = 0xFF; + *destination_pointer++ = (unsigned char)(pow((double)*source_pointer++ / (total_greys - 1), 1.0 / 1.8) * 255.0); + } + } + + break; + + case FONT_PIXEL_MODE_MONO: + for (unsigned int y = 0; y < height; ++y) + { + const unsigned char *source_pointer = pixels + y * pitch; + unsigned char *destination_pointer = buffer + y * width * 4; + + for (unsigned int x = 0; x < width; ++x) + { + *destination_pointer++ = 0xFF; + *destination_pointer++ = 0xFF; + *destination_pointer++ = 0xFF; + *destination_pointer++ = *source_pointer++ ? 0xFF : 0; + } + } + + break; + } + + glGenTextures(1, &glyph->texture_id); + glBindTexture(GL_TEXTURE_2D, glyph->texture_id); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + glyph->width = width; + glyph->height = height; + + free(buffer); + + return glyph; +} + +void Backend_UnloadGlyph(Backend_Glyph *glyph) +{ + glDeleteTextures(1, &glyph->texture_id); + free(glyph); +} + +static void DrawGlyphCommon(Backend_Glyph *glyph, long x, long y, const unsigned char *colours) +{ + // Disable colour-keying + glUseProgram(0); + + glBindTexture(GL_TEXTURE_2D, glyph->texture_id); + + glBegin(GL_QUADS); + glColor3f(colours[0] / 255.0f, colours[1] / 255.0f, colours[2] / 255.0f); + glTexCoord2f(0.0f, 0.0f); + glVertex2f((GLfloat)x, (GLfloat)y); + glTexCoord2f(1.0f, 0.0f); + glVertex2f((GLfloat)x + glyph->width, (GLfloat)y); + glTexCoord2f(1.0f, 1.0f); + glVertex2f((GLfloat)x + glyph->width, (GLfloat)y + glyph->height); + glTexCoord2f(0.0f, 1.0f); + glVertex2f((GLfloat)x, (GLfloat)y + glyph->height); + glEnd(); +} + +void Backend_DrawGlyph(Backend_Surface *surface, Backend_Glyph *glyph, long x, long y, const unsigned char *colours) +{ + // Point our framebuffer to the destination texture + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, surface->texture_id, 0); + + DrawGlyphCommon(glyph, x, y, colours); +} + +void Backend_DrawGlyphToScreen(Backend_Glyph *glyph, long x, long y, const unsigned char *colours) +{ + // Point our framebuffer to the screen texture + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, framebuffer_surface.texture_id, 0); + + DrawGlyphCommon(glyph, x, y, colours); } void Backend_HandleDeviceLoss(void)