upiwin/src/dc_screen.c

310 lines
7.1 KiB
C
Executable File

/*
* UPIWIN - Micro Pi Windowing Framework Kernel
* Copyright (C) 2019 Amy Bowersox/Erbosoft Metaverse Design Solutions
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*-------------------------------------------------------------------------
*/
#include <stdlib.h>
#include <string.h>
#include "log.h"
#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)
{
return priv->pdata + (y * priv->pix_per_row) + x;
}
inline static UINT16 native_from_COLORREF(COLORREF cr)
{
return (UINT16)(((cr << 8) & 0xF800) | ((cr >> 5) & 0x7E0) | ((cr >> 19) & 0x1F));
}
inline static COLORREF COLORREF_from_native(UINT16 cr)
{
UINT32 tmp = cr;
return (COLORREF)(((tmp << 19) & 0xF80000) | ((tmp << 5) & 0xFC00) | ((tmp >> 8) & 0xF800));
}
static inline UINT16 apply_rop2(INT32 op, UINT16 disp, UINT16 pen)
{
switch (op)
{
case R2_BLACK:
return 0;
case R2_NOTMERGEPEN:
return ~(disp | pen);
case R2_MASKNOTPEN:
return disp & (~pen);
case R2_NOTCOPYPEN:
return ~pen;
case R2_MASKPENNOT:
return (~disp) & pen;
case R2_NOT:
return ~disp;
case R2_XORPEN:
return disp ^ pen;
case R2_NOTMASKPEN:
return ~(disp & pen);
case R2_MASKPEN:
return disp & pen;
case R2_NOTXORPEN:
return ~(disp ^ pen);
case R2_NOP:
return disp;
case R2_MERGENOTPEN:
return disp | (~pen);
case R2_COPYPEN:
return pen;
case R2_MERGEPENNOT:
return (~disp) | pen;
case R2_MERGEPEN:
return disp | pen;
case R2_WHITE:
return (UINT16)(-1);
}
return pen; /* last ditch default */
}
static COLORREF screen_set_pixel(PVOID privdata, INT32 x, INT32 y, COLORREF color, INT32 op)
{
PSCREENPRIVDATA priv = (PSCREENPRIVDATA)privdata;
UINT16 pencolor = native_from_COLORREF(color);
PUINT16 loc = loc_from_coords(priv, x, y);
UINT16 screen = *loc;
*loc = apply_rop2(op, screen, pencolor);
return COLORREF_from_native(screen);
}
static BOOL screen_line(PVOID privdata, INT32 x1, INT32 y1, INT32 x2, INT32 y2, COLORREF color, INT32 op)
{
PSCREENPRIVDATA priv = (PSCREENPRIVDATA)privdata;
UINT16 pencolor = native_from_COLORREF(color);
INT32 dx = x2 - x1;
INT32 dy = y2 - y1;
INT32 tmp;
PUINT16 loc;
ASSERT(x1 >= 0);
ASSERT(x1 < Fb_Info->width);
ASSERT(y1 >= 0);
ASSERT(y1 < Fb_Info->height);
ASSERT(x2 >= 0);
ASSERT(x2 < Fb_Info->width);
ASSERT(y2 >= 0);
ASSERT(y2 < Fb_Info->height);
/* uses Bresenham's line algorithm with 16-bit fixed-point arithmetic */
if (ABS(dx) < ABS(dy))
{
if (y1 > y2)
{
tmp = x1;
x1 = x2;
x2 = tmp;
tmp = y1;
y1 = y2;
y2 = tmp;
dx = -dx;
dy = -dy;
}
loc = loc_from_coords(priv, x1, y1);
tmp = x1;
x1 <<= 16;
dx = (dx << 16) / dy;
while (y1 <= y2)
{
*loc = apply_rop2(op, *loc, pencolor);
x1 += dx;
++y1;
loc += priv->pix_per_row;
if (tmp != (x1 >> 16))
{
loc += ((x1 >> 16) - tmp);
tmp = x1 >> 16;
}
}
}
else
{
if (x1 > x2)
{
tmp = x1;
x1 = x2;
x2 = tmp;
tmp = y1;
y1 = y2;
y2 = tmp;
dx = -dx;
dy = -dy;
}
loc = loc_from_coords(priv, x1, y1);
tmp = y1;
y1 <<= 16;
dy = dx ? (dy << 16) / dx : 0;
while (x1 <= x2)
{
*loc = apply_rop2(op, *loc, pencolor);
y1 += dy;
++x1;
++loc;
if (tmp != (y1 >> 16))
{
loc += (((y1 >> 16) - tmp) * priv->pix_per_row);
tmp = y1 >> 16;
}
}
}
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(priv, 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 const DCFUNTABLE screen_funtable; /* forward declaration */
static void screen_context_destroy(PVOID obj);
static PDCTXT screen_create_compat(PVOID privdata)
{
PSCREENPRIVDATA priv_new;
PBITMAP pbmp;
PDCTXT rc;
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_new);
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_solid_rect,
screen_create_compat,
screen_new_bitmap,
screen_bitblt
};
static void screen_context_destroy(PVOID obj)
{
PDCTXT pdctxt = (PDCTXT)obj;
_DC_FinalizeCommon(pdctxt);
free(pdctxt->privdata);
}
PDCTXT DC_CreateScreenContext(void)
{
PDCTXT rc;
PSCREENPRIVDATA priv;
priv = (PSCREENPRIVDATA)malloc(sizeof(SCREENPRIVDATA));
if (!priv)
return NULL;
priv->pix_per_row = Fb_Info->width;
priv->pdata = Fb_Ptr;
rc = _DC_Allocate(&screen_funtable, priv);
if (rc)
{
rc->hdr.dtor = screen_context_destroy;
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);
}