6502-sim/text.c
2023-06-15 17:08:20 +00:00

171 lines
4.2 KiB
C

#include <stdint.h>
#include <assert.h>
#include <SDL_render.h>
#include <ft2build.h>
#include FT_FREETYPE_H
typedef struct glyph_texture {
SDL_Texture * texture;
int advance;
int bearing_x;
int bearing_y;
} glyph_texture_t;
static int line_height;
static glyph_texture_t glyph_textures[256] = {0};
const char * printable = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!\"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ ";
int create_instruction_textures(SDL_Renderer * renderer)
{
FT_Library library;
FT_Face face;
FT_Error error;
error = FT_Init_FreeType(&library);
if (error) {
fprintf(stderr, "FT_Init_FreeType\n");
return -1;
}
error = FT_New_Face(library, "/usr/share/fonts/TTF/DejaVuSansMono.ttf", 0, &face);
if (error) {
fprintf(stderr, "FT_New_Face\n");
return -1;
}
assert(FT_IS_FIXED_WIDTH(face));
error = FT_Set_Pixel_Sizes(face, 0, 32);
if (error) {
fprintf(stderr, "FT_Select_Size: %s %d\n", FT_Error_String(error), error);
return -1;
}
line_height = (face->height * face->size->metrics.y_ppem) / face->units_per_EM;
SDL_Surface * surface;
SDL_Texture * texture;
unsigned long c;
int ix = 0;
while ((c = printable[ix++]) != 0) {
unsigned int glyph_index = FT_Get_Char_Index(face, c);
error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
if (error) {
fprintf(stderr, "FT_Load_Glyph: %ld %s %d\n", c, FT_Error_String(error), error);
return -1;
}
error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
if (error) {
fprintf(stderr, "FT_Render_Glyph: %ld %s %d\n", c, FT_Error_String(error), error);
return -1;
}
assert(face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
surface = SDL_CreateRGBSurface(0,
face->glyph->bitmap.width,
face->glyph->bitmap.rows,
32,
0xFF000000,
0x00FF0000,
0x0000FF00,
0x000000FF);
assert(surface != NULL);
SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND);
SDL_LockSurface(surface);
for (unsigned int y = 0; y < face->glyph->bitmap.rows; y++) {
for (unsigned int x = 0; x < face->glyph->bitmap.width; x++) {
uint8_t alpha = ((uint8_t *)face->glyph->bitmap.buffer)[face->glyph->bitmap.pitch * y + x];
((uint32_t *)surface->pixels)[(surface->pitch / 4) * y + x] = 0xFFFFFF00 + alpha;
}
}
SDL_UnlockSurface(surface);
texture = SDL_CreateTextureFromSurface(renderer, surface);
SDL_FreeSurface(surface);
glyph_textures[c] = (glyph_texture_t){
.texture = texture,
.advance = face->glyph->metrics.horiAdvance / 64,
.bearing_x = face->glyph->metrics.horiBearingX / 64,
.bearing_y = face->glyph->metrics.horiBearingY / 64,
};
}
return 0;
}
void ull_base16(void * buf, size_t len, unsigned long long n)
{
while (len > 0) {
uint8_t ni = n & 0xf;
n >>= 4;
uint8_t c;
switch (ni) {
case 0x0:
case 0x1:
case 0x2:
case 0x3:
case 0x4:
case 0x5:
case 0x6:
case 0x7:
case 0x8:
case 0x9:
c = '0' + (ni - 0x0);
break;
case 0xA:
case 0xB:
case 0xC:
case 0xD:
case 0xE:
case 0xF:
c = 'A' + (ni - 0xA);
break;
default:
assert(0);
}
((uint8_t *)buf)[--len] = c;
}
}
void render_text(SDL_Renderer * renderer, int col, int row,
const void * buf, int len,
uint8_t r, uint8_t g, uint8_t b)
{
uint8_t c;
assert(buf != NULL);
int x_origin = col * glyph_textures[((uint8_t *)buf)[0]].advance;
int y_origin = row * line_height;
int x_offset = 0;
SDL_Rect rect;
for (int ix = 0; ix < len; ix++) {
c = ((uint8_t *)buf)[ix];
assert(c != 0);
glyph_texture_t * glyph = &glyph_textures[c];
SDL_QueryTexture(glyph->texture, NULL, NULL, &rect.w, &rect.h);
rect.x = x_origin + x_offset + glyph->bearing_x;
rect.y = y_origin - glyph->bearing_y;
SDL_SetTextureColorMod(glyph->texture, r, g, b);
SDL_RenderCopy(renderer, glyph->texture, NULL, &rect);
x_offset += glyph->advance;
}
}