diff --git a/src/Makefile b/src/Makefile index 86ff8a0..df44460 100644 --- a/src/Makefile +++ b/src/Makefile @@ -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 \ diff --git a/src/bitmap.c b/src/bitmap.c new file mode 100755 index 0000000..180d3f8 --- /dev/null +++ b/src/bitmap.c @@ -0,0 +1,25 @@ +#include +#include +#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)); +} diff --git a/src/bitmap.h b/src/bitmap.h new file mode 100755 index 0000000..db09917 --- /dev/null +++ b/src/bitmap.h @@ -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 */ \ No newline at end of file diff --git a/src/dc_screen.c b/src/dc_screen.c index 37d173e..caf5595 100755 --- a/src/dc_screen.c +++ b/src/dc_screen.c @@ -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); +} diff --git a/src/dc_screen.h b/src/dc_screen.h index ecd4f31..560187c 100755 --- a/src/dc_screen.h +++ b/src/dc_screen.h @@ -10,5 +10,6 @@ typedef struct tagSCREENPRIVDATA { } SCREENPRIVDATA, *PSCREENPRIVDATA; extern PDCTXT DC_CreateScreenContext(void); +extern PDCTXT _DC_CreateScreenCompatibleContext(void); #endif /* __DC_SCREEN_H_INCLUDED */ diff --git a/src/devctxt.c b/src/devctxt.c index 9971cbc..9e954d3 100755 --- a/src/devctxt.c +++ b/src/devctxt.c @@ -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); +} diff --git a/src/devctxt.h b/src/devctxt.h index 1b8d3a4..327aab3 100755 --- a/src/devctxt.h +++ b/src/devctxt.h @@ -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_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)) diff --git a/src/ep_devctxt.c b/src/ep_devctxt.c index 651f317..e61611e 100755 --- a/src/ep_devctxt.c +++ b/src/ep_devctxt.c @@ -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",