291 lines
6.2 KiB
C
Executable File
291 lines
6.2 KiB
C
Executable File
#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);
|
|
}
|