From ef00cac45de322ba9366731809c680056b5200b1 Mon Sep 17 00:00:00 2001 From: inmarket Date: Tue, 13 Jan 2015 13:50:46 +1000 Subject: [PATCH] Add support and demo for pixmaps (in memory drawing) --- demos/modules/gdisp/pixmaps/demo.mk | 3 + demos/modules/gdisp/pixmaps/gfxconf.h | 48 ++++++ demos/modules/gdisp/pixmaps/main.c | 83 ++++++++++ gfxconf.example.h | 3 + src/gdisp/driver.h | 125 +++++++++++++-- src/gdisp/gdisp_colors.h | 2 + src/gdisp/gdisp_gdisp.c | 2 +- src/gdisp/gdisp_pixmap.c | 223 ++++++++++++++++++++++++++ src/gdisp/gdisp_pixmap.h | 87 ++++++++++ src/gdisp/sys_defs.h | 4 + src/gdisp/sys_make.mk | 1 + src/gdisp/sys_options.h | 16 ++ 12 files changed, 584 insertions(+), 13 deletions(-) create mode 100644 demos/modules/gdisp/pixmaps/demo.mk create mode 100644 demos/modules/gdisp/pixmaps/gfxconf.h create mode 100644 demos/modules/gdisp/pixmaps/main.c create mode 100644 src/gdisp/gdisp_pixmap.c create mode 100644 src/gdisp/gdisp_pixmap.h diff --git a/demos/modules/gdisp/pixmaps/demo.mk b/demos/modules/gdisp/pixmaps/demo.mk new file mode 100644 index 00000000..9e4858ec --- /dev/null +++ b/demos/modules/gdisp/pixmaps/demo.mk @@ -0,0 +1,3 @@ +DEMODIR = $(GFXLIB)/demos/modules/gdisp/pixmaps +GFXINC += $(DEMODIR) +GFXSRC += $(DEMODIR)/main.c diff --git a/demos/modules/gdisp/pixmaps/gfxconf.h b/demos/modules/gdisp/pixmaps/gfxconf.h new file mode 100644 index 00000000..ddd7d1ec --- /dev/null +++ b/demos/modules/gdisp/pixmaps/gfxconf.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2012, 2013, Joel Bodenmann aka Tectu + * Copyright (c) 2012, 2013, Andrew Hannam aka inmarket + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _GFXCONF_H +#define _GFXCONF_H + +/* The operating system to use. One of these must be defined - preferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE +//#define GFX_USE_OS_WIN32 FALSE +//#define GFX_USE_OS_LINUX FALSE +//#define GFX_USE_OS_OSX FALSE + +/* GFX sub-systems to turn on */ +#define GFX_USE_GDISP TRUE + +/* Features for the GDISP sub-system. */ +#define GDISP_NEED_VALIDATION TRUE +#define GDISP_NEED_CLIP TRUE +#define GDISP_NEED_PIXMAP TRUE + +#endif /* _GFXCONF_H */ + diff --git a/demos/modules/gdisp/pixmaps/main.c b/demos/modules/gdisp/pixmaps/main.c new file mode 100644 index 00000000..3adcf03f --- /dev/null +++ b/demos/modules/gdisp/pixmaps/main.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2012, 2013, Joel Bodenmann aka Tectu + * Copyright (c) 2012, 2013, Andrew Hannam aka inmarket + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "gfx.h" + +#define PIXMAP_WIDTH 40 +#define PIXMAP_HEIGHT 10 + +static GDisplay *pix; +static pixel_t *surface; + +int main(void) { + coord_t width, height; + coord_t i, j; + + // Initialize and clear the display + gfxInit(); + + // Get the screen size + width = gdispGetWidth(); + height = gdispGetHeight(); + + // Create a pixmap and get a pointer to the bits + pix = gdispCreatePixmap(PIXMAP_WIDTH, PIXMAP_HEIGHT); + surface = gdispGetPixmapBits(pix); + + // A pixmap can be treated either as a virtual display or as a memory framebuffer surface. + // We demonstrate writing to it using both methods. + + // First demo drawing onto the surface directly + for(j = 0; j < PIXMAP_HEIGHT; j++) + for(i = 0; i < PIXMAP_WIDTH; i++) + surface[j*PIXMAP_WIDTH + i] = RGB2COLOR(0, 255-i*(256/PIXMAP_WIDTH), j*(256/PIXMAP_HEIGHT)); + + // Secondly, show drawing a line on it like a virtual display + gdispGDrawLine(pix, 0, 0, gdispGGetWidth(pix)-1, gdispGGetHeight(pix)-1, White); + + i = j = 0; + while(TRUE) { + // Clear the old position + gdispFillArea(i, j, PIXMAP_WIDTH, PIXMAP_HEIGHT, Black); + + // Change the position + i += PIXMAP_WIDTH/2; + if (i >= width - PIXMAP_WIDTH/2) { + i %= width - PIXMAP_WIDTH/2; + j = (j + PIXMAP_HEIGHT/2) % (height - PIXMAP_HEIGHT/2); + } + + // Blit the pixmap to the real display at the new position + gdispBlitArea(i, j, PIXMAP_WIDTH, PIXMAP_HEIGHT, surface); + + // Wait + gfxSleepMilliseconds(100); + } +} + diff --git a/gfxconf.example.h b/gfxconf.example.h index 4d18d37c..3a91d21a 100644 --- a/gfxconf.example.h +++ b/gfxconf.example.h @@ -104,6 +104,9 @@ // #define GDISP_NEED_IMAGE_PNG FALSE // #define GDISP_NEED_IMAGE_ACCOUNTING FALSE +//#define GDISP_NEED_PIXMAP FALSE +// #define GDISP_NEED_PIXMAP_IMAGE FALSE + //#define GDISP_DEFAULT_ORIENTATION GDISP_ROTATE_LANDSCAPE // If not defined the native hardware orientation is used. //#define GDISP_LINEBUF_SIZE 128 //#define GDISP_STARTUP_COLOR Black diff --git a/src/gdisp/driver.h b/src/gdisp/driver.h index 8d22135d..db626a69 100644 --- a/src/gdisp/driver.h +++ b/src/gdisp/driver.h @@ -21,17 +21,47 @@ // Include the GDRIVER infrastructure #include "src/gdriver/sys_defs.h" +// Are we currently compiling the driver itself? +#if defined(GDISP_DRIVER_VMT) + #define IN_DRIVER TRUE +#else + #define IN_DRIVER FALSE +#endif + +// Is this a multiple driver situation? +#if defined(GDISP_DRIVER_LIST) + #define IS_MULTIPLE TRUE +#else + #define IS_MULTIPLE FALSE +#endif + +// Do we need to use VMT calling rather than direct calls to the driver? +#if IS_MULTIPLE || GDISP_NEED_PIXMAP + #define USE_VMT TRUE +#else + #define USE_VMT FALSE +#endif + +// Are we in the pixmap virtual driver +#ifndef IN_PIXMAP_DRIVER + #define IN_PIXMAP_DRIVER FALSE +#endif + +//------------------------------------------------------------------------------------------------------------ + // Our special auto-detect hardware code which uses the VMT. #define HARDWARE_AUTODETECT 2 -#if defined(GDISP_DRIVER_LIST) && !defined(GDISP_DRIVER_VMT) +#if USE_VMT && !IN_DRIVER // Multiple controllers the default is to hardware detect #define HARDWARE_DEFAULT HARDWARE_AUTODETECT #else - // The default is to call the routines directly + // The default is not to include code functions that aren't needed #define HARDWARE_DEFAULT FALSE #endif +//------------------------------------------------------------------------------------------------------------ + /** * @name GDISP hardware accelerated support * @{ @@ -191,9 +221,66 @@ #endif /** @} */ -/*===========================================================================*/ -/* External declarations. */ -/*===========================================================================*/ +//------------------------------------------------------------------------------------------------------------ + +// For pixmaps certain routines MUST not be FALSE as they are needed for pixmap drawing +// Similarly some routines MUST not be TRUE as pixmap's don't provide them. +#if GDISP_NEED_PIXMAP && !IN_DRIVER + #if !GDISP_HARDWARE_DEINIT + #undef GDISP_HARDWARE_DEINIT + #define GDISP_HARDWARE_DEINIT HARDWARE_AUTODETECT + #endif + #if !GDISP_HARDWARE_DRAWPIXEL + #undef GDISP_HARDWARE_DRAWPIXEL + #define GDISP_HARDWARE_DRAWPIXEL HARDWARE_AUTODETECT + #endif + #if !GDISP_HARDWARE_PIXELREAD + #undef GDISP_HARDWARE_PIXELREAD + #define GDISP_HARDWARE_PIXELREAD HARDWARE_AUTODETECT + #endif + #if !GDISP_HARDWARE_CONTROL + #undef GDISP_HARDWARE_CONTROL + #define GDISP_HARDWARE_CONTROL HARDWARE_AUTODETECT + #endif + #if GDISP_HARDWARE_FLUSH == TRUE + #undef GDISP_HARDWARE_FLUSH + #define GDISP_HARDWARE_FLUSH HARDWARE_AUTODETECT + #endif + #if GDISP_HARDWARE_STREAM_WRITE == TRUE + #undef GDISP_HARDWARE_STREAM_WRITE + #define GDISP_HARDWARE_STREAM_WRITE HARDWARE_AUTODETECT + #endif + #if GDISP_HARDWARE_STREAM_READ == TRUE + #undef GDISP_HARDWARE_STREAM_READ + #define GDISP_HARDWARE_STREAM_READ HARDWARE_AUTODETECT + #endif + #if GDISP_HARDWARE_CLEARS == TRUE + #undef GDISP_HARDWARE_CLEARS + #define GDISP_HARDWARE_CLEARS HARDWARE_AUTODETECT + #endif + #if GDISP_HARDWARE_FILLS == TRUE + #undef GDISP_HARDWARE_FILLS + #define GDISP_HARDWARE_FILLS HARDWARE_AUTODETECT + #endif + #if GDISP_HARDWARE_BITFILLS == TRUE + #undef GDISP_HARDWARE_BITFILLS + #define GDISP_HARDWARE_BITFILLS HARDWARE_AUTODETECT + #endif + #if GDISP_HARDWARE_SCROLL == TRUE + #undef GDISP_HARDWARE_SCROLL + #define GDISP_HARDWARE_SCROLL HARDWARE_AUTODETECT + #endif + #if GDISP_HARDWARE_QUERY == TRUE + #undef GDISP_HARDWARE_QUERY + #define GDISP_HARDWARE_QUERY HARDWARE_AUTODETECT + #endif + #if GDISP_HARDWARE_CLIP == TRUE + #undef GDISP_HARDWARE_CLIP + #define GDISP_HARDWARE_CLIP HARDWARE_AUTODETECT + #endif +#endif + +//------------------------------------------------------------------------------------------------------------ /* Verify information for packed pixels and define a non-packed pixel macro */ #if !GDISP_PACKED_PIXELS @@ -224,6 +311,8 @@ void gdispPackPixels(const pixel_t *buf, coord_t cx, coord_t x, coord_t y, color_t color); #endif +//------------------------------------------------------------------------------------------------------------ + struct GDisplay { struct GDriver d; // This must be the first element #define gvmt(g) ((const GDISPVMT const *)((g)->d.vmt)) // For ease of access to the vmt member @@ -309,14 +398,16 @@ typedef struct GDISPVMT { void (*flush)(GDisplay *g); // Uses no parameters } GDISPVMT; +//------------------------------------------------------------------------------------------------------------ + // Do we need function definitions or macro's (via the VMT) -#if !defined(GDISP_DRIVER_LIST) || defined(GDISP_DRIVER_VMT) || defined(__DOXYGEN__) +#if IN_DRIVER || !USE_VMT || defined(__DOXYGEN__) #ifdef __cplusplus extern "C" { #endif // Should the driver routines should be static or not - #if defined(GDISP_DRIVER_LIST) + #if USE_VMT #define LLDSPEC static #else #define LLDSPEC @@ -325,8 +416,8 @@ typedef struct GDISPVMT { /** * @brief Initialize the driver. * @return TRUE if successful. - * @param[in] g The driver structure - * @param[out] g->g The driver must fill in the GDISPControl structure + * @param[in] g The driver structure + * @param[out] g->g The driver must fill in the GDISPControl structure */ LLDSPEC bool_t gdisp_lld_init(GDisplay *g); @@ -602,16 +693,18 @@ typedef struct GDISPVMT { #define gdisp_lld_set_clip(g) gvmt(g)->setclip(g) #endif +//------------------------------------------------------------------------------------------------------------ + // If compiling the driver then build the VMT and set the low level driver color macros. -#ifdef GDISP_DRIVER_VMT +#if IN_DRIVER // Make sure the driver has a valid model #if !GDISP_HARDWARE_STREAM_WRITE && !GDISP_HARDWARE_DRAWPIXEL #error "GDISP Driver: Either GDISP_HARDWARE_STREAM_WRITE or GDISP_HARDWARE_DRAWPIXEL must be TRUE" #endif - // If we are not using multiple displays then hard-code the VMT name - #if !defined(GDISP_DRIVER_LIST) + // If we are not using multiple displays then hard-code the VMT name (except for the pixmap driver) + #if !IS_MULTIPLE && !IN_PIXMAP_DRIVER #undef GDISP_DRIVER_VMT #define GDISP_DRIVER_VMT GDISPVMT_OnlyOne #endif @@ -707,6 +800,8 @@ typedef struct GDISPVMT { #endif }}; + //-------------------------------------------------------------------------------------------------------- + /* Low level driver pixel format information */ //------------------------- // True-Color color system @@ -956,6 +1051,12 @@ typedef struct GDISPVMT { #endif +//------------------------------------------------------------------------------------------------------------ + +#undef IN_PIXMAP_DRIVER +#undef IS_MULTIPLE +#undef IN_DRIVER +#undef USE_VMT #endif /* GFX_USE_GDISP */ #endif /* _GDISP_LLD_H */ diff --git a/src/gdisp/gdisp_colors.h b/src/gdisp/gdisp_colors.h index addd9fa9..6f89b3c4 100644 --- a/src/gdisp/gdisp_colors.h +++ b/src/gdisp/gdisp_colors.h @@ -23,6 +23,8 @@ #if GFX_USE_GDISP || defined(__DOXYGEN__) +typedef uint16_t colorformat; + /** * @name Color system masks * diff --git a/src/gdisp/gdisp_gdisp.c b/src/gdisp/gdisp_gdisp.c index 99861571..74fb0883 100644 --- a/src/gdisp/gdisp_gdisp.c +++ b/src/gdisp/gdisp_gdisp.c @@ -625,12 +625,12 @@ void _gdispDeinit(void) bool_t _gdispInitDriver(GDriver *g, void *param, unsigned driverinstance, unsigned systeminstance) { #define gd ((GDisplay *)g) bool_t ret; - (void) param; // Intialise fields gd->systemdisplay = systeminstance; gd->controllerdisplay = driverinstance; gd->flags = 0; + gd->priv = param; MUTEX_INIT(gd); // Call the driver init diff --git a/src/gdisp/gdisp_pixmap.c b/src/gdisp/gdisp_pixmap.c new file mode 100644 index 00000000..19757757 --- /dev/null +++ b/src/gdisp/gdisp_pixmap.c @@ -0,0 +1,223 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +#include "gfx.h" + +#if GFX_USE_GDISP && GDISP_NEED_PIXMAP + +// We undef everything because the system may think we are in a single controller situation +// but the pixmap supports adds another virtual display +#undef GDISP_HARDWARE_DEINIT +#undef GDISP_HARDWARE_FLUSH +#undef GDISP_HARDWARE_STREAM_WRITE +#undef GDISP_HARDWARE_STREAM_READ +#undef GDISP_HARDWARE_STREAM_POS +#undef GDISP_HARDWARE_DRAWPIXEL +#undef GDISP_HARDWARE_CLEARS +#undef GDISP_HARDWARE_FILLS +#undef GDISP_HARDWARE_BITFILLS +#undef GDISP_HARDWARE_SCROLL +#undef GDISP_HARDWARE_PIXELREAD +#undef GDISP_HARDWARE_CONTROL +#undef GDISP_HARDWARE_QUERY +#undef GDISP_HARDWARE_CLIP +#define GDISP_HARDWARE_DEINIT TRUE +#define GDISP_HARDWARE_DRAWPIXEL TRUE +#define GDISP_HARDWARE_PIXELREAD TRUE +#define GDISP_HARDWARE_CONTROL TRUE +#define IN_PIXMAP_DRIVER TRUE +#define GDISP_DRIVER_VMT GDISPVMT_pixmap + +// This pseudo driver currently only supports unpacked formats with more than 8 bits per pixel +// that is, we only support GRAY_SCALE and PALETTE with 8 bits per pixel or any unpacked TRUE_COLOR format. +#if (GDISP_LLD_PIXELFORMAT & GDISP_COLORSYSTEM_GRAYSCALE) && (GDISP_LLD_PIXELFORMAT & 0xFF) != 8 + #error "GDISP Pixmap: Pixmap's do not currently support the specified GDISP_LLD_PIXELFORMAT" +#endif + +#include "src/gdisp/driver.h" +#include "src/gdriver/sys_defs.h" + +typedef struct pixmap { + #if GDISP_NEED_PIXMAP_IMAGE + uint8_t imghdr[8]; // This field must come just before the data member. + #endif + color_t pixels[1]; // We really want pixels[0] but some compilers don't allow that even though it is C standard. + } pixmap; + +GDisplay *gdispCreatePixmap(coord_t width, coord_t height) { + GDisplay *g; + pixmap *p; + unsigned i; + + // Calculate the size of the display surface in bytes + i = width*height*sizeof(color_t); + if (i < 2*sizeof(coord_t)) + i = 2*sizeof(coord_t); + + // Allocate the pixmap + if (!(p = gfxAlloc(i+sizeof(pixmap)-sizeof(p->pixels)))) + return 0; + + // Fill in the image header (if required) + #if GDISP_NEED_PIXMAP_IMAGE + p->imghdr[0] = 'N'; + p->imghdr[1] = 'I'; + p->imghdr[2] = (uint8_t)(width >> 8); + p->imghdr[3] = (uint8_t)width; + p->imghdr[4] = (uint8_t)(height >> 8); + p->imghdr[5] = (uint8_t)height; + p->imghdr[6] = (uint8_t)(GDISP_PIXELFORMAT >> 8); + p->imghdr[7] = (uint8_t)(GDISP_PIXELFORMAT); + #endif + + // Save the width and height so the driver can retrieve it. + ((coord_t *)p->pixels)[0] = width; + ((coord_t *)p->pixels)[1] = height; + + // Register the driver + g = (GDisplay *)gdriverRegister(&GDISPVMT_pixmap->d, p); + if (!g) + gfxFree(p); + return g; +} + +void gdispDeletePixmap(GDisplay *g) { + if (gvmt(g) != GDISPVMT_pixmap) + return; + gdriverUnRegister(&g->d); +} + +pixel_t *gdispGetPixmapBits(GDisplay *g) { + if (gvmt(g) != GDISPVMT_pixmap) + return 0; + return ((pixmap *)g->priv)->pixels; +} + +#if GDISP_NEED_PIXMAP_IMAGE + void *gdispGetPixmapMemoryImage(GDisplay *g) { + if (gvmt(g) != GDISPVMT_pixmap) + return 0; + return ((pixmap *)g->priv)->imghdr; + } +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { + // The user api function should have already allocated and initialised the pixmap + // structure and put it into the priv member during driver initialisation. + if (!g->priv) + return FALSE; + + // Initialize the GDISP structure + // Width and height were saved into the start of the framebuffer. + g->g.Width = ((coord_t *)((pixmap *)g->priv)->pixels)[0]; + g->g.Height = ((coord_t *)((pixmap *)g->priv)->pixels)[1]; + g->g.Backlight = 100; + g->g.Contrast = 50; + g->g.Orientation = GDISP_ROTATE_0; + g->g.Powermode = powerOn; + g->board = 0; + + return TRUE; +} + +LLDSPEC void gdisp_lld_deinit(GDisplay *g) { + gfxFree(g->priv); +} + +LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g) { + unsigned pos; + + #if GDISP_NEED_CONTROL + switch(g->g.Orientation) { + case GDISP_ROTATE_0: + default: + pos = g->p.y * g->g.Width + g->p.x; + break; + case GDISP_ROTATE_90: + pos = (g->g.Width-g->p.x-1) * g->g.Height + g->p.y; + break; + case GDISP_ROTATE_180: + pos = (g->g.Height-g->p.y-1) * g->g.Width + g->g.Width-g->p.x-1; + break; + case GDISP_ROTATE_270: + pos = g->p.x * g->g.Height + g->g.Height-g->p.y-1; + break; + } + #else + pos = g->p.y * g->g.Width + g->p.x; + #endif + + ((pixmap *)(g)->priv)->pixels[pos] = g->p.color; +} + +LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay *g) { + unsigned pos; + + #if GDISP_NEED_CONTROL + switch(g->g.Orientation) { + case GDISP_ROTATE_0: + default: + pos = g->p.y * g->g.Width + g->p.x; + break; + case GDISP_ROTATE_90: + pos = (g->g.Width-g->p.x-1) * g->g.Height + g->p.y; + break; + case GDISP_ROTATE_180: + pos = (g->g.Height-g->p.y-1) * g->g.Width + g->g.Width-g->p.x-1; + break; + case GDISP_ROTATE_270: + pos = g->p.x * g->g.Height + g->g.Height-g->p.y-1; + break; + } + #else + pos = g->p.y * g->g.Width + g->p.x; + #endif + + return ((pixmap *)(g)->priv)->pixels[pos]; +} + +#if GDISP_NEED_CONTROL + LLDSPEC void gdisp_lld_control(GDisplay *g) { + switch(g->p.x) { + case GDISP_CONTROL_ORIENTATION: + if (g->g.Orientation == (orientation_t)g->p.ptr) + return; + switch((orientation_t)g->p.ptr) { + case GDISP_ROTATE_0: + case GDISP_ROTATE_180: + if (g->g.Orientation == GDISP_ROTATE_90 || g->g.Orientation == GDISP_ROTATE_270) { + coord_t tmp; + + tmp = g->g.Width; + g->g.Width = g->g.Height; + g->g.Height = tmp; + } + break; + case GDISP_ROTATE_90: + case GDISP_ROTATE_270: + if (g->g.Orientation == GDISP_ROTATE_0 || g->g.Orientation == GDISP_ROTATE_180) { + coord_t tmp; + + tmp = g->g.Width; + g->g.Width = g->g.Height; + g->g.Height = tmp; + } + break; + default: + return; + } + g->g.Orientation = (orientation_t)g->p.ptr; + return; + } + } +#endif + +#endif /* GFX_USE_GDISP */ diff --git a/src/gdisp/gdisp_pixmap.h b/src/gdisp/gdisp_pixmap.h new file mode 100644 index 00000000..e933a550 --- /dev/null +++ b/src/gdisp/gdisp_pixmap.h @@ -0,0 +1,87 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file src/gdisp/gdisp_pixmap.h + * @brief GDISP image header file. + * + * @defgroup Pixmap Pixmap + * @ingroup GDISP + * + * @note A Pixmap is an off-screen virtual display that can be drawn to just like any other + * display. It can then be copied to a real display using the standard gdispGBlitArea() call. + * @pre GDISP_NEED_PIXMAP must be TRUE in your gfxconf.h + * @{ + */ + +#ifndef _GDISP_PIXMAP_H +#define _GDISP_PIXMAP_H + +#if (GFX_USE_GDISP && GDISP_NEED_PIXMAP) || defined(__DOXYGEN__) + +#ifdef __cplusplus +extern "C" { +#endif + + /** + * @brief Create an off-screen pixmap that can be drawn to just like a normal display + * + * @param[in] width The width of the pixmap to be created + * @param[in] height The height of the pixmap to be created + * + * @note Once created, an off-screen pixmap can be drawn on using the standard gdispGxxxx calls. + * @note It must be destroyed using @p gdispDeleteOffscreenPixmap + * @note Because the RAM for the display area is allocated, on small micros only very small pixmaps should be considered. + * For example a 100x100 at 16 bits per pixel would be 20K of RAM (plus some overheads). + */ + GDisplay *gdispCreatePixmap(coord_t width, coord_t height); + + /** + * @brief Destroy an off-screen pixmap + * + * @param[in] g The pixmap virtual display to delete + * + * @note If a normal display is passed to this routine, it will be ignored. + */ + void gdispDeletePixmap(GDisplay *g); + + /** + * @brief Get a pointer to the pixels of the display surface. + * @return The pointer to the pixmap display surface or NULL if this display is not a pixmap. + * + * @param[in] g The pixmap virtual display + * + * @note The pointer returned can be used for calls to @p gdispGBlitArea() or can be read or written to directly + * by the application code. For any one particular pixmap the pointer will not change over the life of the pixmap + * (although different pixmaps will have different pixel pointers). Once a pixmap is deleted, the pixel pointer + * should not be used by the application. + */ + pixel_t *gdispGetPixmapBits(GDisplay *g); + + #if GDISP_NEED_PIXMAP_IMAGE || defined(__DOXYGEN__) + /** + * @brief Get a pointer to a native format gdispImage. + * @return A pointer to a NATIVE format gdispImage in memory or NULL if this display is not a pixmap. + * @pre GDISP_NEED_PIXAMP_IMAGE must be TRUE in your gfxconf.h + * + * @param[in] g The pixmap virtual display + * + * @note The pointer returned can be passed to @p gdispImageOpenMemory() or to @gfileOpenMemory(). + * @note If you are just wanting to copy to a real display it is more efficient to use @p gdispGetPixmapBits() and @p gdispGBlitArea(). + * @note Like @p gdispGetPixmapBits(), the pointer returned is valid for the life of the pixmap. + */ + void *gdispGetPixmapMemoryImage(GDisplay *g); + #endif + +#ifdef __cplusplus +} +#endif + +#endif /* GFX_USE_GDISP && GDISP_NEED_PIXMAP */ +#endif /* _GDISP_PIXMAP_H */ +/** @} */ + diff --git a/src/gdisp/sys_defs.h b/src/gdisp/sys_defs.h index f952e41b..6b77bab8 100644 --- a/src/gdisp/sys_defs.h +++ b/src/gdisp/sys_defs.h @@ -1113,6 +1113,10 @@ void gdispGDrawBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, co #if GDISP_NEED_IMAGE || defined(__DOXYGEN__) #include "gdisp_image.h" #endif +#if GDISP_NEED_PIXMAP || defined(__DOXYGEN__) + #include "gdisp_pixmap.h" +#endif + #endif /* GFX_USE_GDISP */ diff --git a/src/gdisp/sys_make.mk b/src/gdisp/sys_make.mk index cbce4224..34710597 100644 --- a/src/gdisp/sys_make.mk +++ b/src/gdisp/sys_make.mk @@ -1,5 +1,6 @@ GFXSRC += $(GFXLIB)/src/gdisp/gdisp_gdisp.c \ $(GFXLIB)/src/gdisp/gdisp_fonts.c \ + $(GFXLIB)/src/gdisp/gdisp_pixmap.c \ $(GFXLIB)/src/gdisp/gdisp_image.c \ $(GFXLIB)/src/gdisp/gdisp_image_native.c \ $(GFXLIB)/src/gdisp/gdisp_image_gif.c \ diff --git a/src/gdisp/sys_options.h b/src/gdisp/sys_options.h index 98be1a46..ebb054e1 100644 --- a/src/gdisp/sys_options.h +++ b/src/gdisp/sys_options.h @@ -177,6 +177,13 @@ #ifndef GDISP_NEED_IMAGE #define GDISP_NEED_IMAGE FALSE #endif + /** + * @brief Is the image interface required. + * @details Defaults to FALSE + */ + #ifndef GDISP_NEED_PIXMAP + #define GDISP_NEED_PIXMAP FALSE + #endif /** * @} * @@ -337,6 +344,15 @@ #ifndef GDISP_NEED_ANTIALIAS #define GDISP_NEED_ANTIALIAS FALSE #endif +/** + * @} + * + * @name GDISP Pixmap Options + * @{ + */ + #ifndef GDISP_NEED_PIXMAP_IMAGE + #define GDISP_NEED_PIXMAP_IMAGE FALSE + #endif /** * @} *