-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implements: * image_ops_create * image_ops_update * image_ops_delete * font_ops_create (Using cairo w/ freetype2) * script_ops_draw_line * script_ops_draw_triangle * script_ops_draw_quad * script_ops_draw_rect * script_ops_draw_rrect * script_ops_draw_arc * script_ops_draw_sector * script_ops_draw_circle * script_ops_draw_text * script_ops_begin_path * script_ops_close_path * script_ops_fill_path * script_ops_stroke_path * script_ops_move_to * script_ops_line_to * script_ops_bezier_to * script_ops_push_state * script_ops_pop_state * script_ops_transform * script_ops_scale * script_ops_rotate * script_ops_translate * script_ops_fill_color * script_ops_fill_linear * script_ops_fill_radial * script_ops_fill_image * script_ops_stroke_width * script_ops_stroke_color * script_ops_line_cap * script_ops_line_join * script_ops_miter_limit * script_ops_font * script_ops_font_size * script_ops_text_align * script_ops_text_base Signed-off-by: Jon Ringle <[email protected]>
- Loading branch information
Showing
7 changed files
with
968 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
#include <cairo.h> | ||
#include <errno.h> | ||
#include <fcntl.h> | ||
#include <linux/fb.h> | ||
#include <stdlib.h> | ||
#include <sys/ioctl.h> | ||
#include <sys/mman.h> | ||
#include <sys/stat.h> | ||
#include <sys/types.h> | ||
|
||
#include "cairo_ctx.h" | ||
#include "comms.h" | ||
#include "device.h" | ||
#include "fontstash.h" | ||
#include "ops/script_ops.h" | ||
|
||
const char* device = "/dev/fb0"; | ||
|
||
typedef struct { | ||
int fd; | ||
|
||
struct fb_var_screeninfo var; | ||
struct fb_fix_screeninfo fix; | ||
} cairo_fb_t; | ||
|
||
cairo_fb_t g_cairo_fb = {0}; | ||
|
||
extern device_info_t g_device_info; | ||
extern device_opts_t g_opts; | ||
|
||
int device_init(const device_opts_t* p_opts, | ||
device_info_t* p_info, | ||
driver_data_t* p_data) | ||
{ | ||
if (g_opts.debug_mode) { | ||
log_info("cairo %s", __func__); | ||
} | ||
|
||
if ((g_cairo_fb.fd = open(device, O_RDWR)) == -1) { | ||
log_error("Failed to open device %s: %s", device, strerror(errno)); | ||
return -1; | ||
} | ||
|
||
if (ioctl(g_cairo_fb.fd, FBIOGET_VSCREENINFO, &g_cairo_fb.var)) { | ||
log_error("Failed to get fb_var_screeninfo: %s", strerror(errno)); | ||
return -1; | ||
} | ||
|
||
if (ioctl(g_cairo_fb.fd, FBIOGET_FSCREENINFO, &g_cairo_fb.fix)) { | ||
log_error("Failed to get fb_fix_screeninfo: %s", strerror(errno)); | ||
return -1; | ||
} | ||
|
||
scenic_cairo_ctx_t* p_ctx = calloc(1, sizeof(scenic_cairo_ctx_t)); | ||
|
||
FT_Error status = FT_Init_FreeType(&p_ctx->ft_library); | ||
if (status != 0) { | ||
log_error("cairo: FT_Init_FreeType: Error: %d", status); | ||
close(g_cairo_fb.fd); | ||
free(p_ctx); | ||
|
||
return -1; | ||
} | ||
|
||
p_info->width = g_cairo_fb.var.xres; | ||
p_info->height = g_cairo_fb.var.yres; | ||
|
||
p_ctx->font_size = 10.0; // Cairo default | ||
p_ctx->text_align = TEXT_ALIGN_LEFT; | ||
p_ctx->text_base = TEXT_BASE_ALPHABETIC; | ||
|
||
p_ctx->clear_color = (color_rgba_t){ | ||
// black opaque | ||
.red = 0.0, | ||
.green = 0.0, | ||
.blue = 0.0, | ||
.alpha = 1.0 | ||
}; | ||
|
||
p_info->v_ctx = p_ctx; | ||
|
||
p_ctx->surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, | ||
p_info->width, p_info->height); | ||
return 0; | ||
} | ||
|
||
int device_close(device_info_t* p_info) | ||
{ | ||
if (g_opts.debug_mode) { | ||
log_info("cairo %s", __func__); | ||
} | ||
close(g_cairo_fb.fd); | ||
|
||
scenic_cairo_ctx_t* p_ctx = (scenic_cairo_ctx_t*)p_info->v_ctx; | ||
cairo_surface_destroy(p_ctx->surface); | ||
free(p_ctx); | ||
} | ||
|
||
void device_poll() | ||
{ | ||
} | ||
|
||
void device_begin_render(driver_data_t* p_data) | ||
{ | ||
if (g_opts.debug_mode) { | ||
log_info("cairo %s", __func__); | ||
} | ||
|
||
scenic_cairo_ctx_t* p_ctx = (scenic_cairo_ctx_t*)p_data->v_ctx; | ||
|
||
p_ctx->cr = cairo_create(p_ctx->surface); | ||
|
||
// Paint surface to clear color | ||
cairo_set_source_rgba(p_ctx->cr, | ||
p_ctx->clear_color.red, | ||
p_ctx->clear_color.green, | ||
p_ctx->clear_color.blue, | ||
p_ctx->clear_color.alpha); | ||
cairo_paint(p_ctx->cr); | ||
} | ||
|
||
void device_begin_cursor_render(driver_data_t* p_data) | ||
{ | ||
scenic_cairo_ctx_t* p_ctx = (scenic_cairo_ctx_t*)p_data->v_ctx; | ||
cairo_translate(p_ctx->cr, p_data->cursor_pos[0], p_data->cursor_pos[1]); | ||
} | ||
|
||
void render_cairo_surface_to_fb(int fd, cairo_surface_t* surface) | ||
{ | ||
cairo_surface_flush(surface); | ||
uint8_t* surface_data = cairo_image_surface_get_data(surface); | ||
|
||
int fb_x = g_cairo_fb.var.xres; | ||
int fb_y = g_cairo_fb.var.yres; | ||
size_t fb_size = fb_x * fb_y * 3; | ||
uint8_t* fbbuff = mmap(NULL, fb_size, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0); | ||
|
||
for(uint32_t i = 0, j = 0; i < fb_size; i += 3, j += 4) { | ||
fbbuff[i+0] = surface_data[j+0]; | ||
fbbuff[i+1] = surface_data[j+1]; | ||
fbbuff[i+2] = surface_data[j+2]; | ||
} | ||
|
||
munmap(fbbuff, fb_size); | ||
} | ||
|
||
void device_end_render(driver_data_t* p_data) | ||
{ | ||
if (g_opts.debug_mode) { | ||
log_info("cairo %s", __func__); | ||
} | ||
|
||
scenic_cairo_ctx_t* p_ctx = (scenic_cairo_ctx_t*)p_data->v_ctx; | ||
render_cairo_surface_to_fb(g_cairo_fb.fd, p_ctx->surface); | ||
|
||
cairo_destroy(p_ctx->cr); | ||
} | ||
|
||
void device_clear_color(float red, float green, float blue, float alpha) | ||
{ | ||
scenic_cairo_ctx_t* p_ctx = (scenic_cairo_ctx_t*)g_device_info.v_ctx; | ||
p_ctx->clear_color = (color_rgba_t){ | ||
.red = red, | ||
.green = green, | ||
.blue = blue, | ||
.alpha = alpha | ||
}; | ||
} | ||
|
||
char* device_gl_error() | ||
{ | ||
return NULL; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
#pragma once | ||
|
||
#include <cairo.h> | ||
#include <ft2build.h> | ||
#include FT_FREETYPE_H | ||
#include "ops/script_ops.h" | ||
|
||
typedef struct { | ||
color_rgba_t clear_color; | ||
FT_Library ft_library; | ||
float font_size; | ||
text_align_t text_align; | ||
text_base_t text_base; | ||
cairo_surface_t* surface; | ||
cairo_t* cr; | ||
} scenic_cairo_ctx_t; | ||
|
||
typedef struct { | ||
cairo_surface_t* surface; | ||
cairo_pattern_t* pattern; | ||
} image_data_t; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
#include "cairo_ctx.h" | ||
#include "font_ops.h" | ||
|
||
#include <cairo-ft.h> | ||
int32_t font_ops_create(void* v_ctx, font_t* p_font, uint32_t size) | ||
{ | ||
scenic_cairo_ctx_t* p_ctx = (scenic_cairo_ctx_t*)v_ctx; | ||
const char* name = p_font->id.p_data; | ||
unsigned char* data = p_font->blob.p_data; | ||
|
||
FT_Face ft_face; | ||
FT_Error ft_status = FT_New_Memory_Face(p_ctx->ft_library, data, size, 0, &ft_face); | ||
|
||
if (ft_status != 0) { | ||
log_error("cairo: FT_New_Memory_Face: Error: %d", ft_status); | ||
return -1; | ||
} | ||
|
||
cairo_font_face_t* font_face = cairo_ft_font_face_create_for_ft_face(ft_face, 0); | ||
cairo_status_t status = cairo_font_face_set_user_data(font_face, NULL, | ||
ft_face, | ||
(cairo_destroy_func_t) FT_Done_Face); | ||
if (status) { | ||
log_error("cairo: Failed to create font face: %d", status); | ||
cairo_font_face_destroy(font_face); | ||
FT_Done_Face(ft_face); | ||
return -1; | ||
} | ||
|
||
return (int32_t)font_face; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
#include <arpa/inet.h> | ||
#include <cairo.h> | ||
#include <stdlib.h> | ||
|
||
#include "cairo_ctx.h" | ||
#include "comms.h" | ||
#include "image_ops.h" | ||
|
||
uint32_t convert_rgba_to_argb(uint32_t pixel) | ||
{ | ||
return ((pixel & 0xFFFFFF00) >> 8) | ((pixel & 0xFF) << 24); | ||
} | ||
|
||
int32_t image_ops_create(void* v_ctx, | ||
uint32_t width, uint32_t height, | ||
void* p_pixels) | ||
{ | ||
cairo_format_t format = CAIRO_FORMAT_ARGB32; | ||
int stride = cairo_format_stride_for_width(format, width); | ||
size_t num_pixels = width * height; | ||
uint32_t* rgba_pixels = (uint32_t*)p_pixels; | ||
uint32_t* argb_pixels = malloc(num_pixels * sizeof(uint32_t)); | ||
|
||
if (!argb_pixels) return 0; | ||
|
||
for(size_t i = 0; i < num_pixels; ++i) { | ||
argb_pixels[i] = convert_rgba_to_argb(htonl(rgba_pixels[i])); | ||
} | ||
|
||
image_data_t* image_data = malloc(sizeof(image_data_t)); | ||
|
||
image_data->surface | ||
= cairo_image_surface_create_for_data((uint8_t*)argb_pixels, | ||
format, | ||
width, height, stride); | ||
|
||
image_data->pattern = cairo_pattern_create_for_surface(image_data->surface); | ||
|
||
static cairo_user_data_key_t dummy_key; | ||
cairo_surface_set_user_data(image_data->surface, &dummy_key, argb_pixels, free); | ||
|
||
return (int32_t)image_data; | ||
} | ||
|
||
void image_ops_update(void* v_ctx, uint32_t image_id, void* p_pixels) | ||
{ | ||
image_data_t* image_data = (image_data_t*)image_id; | ||
uint32_t width = cairo_image_surface_get_width(image_data->surface); | ||
uint32_t height = cairo_image_surface_get_height(image_data->surface); | ||
size_t num_pixels = width * height; | ||
uint32_t* rgba_pixels = (uint32_t*)p_pixels; | ||
uint32_t* argb_pixels = (uint32_t*)cairo_image_surface_get_data(image_data->surface); | ||
|
||
for(size_t i = 0; i < num_pixels; ++i) { | ||
argb_pixels[i] = convert_rgba_to_argb(htonl(rgba_pixels[i])); | ||
} | ||
|
||
cairo_pattern_destroy(image_data->pattern); | ||
image_data->pattern = cairo_pattern_create_for_surface(image_data->surface); | ||
} | ||
|
||
void image_ops_delete(void* v_ctx, uint32_t image_id) | ||
{ | ||
image_data_t* image_data = (image_data_t*)image_id; | ||
cairo_surface_destroy(image_data->surface); | ||
cairo_pattern_destroy(image_data->pattern); | ||
free(image_data); | ||
} |
Oops, something went wrong.