Skip to content
Permalink
1676371de0
Go to file
 
 
Cannot retrieve contributors at this time
466 lines (394 sloc) 12.9 KB
/*
* screen.c
*
* oled
*/
#include <assert.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <cairo.h>
#include <cairo-ft.h>
#include "args.h"
// skip this if you don't want every screen module call to perform null checks
#ifndef CHECK_CR
#define CHECK_CR if (cr == NULL) {return; }
#define CHECK_CRR if (cr == NULL) {return 0; }
#endif
#define NUM_FONTS 67
static char font_path[NUM_FONTS][32];
static float c[16] =
{0, 0.066666666666667, 0.13333333333333, 0.2, 0.26666666666667,
0.33333333333333,
0.4, 0.46666666666667, 0.53333333333333, 0.6, 0.66666666666667,
0.73333333333333, 0.8, 0.86666666666667, 0.93333333333333, 1};
static cairo_surface_t *surface;
static cairo_surface_t *surfacefb;
static cairo_surface_t *image;
static cairo_t *cr;
static cairo_t *crfb;
static cairo_font_face_t *ct[NUM_FONTS];
static FT_Library value;
static FT_Error status;
static FT_Face face[NUM_FONTS];
static double text_xy[2];
typedef struct _cairo_linuxfb_device {
int fb_fd;
unsigned char *fb_data;
long fb_screensize;
struct fb_var_screeninfo fb_vinfo;
struct fb_fix_screeninfo fb_finfo;
} cairo_linuxfb_device_t;
/* Destroy a cairo surface */
void cairo_linuxfb_surface_destroy(void *device)
{
cairo_linuxfb_device_t *dev = (cairo_linuxfb_device_t *)device;
if (dev == NULL) {
return;
}
munmap(dev->fb_data, dev->fb_screensize);
close(dev->fb_fd);
free(dev);
}
/* Create a cairo surface using the specified framebuffer */
cairo_surface_t *cairo_linuxfb_surface_create()
{
cairo_linuxfb_device_t *device;
cairo_surface_t *surface;
const char* fb_name = args_framebuffer();
device = malloc( sizeof(*device) );
if (!device) {
fprintf(stderr, "ERROR (screen) cannot allocate memory\n");
return NULL;
}
// Open the file for reading and writing
device->fb_fd = open(fb_name, O_RDWR);
if (device->fb_fd == -1) {
fprintf(stderr, "ERROR (screen) cannot open framebuffer device");
goto handle_allocate_error;
}
// Get variable screen information
if (ioctl(device->fb_fd, FBIOGET_VSCREENINFO, &device->fb_vinfo) == -1) {
fprintf(stderr, "ERROR (screen) reading variable information");
goto handle_ioctl_error;
}
// Figure out the size of the screen in bytes
device->fb_screensize = device->fb_vinfo.xres * device->fb_vinfo.yres
* device->fb_vinfo.bits_per_pixel / 8;
// Map the device to memory
device->fb_data = (unsigned char *)mmap(0, device->fb_screensize,
PROT_READ | PROT_WRITE, MAP_SHARED,
device->fb_fd, 0);
if ( device->fb_data == (unsigned char *)-1 ) {
fprintf(stderr, "ERROR (screen) failed to map framebuffer device to memory");
goto handle_ioctl_error;
}
// Get fixed screen information
if (ioctl(device->fb_fd, FBIOGET_FSCREENINFO, &device->fb_finfo) == -1) {
fprintf(stderr, "ERROR (screen) reading fixed information");
goto handle_ioctl_error;
}
/* Create the cairo surface which will be used to draw to */
surface = cairo_image_surface_create_for_data(
device->fb_data,
CAIRO_FORMAT_RGB16_565,
device->fb_vinfo.xres,
device->fb_vinfo.yres,
cairo_format_stride_for_width(
CAIRO_FORMAT_RGB16_565,
device
->fb_vinfo.xres) );
cairo_surface_set_user_data(surface, NULL, device,
&cairo_linuxfb_surface_destroy);
return surface;
handle_ioctl_error:
close(device->fb_fd);
handle_allocate_error:
free(device);
return NULL;
}
void screen_display_png(const char *filename, double x, double y){
int img_w, img_h;
//fprintf(stderr, "loading: %s\n", filename);
image = cairo_image_surface_create_from_png (filename);
if(image == NULL) { return; }
img_w = cairo_image_surface_get_width (image);
img_h = cairo_image_surface_get_height (image);
cairo_set_source_surface (cr, image, x, y);
//cairo_paint (cr);
cairo_rectangle (cr, x, y, img_w, img_h);
cairo_fill (cr);
cairo_surface_destroy (image);
}
void screen_init(void) {
surfacefb = cairo_linuxfb_surface_create();
if(surfacefb == NULL) { return; }
crfb = cairo_create(surfacefb);
surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,128,64);
cr = cairo_create(surface);
status = FT_Init_FreeType(&value);
if(status != 0) {
fprintf(stderr, "ERROR (screen) freetype init\n");
return;
}
strcpy(font_path[0], "04B_03__.TTF");
strcpy(font_path[1], "liquid.ttf");
strcpy(font_path[2], "Roboto-Thin.ttf");
strcpy(font_path[3], "Roboto-Light.ttf");
strcpy(font_path[4], "Roboto-Regular.ttf");
strcpy(font_path[5], "Roboto-Medium.ttf");
strcpy(font_path[6], "Roboto-Bold.ttf");
strcpy(font_path[7], "Roboto-Black.ttf");
strcpy(font_path[8], "Roboto-ThinItalic.ttf");
strcpy(font_path[9], "Roboto-LightItalic.ttf");
strcpy(font_path[10], "Roboto-Italic.ttf");
strcpy(font_path[11], "Roboto-MediumItalic.ttf");
strcpy(font_path[12], "Roboto-BoldItalic.ttf");
strcpy(font_path[13], "Roboto-BlackItalic.ttf");
strcpy(font_path[14], "VeraBd.ttf");
strcpy(font_path[15], "VeraBI.ttf");
strcpy(font_path[16], "VeraIt.ttf");
strcpy(font_path[17], "VeraMoBd.ttf");
strcpy(font_path[18], "VeraMoBI.ttf");
strcpy(font_path[19], "VeraMoIt.ttf");
strcpy(font_path[20], "VeraMono.ttf");
strcpy(font_path[21], "VeraSeBd.ttf");
strcpy(font_path[22], "VeraSe.ttf");
strcpy(font_path[23], "Vera.ttf");
//------------------
// bitmap fonts
strcpy(font_path[24], "bmp/tom-thumb.bdf");
// FIXME: this is totally silly...
int i = 25;
strcpy(font_path[i++], "bmp/creep.bdf");
strcpy(font_path[i++], "bmp/ctrld-fixed-10b.bdf");
strcpy(font_path[i++], "bmp/ctrld-fixed-10r.bdf");
strcpy(font_path[i++], "bmp/ctrld-fixed-13b.bdf");
strcpy(font_path[i++], "bmp/ctrld-fixed-13b-i.bdf");
strcpy(font_path[i++], "bmp/ctrld-fixed-13r.bdf");
strcpy(font_path[i++], "bmp/ctrld-fixed-13r-i.bdf");
strcpy(font_path[i++], "bmp/ctrld-fixed-16b.bdf");
strcpy(font_path[i++], "bmp/ctrld-fixed-16b-i.bdf");
strcpy(font_path[i++], "bmp/ctrld-fixed-16r.bdf");
strcpy(font_path[i++], "bmp/ctrld-fixed-16r-i.bdf");
strcpy(font_path[i++], "bmp/scientifica-11.bdf");
strcpy(font_path[i++], "bmp/scientificaBold-11.bdf");
strcpy(font_path[i++], "bmp/scientificaItalic-11.bdf");
strcpy(font_path[i++], "bmp/ter-u12b.bdf");
strcpy(font_path[i++], "bmp/ter-u12n.bdf");
strcpy(font_path[i++], "bmp/ter-u14b.bdf");
strcpy(font_path[i++], "bmp/ter-u14n.bdf");
strcpy(font_path[i++], "bmp/ter-u14v.bdf");
strcpy(font_path[i++], "bmp/ter-u16b.bdf");
strcpy(font_path[i++], "bmp/ter-u16n.bdf");
strcpy(font_path[i++], "bmp/ter-u16v.bdf");
strcpy(font_path[i++], "bmp/ter-u18b.bdf");
strcpy(font_path[i++], "bmp/ter-u18n.bdf");
strcpy(font_path[i++], "bmp/ter-u20b.bdf");
strcpy(font_path[i++], "bmp/ter-u20n.bdf");
strcpy(font_path[i++], "bmp/ter-u22b.bdf");
strcpy(font_path[i++], "bmp/ter-u22n.bdf");
strcpy(font_path[i++], "bmp/ter-u24b.bdf");
strcpy(font_path[i++], "bmp/ter-u24n.bdf");
strcpy(font_path[i++], "bmp/ter-u28b.bdf");
strcpy(font_path[i++], "bmp/ter-u28n.bdf");
strcpy(font_path[i++], "bmp/ter-u32b.bdf");
strcpy(font_path[i++], "bmp/ter-u32n.bdf");
strcpy(font_path[i++], "bmp/unscii-16-full.pcf");
strcpy(font_path[i++], "bmp/unscii-16.pcf");
strcpy(font_path[i++], "bmp/unscii-8-alt.pcf");
strcpy(font_path[i++], "bmp/unscii-8-fantasy.pcf");
strcpy(font_path[i++], "bmp/unscii-8-mcr.pcf");
strcpy(font_path[i++], "bmp/unscii-8.pcf");
strcpy(font_path[i++], "bmp/unscii-8-tall.pcf");
strcpy(font_path[i++], "bmp/unscii-8-thin.pcf");
assert(i == NUM_FONTS);
fprintf(stderr, "fonts: \n");
for (int i=0; i<NUM_FONTS; ++i) {
fprintf(stderr, " %d: %s\n", i, font_path[i]);
}
char filename[256];
for(int i = 0; i < NUM_FONTS; i++) {
// FIXME should be path relative to norns/
snprintf(filename, 256, "%s/norns/resources/%s", getenv(
"HOME"), font_path[i]);
status = FT_New_Face(value, filename, 0, &face[i]);
if(status != 0) {
fprintf(stderr, "ERROR (screen) font load: %s\n", filename);
return;
}
else{
ct[i] = cairo_ft_font_face_create_for_ft_face(face[i], 0);
}
}
cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
cairo_paint(cr);
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
cairo_font_options_t *font_options = cairo_font_options_create();
cairo_font_options_set_antialias(font_options,CAIRO_ANTIALIAS_SUBPIXEL);
cairo_set_font_options(cr, font_options);
cairo_font_options_destroy(font_options);
// default font
cairo_set_font_face (cr, ct[0]);
cairo_set_font_size(cr, 8.0);
// config buffer
cairo_set_operator(crfb, CAIRO_OPERATOR_SOURCE);
cairo_set_source_surface(crfb,surface,0,0);
}
void screen_deinit(void) {
CHECK_CR
cairo_destroy(cr);
cairo_surface_destroy(surface);
cairo_destroy(crfb);
cairo_surface_destroy(surfacefb);
}
void screen_update(void) {
CHECK_CR
cairo_paint(crfb);
}
void screen_save(void) {
CHECK_CR
cairo_save(cr);
}
void screen_restore(void) {
CHECK_CR
cairo_restore(cr);
}
void screen_font_face(int i) {
CHECK_CR
if( (i >= 0) && (i < NUM_FONTS) ) {
cairo_set_font_face(cr,ct[i]);
}
}
void screen_font_size(double z) {
CHECK_CR
cairo_set_font_size(cr,z);
}
void screen_aa(int s) {
CHECK_CR
cairo_font_options_t *font_options = cairo_font_options_create();
if(s == 0) {
cairo_set_antialias(cr,CAIRO_ANTIALIAS_NONE);
cairo_font_options_set_antialias(font_options,CAIRO_ANTIALIAS_NONE);
} else {
cairo_set_antialias(cr,CAIRO_ANTIALIAS_DEFAULT);
cairo_font_options_set_antialias(font_options,CAIRO_ANTIALIAS_SUBPIXEL);
}
cairo_set_font_options(cr, font_options);
cairo_font_options_destroy(font_options);
}
void screen_level(int z) {
CHECK_CR
cairo_set_source_rgb(cr,c[z],c[z],c[z]);
}
void screen_line_width(double w) {
CHECK_CR
cairo_set_line_width(cr,w);
}
void screen_line_cap(const char *style) {
CHECK_CR
if(strcmp(style, "round") == 0){
cairo_set_line_cap(cr,CAIRO_LINE_CAP_ROUND);
}else if(strcmp(style, "square") == 0){
cairo_set_line_cap(cr,CAIRO_LINE_CAP_SQUARE);
}else{
cairo_set_line_cap(cr,CAIRO_LINE_CAP_BUTT);
}
}
void screen_line_join(const char *style) {
CHECK_CR
if(strcmp(style, "round") == 0){
cairo_set_line_join(cr,CAIRO_LINE_JOIN_ROUND);
}else if(strcmp(style, "bevel") == 0){
cairo_set_line_join(cr,CAIRO_LINE_JOIN_BEVEL);
}else{
cairo_set_line_join(cr,CAIRO_LINE_JOIN_MITER);
}
}
void screen_miter_limit(double limit) {
CHECK_CR
cairo_set_miter_limit(cr,limit);
}
void screen_move(double x, double y) {
CHECK_CR
cairo_move_to(cr,x,y);
}
void screen_line(double x, double y) {
CHECK_CR
cairo_line_to(cr,x,y);
}
void screen_line_rel(double x, double y) {
CHECK_CR
cairo_rel_line_to(cr,x,y);
}
void screen_move_rel(double x, double y) {
CHECK_CR
cairo_rel_move_to(cr,x,y);
}
void screen_curve(double x1,
double y1,
double x2,
double y2,
double x3,
double y3) {
CHECK_CR
cairo_curve_to(cr,x1,y1,x2,y2,x3,y3);
}
void screen_curve_rel(double dx1,
double dy1,
double dx2,
double dy2,
double dx3,
double dy3) {
CHECK_CR
cairo_rel_curve_to(cr,dx1,dy1,dx2,dy2,dx3,dy3);
}
void screen_arc(double x, double y, double r, double a1, double a2) {
CHECK_CR
cairo_arc(cr,x,y,r,a1,a2);
}
void screen_rect(double x, double y, double w, double h) {
CHECK_CR
cairo_rectangle(cr,x,y,w,h);
}
void screen_close_path(void) {
CHECK_CR
cairo_close_path(cr);
}
void screen_stroke(void) {
CHECK_CR
cairo_stroke(cr);
}
void screen_fill(void) {
CHECK_CR
cairo_fill(cr);
}
void screen_text(const char *s) {
CHECK_CR
cairo_show_text(cr, s);
}
void screen_clear(void) {
CHECK_CR
cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
cairo_paint(cr);
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
}
double *screen_extents(const char *s) {
CHECK_CRR
cairo_text_extents_t extents;
cairo_text_extents(cr, s, &extents);
text_xy[0] = extents.width;
text_xy[1] = extents.height;
return text_xy;
}
extern void screen_export_png(const char *s) {
CHECK_CR
cairo_surface_write_to_png(surface, s);
}
#undef CHECK_CR
#undef CHECK_CRR