2020-05-29 15:57:22 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
#include "SDL_surface.h"
|
2020-05-30 18:07:31 +02:00
|
|
|
#include "font_renderer_alpha.h"
|
2020-05-29 15:57:22 +02:00
|
|
|
|
|
|
|
#define MAX_GLYPHSET 256
|
|
|
|
|
|
|
|
typedef struct { uint8_t b, g, r, a; } RenColor;
|
|
|
|
typedef struct { int x, y, width, height; } RenRect;
|
|
|
|
|
|
|
|
struct RenImage {
|
|
|
|
RenColor *pixels;
|
|
|
|
int width, height;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct GlyphSetA {
|
|
|
|
RenImage *image;
|
|
|
|
// FIXME: add glyphs information for AGG implementation
|
|
|
|
// stbtt_bakedchar glyphs[256];
|
|
|
|
};
|
|
|
|
|
|
|
|
struct RenFontA {
|
2020-05-30 18:07:31 +02:00
|
|
|
font_renderer_alpha *renderer;
|
2020-05-29 15:57:22 +02:00
|
|
|
float size;
|
|
|
|
int height;
|
|
|
|
};
|
|
|
|
|
2020-05-29 18:41:55 +02:00
|
|
|
template <typename T>
|
|
|
|
static T* check_alloc(T *ptr) {
|
|
|
|
if (ptr == 0) {
|
2020-05-29 15:57:22 +02:00
|
|
|
fprintf(stderr, "Fatal error: memory allocation failed\n");
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
RenImage* ren_new_image(int width, int height) {
|
|
|
|
assert(width > 0 && height > 0);
|
2020-05-29 18:41:55 +02:00
|
|
|
RenImage *image = (RenImage *) malloc(sizeof(RenImage) + width * height * sizeof(RenColor));
|
2020-05-29 15:57:22 +02:00
|
|
|
check_alloc(image);
|
2020-05-29 18:41:55 +02:00
|
|
|
image->pixels = (RenColor*) (image + 1);
|
2020-05-29 15:57:22 +02:00
|
|
|
image->width = width;
|
|
|
|
image->height = height;
|
|
|
|
return image;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ren_free_image(RenImage *image) {
|
|
|
|
free(image);
|
|
|
|
}
|
|
|
|
|
|
|
|
RenFontA* ren_load_font_agg(const char *filename, float size) {
|
2020-05-29 18:41:55 +02:00
|
|
|
RenFontA *font = NULL;
|
2020-05-29 15:57:22 +02:00
|
|
|
|
|
|
|
/* init font */
|
2020-05-29 18:41:55 +02:00
|
|
|
font = (RenFontA *) check_alloc(calloc(1, sizeof(RenFontA)));
|
2020-05-29 15:57:22 +02:00
|
|
|
font->size = size;
|
|
|
|
|
2020-05-30 18:07:31 +02:00
|
|
|
font->renderer = new font_renderer_alpha(true, false);
|
2020-05-29 15:57:22 +02:00
|
|
|
font->renderer->load_font(filename);
|
|
|
|
|
2020-05-30 15:19:12 +02:00
|
|
|
int ascender, descender;
|
|
|
|
font->renderer->get_font_vmetrics(ascender, descender);
|
|
|
|
fprintf(stderr, "Font metrics ascender: %d descender: %d\n", ascender, descender);
|
|
|
|
|
2020-05-30 16:26:10 +02:00
|
|
|
float scale = font->renderer->scale_for_em_to_pixels(size);
|
|
|
|
font->height = (ascender - descender) * scale + 0.5;
|
|
|
|
|
|
|
|
fprintf(stderr, "Font height: %d\n", font->height);
|
|
|
|
|
2020-05-29 15:57:22 +02:00
|
|
|
return font;
|
|
|
|
}
|
|
|
|
|
2020-05-29 18:41:55 +02:00
|
|
|
static GlyphSetA* load_glyphset_agg(RenFontA *font, int idx) {
|
2020-05-30 18:07:31 +02:00
|
|
|
const int pixel_size = 1;
|
2020-05-29 18:41:55 +02:00
|
|
|
GlyphSetA *set = (GlyphSetA *) check_alloc(calloc(1, sizeof(GlyphSetA)));
|
2020-05-29 15:57:22 +02:00
|
|
|
|
|
|
|
/* init image */
|
2020-05-30 18:07:31 +02:00
|
|
|
int width = 128;
|
|
|
|
int height = 128;
|
2020-05-29 15:57:22 +02:00
|
|
|
retry:
|
|
|
|
set->image = ren_new_image(width, height);
|
|
|
|
|
2020-05-30 18:07:31 +02:00
|
|
|
memset(set->image->pixels, 0x00, width * height * pixel_size);
|
2020-05-29 18:41:55 +02:00
|
|
|
|
|
|
|
agg::rendering_buffer ren_buf((agg::int8u *) set->image->pixels, width, height, -width * pixel_size);
|
2020-05-30 18:07:31 +02:00
|
|
|
// FIXME: figure out how to precisely layout each glyph.
|
2020-05-29 18:41:55 +02:00
|
|
|
double x = 4, y = height - font->size * 3 / 2;
|
|
|
|
int res = 0;
|
2020-05-30 18:07:31 +02:00
|
|
|
const agg::alpha8 text_color(0xff);
|
2020-05-29 18:41:55 +02:00
|
|
|
for (int i = 0; i < 256; i++) {
|
|
|
|
if (x + font->size * 3 / 2 > width) {
|
|
|
|
x = 4;
|
|
|
|
y -= font->size * 3 / 2;
|
|
|
|
}
|
|
|
|
if (y < 0) {
|
|
|
|
res = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// FIXME: we are ignoring idx and with a char we cannot pass codepoint > 255.
|
|
|
|
char text[2] = {char(i % 256), 0};
|
|
|
|
// FIXME: using font->size below is wrong.
|
|
|
|
font->renderer->render_text(ren_buf, font->size, text_color, x, y, text);
|
|
|
|
}
|
2020-05-29 15:57:22 +02:00
|
|
|
|
|
|
|
/* retry with a larger image buffer if the buffer wasn't large enough */
|
|
|
|
if (res < 0) {
|
|
|
|
width *= 2;
|
|
|
|
height *= 2;
|
|
|
|
ren_free_image(set->image);
|
|
|
|
goto retry;
|
|
|
|
}
|
|
|
|
|
2020-05-30 18:07:31 +02:00
|
|
|
/* convert 8bit data to 32bit */
|
|
|
|
for (int i = width * height - 1; i >= 0; i--) {
|
|
|
|
uint8_t n = *((uint8_t*) set->image->pixels + i);
|
|
|
|
RenColor c = {0xff, 0xff, 0xff, n};
|
|
|
|
set->image->pixels[i] = c;
|
|
|
|
}
|
|
|
|
|
2020-05-29 15:57:22 +02:00
|
|
|
return set;
|
|
|
|
}
|
|
|
|
|
2020-05-29 18:41:55 +02:00
|
|
|
extern "C" int main(int argc, char *argv[]);
|
|
|
|
|
2020-05-29 15:57:22 +02:00
|
|
|
int main(int argc, char *argv[]) {
|
|
|
|
if (argc < 3) {
|
|
|
|
fprintf(stderr, "usage: %s <font-filename> <size>\n", argv[0]);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
const char *filename = argv[1];
|
|
|
|
const int size = atoi(argv[2]);
|
2020-05-29 18:41:55 +02:00
|
|
|
RenFontA *font = ren_load_font_agg(filename, size);
|
|
|
|
GlyphSetA *set = load_glyphset_agg(font, 0);
|
2020-05-29 15:57:22 +02:00
|
|
|
SDL_Surface *surface = SDL_CreateRGBSurfaceWithFormatFrom(
|
|
|
|
set->image->pixels,
|
|
|
|
set->image->width, set->image->height, 32, set->image->width * 4,
|
|
|
|
SDL_PIXELFORMAT_RGBA32);
|
2020-05-29 18:41:55 +02:00
|
|
|
SDL_SaveBMP(surface, "agg-glyphset.bmp");
|
2020-05-29 15:57:22 +02:00
|
|
|
return 0;
|
|
|
|
}
|