/* init buffered windows by allocating pixmap buffer and clearing background*/ void GsInitWindowBuffer(GR_WINDOW *wp, GR_SIZE width, GR_SIZE height) { /* create same size RGBA pixmap for buffer*/ GR_WINDOW_ID id; /* check if buffer size changed*/ if (wp->buffer) { if (wp->width == width && wp->height == height) return; GsDestroyPixmap(wp->buffer); } id = GsNewPixmap(width, height, MWIF_RGBA8888, NULL); wp->buffer = GsFindPixmap(id); if (!wp->buffer) { wp->props &= ~(GR_WM_PROPS_BUFFERED | GR_WM_PROPS_DRAWING_DONE); return; } /* mark buffer as not ready for display*/ wp->props &= ~GR_WM_PROPS_DRAWING_DONE; /* clear buffer to background color*/ if (!(wp->props & GR_WM_PROPS_NOBACKGROUND)) { GR_PIXMAP *pp = wp->buffer; /* clip to pixmap boundaries*/ #if DYNAMICREGIONS GdSetClipRegion(pp->psd, GdAllocRectRegion(0, 0, pp->psd->xvirtres, pp->psd->yvirtres)); #else MWCLIPRECT cliprect; cliprect.x = 0; cliprect.y = 0; cliprect.width = pp->psd->xvirtres; cliprect.height = pp->psd->yvirtres; GdSetClipRects(pp->psd, 1, &cliprect); #endif clipwp = NULL; /* reset clip cache for next window draw*/ curgcp = NULL; /* invalidate gc cache since we're changing color and mode*/ GdSetFillMode(GR_FILL_SOLID); GdSetMode(GR_MODE_COPY); GdSetForegroundColor(pp->psd, wp->background); GdFillRect(pp->psd, 0, 0, pp->width, pp->height); } }
/* * Setup clip region from device context's associated window or bitmap. * Memory DC's are always associated with the desktop window, and are * always visible. Return the DC's hwnd if window is visible. */ HWND MwPrepareDC(HDC hdc) { HWND hwnd; if(!hdc || !hdc->hwnd) return NULL; hwnd = hdc->hwnd; if (hwnd->unmapcount) return NULL; /* * If the window is not the currently clipped one, then * make it the current one and define its clip rectangles. */ if(hdc != cliphdc) { /* clip memory dc's to the bitmap size*/ if(hdc->psd->flags&PSF_MEMORY) { #if DYNAMICREGIONS GdSetClipRegion(hdc->psd, GdAllocRectRegion(0, 0, hdc->psd->xvirtres, hdc->psd->yvirtres)); #else static MWCLIPRECT crc = {0, 0, 0, 0}; crc.width = hdc->psd->xvirtres; crc.height = hdc->psd->yvirtres; GdSetClipRects(hdc->psd, 1, &crc); #endif } else MwSetClipWindow(hdc); cliphdc = hdc; } return hwnd; }
/* * Prepare to do drawing in a window or pixmap using the specified * graphics context. Returns the drawable pointer if successful, * and the type of drawing id that was supplied. Returns the special value * GR_DRAW_TYPE_NONE if an error is generated, or if drawing is useless. */ GR_DRAW_TYPE GsPrepareDrawing(GR_DRAW_ID id, GR_GC_ID gcid, GR_DRAWABLE **retdp) { GR_WINDOW *wp; /* found window */ GR_PIXMAP *pp; /* found pixmap */ GR_GC *gcp; /* found graphics context */ GR_FONT *fontp; GR_REGION *regionp; /* user clipping region */ MWCLIPREGION *reg; PMWFONT pf; *retdp = NULL; gcp = GsFindGC(gcid); if (gcp == NULL) return GR_DRAW_TYPE_NONE; /* * If the graphics context is not the current one, then * make it the current one and remember to update it. */ if (gcp != curgcp) { curgcp = gcp; gcp->changed = GR_TRUE; } /* * Look for window or pixmap id */ pp = NULL; wp = GsFindWindow(id); if (wp == NULL) { pp = GsFindPixmap(id); if (pp == NULL) return GR_DRAW_TYPE_NONE; #if DYNAMICREGIONS reg = GdAllocRectRegion(0, 0, pp->psd->xvirtres, pp->psd->yvirtres); /* intersect with user region if any*/ if (gcp->regionid) { regionp = GsFindRegion(gcp->regionid); if (regionp) GdIntersectRegion(reg, reg, regionp->rgn); } GdSetClipRegion(pp->psd, reg); #else { MWCLIPRECT cliprect; /* FIXME: setup pixmap clipping, different from windows*/ cliprect.x = 0; cliprect.y = 0; cliprect.width = pp->psd->xvirtres; cliprect.height = pp->psd->yvirtres; GdSetClipRects(pp->psd, 1, &cliprect); } #endif /* reset clip cache for next window draw*/ clipwp = NULL; } else { if (!wp->output) { GsError(GR_ERROR_INPUT_ONLY_WINDOW, id); return GR_DRAW_TYPE_NONE; } if (wp->unmapcount) return GR_DRAW_TYPE_NONE; /* * If the window is not the currently clipped one, * then make it the current one and define its clip rectangles. */ if (wp != clipwp || gcp->changed) { /* find user region for intersect*/ if (gcp->regionid) regionp = GsFindRegion(gcp->regionid); else regionp = NULL; /* * Special handling if user region is not at offset 0,0 */ if (regionp && (gcp->xoff || gcp->yoff)) { MWCLIPREGION *local = GdAllocRegion(); GdCopyRegion(local, regionp->rgn); GdOffsetRegion(local, gcp->xoff, gcp->yoff); GsSetClipWindow(wp, local, gcp->mode & ~GR_MODE_DRAWMASK); GdDestroyRegion(local); } else { GsSetClipWindow(wp, regionp? regionp->rgn: NULL, gcp->mode & ~GR_MODE_DRAWMASK); } } } /* * If the graphics context has been changed, then tell the * device driver about it. */ if (gcp->changed) { GdSetForeground(GdFindColor(gcp->foreground)); GdSetBackground(GdFindColor(gcp->background)); GdSetMode(gcp->mode & GR_MODE_DRAWMASK); GdSetUseBackground(gcp->usebackground); fontp = GsFindFont(gcp->fontid); pf = fontp? fontp->pfont: stdfont; GdSetFont(pf); gcp->changed = GR_FALSE; } *retdp = wp? (GR_DRAWABLE *)wp: (GR_DRAWABLE *)pp; return wp? GR_DRAW_TYPE_WINDOW: GR_DRAW_TYPE_PIXMAP; }
/* * Set the clip rectangles for a window taking into account other * windows that may be obscuring it. The windows that may be obscuring * this one are the siblings of each direct ancestor which are higher * in priority than those ancestors. Also, each parent limits the visible * area of the window. The clipping is not done if it is already up to * date of if the window is not outputtable. */ void GsSetClipWindow(GR_WINDOW *wp, MWCLIPREGION *userregion, int flags) { GR_WINDOW *pwp; /* parent window */ GR_WINDOW *sibwp; /* sibling windows */ MWCLIPRECT *clip; /* first clip rectangle */ GR_COUNT count; /* number of clip rectangles */ GR_COUNT newcount; /* number of new rectangles */ GR_COUNT i; /* current index */ GR_COORD minx; /* minimum clip x coordinate */ GR_COORD miny; /* minimum clip y coordinate */ GR_COORD maxx; /* maximum clip x coordinate */ GR_COORD maxy; /* maximum clip y coordinate */ GR_COORD diff; /* difference in coordinates */ GR_SIZE bs; /* border size */ GR_BOOL toomany; /* TRUE if too many clip rects */ MWCLIPRECT cliprects[MAX_CLIPRECTS]; /* clip rectangles */ if (!wp->realized || !wp->output || (wp == clipwp)) return; clipwp = wp; /* * Start with the rectangle for the complete window. * We will then cut pieces out of it as needed. */ count = 1; clip = cliprects; clip->x = wp->x; clip->y = wp->y; clip->width = wp->width; clip->height = wp->height; /* * First walk upwards through all parent windows, * and restrict the visible part of this window to the part * that shows through all of those parent windows. */ pwp = wp; while (pwp != rootwp) { pwp = pwp->parent; diff = pwp->x - clip->x; if (diff > 0) { clip->width -= diff; clip->x = pwp->x; } diff = (pwp->x + pwp->width) - (clip->x + clip->width); if (diff < 0) clip->width += diff; diff = pwp->y - clip->y; if (diff > 0) { clip->height -= diff; clip->y = pwp->y; } diff = (pwp->y + pwp->height) - (clip->y + clip->height); if (diff < 0) clip->height += diff; } /* * If the window is completely clipped out of view, then * set the clipping region to indicate that. */ if ((clip->width <= 0) || (clip->height <= 0)) { GdSetClipRects(clipwp->psd, 1, cliprects); return; } /* * Now examine all windows that obscure this window, and * for each obscuration, break up the clip rectangles into * the smaller pieces that are still visible. The windows * that can obscure us are the earlier siblings of all of * our parents. */ toomany = GR_FALSE; pwp = wp; /*while (pwp != rootwp) {*/ while (pwp != NULL) { wp = pwp; pwp = wp->parent; if(!pwp) { /* We're clipping the root window*/ sibwp = rootwp->children; wp = NULL; } else sibwp = pwp->children; for (; sibwp != wp; sibwp = sibwp->siblings) { if (!sibwp->realized || !sibwp->output) continue; bs = sibwp->bordersize; minx = sibwp->x - bs; miny = sibwp->y - bs; maxx = sibwp->x + sibwp->width + bs - 1; maxy = sibwp->y + sibwp->height + bs - 1; newcount = count; for (i = 0; i < count; i++) { if (newcount > MAX_CLIPRECTS - 3) { toomany = GR_TRUE; break; } newcount += GsSplitClipRect(&cliprects[i], &cliprects[newcount], minx, miny, maxx, maxy); } count = newcount; } if(pwp == rootwp) break; } if (toomany) { GsError(GR_ERROR_TOO_MUCH_CLIPPING, wp->id); clip->x = 0; clip->y = 0; clip->width = -1; clip->height = -1; count = 1; } /* * Set the clip rectangles. */ GdSetClipRects(clipwp->psd, count, cliprects); }
/* * Prepare to do drawing in a window or pixmap using the specified * graphics context. Returns the drawable pointer if successful, * and the type of drawing id that was supplied. Returns the special value * GR_DRAW_TYPE_NONE if an error is generated, or if drawing is useless. */ GR_DRAW_TYPE GsPrepareDrawing(GR_DRAW_ID id, GR_GC_ID gcid, GR_DRAWABLE **retdp) { GR_WINDOW *wp; /* found window */ GR_PIXMAP *pp; /* found pixmap */ GR_GC *gcp; /* found graphics context */ GR_REGION *regionp; /* user clipping region */ MWCLIPREGION*reg; *retdp = NULL; gcp = GsFindGC(gcid); if (gcp == NULL) return GR_DRAW_TYPE_NONE; /* * If the graphics context is not the current one, then * make it the current one and remember to update it. */ if (gcp != curgcp) { curgcp = gcp; gcp->changed = GR_TRUE; } /* * Look for window or pixmap id */ pp = NULL; wp = GsFindWindow(id); if (wp == NULL) { pp = GsFindPixmap(id); if (pp == NULL) return GR_DRAW_TYPE_NONE; havepixmap: #if DYNAMICREGIONS reg = GdAllocRectRegion(0, 0, pp->psd->xvirtres, pp->psd->yvirtres); /* intersect with user region if any*/ if (gcp->regionid) { regionp = GsFindRegion(gcp->regionid); if (regionp) { /* handle pixmap offsets*/ if (gcp->xoff || gcp->yoff) { MWCLIPREGION *local = GdAllocRegion(); GdCopyRegion(local, regionp->rgn); GdOffsetRegion(local, gcp->xoff, gcp->yoff); GdIntersectRegion(reg, reg, local); GdDestroyRegion(local); } else GdIntersectRegion(reg, reg, regionp->rgn); } } GdSetClipRegion(pp->psd, reg); #else { MWCLIPRECT cliprect; /* FIXME: setup pixmap clipping, different from windows*/ cliprect.x = 0; cliprect.y = 0; cliprect.width = pp->psd->xvirtres; cliprect.height = pp->psd->yvirtres; GdSetClipRects(pp->psd, 1, &cliprect); } #endif /* reset clip cache for next window draw*/ clipwp = NULL; } else { if (!wp->output) { GsError(GR_ERROR_INPUT_ONLY_WINDOW, id); return GR_DRAW_TYPE_NONE; } /* check if buffered window*/ if (wp->props & GR_WM_PROPS_BUFFERED) { pp = wp->buffer; wp = NULL; goto havepixmap; /* draw into pixmap buffer*/ } if (!wp->realized) return GR_DRAW_TYPE_NONE; /* * If the window is not the currently clipped one, * then make it the current one and define its clip rectangles. */ if (wp != clipwp || gcp->changed) { #if DYNAMICREGIONS /* find user region for intersect*/ regionp = gcp->regionid? GsFindRegion(gcp->regionid): NULL; /* Special handling if user region is not at offset 0,0*/ if (regionp && (gcp->xoff || gcp->yoff)) { MWCLIPREGION *local = GdAllocRegion(); GdCopyRegion(local, regionp->rgn); GdOffsetRegion(local, gcp->xoff, gcp->yoff); GsSetClipWindow(wp, local, gcp->mode & ~GR_MODE_DRAWMASK); GdDestroyRegion(local); } else GsSetClipWindow(wp, regionp? regionp->rgn: NULL, gcp->mode & ~GR_MODE_DRAWMASK); #else GsSetClipWindow(wp, NULL, gcp->mode & ~GR_MODE_DRAWMASK); #endif /* DYNAMICREGIONS*/ } } /* * If the graphics context has been changed, then tell the * device driver about it. */ if (gcp->changed) { PSD psd = (wp ? wp->psd : pp->psd); uint32_t mask; int count; if (gcp->linestyle == GR_LINE_SOLID) { mask = 0; count = 0; } else { mask = gcp->dashmask; count = gcp->dashcount; } if (gcp->fgispixelval) GdSetForegroundPixelVal(psd, gcp->foreground); else GdSetForegroundColor(psd, gcp->foreground); if (gcp->bgispixelval) GdSetBackgroundPixelVal(psd, gcp->background); else GdSetBackgroundColor(psd, gcp->background); GdSetMode(gcp->mode & GR_MODE_DRAWMASK); GdSetUseBackground(gcp->usebackground); #if MW_FEATURE_SHAPES GdSetDash(&mask, &count); GdSetFillMode(gcp->fillmode); GdSetTSOffset(gcp->ts_offset.x, gcp->ts_offset.y); switch(gcp->fillmode) { case GR_FILL_STIPPLE: case GR_FILL_OPAQUE_STIPPLE: GdSetStippleBitmap(gcp->stipple.bitmap, gcp->stipple.width, gcp->stipple.height); break; case GR_FILL_TILE: GdSetTilePixmap(gcp->tile.psd, gcp->tile.width, gcp->tile.height); break; } #endif gcp->changed = GR_FALSE; } *retdp = wp? (GR_DRAWABLE *)wp: (GR_DRAWABLE *)pp; return wp? GR_DRAW_TYPE_WINDOW: GR_DRAW_TYPE_PIXMAP; }
/* * Open low level graphics driver */ PSD GdOpenScreen(void) { PSD psd; MWPALENTRY * stdpal; MWSCREENINFO sinfo; psd = scrdev.Open(&scrdev); if (!psd) return NULL; GdGetScreenInfo(psd, &sinfo); gr_pixtype = sinfo.pixtype; gr_ncolors = sinfo.ncolors; /* assume no user changable palette entries*/ gr_firstuserpalentry = (int)psd->ncolors; /* set palette according to system colors and devpalX.c*/ switch((int)psd->ncolors) { #if !defined(NOSTDPAL1) /* don't require stdpal1 if not needed */ case 2: /* 1bpp*/ { extern MWPALENTRY mwstdpal1[2]; stdpal = mwstdpal1; } break; #endif #if !defined(NOSTDPAL2) /* don't require stdpal2 if not needed */ case 4: /* 2bpp*/ { extern MWPALENTRY mwstdpal2[4]; stdpal = mwstdpal2; } break; #endif #if !defined(NOSTDPAL4) /* don't require stdpal4 if not needed */ case 8: /* 3bpp - not fully supported*/ case 16: /* 4bpp*/ { extern MWPALENTRY mwstdpal4[16]; stdpal = mwstdpal4; } break; #endif #if !defined(NOSTDPAL8) /* don't require large stdpal8 if not needed */ case 256: /* 8bpp*/ { extern MWPALENTRY mwstdpal8[256]; #if xxxALPHABLEND /* don't change uniform palette if alpha blending*/ gr_firstuserpalentry = 256; #else /* start after last system-reserved color*/ gr_firstuserpalentry = FIRSTUSERPALENTRY; #endif stdpal = mwstdpal8; } break; #endif /* !defined(NOSTDPAL8)*/ default: /* truecolor*/ /* no palette*/ gr_firstuserpalentry = 0; stdpal = NULL; } /* reset next user palette entry, write hardware palette*/ GdResetPalette(); GdSetPalette(psd, 0, (int)psd->ncolors, stdpal); #if xxxALPHABLEND /* one-time create alpha lookup table for 8bpp systems (takes ~1 sec)*/ if(psd->ncolors == 256) init_alpha_lookup(); #endif #if !NOFONTSORCLIPPING /* init local vars*/ GdSetMode(MWMODE_COPY); GdSetForeground(GdFindColor(MWRGB(255, 255, 255))); /* WHITE*/ GdSetBackground(GdFindColor(MWRGB(0, 0, 0))); /* BLACK*/ GdSetUseBackground(TRUE); GdSetFont(GdCreateFont(psd, MWFONT_SYSTEM_VAR, 0, NULL)); #if DYNAMICREGIONS GdSetClipRegion(psd, GdAllocRectRegion(0, 0, psd->xvirtres, psd->yvirtres)); #else GdSetClipRects(psd, 0, NULL); #endif /* DYNAMICREGIONS*/ #endif /* NOFONTSORCLIPPING*/ /* fill black (actually fill to first palette entry or truecolor 0*/ psd->FillRect(psd, 0, 0, psd->xvirtres-1, psd->yvirtres-1, 0); return psd; }
/* * Setup clip region from device context's associated window or bitmap. * Memory DC's are always associated with the desktop window, and are * always visible. Return the DC's hwnd if window is visible. */ HWND MwPrepareDC(HDC hdc) { HWND hwnd; if(!hdc || !hdc->hwnd) return NULL; hwnd = hdc->hwnd; if (hwnd->unmapcount) return NULL; /* * If the window is not the currently clipped one, then * make it the current one and define its clip rectangles. */ if(hdc != cliphdc) { /* clip memory dc's to the bitmap size*/ if(hdc->psd->flags&PSF_MEMORY) { #if DYNAMICREGIONS /* If hdc has a clip region, use it! */ if (hdc->region != NULL && hdc->region->rgn != NULL && hdc->region->rgn->size != 0) { LPRECT rptr = &(hdc->region->rgn->extents); MWCOORD left, top; /* Bound left,top to 0,0 if they are negative * to avoid an assertion later. */ left = (rptr->left <= 0) ? 0 : rptr->left; top = (rptr->top <= 0) ? 0 : rptr->top; GdSetClipRegion(hdc->psd, GdAllocRectRegion(rptr->left, rptr->top, rptr->right, rptr->bottom)); } else { GdSetClipRegion(hdc->psd, GdAllocRectRegion(0, 0, hdc->psd->xvirtres, hdc->psd->yvirtres)); } #else static MWCLIPRECT crc = {0, 0, 0, 0}; /* If hdc has a clip region, use it! */ if (hdc->region != NULL && hdc->region->rgn != NULL && hdc->region->rgn->size != 0) { LPRECT rptr = &(hdc->region->rgn->extents); /* Bound left,top to 0,0 if they are negative * to avoid an assertion later. */ if (rptr->left > 0) crc.x = rptr->left; if (rptr->top > 0) crc.y = rptr->top; crc.width = rptr->right; crc.height = rptr->bottom; } else { crc.width = hdc->psd->xvirtres; crc.height = hdc->psd->yvirtres; } GdSetClipRects(hdc->psd, 1, &crc); #endif } else MwSetClipWindow(hdc); cliphdc = hdc; } return hwnd; }
/** * Open low level graphics driver. * * @return The screen drawing surface. */ PSD GdOpenScreen(void) { PSD psd; MWPALENTRY * stdpal; psd = scrdev.Open(&scrdev); if (!psd) return NULL; /* assume no user changable palette entries*/ gr_firstuserpalentry = (int)psd->ncolors; /* set palette according to system colors and devpalX.c*/ switch((int)psd->ncolors) { #if !defined(NOSTDPAL1) /* don't require stdpal1 if not needed */ case 2: /* 1bpp*/ { extern MWPALENTRY mwstdpal1[2]; stdpal = mwstdpal1; } break; #endif #if !defined(NOSTDPAL2) /* don't require stdpal2 if not needed */ case 4: /* 2bpp*/ { extern MWPALENTRY mwstdpal2[4]; stdpal = mwstdpal2; } break; #endif #if !defined(NOSTDPAL4) /* don't require stdpal4 if not needed */ case 8: /* 3bpp - not fully supported*/ case 16: /* 4bpp*/ { extern MWPALENTRY mwstdpal4[16]; stdpal = mwstdpal4; } break; #endif #if !defined(NOSTDPAL8) /* don't require large stdpal8 if not needed */ case 256: /* 8bpp*/ { extern MWPALENTRY mwstdpal8[256]; #if UNIFORMPALETTE /* don't change uniform palette if alpha blending*/ gr_firstuserpalentry = 256; #else /* start after last system-reserved color*/ gr_firstuserpalentry = FIRSTUSERPALENTRY; #endif stdpal = mwstdpal8; } break; #endif /* !defined(NOSTDPAL8)*/ default: /* truecolor*/ /* no palette*/ gr_firstuserpalentry = 0; stdpal = NULL; } /* reset next user palette entry, write hardware palette*/ GdResetPalette(); GdSetPalette(psd, 0, (int)psd->ncolors, stdpal); /* init local vars*/ GdSetMode(MWROP_COPY); GdSetFillMode(MWFILL_SOLID); /* Set the fill mode to solid */ GdSetForegroundColor(psd, MWRGB(255, 255, 255)); /* WHITE*/ GdSetBackgroundColor(psd, MWRGB(0, 0, 0)); /* BLACK*/ GdSetUseBackground(TRUE); /* select first builtin font (usually MWFONT_SYSTEM_VAR)*/ //GdSetFont(GdCreateFont(psd, NULL, 0, 0, NULL)); GdSetDash(0, 0); /* No dashing to start */ GdSetStippleBitmap(0,0,0); /* No stipple to start */ #if !NOCLIPPING #if DYNAMICREGIONS GdSetClipRegion(psd, GdAllocRectRegion(0, 0, psd->xvirtres, psd->yvirtres)); #else GdSetClipRects(psd, 0, NULL); #endif /* DYNAMICREGIONS*/ #endif /* NOCLIPPING*/ /* fill black (actually fill to first palette entry or truecolor 0*/ psd->FillRect(psd, 0, 0, psd->xvirtres-1, psd->yvirtres-1, 0); return psd; }