toaruos/userspace/lib/shmemfonts.c
Kevin Lange df4d1cca39 Text shadows in various places.
- Desktop icons use the shadowing
- The login screen uses shadows instead of poorly-executed strokes
- The blur_test app has been updated to show multiple blur levels,
  but does not use the library function.
2012-10-16 19:05:58 -07:00

156 lines
3.9 KiB
C

/* vim: tabstop=4 shiftwidth=4 noexpandtab
*
*
* Shared-memory font management and access library.
*
*/
#include <stdint.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_CACHE_H
#include "graphics.h"
#include "shmemfonts.h"
static FT_Library library;
static FT_Face face; /* perhaps make this an array ? */
static FT_GlyphSlot slot;
static FT_UInt glyph_index;
static int initialized = 0;
static float opacity = 1.0;
static int _font_size = 12;
#define SGFX(CTX,x,y,WIDTH) *((uint32_t *)&CTX[((WIDTH) * (y) + (x)) * 4])
#define FONT_SIZE 12
/*
* XXX: take font name as an argument / allow multiple fonts
*/
static void _loadSansSerif() {
char * font;
size_t s = 0;
int error;
font = (char *)syscall_shm_obtain(WINS_SERVER_IDENTIFIER ".fonts.sans-serif", &s);
error = FT_New_Memory_Face(library, font, s, 0, &face);
error = FT_Set_Pixel_Sizes(face, FONT_SIZE, FONT_SIZE);
}
void init_shmemfonts() {
if (!initialized) {
FT_Init_FreeType(&library);
_loadSansSerif();
initialized = 1;
}
}
void set_font_size(int size) {
_font_size = size;
FT_Set_Pixel_Sizes(face, size, size);
}
void set_text_opacity(float new_opacity) {
opacity = new_opacity;
}
/*
* Draw a character to a context.
*/
static void draw_char(FT_Bitmap * bitmap, int x, int y, uint32_t fg, gfx_context_t * ctx) {
int i, j, p, q;
int x_max = x + bitmap->width;
int y_max = y + bitmap->rows;
for (j = y, q = 0; j < y_max; j++, q++) {
for ( i = x, p = 0; i < x_max; i++, p++) {
SGFX(ctx->backbuffer,i,j,ctx->width) = alpha_blend(SGFX(ctx->backbuffer,i,j,ctx->width),fg,rgb(bitmap->buffer[q * bitmap->width + p] * opacity,0,0));
}
}
}
uint32_t draw_string_width(char * string) {
slot = face->glyph;
int pen_x = 0, i = 0;
int len = strlen(string);
int error;
for (i = 0; i < len; ++i) {
FT_UInt glyph_index;
glyph_index = FT_Get_Char_Index( face, string[i]);
error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
if (error) {
printf("Error loading glyph for '%c'\n", string[i]);
continue;
}
slot = (face)->glyph;
pen_x += slot->advance.x >> 6;
}
return pen_x;
}
void draw_string(gfx_context_t * ctx, int x, int y, uint32_t fg, char * string) {
slot = face->glyph;
int pen_x = x, pen_y = y, i = 0;
int len = strlen(string);
int error;
for (i = 0; i < len; ++i) {
FT_UInt glyph_index;
glyph_index = FT_Get_Char_Index( face, string[i]);
error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
if (error) {
printf("Error loading glyph for '%c'\n", string[i]);
continue;
}
slot = (face)->glyph;
if (slot->format == FT_GLYPH_FORMAT_OUTLINE) {
error = FT_Render_Glyph((face)->glyph, FT_RENDER_MODE_NORMAL);
if (error) {
printf("Error rendering glyph for '%c'\n", string[i]);
continue;
}
}
draw_char(&slot->bitmap, pen_x + slot->bitmap_left, pen_y - slot->bitmap_top, fg, ctx);
pen_x += slot->advance.x >> 6;
pen_y += slot->advance.y >> 6;
}
}
void draw_string_shadow(gfx_context_t * ctx, int x, int y, uint32_t fg, char * string, uint32_t shadow_color, int darkness, int offset_x, int offset_y, double radius) {
#define OFFSET_X 5
#define OFFSET_Y 5
#define WIDTH_PAD 15
#define HEIGHT_PAD 15
gfx_context_t * tmp_c, * out_c;
sprite_t * tmp_s, * out_s;
size_t width = draw_string_width(string) + WIDTH_PAD;
size_t height = _font_size + HEIGHT_PAD;
tmp_s = create_sprite(width, height, ALPHA_EMBEDDED);
tmp_c = init_graphics_sprite(tmp_s);
out_s = create_sprite(width, height, ALPHA_EMBEDDED);
out_c = init_graphics_sprite(out_s);
draw_fill(tmp_c, rgba(0,0,0,0));
draw_string(tmp_c, OFFSET_X + offset_x, OFFSET_Y + offset_y + _font_size, shadow_color, string);
blur_context(out_c, tmp_c, radius);
draw_string(out_c, OFFSET_X, OFFSET_Y + _font_size, fg, string);
for (int i = 0; i < darkness; ++i) {
draw_sprite(ctx, out_s, x - OFFSET_X, y - OFFSET_Y - _font_size);
}
sprite_free(tmp_s);
free(tmp_c);
sprite_free(out_s);
free(out_c);
}