From ca3c2f8a4c92c09de7ce2bb2a26465b1dd360138 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Mon, 18 May 2015 16:46:14 +0200 Subject: [PATCH] CLean the ili9341 driver --- kandinsky/Makefile | 19 ++- kandinsky/fonts/rasterizer.c | 247 ++++++++++++++++++++++++++++ kandinsky/include/kandinsky/color.h | 8 + kandinsky/include/kandinsky/line.h | 2 +- kandinsky/include/kandinsky/point.h | 2 +- kandinsky/include/kandinsky/text.h | 9 + kandinsky/src/line.c | 2 +- kandinsky/src/text.c | 22 +++ platform/ili9341/ili9341.c | 24 ++- 9 files changed, 330 insertions(+), 5 deletions(-) create mode 100644 kandinsky/fonts/rasterizer.c create mode 100644 kandinsky/include/kandinsky/color.h create mode 100644 kandinsky/include/kandinsky/text.h create mode 100644 kandinsky/src/text.c diff --git a/kandinsky/Makefile b/kandinsky/Makefile index c480a32d3..8f3a9da1a 100644 --- a/kandinsky/Makefile +++ b/kandinsky/Makefile @@ -1,2 +1,19 @@ CFLAGS += -Ikandinsky/include -objs += $(addprefix kandinsky/src/, line.o) +objs += $(addprefix kandinsky/src/, line.o text.o font.o) + +FREETYPE_PATH := /usr/local/Cellar/freetype/2.5.5 +LIBPNG_PATH := /usr/local/Cellar/libpng/1.6.17 + +kandinsky/src/text.c: kandinsky/src/font.h + +font_files = $(addprefix kandinsky/src/, font.h font.c) + +$(font_files): kandinsky/fonts/rasterizer + @echo "RASTER $(font_files)" + @$< kandinsky/fonts/DroidSansMono.ttf 20 20 $(font_files) + +kandinsky/fonts/rasterizer: kandinsky/fonts/rasterizer.c + @echo "HOSTCC $@" + @clang -I$(FREETYPE_PATH)/include/freetype2 -L$(FREETYPE_PATH)/lib -lfreetype $< -o $@ + +products += $(font_files) kandinsky/fonts/rasterizer diff --git a/kandinsky/fonts/rasterizer.c b/kandinsky/fonts/rasterizer.c new file mode 100644 index 000000000..6198ade22 --- /dev/null +++ b/kandinsky/fonts/rasterizer.c @@ -0,0 +1,247 @@ +/* example1.c */ +/* */ +/* This small program shows how to print a rotated string with the */ +/* FreeType 2 library. */ + +/* + * Usage: rasterizer font_name glyph_width glyph_height + * -> Generates a .png image with the font rasterized + * -> Generates a .c file with the content of the font + */ + +#include +#include +#include + +#include +#include FT_FREETYPE_H + +#define ENSURE(action, description...) { if (!(action)) { fprintf(stderr, "Error: "); fprintf(stderr, description); fprintf(stderr, "\n"); exit(-1);}} + +// Pixel format is RGB888 + +typedef struct { + unsigned char red; + unsigned char green; + unsigned char blue; +} pixel_t; + +typedef struct { + pixel_t * pixels; + int width; + int height; +} image_t; + +#ifdef GENERATE_PNG +#include +void writeImageToPNGFile(image_t * image, char * filename); +#endif + +#define CHARACTER_RANGE_START 0x20 +#define CHARACTER_RANGE_END 0x7E + +#define GRID_WIDTH 19 +#define GRID_HEIGHT 5 + +#if (GRID_WIDTH*GRID_HEIGHT < (CHARACTER_RANGE_END-CHARACTER_RANGE_START+1)) +#error Grid too small. Consider increasing GRID_WIDTH or GRID_HEIGHT +#endif + + +void drawGlyphInImage(FT_Bitmap * glyphBitmap, image_t * image, int x, int y); + +int main(int argc, char * argv[]) { + FT_Library library; + FT_Face face; + image_t bitmap_image; + + int expectedNumberOfArguments = 6; +#ifdef GENERATE_PNG + expectedNumberOfArguments = 7; +#endif + if (argc != expectedNumberOfArguments) { +#ifdef GENERATE_PNG + fprintf(stderr, "Usage: %s font_file glyph_width glyph_height output_header output_implementation output_png\n", argv[0]); +#else + fprintf(stderr, "Usage: %s font_file glyph_width glyph_height output_header output_implementation\n", argv[0]); +#endif + fprintf(stderr, " font_file: Path of the font file to load\n"); + fprintf(stderr, " glyph_width: Width of bitmap glyphs, in pixels\n"); + fprintf(stderr, " glyph_height: Height of bitmap glyphs, in pixels\n"); + fprintf(stderr, " output_header: Name of the generated C header file\n"); + fprintf(stderr, " output_implementation: Name of the generated C source file\n"); +#ifdef GENERATE_PNG + fprintf(stderr, " output_png: Name of the generated PNG file\n"); +#endif + exit(1); + } + + char * font_file = argv[1]; + int requested_glyph_width = atoi(argv[2]); + int requested_glyph_height = atoi(argv[3]); + char * output_header = argv[4]; + char * output_implementation = argv[5]; +#ifdef GENERATE_PNG + char * output_png = argv[6]; +#endif + + ENSURE(!FT_Init_FreeType(&library), "Initializing library"); + + // 0 means we're picking the first face in the provided file + ENSURE(!FT_New_Face(library, font_file, 0, &face), "Loading font file %s", font_file); + + ENSURE(!FT_Set_Pixel_Sizes(face, requested_glyph_width, requested_glyph_height), "Setting face pixel size to %dx%d", requested_glyph_width, requested_glyph_height); + + int maxHeight = 0; + int maxWidth = 0; + int minTop = requested_glyph_height; + for (unsigned char character = CHARACTER_RANGE_START; character <= CHARACTER_RANGE_END; character++) { + ENSURE(!FT_Load_Char(face, character, FT_LOAD_RENDER), "Loading character 0x%02x", character); + int top = requested_glyph_height - face->glyph->bitmap_top; + int height = top + face->glyph->bitmap.rows; + int width = face->glyph->bitmap.width; + if (top < minTop) { + minTop = top; + } + if (height > maxHeight) { + maxHeight = height; + } + if (width > maxWidth) { + maxWidth = width; + } + } + + int glyph_width = maxWidth; + int glyph_height = maxHeight-minTop; + //printf("Actual glyph size = %dx%d\n", glyph_width, glyph_height); + + int grid_size = 1; + + bitmap_image.width = GRID_WIDTH*glyph_width+(GRID_WIDTH-1)*grid_size; + bitmap_image.height = GRID_HEIGHT*glyph_height+(GRID_HEIGHT-1)*grid_size; + bitmap_image.pixels = malloc(sizeof(pixel_t)*bitmap_image.width*bitmap_image.height); + ENSURE(bitmap_image.pixels != NULL, "Allocating bitmap image of size %dx%d at %ld bytes per pixel", bitmap_image.width, bitmap_image.height, sizeof(pixel_t)); + + // Draw the grid and the background + for (int i = 0; i= glyph_width || j%(glyph_height+grid_size) >= glyph_height) { + pixel = (pixel_t){.red = 0xFF, .green = 0, .blue = 0}; + } + *(bitmap_image.pixels + j*bitmap_image.width + i) = pixel; + } + } + + + + // We're doing the ASCII table, so characters from 0 to 255 inclusive + for (unsigned char character = CHARACTER_RANGE_START; character <= CHARACTER_RANGE_END; character++) { + int x = (character-CHARACTER_RANGE_START)%(GRID_WIDTH); + int y = (character-CHARACTER_RANGE_START)/(GRID_WIDTH); + // FT_LOAD_RENDER: Render the glyph upon load + ENSURE(!FT_Load_Char(face, character, FT_LOAD_RENDER), "Loading character 0x%02x", character); + //printf("Advances = %dx%d\n", face->glyph->bitmap_left, face->glyph->bitmap_top); + drawGlyphInImage(&face->glyph->bitmap, + &bitmap_image, + x*(glyph_width+grid_size) /* + face->glyph->bitmap_left*/, + y*(glyph_height+grid_size) + requested_glyph_height - face->glyph->bitmap_top - minTop);// + glyph_height - face->glyph->bitmap_top - maxHeight); + } + +#if GENERATE_PNG + writeImageToPNGFile(&bitmap_image, output_png); +#endif + + FILE * headerFile = fopen(output_header, "w"); + fprintf(headerFile, "/* Auto-generated by rasterizer */\n\n"); + fprintf(headerFile, "#define BITMAP_FONT_FIRST_CHARACTER 0x%2x\n", CHARACTER_RANGE_START); + fprintf(headerFile, "#define BITMAP_FONT_LAST_CHARACTER 0x%2x\n\n", CHARACTER_RANGE_END); + fprintf(headerFile, "#define BITMAP_FONT_CHARACTER_WIDTH %d\n", glyph_width); + fprintf(headerFile, "#define BITMAP_FONT_CHARACTER_HEIGHT %d\n\n", glyph_height); + fprintf(headerFile, "extern unsigned char bitmapFont[%d][%d][%d];\n", CHARACTER_RANGE_END-CHARACTER_RANGE_START+1, glyph_height, glyph_width); + fclose(headerFile); + + FILE * sourceFile = fopen(output_implementation, "w"); + fprintf(sourceFile, "/* Auto-generated by rasterizer */\n\n"); + fprintf(sourceFile, "unsigned char bitmapFont[%d][%d][%d] = {\n", CHARACTER_RANGE_END-CHARACTER_RANGE_START+1, glyph_height, glyph_width); + for (unsigned char character = CHARACTER_RANGE_START; character <= CHARACTER_RANGE_END; character++) { + fprintf(sourceFile, " {\n"); + int characterX = ((character-CHARACTER_RANGE_START)%GRID_WIDTH * (glyph_width+grid_size)); + int characterY = ((character-CHARACTER_RANGE_START)/GRID_WIDTH * (glyph_height+grid_size)); + for (int y = 0; y < glyph_height; y++) { + fprintf(sourceFile, " {"); + for (int x = 0; x < glyph_width; x++) { + pixel_t * pixel = (bitmap_image.pixels + (y+characterY)*bitmap_image.width + (x+characterX)); + fprintf(sourceFile, "0x%02x", pixel->green); + if (x+1 < glyph_width) { + fprintf(sourceFile, ", "); + } + } + fprintf(sourceFile, "}"); + if (y+1 < glyph_height) { + fprintf(sourceFile, ","); + } + fprintf(sourceFile, "\n"); + } + fprintf(sourceFile, " }"); + if (character+1 <= CHARACTER_RANGE_END) { + fprintf(sourceFile, ","); + } + fprintf(sourceFile, "\n"); + } + + fprintf(sourceFile, "};\n"); + fclose(sourceFile); + + free(bitmap_image.pixels); + + return 0; +} + +void drawGlyphInImage(FT_Bitmap * glyphBitmap, image_t * image, int x, int y) { + // printf("Drawing glyph. Size is %dx%d, pitch is %d\n", glyphBitmap->width, glyphBitmap->rows, glyphBitmap->pitch); + ENSURE(glyphBitmap->pixel_mode == FT_PIXEL_MODE_GRAY, "Checking glyph is in FT_PIXEL_MODE_GRAY"); + for (int j=0;jrows;j++) { + for (int i=0;iwidth;i++) { + uint8_t glyphPixel = *(glyphBitmap->buffer + j*glyphBitmap->pitch + i); + pixel_t * currentPixelPointer = (image->pixels + (y+j)*image->width + (x+i)); + *currentPixelPointer = (pixel_t){.red = (0xFF-glyphPixel), .green = (0xFF-glyphPixel), .blue = (0xFF-glyphPixel)}; // Alpha blending + } + } +} + +#if GENERATE_PNG + +void writeImageToPNGFile(image_t * image, char * filename) { + FILE * file = fopen(filename, "wb"); // Write in binary mode + ENSURE(file != NULL, "Opening file %s", filename); + + png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + ENSURE(png != NULL, "Allocating PNG write structure"); + + png_infop info = png_create_info_struct(png); + ENSURE(info != NULL, "Allocating info structure"); + + png_init_io(png, file); + + png_set_IHDR(png, info, + image->width, image->height, + 8, // Number of bits per channel + PNG_COLOR_TYPE_RGB, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + + png_write_info(png, info); + + for (int j=0;jheight;j++) { + png_write_row(png, (png_bytep)(image->pixels+j*image->width)); + } + + png_write_end(png, NULL); + + png_free_data(png, info, PNG_FREE_ALL, -1); // -1 = all items + png_destroy_write_struct(&png, (png_infopp)NULL); + fclose(file); +} +#endif diff --git a/kandinsky/include/kandinsky/color.h b/kandinsky/include/kandinsky/color.h new file mode 100644 index 000000000..580cbb3b5 --- /dev/null +++ b/kandinsky/include/kandinsky/color.h @@ -0,0 +1,8 @@ +#ifndef KANDINSKY_COLOR_H +#define KANDINSKY_COLOR_H + +#include + +typedef uint8_t KDColor; + +#endif diff --git a/kandinsky/include/kandinsky/line.h b/kandinsky/include/kandinsky/line.h index 034219c43..5bb8c0ead 100644 --- a/kandinsky/include/kandinsky/line.h +++ b/kandinsky/include/kandinsky/line.h @@ -3,6 +3,6 @@ #include -void KDDrawLine(kdpoint_t * p1, kdpoint_t * p2); +void KDDrawLine(KDPoint p1, KDPoint p2); #endif diff --git a/kandinsky/include/kandinsky/point.h b/kandinsky/include/kandinsky/point.h index 98b8f4a89..02cc3daf5 100644 --- a/kandinsky/include/kandinsky/point.h +++ b/kandinsky/include/kandinsky/point.h @@ -6,6 +6,6 @@ typedef struct { uint16_t x; uint16_t y; -} kdpoint_t; +} KDPoint; #endif diff --git a/kandinsky/include/kandinsky/text.h b/kandinsky/include/kandinsky/text.h new file mode 100644 index 000000000..6067392a7 --- /dev/null +++ b/kandinsky/include/kandinsky/text.h @@ -0,0 +1,9 @@ +#ifndef KANDINSKY_TEXT_H +#define KANDINSKY_TEXT_H + +#include + +void KDDrawChar(char character, KDPoint p); +void KDDrawString(char * text, KDPoint p); + +#endif diff --git a/kandinsky/src/line.c b/kandinsky/src/line.c index f6597f330..0d8bc2d48 100644 --- a/kandinsky/src/line.c +++ b/kandinsky/src/line.c @@ -1,7 +1,7 @@ #include #include "framebuffer.h" -void KDDrawLine(kdpoint_t * p1, kdpoint_t * p2) { +void KDDrawLine(KDPoint p1, KDPoint p2) { for (int i=0; i<10; i++) { PIXEL(i,i) = 0xFF; } diff --git a/kandinsky/src/text.c b/kandinsky/src/text.c new file mode 100644 index 000000000..20865572f --- /dev/null +++ b/kandinsky/src/text.c @@ -0,0 +1,22 @@ +#include +#include "framebuffer.h" +#include "font.h" + +void KDDrawChar(char character, KDPoint p) { + char * framebuffer = FRAMEBUFFER_ADDRESS; + for (int j=0; j