[lib] generic graphics routines
This commit is contained in:
48
include/dev/display.h
Normal file
48
include/dev/display.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2010 Travis Geiselbrecht
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef __DEV_DISPLAY_H
|
||||
#define __DEV_DISPLAY_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <lib/gfx.h>
|
||||
|
||||
int display_init(void *framebuffer);
|
||||
int display_enable(bool enable);
|
||||
void display_pre_freq_change(void);
|
||||
void display_post_freq_change(void);
|
||||
|
||||
struct display_info {
|
||||
void *framebuffer;
|
||||
gfx_format format;
|
||||
uint width;
|
||||
uint height;
|
||||
uint stride;
|
||||
|
||||
// Update function
|
||||
void (*flush)(uint starty, uint endy);
|
||||
};
|
||||
|
||||
void display_get_info(struct display_info *info);
|
||||
|
||||
#endif
|
||||
|
||||
86
include/lib/gfx.h
Normal file
86
include/lib/gfx.h
Normal file
@@ -0,0 +1,86 @@
|
||||
#ifndef __LIB_GFX_H
|
||||
#define __LIB_GFX_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
// gfx library
|
||||
|
||||
// different graphics formats
|
||||
typedef enum {
|
||||
GFX_FORMAT_RGB_565,
|
||||
GFX_FORMAT_ARGB_8888,
|
||||
GFX_FORMAT_RGB_x888,
|
||||
|
||||
GFX_FORMAT_MAX
|
||||
} gfx_format;
|
||||
|
||||
#define MAX_ALPHA 255
|
||||
|
||||
/**
|
||||
* @brief Describe a graphics drawing surface
|
||||
*
|
||||
* The gfx_surface object represents a framebuffer that can be rendered
|
||||
* to. Elements include a pointer to the actual pixel memory, its size, its
|
||||
* layout, and pointers to basic drawing functions.
|
||||
*
|
||||
* @ingroup graphics
|
||||
*/
|
||||
typedef struct gfx_surface {
|
||||
void *ptr;
|
||||
bool free_on_destroy;
|
||||
gfx_format format;
|
||||
uint width;
|
||||
uint height;
|
||||
uint stride;
|
||||
uint pixelsize;
|
||||
size_t len;
|
||||
uint alpha;
|
||||
|
||||
// function pointers
|
||||
void (*copyrect)(struct gfx_surface *, uint x, uint y, uint width, uint height, uint x2, uint y2);
|
||||
void (*fillrect)(struct gfx_surface *, uint x, uint y, uint width, uint height, uint color);
|
||||
void (*putpixel)(struct gfx_surface *, uint x, uint y, uint color);
|
||||
void (*flush)(uint starty, uint endy);
|
||||
} gfx_surface;
|
||||
|
||||
// copy a rect from x,y with width x height to x2, y2
|
||||
void gfx_copyrect(gfx_surface *surface, uint x, uint y, uint width, uint height, uint x2, uint y2);
|
||||
|
||||
// fill a rect within the surface with a color
|
||||
void gfx_fillrect(gfx_surface *surface, uint x, uint y, uint width, uint height, uint color);
|
||||
|
||||
// draw a pixel at x, y in the surface
|
||||
void gfx_putpixel(gfx_surface *surface, uint x, uint y, uint color);
|
||||
|
||||
// clear the entire surface with a color
|
||||
static inline void gfx_clear(gfx_surface *surface, uint color)
|
||||
{
|
||||
surface->fillrect(surface, 0, 0, surface->width, surface->height, color);
|
||||
|
||||
if (surface->flush)
|
||||
surface->flush(0, surface->height-1);
|
||||
}
|
||||
|
||||
// blend between two surfaces
|
||||
void gfx_surface_blend(struct gfx_surface *target, struct gfx_surface *source, uint destx, uint desty);
|
||||
|
||||
void gfx_flush(struct gfx_surface *surface);
|
||||
|
||||
void gfx_flush_rows(struct gfx_surface *surface, uint start, uint end);
|
||||
|
||||
// surface setup
|
||||
gfx_surface *gfx_create_surface(void *ptr, uint width, uint height, uint stride, gfx_format format);
|
||||
|
||||
// utility routine to make a surface out of a display info
|
||||
struct display_info;
|
||||
gfx_surface *gfx_create_surface_from_display(struct display_info *);
|
||||
|
||||
// free the surface
|
||||
// optionally frees the buffer if the free bit is set
|
||||
void gfx_surface_destroy(struct gfx_surface *surface);
|
||||
|
||||
// utility routine to fill the display with a little moire pattern
|
||||
void gfx_draw_pattern(void);
|
||||
|
||||
#endif
|
||||
|
||||
621
lib/gfx/gfx.c
Normal file
621
lib/gfx/gfx.c
Normal file
@@ -0,0 +1,621 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2010 Travis Geiselbrecht
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup graphics Graphics
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Graphics drawing library
|
||||
*/
|
||||
|
||||
#include <debug.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <arch/ops.h>
|
||||
#include <sys/types.h>
|
||||
#include <lib/gfx.h>
|
||||
#include <dev/display.h>
|
||||
|
||||
#define LOCAL_TRACE 0
|
||||
|
||||
static uint16_t ARGB8888_to_RGB565(uint32_t in)
|
||||
{
|
||||
uint16_t out;
|
||||
|
||||
out = (in >> 3) & 0x1f; // b
|
||||
out |= ((in >> 10) & 0x3f) << 5; // g
|
||||
out |= ((in >> 19) & 0x1f) << 11; // r
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Copy a rectangle of pixels from one part of the display to another.
|
||||
*/
|
||||
void gfx_copyrect(gfx_surface *surface, uint x, uint y, uint width, uint height, uint x2, uint y2)
|
||||
{
|
||||
// trim
|
||||
if (x >= surface->width)
|
||||
return;
|
||||
if (x2 >= surface->width)
|
||||
return;
|
||||
if (y >= surface->height)
|
||||
return;
|
||||
if (y2 >= surface->height)
|
||||
return;
|
||||
if (width == 0 || height == 0)
|
||||
return;
|
||||
|
||||
// clip the width to src or dest
|
||||
if (x + width > surface->width)
|
||||
width = surface->width - x;
|
||||
if (x2 + width > surface->width)
|
||||
width = surface->width - x2;
|
||||
|
||||
// clip the height to src or dest
|
||||
if (y + height > surface->height)
|
||||
height = surface->height - y;
|
||||
if (y2 + height > surface->height)
|
||||
height = surface->height - y2;
|
||||
|
||||
surface->copyrect(surface, x, y, width, height, x2, y2);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Fill a rectangle on the screen with a constant color.
|
||||
*/
|
||||
void gfx_fillrect(gfx_surface *surface, uint x, uint y, uint width, uint height, uint color)
|
||||
{
|
||||
LTRACEF("surface %p, x %u y %u w %u h %u c %u\n", surface, x, y, width, height, color);
|
||||
// trim
|
||||
if (unlikely(x >= surface->width))
|
||||
return;
|
||||
if (y >= surface->height)
|
||||
return;
|
||||
if (width == 0 || height == 0)
|
||||
return;
|
||||
|
||||
// clip the width
|
||||
if (x + width > surface->width)
|
||||
width = surface->width - x;
|
||||
|
||||
// clip the height
|
||||
if (y + height > surface->height)
|
||||
height = surface->height - y;
|
||||
|
||||
surface->fillrect(surface, x, y, width, height, color);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write a single pixel to the screen.
|
||||
*/
|
||||
void gfx_putpixel(gfx_surface *surface, uint x, uint y, uint color)
|
||||
{
|
||||
if (unlikely(x >= surface->width))
|
||||
return;
|
||||
if (y >= surface->height)
|
||||
return;
|
||||
|
||||
surface->putpixel(surface, x, y, color);
|
||||
}
|
||||
|
||||
static void putpixel16(gfx_surface *surface, uint x, uint y, uint color)
|
||||
{
|
||||
uint16_t *dest = &((uint16_t *)surface->ptr)[x + y * surface->stride];
|
||||
|
||||
// colors come in in ARGB 8888 form, flatten them
|
||||
*dest = ARGB8888_to_RGB565(color);
|
||||
}
|
||||
|
||||
static void putpixel32(gfx_surface *surface, uint x, uint y, uint color)
|
||||
{
|
||||
uint32_t *dest = &((uint32_t *)surface->ptr)[x + y * surface->stride];
|
||||
|
||||
*dest = color;
|
||||
}
|
||||
|
||||
static void copyrect16(gfx_surface *surface, uint x, uint y, uint width, uint height, uint x2, uint y2)
|
||||
{
|
||||
// copy
|
||||
const uint16_t *src = &((const uint16_t *)surface->ptr)[x + y * surface->stride];
|
||||
uint16_t *dest = &((uint16_t *)surface->ptr)[x2 + y2 * surface->stride];
|
||||
uint stride_diff = surface->stride - width;
|
||||
|
||||
if (dest < src) {
|
||||
uint i, j;
|
||||
for (i=0; i < height; i++) {
|
||||
for (j=0; j < width; j++) {
|
||||
*dest = *src;
|
||||
dest++;
|
||||
src++;
|
||||
}
|
||||
dest += stride_diff;
|
||||
src += stride_diff;
|
||||
}
|
||||
} else {
|
||||
// copy backwards
|
||||
src += height * surface->stride + width;
|
||||
dest += height * surface->stride + width;
|
||||
|
||||
uint i, j;
|
||||
for (i=0; i < height; i++) {
|
||||
for (j=0; j < width; j++) {
|
||||
*dest = *src;
|
||||
dest--;
|
||||
src--;
|
||||
}
|
||||
dest -= stride_diff;
|
||||
src -= stride_diff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void fillrect16(gfx_surface *surface, uint x, uint y, uint width, uint height, uint color)
|
||||
{
|
||||
uint16_t *dest = &((uint16_t *)surface->ptr)[x + y * surface->stride];
|
||||
uint stride_diff = surface->stride - width;
|
||||
|
||||
uint16_t color16 = ARGB8888_to_RGB565(color);
|
||||
|
||||
uint i, j;
|
||||
for (i=0; i < height; i++) {
|
||||
for (j=0; j < width; j++) {
|
||||
*dest = color16;
|
||||
dest++;
|
||||
}
|
||||
dest += stride_diff;
|
||||
}
|
||||
}
|
||||
|
||||
static void copyrect32(gfx_surface *surface, uint x, uint y, uint width, uint height, uint x2, uint y2)
|
||||
{
|
||||
// copy
|
||||
const uint32_t *src = &((const uint32_t *)surface->ptr)[x + y * surface->stride];
|
||||
uint32_t *dest = &((uint32_t *)surface->ptr)[x2 + y2 * surface->stride];
|
||||
uint stride_diff = surface->stride - width;
|
||||
|
||||
if (dest < src) {
|
||||
uint i, j;
|
||||
for (i=0; i < height; i++) {
|
||||
for (j=0; j < width; j++) {
|
||||
*dest = *src;
|
||||
dest++;
|
||||
src++;
|
||||
}
|
||||
dest += stride_diff;
|
||||
src += stride_diff;
|
||||
}
|
||||
} else {
|
||||
// copy backwards
|
||||
src += height * surface->stride + width;
|
||||
dest += height * surface->stride + width;
|
||||
|
||||
uint i, j;
|
||||
for (i=0; i < height; i++) {
|
||||
for (j=0; j < width; j++) {
|
||||
*dest = *src;
|
||||
dest--;
|
||||
src--;
|
||||
}
|
||||
dest -= stride_diff;
|
||||
src -= stride_diff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void fillrect32(gfx_surface *surface, uint x, uint y, uint width, uint height, uint color)
|
||||
{
|
||||
uint32_t *dest = &((uint32_t *)surface->ptr)[x + y * surface->stride];
|
||||
uint stride_diff = surface->stride - width;
|
||||
|
||||
uint i, j;
|
||||
for (i=0; i < height; i++) {
|
||||
for (j=0; j < width; j++) {
|
||||
*dest = color;
|
||||
dest++;
|
||||
}
|
||||
dest += stride_diff;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t alpha32_add_ignore_destalpha(uint32_t dest, uint32_t src)
|
||||
{
|
||||
uint32_t cdest[3];
|
||||
uint32_t csrc[3];
|
||||
|
||||
uint32_t srca;
|
||||
uint32_t srcainv;
|
||||
|
||||
srca = (src >> 24) & 0xff;
|
||||
if (srca == 0) {
|
||||
return dest;
|
||||
} else if (srca == 255) {
|
||||
return src;
|
||||
}
|
||||
srca++;
|
||||
srcainv = (255 - srca);
|
||||
|
||||
cdest[0] = (dest >> 16) & 0xff;
|
||||
cdest[1] = (dest >> 8) & 0xff;
|
||||
cdest[2] = (dest >> 0) & 0xff;
|
||||
|
||||
csrc[0] = (src >> 16) & 0xff;
|
||||
csrc[1] = (src >> 8) & 0xff;
|
||||
csrc[2] = (src >> 0) & 0xff;
|
||||
|
||||
// if (srca > 0)
|
||||
// printf("s %d %d %d d %d %d %d a %d ai %d\n", csrc[0], csrc[1], csrc[2], cdest[0], cdest[1], cdest[2], srca, srcainv);
|
||||
|
||||
uint32_t cres[3];
|
||||
|
||||
cres[0] = ((csrc[0] * srca) / 256) + ((cdest[0] * srcainv) / 256);
|
||||
cres[1] = ((csrc[1] * srca) / 256) + ((cdest[1] * srcainv) / 256);
|
||||
cres[2] = ((csrc[2] * srca) / 256) + ((cdest[2] * srcainv) / 256);
|
||||
|
||||
return (srca << 24) | (cres[0] << 16) | (cres[1] << 8) | (cres[2]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Copy pixels from source to dest.
|
||||
*
|
||||
* Currently does not support alpha channel.
|
||||
*/
|
||||
void gfx_surface_blend(struct gfx_surface *target, struct gfx_surface *source, uint destx, uint desty)
|
||||
{
|
||||
DEBUG_ASSERT(target->format == source->format);
|
||||
|
||||
LTRACEF("target %p, source %p, destx %u, desty %u\n", target, source, destx, desty);
|
||||
|
||||
if (destx >= target->width)
|
||||
return;
|
||||
if (desty >= target->height)
|
||||
return;
|
||||
|
||||
uint width = source->width;
|
||||
if (destx + width > target->width)
|
||||
width = target->width - destx;
|
||||
|
||||
uint height = source->height;
|
||||
if (desty + height > target->height)
|
||||
height = target->height - desty;
|
||||
|
||||
// XXX total hack to deal with various blends
|
||||
if (source->format == GFX_FORMAT_RGB_565 && target->format == GFX_FORMAT_RGB_565) {
|
||||
// 16 bit to 16 bit
|
||||
const uint16_t *src = (const uint16_t *)source->ptr;
|
||||
uint16_t *dest = &((uint16_t *)target->ptr)[destx + desty * target->stride];
|
||||
uint dest_stride_diff = target->stride - width;
|
||||
uint source_stride_diff = source->stride - width;
|
||||
|
||||
LTRACEF("w %u h %u dstride %u sstride %u\n", width, height, dest_stride_diff, source_stride_diff);
|
||||
|
||||
uint i, j;
|
||||
for (i=0; i < height; i++) {
|
||||
for (j=0; j < width; j++) {
|
||||
*dest = *src;
|
||||
dest++;
|
||||
src++;
|
||||
}
|
||||
dest += dest_stride_diff;
|
||||
src += source_stride_diff;
|
||||
}
|
||||
} else if (source->format == GFX_FORMAT_ARGB_8888 && target->format == GFX_FORMAT_ARGB_8888) {
|
||||
// both are 32 bit modes, both alpha
|
||||
const uint32_t *src = (const uint32_t *)source->ptr;
|
||||
uint32_t *dest = &((uint32_t *)target->ptr)[destx + desty * target->stride];
|
||||
uint dest_stride_diff = target->stride - width;
|
||||
uint source_stride_diff = source->stride - width;
|
||||
|
||||
LTRACEF("w %u h %u dstride %u sstride %u\n", width, height, dest_stride_diff, source_stride_diff);
|
||||
|
||||
uint i, j;
|
||||
for (i=0; i < height; i++) {
|
||||
for (j=0; j < width; j++) {
|
||||
// XXX ignores destination alpha
|
||||
*dest = alpha32_add_ignore_destalpha(*dest, *src);
|
||||
dest++;
|
||||
src++;
|
||||
}
|
||||
dest += dest_stride_diff;
|
||||
src += source_stride_diff;
|
||||
}
|
||||
} else if (source->format == GFX_FORMAT_RGB_x888 && target->format == GFX_FORMAT_RGB_x888) {
|
||||
// both are 32 bit modes, no alpha
|
||||
const uint32_t *src = (const uint32_t *)source->ptr;
|
||||
uint32_t *dest = &((uint32_t *)target->ptr)[destx + desty * target->stride];
|
||||
uint dest_stride_diff = target->stride - width;
|
||||
uint source_stride_diff = source->stride - width;
|
||||
|
||||
LTRACEF("w %u h %u dstride %u sstride %u\n", width, height, dest_stride_diff, source_stride_diff);
|
||||
|
||||
uint i, j;
|
||||
for (i=0; i < height; i++) {
|
||||
for (j=0; j < width; j++) {
|
||||
*dest = *src;
|
||||
dest++;
|
||||
src++;
|
||||
}
|
||||
dest += dest_stride_diff;
|
||||
src += source_stride_diff;
|
||||
}
|
||||
} else {
|
||||
panic("gfx_surface_blend: unimplemented colorspace combination (source %d target %d)\n", source->format, target->format);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Ensure all graphics rendering is sent to display
|
||||
*/
|
||||
void gfx_flush(gfx_surface *surface)
|
||||
{
|
||||
arch_clean_cache_range((addr_t)surface->ptr, surface->len);
|
||||
|
||||
if (surface->flush)
|
||||
surface->flush(0, surface->height-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Ensure that a sub-region of the display is up to date.
|
||||
*/
|
||||
void gfx_flush_rows(struct gfx_surface *surface, uint start, uint end)
|
||||
{
|
||||
if (start > end) {
|
||||
uint temp = start;
|
||||
start = end;
|
||||
end = temp;
|
||||
}
|
||||
|
||||
if (start >= surface->height)
|
||||
return;
|
||||
if (end >= surface->height)
|
||||
end = surface->height - 1;
|
||||
|
||||
arch_clean_cache_range((addr_t)surface->ptr + start * surface->stride * surface->pixelsize, (end - start + 1) * surface->stride * surface->pixelsize);
|
||||
|
||||
if (surface->flush)
|
||||
surface->flush(start, end);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a new graphics surface object
|
||||
*/
|
||||
gfx_surface *gfx_create_surface(void *ptr, uint width, uint height, uint stride, gfx_format format)
|
||||
{
|
||||
DEBUG_ASSERT(width > 0);
|
||||
DEBUG_ASSERT(height > 0);
|
||||
DEBUG_ASSERT(stride >= width);
|
||||
DEBUG_ASSERT(format < GFX_FORMAT_MAX);
|
||||
|
||||
gfx_surface *surface = malloc(sizeof(gfx_surface));
|
||||
|
||||
surface->free_on_destroy = false;
|
||||
surface->format = format;
|
||||
surface->width = width;
|
||||
surface->height = height;
|
||||
surface->stride = stride;
|
||||
surface->alpha = MAX_ALPHA;
|
||||
|
||||
// set up some function pointers
|
||||
switch (format) {
|
||||
case GFX_FORMAT_RGB_565:
|
||||
surface->copyrect = ©rect16;
|
||||
surface->fillrect = &fillrect16;
|
||||
surface->putpixel = &putpixel16;
|
||||
surface->pixelsize = 2;
|
||||
surface->len = surface->height * surface->stride * surface->pixelsize;
|
||||
break;
|
||||
case GFX_FORMAT_RGB_x888:
|
||||
case GFX_FORMAT_ARGB_8888:
|
||||
surface->copyrect = ©rect32;
|
||||
surface->fillrect = &fillrect32;
|
||||
surface->putpixel = &putpixel32;
|
||||
surface->pixelsize = 4;
|
||||
surface->len = surface->height * surface->stride * surface->pixelsize;
|
||||
break;
|
||||
default:
|
||||
dprintf(INFO, "invalid graphics format\n");
|
||||
DEBUG_ASSERT(0);
|
||||
free(surface);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ptr == NULL) {
|
||||
// allocate a buffer
|
||||
ptr = malloc(surface->len);
|
||||
DEBUG_ASSERT(ptr);
|
||||
surface->free_on_destroy = true;
|
||||
}
|
||||
surface->ptr = ptr;
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a new graphics surface object from a display
|
||||
*/
|
||||
gfx_surface *gfx_create_surface_from_display(struct display_info *info)
|
||||
{
|
||||
gfx_surface* surface;
|
||||
surface = gfx_create_surface(info->framebuffer, info->width, info->height, info->stride, info->format);
|
||||
|
||||
surface->flush = info->flush;
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Destroy a graphics surface and free all resources allocated to it.
|
||||
*
|
||||
* @param surface Surface to destroy. This pointer is no longer valid after
|
||||
* this call.
|
||||
*/
|
||||
void gfx_surface_destroy(struct gfx_surface *surface)
|
||||
{
|
||||
if (surface->free_on_destroy)
|
||||
free(surface->ptr);
|
||||
free(surface);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write a test pattern to the default display.
|
||||
*/
|
||||
void gfx_draw_pattern(void)
|
||||
{
|
||||
struct display_info info;
|
||||
display_get_info(&info);
|
||||
|
||||
gfx_surface *surface = gfx_create_surface_from_display(&info);
|
||||
|
||||
uint x, y;
|
||||
for (y = 0; y < surface->height; y++) {
|
||||
for (x = 0; x < surface->width; x++) {
|
||||
uint scaledx;
|
||||
uint scaledy;
|
||||
|
||||
scaledx = x * 256 / surface->width;
|
||||
scaledy = y * 256 / surface->height;
|
||||
|
||||
gfx_putpixel(surface, x, y, (scaledx * scaledy) << 16 | (scaledx >> 1) << 8 | scaledy >> 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (surface->flush)
|
||||
surface->flush(0, surface->height-1);
|
||||
|
||||
gfx_surface_destroy(surface);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Fill default display with white
|
||||
*/
|
||||
void gfx_draw_pattern_white(void)
|
||||
{
|
||||
struct display_info info;
|
||||
display_get_info(&info);
|
||||
|
||||
gfx_surface *surface = gfx_create_surface_from_display(&info);
|
||||
|
||||
uint x, y;
|
||||
for (y = 0; y < surface->height; y++) {
|
||||
for (x = 0; x < surface->width; x++) {
|
||||
gfx_putpixel(surface, x, y, 0xFFFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
if (surface->flush)
|
||||
surface->flush(0, surface->height-1);
|
||||
|
||||
gfx_surface_destroy(surface);
|
||||
}
|
||||
|
||||
#if defined(WITH_LIB_CONSOLE)
|
||||
|
||||
#if DEBUGLEVEL > 1
|
||||
#include <lib/console.h>
|
||||
|
||||
static int cmd_gfx(int argc, const cmd_args *argv);
|
||||
|
||||
STATIC_COMMAND_START
|
||||
STATIC_COMMAND("gfx", "gfx commands", &cmd_gfx)
|
||||
STATIC_COMMAND_END(gfx);
|
||||
|
||||
static int gfx_draw_rgb_bars(gfx_surface *surface)
|
||||
{
|
||||
uint x, y;
|
||||
|
||||
int step32 = surface->height*100 / 32;
|
||||
int step64 = surface->height*100 / 64;
|
||||
int color;
|
||||
|
||||
for (y = 0; y < surface->height; y++) {
|
||||
//R
|
||||
for (x = 0; x < surface->width/3; x++) {
|
||||
color = y*100 / step32;
|
||||
gfx_putpixel(surface, x, y, color << 16);
|
||||
}
|
||||
//G
|
||||
for (;x < 2*(surface->width/3); x++) {
|
||||
color = y*100 / step64;
|
||||
gfx_putpixel(surface, x, y, color << 8);
|
||||
}
|
||||
//B
|
||||
for (;x < surface->width; x++) {
|
||||
color = y*100 / step32;
|
||||
gfx_putpixel(surface, x, y, color);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int cmd_gfx(int argc, const cmd_args *argv)
|
||||
{
|
||||
if (argc < 2) {
|
||||
printf("not enough arguments:\n");
|
||||
usage:
|
||||
printf("%s rgb_bars : Fill frame buffer with rgb bars\n", argv[0].str);
|
||||
printf("%s fill r g b : Fill frame buffer with RGB565 value and force update\n", argv[0].str);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct display_info info;
|
||||
display_get_info(&info);
|
||||
|
||||
gfx_surface *surface = gfx_create_surface_from_display(&info);
|
||||
|
||||
if (!strcmp(argv[1].str, "rgb_bars"))
|
||||
{
|
||||
gfx_draw_rgb_bars(surface);
|
||||
}
|
||||
else if (!strcmp(argv[1].str, "fill"))
|
||||
{
|
||||
uint x, y;
|
||||
|
||||
for (y = 0; y < surface->height; y++)
|
||||
{
|
||||
for (x = 0; x < surface->width; x++)
|
||||
{
|
||||
/* write pixel to frame buffer */
|
||||
gfx_putpixel(surface, x, y, (argv[2].i << 16) | (argv[3].i << 8) | argv[4].i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (surface->flush)
|
||||
surface->flush(0, surface->height-1);
|
||||
|
||||
gfx_surface_destroy(surface);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
4
lib/gfx/rules.mk
Normal file
4
lib/gfx/rules.mk
Normal file
@@ -0,0 +1,4 @@
|
||||
LOCAL_DIR := $(GET_LOCAL_DIR)
|
||||
|
||||
OBJS += \
|
||||
$(LOCAL_DIR)/gfx.o
|
||||
Reference in New Issue
Block a user