#include #include #include #include #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; } }