#include #include #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); }