171 lines
4.2 KiB
C
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;
|
|
}
|
|
}
|