work in progress - support for bitmaps and BitBlt

This commit is contained in:
Amy Bowersox 2019-12-10 17:09:16 -07:00
parent 59c8dcc638
commit b390886277
8 changed files with 278 additions and 9 deletions

View File

@ -3,7 +3,7 @@ RESOURCES=../resources
SPLASHSCREEN=splash-vmwcblk.png
OBJS=main.o sysinput.o ep_init.o ep_upiwin.o ep_backlight.o ep_msg.o ep_devctxt.o ep_upiwin_tmp.o ep_util.o \
fbinit.o rect.o gfxobj.o devctxt.o dc_screen.o fontengine.o fbprimitive.o \
fbinit.o rect.o gfxobj.o devctxt.o dc_screen.o fontengine.o bitmap.o fbprimitive.o \
log.o gpio.o msg_queue.o time_func.o config.o splash.o
LIBS=-lpython3.7m -lcrypt -lfreetype -lbcm2835 -lpthread -ldl -lutil -lm
CFLAGS=-I/usr/include/python3.7m -I/usr/include/freetype2 -I/usr/include/libpng16 \

25
src/bitmap.c Executable file
View File

@ -0,0 +1,25 @@
#include <stdlib.h>
#include <string.h>
#include "bitmap.h"
PBITMAP BMP_Create(INT32 width, INT32 height, const VOID *bits)
{
PBITMAP rc;
UINT32 tot_size = sizeof(BITMAP) + (width * height * sizeof(UINT16));
rc = (PBITMAP)malloc(tot_size);
if (!rc)
return NULL;
memset(rc, 0, tot_size);
_Go_init(&(rc->hdr), BMP_SIG_WORD, tot_size);
rc->width = width;
rc->height = height;
if (bits)
memcpy(rc->bits, bits, width * height * sizeof(UINT16));
return rc;
}
void BMP_Delete(PBITMAP pbmp)
{
Go_release(&(pbmp->hdr));
}

19
src/bitmap.h Executable file
View File

@ -0,0 +1,19 @@
#ifndef __BITMAP_H_INCLUDED
#define __BITMAP_H_INCLUDED
#include "wintype.h"
#include "gfxobj.h"
#define BMP_SIG_WORD 0x706D4221 /* !Bmp */
typedef struct tagBITMAP {
GFXOBJECT hdr;
INT32 width;
INT32 height;
UINT16 bits[0];
} BITMAP, *PBITMAP;
extern PBITMAP BMP_Create(INT32 width, INT32 height, const VOID *bits);
extern void BMP_Delete(PBITMAP pbmp);
#endif /* __BITMAP_H_INCLUDED */

View File

@ -3,6 +3,7 @@
#include "fbinit.h"
#include "devctxt.h"
#include "dc_screen.h"
#include "bitmap.h"
inline static PUINT16 loc_from_coords(PSCREENPRIVDATA priv, INT32 x, INT32 y)
{
@ -151,9 +152,97 @@ static BOOL screen_line(PVOID privdata, INT32 x1, INT32 y1, INT32 x2, INT32 y2,
return TRUE;
}
static BOOL screen_solid_rect(PVOID privdata, PRECT rect, COLORREF color, INT32 op)
{
PSCREENPRIVDATA priv = (PSCREENPRIVDATA)privdata;
UINT16 pencolor = native_from_COLORREF(color);
PUINT16 ps, p;
int y, x;
ps = loc_from_coords(rect->left, rect->top);
for (y = rect->top; y < rect->bottom; y++)
{
p = ps;
for (x = rect->left; x < rect->right; x++)
{
*p = apply_rop2(op, *p, pencolor);
++p;
}
ps += priv->pix_per_row;
}
return TRUE;
}
static PDCTXT screen_create_compat(PVOID privdata)
{
PSCREENPRIVDATA priv_new;
PBITMAP pbmp;
pbmp = BMP_Create(1, 1, NULL);
if (!pbmp)
return NULL;
priv_new = (PSCREENPRIVDATA)malloc(sizeof(SCREENPRIVDATA));
if (!priv_new)
{
Go_release(&(pbmp->hdr));
return NULL;
}
priv_new->pix_per_row = pbmp->width;
priv_new->pdata = pbmp->bits;
rc = _DC_Allocate(&screen_funtable, priv_new);
if (rc)
{
rc->hdr.dtor = screen_context_destroy;
rc->flags = DCFLG_IS_MEMORY;
rc->baserect.left = rc->baserect.top = 0;
rc->baserect.right = pbmp->width;
rc->baserect.bottom = pbmp->height;
memcpy(&(rc->cliprect), &(rc->baserect), sizeof(RECT));
rc->cur_bitmap = pbmp;
}
else
{
free(priv);
Go_release(&(pbmp->hdr));
}
return rc;
}
BOOL screen_new_bitmap(PVOID privdata, PBITMAP pbmp)
{
PSCREENPRIVDATA priv = (PSCREENPRIVDATA)privdata;
priv->pix_per_row = pbmp->width;
priv->pdata = pbmp->bits;
return TRUE;
}
BOOL screen_bitblt(PVOID p_dest, PRECT r_dest, PVOID p_src, PRECT r_src, UINT32 op)
{
PSCREENPRIVDATA dest = (PSCREENPRIVDATA)p_dest;
PSCREENPRIVDATA src = (PSCREENPRIVDATA)p_src;
PUINT16 pd, ps;
INT32 width, i;
pd = loc_from_coords(dest, r_dest->left, r_dest->top);
ps = loc_from_coords(src, r_src->left, r_src->top);
width = r_src->right - r_src->left;
for (i = r_src->top; i < r_src->bottom; ++i)
{
memcpy(pd, ps, width * sizeof(UINT16));
pd += dest->pix_per_row;
ps += src->pix_per_row;
}
return TRUE;
}
static const DCFUNTABLE screen_funtable = {
screen_set_pixel,
screen_line
screen_line,
screen_solid_rect,
screen_create_compat,
screen_new_bitmap,
screen_bitblt
};
static void screen_context_destroy(PVOID obj)
@ -178,11 +267,18 @@ PDCTXT DC_CreateScreenContext(void)
if (rc)
{
rc->hdr.dtor = screen_context_destroy;
rc->cliprect.left = rc->cliprect.top = 0;
rc->cliprect.right = Fb_Info->width - 1;
rc->cliprect.bottom = Fb_Info->height - 1;
rc->flags = DCFLG_IS_SCREEN;
rc->baserect.left = rc->baserect.top = 0;
rc->baserect.right = Fb_Info->width;
rc->baserect.bottom = Fb_Info->height;
memcpy(&(rc->cliprect), &(rc->baserect), sizeof(RECT));
}
else
free(priv);
return rc;
}
PDCTXT _DC_CreateScreenCompatibleContext(void)
{
return screen_create_compat(NULL);
}

View File

@ -10,5 +10,6 @@ typedef struct tagSCREENPRIVDATA {
} SCREENPRIVDATA, *PSCREENPRIVDATA;
extern PDCTXT DC_CreateScreenContext(void);
extern PDCTXT _DC_CreateScreenCompatibleContext(void);
#endif /* __DC_SCREEN_H_INCLUDED */

View File

@ -4,6 +4,8 @@
#include "gfxtype.h"
#include "gfxobj.h"
#include "devctxt.h"
#include "bitmap.h"
#include "dc_screen.h"
inline static BYTE line_clip_outcode(INT32 x, INT32 y, INT32 xmin, INT32 ymin, INT32 xmax, INT32 ymax)
{
@ -124,7 +126,8 @@ PDCTXT _DC_Allocate(PDCFUNTABLE funcs, PVOID privdata)
void _DC_FinalizeCommon(PDCTXT pdctxt)
{
/* nothing here yet */
if (pdctxt->cur_bitmap)
Go_release(&(pdctxt->cur_bitmap->hdr));
}
COLORREF DC_SetPixel(PDCTXT pdctxt, INT32 x, INT32 y, COLORREF color)
@ -163,6 +166,15 @@ BOOL DC_Rectangle(PDCTXT pdctxt, INT32 left, INT32 top, INT32 right, INT32 botto
return TRUE;
}
BOOL DC_SolidRectangle(PDCTXT pdctxt, INT32 left, INT32 top, INT32 right, INT32 bottom)
{
RECT rect, actual;
G_set_rect(&rect, left, top, right, bottom);
if (!G_intersect_rect(&actual, &rect, &(pdctxt->cliprect)))
return TRUE;
return (*(pdctxt->funcs-solid_rect))(pdctxt->privdata, &actual, pdctxt->color, pdctxt->rop2);
}
UINT32 DC_GetROP2(PDCTXT pdctxt)
{
return pdctxt->rop2;
@ -198,3 +210,50 @@ BOOL DC_SetClipRect(PDCTXT pdctxt, PRECT prect)
memcpy(&(pdctxt->cliprect), prect, sizeof(RECT));
return TRUE;
}
PDCTXT DC_CreateCompatible(PDCTXT pdctxt)
{
if (pdctxt)
return (*(pdctxt->funcs->create_compat))(pdctxt->privdata);
return _DC_CreateScreenCompatibleContext();
}
PGFXOBJECT DC_SelectObject(PDCTXT pdctxt, PGFXOBJECT pobj)
{
if (pobj->sig == BMP_SIG_WORD)
{
if ((pdctxt->flags & DCFLG_TYPES) == DCFLG_IS_MEMORY)
{
RECT rtmp;
PBITMAP rbmp = pdctxt->cur_bitmap;
Go_addref(pobj);
if ((*(pdctxt->funcs->new_bitmap))(pdctxt->privdata, (PBITMAP)pobj))
{
pdctxt->cur_bitmap = (PBITMAP)pobj;
pdctxt->baserect.left = pdctxt->baserect.top = 0;
pdctxt->baserect.right = ((PBITMAP)pobj)->width;
pdctxt->baserect.bottom = ((PBITMAP)pobj)->height;
G_intersect_rect(&rtmp, &(pdctxt->baserect), &(pdctxt->cliprect));
memcpy(&(pdctxt->cliprect), &rtmp, sizeof(RECT));
return rbmp;
}
Go_release(pobj);
}
}
return NULL;
}
BOOL DC_BitBlt(PDCTXT dest, INT32 x, INT32 y, INT32 width, INT32 height, PDCTXT source, INT32 x1, INT32 y1, UINT32 rop)
{
RECT destrect, actualdest, srcrect, actualsrc;
G_set_rect(&destrect, x, y, x + width, y + height);
if (!G_rect_intersect(&actualdest, &destrect, &(dest->cliprect)))
return TRUE; /* no-op */
G_set_rect(&srcrect, x1, y1, x1 + (actualdest.right - actualdest.left), y1 + (actualdest.bottom - actualdest.top));
if (!G_rect_intersect(&actualsrc, &srcrect, &(src->baserect)))
return TRUE;
actualdest.right = actualdest.left + (actualsrc.right - actualsrc.left);
actualdest.bottom = actualdest.top + (actualsrc.bottom - actualsrc.top);
return (*(dest->funcs->bitblt))(dest->privdata, &actualdest, src->privdata, &actualsrc, rop);
}

View File

@ -27,10 +27,18 @@
typedef COLORREF (*DCtx_SetPixel)(PVOID privdata, INT32 x, INT32 y, COLORREF color, INT32 op);
typedef BOOL (*DCtx_Line)(PVOID privdata, INT32 x1, INT32 y1, INT32 x2, INT32 y2, COLORREF color, INT32 op);
typedef BOOL (*DCtx_SolidRect)(PVOID privdata, PRECT rect, COLORREF color, INT32 op);
typedef PDCTXT (*DCtx_CreateCompat)(PVOID privdata);
typedef BOOL (*DCtx_NewBitmap)(PVOID privdata, PBITMAP pbmp);
typedef BOOL (*DCtx_BitBlt)(PVOID p_dest, PRECT r_dest, PVOID p_src, PRECT r_src, UINT32 op);
typedef struct tagDCFUNTABLE {
DCtx_SetPixel set_pixel; /* sets a single pixel on the display */
DCtx_Line line; /* draws a line on the display */
DCtx_SolidRect solid_rect; /* draws a solid rectangle on the display */
DCtx_CreateCompat create_compat; /* create a memory DC compatible with this one */
DCtx_NewBitmap new_bitmap; /* new bitmap selected notification */
DCtx_BitBlt bitblt; /* bit block transfer */
} DCFUNTABLE;
typedef const DCFUNTABLE *PDCFUNTABLE;
@ -39,12 +47,19 @@ typedef struct tagDCTXT {
GFXOBJECT hdr; /* the header of all objects */
PDCFUNTABLE funcs; /* device context functions */
PVOID privdata; /* private data for the type of DC */
UINT32 flags; /* flags for the DC */
RECT baserect; /* base rectangle */
RECT cliprect; /* clipping rectangle */
POINT pos; /* current position */
UINT32 rop2; /* current raster operation */
COLORREF color; /* current drawing color (XXX replace with pens later) */
PBITMAP cur_bitmap; /* current selected bitmap */
} DCTXT, *PDCTXT;
#define DCFLG_TYPES 0x03
#define DCFLG_IS_SCREEN 0x00
#define DCFLG_IS_MEMORY 0x01
extern PDCTXT _DC_Allocate(PDCFUNTABLE funcs, PVOID privdata);
extern void _DC_FinalizeCommon(PDCTXT pdctxt);
@ -52,12 +67,16 @@ extern COLORREF DC_SetPixel(PDCTXT pdctxt, INT32 x, INT32 y, COLORREF color);
extern BOOL DC_LineTo(PDCTXT pdctxt, INT32 x, INT32 y);
extern BOOL DC_MoveTo(PDCTXT pdctxt, INT32 x, INT32 y, PPOINT oldpt);
extern BOOL DC_Rectangle(PDCTXT pdctxt, INT32 left, INT32 top, INT32 right, INT32 bottom);
extern BOOL DC_SolidRectangle(PDCTXT pdctxt, INT32 left, INT32 top, INT32 right, INT32 bottom);
extern UINT32 DC_GetROP2(PDCTXT pdctxt);
extern UINT32 DC_SetROP2(PDCTXT pdctxt, UINT32 rop);
extern COLORREF DC_GetTextColor(PDCTXT pdctxt);
extern COLORREF DC_SetTextColor(PDCTXT pdctxt, COLORREF cr);
extern BOOL DC_GetClipRect(PDCTXT pdctxt, PRECT prect);
extern BOOL DC_SetClipRect(PDCTXT pdctxt, PRECT prect);
extern PDCTXT DC_CreateCompatible(PDCTXT pdctxt);
extern PGFXOBJECT DC_SelectObject(PDCTXT pdctxt, PGFXOBJECT pobj);
extern BOOL DC_BitBlt(PDCTXT dest, INT32 x, INT32 y, INT32 width, INT32 height, PDCTXT source, INT32 x1, INT32 y1, UINT32 rop);
#define DC_addref(pdctxt) Go_addref(&(pdctxt->hdr))
#define DC_release(pdctxt) Go_release(&(pdctxt->hdr))

View File

@ -13,6 +13,8 @@ typedef struct tagDevCtxtObject {
PDCTXT pdctxt;
} DevCtxtObject;
PyTypeObject DevCtxtType; /* forward declaration */
static PyObject *devctxt_set_pixel(DevCtxtObject *self, PyObject *args)
{
INT32 x, y;
@ -77,6 +79,41 @@ static PyObject *devctxt_rectangle(DevCtxtObject *self, PyObject *args)
return PyBool_FromLong(rc);
}
static PyObject *devctxt_solid_rectangle(DevCtxtObject *self, PyObject *args)
{
INT32 left, top, right, bottom;
BOOL rc;
if (!PyArg_ParseTuple(args, "iiii", &left, &top, &right, &bottom))
return NULL;
if (!(self->pdctxt))
{
PyErr_SetString(PyExc_RuntimeError, "bad device context");
return NULL;
}
rc = DC_SolidRectangle(self->pdctxt, left, top, right, bottom);
return PyBool_FromLong(rc);
}
static PyObject *devctxt_bitblt(DevCtxtObject *self, PyObject *args)
{
INT32 x, y, width, height, x1, y1;
UINT32 rop;
DevCtxtObject *source;
BOOL rc;
if (!PyArg_ParseTuple(args, "iiiiO!iik", &x, &y, &width, &height, &DevCtxtType, &source, &x1, &y1, &rop))
return NULL;
if (!(self->pdctxt) || !(source->pdctxt))
{
PyErr_SetString(PyExc_RuntimeError, "bad device context");
return NULL;
}
rc = DC_BitBlt(self->pdctxt, x, y, width, height, source->pdctxt, x1, y1, rop);
return PyBool_FromLong(rc);
}
static PyObject *devctxt_get_clip_rect(DevCtxtObject *self, PyObject *args)
{
RECT rect;
@ -117,6 +154,10 @@ static PyMethodDef DevCtxtMethods[] = {
"Draws a line from the current position to the specified location."},
{"rectangle", (PyCFunction)devctxt_rectangle, METH_VARARGS,
"Draws a rectangle."},
{"solid_rectangle", (PyCFunction)devctxt_solid_rectangle, METH_VARARGS,
"Draws a solid rectangle."},
{"bitblt", (PyCFunction)devctxt_bitblt, METH_VARARGS,
"Copy bits from one device context to another."},
{"get_clip_rect", (PyCFunction)devctxt_get_clip_rect, METH_VARARGS,
"Returns the current clipping rectangle of the device context."},
{"set_clip_rect", (PyCFunction)devctxt_set_clip_rect, METH_VARARGS,
@ -218,6 +259,15 @@ static int devctxt_init(DevCtxtObject *self, PyObject *args, PyObject *kwds)
return -1;
}
}
else if (strcmp(type, "memory") == 0)
{
self->pdctxt = _DC_CreateScreenCompatibleContext();
if (!(self->pdctxt))
{
PyErr_SetString(PyExc_RuntimeError, "unable to create memory context");
return -1;
}
}
else
{
PyErr_Format(PyExc_RuntimeError, "invalid type '%s'", type);
@ -226,7 +276,7 @@ static int devctxt_init(DevCtxtObject *self, PyObject *args, PyObject *kwds)
return 0;
}
static PyTypeObject DevCtxtType = {
PyTypeObject DevCtxtType = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "upiwin.DevCtxt",
.tp_doc = "Device context object",