/* * Copyright (c) 2002-2007 Hypertriton, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Low-level primitive graphics routines for use by GUI widgets. */ #include "opengl.h" #include #include #include "widget.h" #include "window.h" #include "primitive.h" #include "gui_math.h" AG_PrimitiveOps agPrim; #ifdef HAVE_OPENGL static Uint8 DisabledStipple[128]; /* Stiple pattern for "disabled" items */ #endif /* Add to individual RGB components of a pixel. */ /* TODO use SIMD to compute the components in parallel */ static __inline__ Uint32 ColorShift(Uint32 pixel, Sint8 *shift) { Sint8 r = shift[0]; Sint8 g = shift[1]; Sint8 b = shift[2]; Uint32 rv = 0; int v1, v2; v1 = ((pixel & agVideoFmt->Rmask) >> agVideoFmt->Rshift); v2 = ((v1 << agVideoFmt->Rloss) + (v1 >> (8 - agVideoFmt->Rloss))) + r; if (v2 < 0) { v2 = 0; } else if (v2 > 255) { v2 = 255; } rv |= (v2 >> agVideoFmt->Rloss) << agVideoFmt->Rshift; v1 = ((pixel & agVideoFmt->Gmask) >> agVideoFmt->Gshift); v2 = ((v1 << agVideoFmt->Gloss) + (v1 >> (8 - agVideoFmt->Gloss))) + g; if (v2 < 0) { v2 = 0; } else if (v2 > 255) { v2 = 255; } rv |= (v2 >> agVideoFmt->Gloss) << agVideoFmt->Gshift; v1 = ((pixel & agVideoFmt->Bmask) >> agVideoFmt->Bshift); v2 = ((v1 << agVideoFmt->Bloss) + (v1 >> (8 - agVideoFmt->Bloss))) + b; if (v2 < 0) { v2 = 0; } else if (v2 > 255) { v2 = 255; } rv |= (v2 >> agVideoFmt->Bloss) << agVideoFmt->Bshift; rv |= agVideoFmt->Amask; return (rv); } static void ArrowUpFB(void *p, int x0, int y0, int h, Uint32 c1, Uint32 c2) { AG_Widget *wid = p; int y1 = wid->rView.y1 + y0 - (h>>1); int y2 = y1 + h - 1; int xs = wid->rView.x1 + x0, xe = xs; int x, y; AG_LockView(); for (y = y1; y < y2; y+=2) { for (x = xs; x <= xe; x++) { AG_VIEW_PUT_PIXEL2_CLIPPED(x, y, (x == xs || x == xe) ? c2 : c1); AG_VIEW_PUT_PIXEL2_CLIPPED(x, y+1, c1); } xs--; xe++; } AG_UnlockView(); } static void ArrowDownFB(void *p, int x0, int y0, int h, Uint32 c1, Uint32 c2) { AG_Widget *wid = p; int y1 = wid->rView.y1 + y0 - (h>>1); int y2 = y1+h-1; int xs = wid->rView.x1 + x0, xe = xs; int x, y; AG_LockView(); for (y = y2; y > y1; y-=2) { for (x = xs; x <= xe; x++) { AG_VIEW_PUT_PIXEL2_CLIPPED(x, y, (x == xs || x == xe) ? c2 : c1); AG_VIEW_PUT_PIXEL2_CLIPPED(x, y-1, c1); } xs--; xe++; } AG_UnlockView(); } static void ArrowLeftFB(void *p, int x0, int y0, int h, Uint32 c1, Uint32 c2) { AG_Widget *wid = p; int x1 = wid->rView.x1 + x0 - (h>>1); int x2 = x1+h-1; int ys = wid->rView.y1 + y0, ye = ys; int x, y; AG_LockView(); for (x = x1; x < x2; x+=2) { for (y = ys; y <= ye; y++) { AG_VIEW_PUT_PIXEL2_CLIPPED(x+1, y, c1); AG_VIEW_PUT_PIXEL2_CLIPPED(x, y, (y == ys || y == ye) ? c2 : c1); } ys--; ye++; } AG_UnlockView(); } static void ArrowRightFB(void *p, int x0, int y0, int h, Uint32 c1, Uint32 c2) { AG_Widget *wid = p; int x1 = wid->rView.x1 + x0 - (h>>1); int x2 = x1+h-1; int ys = wid->rView.y1 + y0, ye = ys; int x, y; AG_LockView(); for (x = x2; x > x1; x-=2) { for (y = ys; y <= ye; y++) { AG_VIEW_PUT_PIXEL2_CLIPPED(x-1, y, c1); AG_VIEW_PUT_PIXEL2_CLIPPED(x, y, (y == ys || y == ye) ? c2 : c1); } ys--; ye++; } AG_UnlockView(); } /* Render a 3D-style box. */ static void Box(void *p, AG_Rect r, int z, Uint32 c) { AG_Widget *wid = p; Uint32 cBg; if (AG_WidgetFocused(wid)) { cBg = ColorShift(c, (z<0) ? agFocusSunkColorShift : agFocusRaisedColorShift); } else { cBg = ColorShift(c, (z<0) ? agNofocusSunkColorShift : agNofocusRaisedColorShift); } AG_DrawRectFilled(wid, r, cBg); AG_DrawFrame(wid, r, z, c); } /* Render a 3D-style box with dithering. */ static void BoxDisabledFB(void *p, AG_Rect r, int z, Uint32 c1, Uint32 c2) { AG_Widget *wid = p; int x, y; int flag = 0; Uint32 cDither; if (AG_WidgetFocused(wid)) { cDither = ColorShift(c2, (z<0) ? agFocusSunkColorShift : agFocusRaisedColorShift); } else { cDither = ColorShift(c2, (z<0) ? agNofocusSunkColorShift : agNofocusRaisedColorShift); } /* XXX inefficient */ AG_DrawBox(p, r, z, c1); AG_LockView(); for (y = r.y; y < r.y+r.h-2; y++) { flag = !flag; for (x = r.x+1+flag; x < r.x+r.w-2; x+=2) AG_WidgetPutPixel(wid, x, y, cDither); } AG_UnlockView(); } /* Render a 3D-style box with rounded top edges. */ static void BoxRoundedTopFB(void *p, AG_Rect r, int z, int rad, Uint32 cBg) { AG_Widget *wid = p; AG_Rect rd; Uint32 cLeft, cRight; int v, e, u; int x, y, i; cLeft = ColorShift(cBg, (z<0) ? agLowColorShift:agHighColorShift); cRight = ColorShift(cBg, (z<0) ? agHighColorShift:agLowColorShift); /* Center */ rd.x = r.x+rad; rd.y = r.y+rad; rd.w = r.w - rad*2; rd.h = r.h - rad; AG_DrawRectFilled(wid, rd, cBg); /* Top */ rd.y = r.y; rd.h = r.h; AG_DrawRectFilled(wid, rd, cBg); /* Left */ rd.x = r.x; rd.y = r.y+rad; rd.w = rad; rd.h = r.h-rad; AG_DrawRectFilled(wid, rd, cBg); /* Right */ rd.x = r.x+r.w-rad; rd.y = r.y+rad; rd.w = rad; rd.h = r.h-rad; AG_DrawRectFilled(wid, rd, cBg); /* Top, left and right lines */ AG_DrawLineH(wid, r.x+rad, r.x+r.w-rad, r.y, cBg); AG_DrawLineV(wid, r.x, r.y+rad, r.y+r.h, cLeft); AG_DrawLineV(wid, r.x+r.w-1, r.y+rad, r.y+r.h, cRight); /* Top left and top right rounded edges */ v = 2*rad - 1; e = 0; u = 0; x = 0; y = rad; AG_LockView(); while (x <= y) { AG_WidgetPutPixel(wid, r.x+rad-x, r.y+rad-y, cLeft); AG_WidgetPutPixel(wid, r.x+rad-y, r.y+rad-x, cLeft); AG_WidgetPutPixel(wid, r.x-rad+(r.w-1)+x, r.y+rad-y, cRight); AG_WidgetPutPixel(wid, r.x-rad+(r.w-1)+y, r.y+rad-x, cRight); for (i = 0; i < x; i++) { AG_WidgetPutPixel(wid, r.x+rad-i, r.y+rad-y, cBg); AG_WidgetPutPixel(wid, r.x-rad+(r.w-1)+i, r.y+rad-y, cBg); } for (i = 0; i < y; i++) { AG_WidgetPutPixel(wid, r.x+rad-i, r.y+rad-x, cBg); AG_WidgetPutPixel(wid, r.x-rad+(r.w-1)+i, r.y+rad-x, cBg); } e += u; u += 2; if (v < 2*e) { y--; e -= v; v -= 2; } x++; } AG_UnlockView(); } /* Render a 3D-style box with rounded edges. */ static void BoxRoundedFB(void *p, AG_Rect r, int z, int pRad, Uint32 c) { AG_Widget *wid = p; int rad = pRad; AG_Rect rd; Uint32 cL, cR, cBg; int v, e, u; int x, y, i; int w1 = r.w - 1; if (rad*2 > r.w || rad*2 > r.h) { rad = MIN(r.w/2, r.h/2); } if (r.w < 4 || r.h < 4) return; if (AG_WidgetFocused(wid)) { cBg = ColorShift(c, (z<0) ? agFocusSunkColorShift : agFocusRaisedColorShift); } else { cBg = ColorShift(c, (z<0) ? agNofocusSunkColorShift : agNofocusRaisedColorShift); } cL = ColorShift(cBg, (z<0) ? agLowColorShift:agHighColorShift); cR = ColorShift(cBg, (z<0) ? agHighColorShift:agLowColorShift); /* Center */ rd.x = r.x+rad; rd.y = r.y+rad; rd.w = r.w - rad*2; rd.h = r.h - rad*2; AG_DrawRectFilled(wid, rd, cBg); /* Top */ rd.y = r.y; rd.h = rad; AG_DrawRectFilled(wid, rd, cBg); /* Bottom */ rd.y = r.h-rad; rd.h = rad; AG_DrawRectFilled(wid, rd, cBg); /* Left */ rd.x = r.x; rd.y = r.y+rad; rd.w = rad; rd.h = r.h-rad*2; AG_DrawRectFilled(wid, rd, cBg); /* Right */ rd.x = r.x+r.w-rad; rd.y = r.y+rad; rd.w = rad; rd.h = r.h-rad*2; AG_DrawRectFilled(wid, rd, cBg); /* Rounded edges */ v = 2*rad - 1; e = 0; u = 0; x = 0; y = rad; AG_LockView(); while (x <= y) { AG_WidgetPutPixel(wid, r.x+rad-x, r.y+rad-y, cL); AG_WidgetPutPixel(wid, r.x+rad-y, r.y+rad-x, cL); AG_WidgetPutPixel(wid, r.x-rad+w1+x, r.y+rad-y, cR); AG_WidgetPutPixel(wid, r.x-rad+w1+y, r.y+rad-x, cR); AG_WidgetPutPixel(wid, r.x+rad-x, r.y+r.h-rad+y, cL); AG_WidgetPutPixel(wid, r.x+rad-y, r.y+r.h-rad+x, cL); AG_WidgetPutPixel(wid, r.x-rad+w1+x, r.y+r.h-rad+y, cR); AG_WidgetPutPixel(wid, r.x-rad+w1+y, r.y+r.h-rad+x, cR); for (i = 0; i < x; i++) { AG_WidgetPutPixel(wid, r.x+rad-i, r.y+rad-y, cBg); AG_WidgetPutPixel(wid, r.x-rad+w1+i, r.y+rad-y, cBg); AG_WidgetPutPixel(wid, r.x+rad-i, r.y+r.h-rad+y,cBg); AG_WidgetPutPixel(wid, r.x-rad+w1+i, r.y+r.h-rad+y,cBg); } for (i = 0; i < y; i++) { AG_WidgetPutPixel(wid, r.x + rad - i, r.y + rad - x, cBg); AG_WidgetPutPixel(wid, r.x - rad + w1 + i, r.y + rad - x, cBg); AG_WidgetPutPixel(wid, r.x + rad - i, r.y + r.h - rad + x, cBg); AG_WidgetPutPixel(wid, r.x - rad + w1 + i, r.y + r.h - rad + x, cBg); } e += u; u += 2; if (v < 2*e) { y--; e -= v; v -= 2; } x++; } /* Contour lines */ AG_DrawLineH(wid, r.x+rad, r.x+r.w-rad, r.y, cBg); AG_DrawLineH(wid, r.x+rad/2, r.x+r.w-rad/2, r.y, cL); AG_DrawLineH(wid, r.x+rad/2, r.x+r.w-rad/2, r.y+r.h, cR); AG_DrawLineV(wid, r.x, r.y+rad, r.y+r.h-rad, cL); AG_DrawLineV(wid, r.x+w1, r.y+rad, r.y+r.h-rad, cR); AG_UnlockView(); } /* Render a 3D-style frame. */ static void Frame(void *p, AG_Rect r, int z, Uint32 color) { AG_Widget *wid = p; Uint32 cLeft = ColorShift(color, (z<0) ? agLowColorShift : agHighColorShift); Uint32 cRight = ColorShift(color, (z<0) ? agHighColorShift : agLowColorShift); AG_DrawLineH(wid, r.x, r.x+r.w-1, r.y, cLeft); AG_DrawLineH(wid, r.x, r.x+r.w, r.y+r.h-1, cRight); AG_DrawLineV(wid, r.x, r.y, r.y+r.h-1, cLeft); AG_DrawLineV(wid, r.x+r.w-1, r.y, r.y+r.h-1, cRight); } /* Render a blended 3D-style frame. */ static void FrameBlended(void *p, AG_Rect r, Uint8 c[4], AG_BlendFn func) { AG_Widget *wid = p; AG_DrawLineBlended(wid, r.x, r.y, r.x+r.w-1, r.y, c, func); AG_DrawLineBlended(wid, r.x, r.y, r.x, r.y+r.h-1, c, func); AG_DrawLineBlended(wid, r.x, r.y+r.h-1, r.x+r.w-1, r.y+r.h-1, c, func); AG_DrawLineBlended(wid, r.x+r.w-1, r.y, r.x+r.w-1, r.y+r.h-1, c, func); } /* Render a circle using a modified Bresenham line algorithm. */ static void CircleFB(void *p, int px, int py, int radius, Uint32 color) { AG_Widget *wid = p; int v = 2*radius - 1; int e = 0, u = 1; int x = 0, y = radius; AG_LockView(); while (x < y) { AG_WidgetPutPixel(wid, px+x, py+y, color); AG_WidgetPutPixel(wid, px+x, py-y, color); AG_WidgetPutPixel(wid, px-x, py+y, color); AG_WidgetPutPixel(wid, px-x, py-y, color); e += u; u += 2; if (v < 2*e) { y--; e -= v; v -= 2; } x++; AG_WidgetPutPixel(wid, px+y, py+x, color); AG_WidgetPutPixel(wid, px+y, py-x, color); AG_WidgetPutPixel(wid, px-y, py+x, color); AG_WidgetPutPixel(wid, px-y, py-x, color); } AG_WidgetPutPixel(wid, px-radius, py, color); AG_WidgetPutPixel(wid, px+radius, py, color); AG_UnlockView(); } static void Circle2FB(void *p, int px, int py, int radius, Uint32 color) { AG_Widget *wid = p; int v = 2*radius - 1; int e = 0, u = 1; int x = 0, y = radius; AG_LockView(); while (x < y) { AG_WidgetPutPixel(wid, px+x, py+y, color); AG_WidgetPutPixel(wid, px+x+1, py+y, color); AG_WidgetPutPixel(wid, px+x, py-y, color); AG_WidgetPutPixel(wid, px+x+1, py-y, color); AG_WidgetPutPixel(wid, px-x, py+y, color); AG_WidgetPutPixel(wid, px-x-1, py+y, color); AG_WidgetPutPixel(wid, px-x, py-y, color); AG_WidgetPutPixel(wid, px-x-1, py-y, color); e += u; u += 2; if (v < 2*e) { y--; e -= v; v -= 2; } x++; AG_WidgetPutPixel(wid, px+y, py+x, color); AG_WidgetPutPixel(wid, px+y+1, py+x, color); AG_WidgetPutPixel(wid, px+y, py-x, color); AG_WidgetPutPixel(wid, px+y+1, py-x, color); AG_WidgetPutPixel(wid, px-y, py+x, color); AG_WidgetPutPixel(wid, px-y-1, py+x, color); AG_WidgetPutPixel(wid, px-y, py-x, color); AG_WidgetPutPixel(wid, px-y-1, py-x, color); } AG_WidgetPutPixel(wid, px-radius, py, color); AG_WidgetPutPixel(wid, px+radius, py, color); AG_UnlockView(); } /* Render a 3D-style line. */ static void Line2(void *wid, int x1, int y1, int x2, int y2, Uint32 color) { AG_DrawLine(wid, x1, y1, x2, y2, ColorShift(color, agHighColorShift)); AG_DrawLine(wid, x1+1, y1+1, x2+1, y2+1, ColorShift(color, agLowColorShift)); } /* * Render a line segment between two points using the Bresenham algorithm * as presented by Foley & Van Dam [1990]. */ static void LineFB(void *widget, int x1, int y1, int x2, int y2, Uint32 color) { AG_Widget *wid = widget; int dx, dy; int inc1, inc2; int x, y, d; int xend, yend; int xdir, ydir; dx = abs(x2 - x1); dy = abs(y2 - y1); AG_LockView(); if (dy <= dx) { d = dy*2 - dx; inc1 = dy*2; inc2 = (dy-dx)*2; if (x1 > x2) { x = x2; y = y2; ydir = -1; xend = x1; } else { x = x1; y = y1; ydir = 1; xend = x2; } AG_WidgetPutPixel(wid, x, y, color); if (((y2-y1)*ydir) > 0) { while (x < xend) { x++; if (d < 0) { d += inc1; } else { y++; d += inc2; } AG_WidgetPutPixel(wid, x, y, color); } } else { while (x < xend) { x++; if (d < 0) { d += inc1; } else { y--; d += inc2; } AG_WidgetPutPixel(wid, x, y, color); } } } else { d = dx*2 - dy; inc1 = dx*2; inc2 = (dx-dy)*2; if (y1 > y2) { y = y2; x = x2; yend = y1; xdir = -1; } else { y = y1; x = x1; yend = y2; xdir = 1; } AG_WidgetPutPixel(wid, x, y, color); if (((x2-x1)*xdir) > 0) { while (y < yend) { y++; if (d < 0) { d += inc1; } else { x++; d += inc2; } AG_WidgetPutPixel(wid, x, y, color); } } else { while (y < yend) { y++; if (d < 0) { d += inc1; } else { x--; d += inc2; } AG_WidgetPutPixel(wid, x, y, color); } } } AG_UnlockView(); } static __inline__ int ClipHorizLine(AG_Widget *wid, int *x1, int *x2, int *y, int *dx) { SDL_Rect *rd = &agView->v->clip_rect; if ((wid->rView.y1 + *y) < rd->y || (wid->rView.y1 + *y) >= rd->y+rd->h) { return (1); } if (*x1 > *x2) { *dx = *x2; *x2 = *x1; *x1 = *dx; } if (wid->rView.x1 + *x1 < rd->x) *x1 = rd->x - wid->rView.x1; if (wid->rView.x1 + *x2 >= rd->x+rd->w) *x2 = rd->x + rd->w - wid->rView.x1 - 1; *dx = *x2 - *x1; return (*dx <= 0); } static void LineH32(void *widget, int x1, int x2, int y, Uint32 c) { AG_Widget *wid = widget; Uint8 *pDst, *pEnd; int dx; if (ClipHorizLine(wid, &x1, &x2, &y, &dx)) { return; } AG_LockView(); pDst = (Uint8 *)agView->v->pixels + (wid->rView.y1 + y)*agView->v->pitch + ((wid->rView.x1 + x1) << 2); pEnd = pDst + (dx<<2); while (pDst < pEnd) { *(Uint32 *)pDst = c; pDst += 4; } AG_UnlockView(); } static void LineH24(void *widget, int x1, int x2, int y, Uint32 c) { AG_Widget *wid = widget; Uint8 *pDst, *pEnd; int dx; if (ClipHorizLine(wid, &x1, &x2, &y, &dx)) { return; } AG_LockView(); pDst = (Uint8 *)agView->v->pixels + (wid->rView.y1 + y)*agView->v->pitch + (wid->rView.x1 + x1)*3; pEnd = pDst + dx*3; while (pDst < pEnd) { #if AG_BYTEORDER == AG_BIG_ENDIAN pDst[0] = (c >>16) & 0xff; pDst[1] = (c >>8) & 0xff; pDst[2] = c & 0xff; #else pDst[2] = (c>>16) & 0xff; pDst[1] = (c>>8) & 0xff; pDst[0] = c & 0xff; #endif pDst += 3; } AG_UnlockView(); } static void LineH16(void *widget, int x1, int x2, int y, Uint32 c) { AG_Widget *wid = widget; Uint8 *pDst, *pEnd; int dx; if (ClipHorizLine(wid, &x1, &x2, &y, &dx)) { return; } AG_LockView(); pDst = (Uint8 *)agView->v->pixels + (wid->rView.y1 + y)*agView->v->pitch + ((wid->rView.x1 + x1)<<1); pEnd = pDst + (dx<<1); while (pDst < pEnd) { *(Uint16 *)pDst = c; pDst += 2; } AG_UnlockView(); } static void LineH8(void *widget, int x1, int x2, int y, Uint32 c) { AG_Widget *wid = widget; Uint8 *pDst, *pEnd; int dx; if (ClipHorizLine(wid, &x1, &x2, &y, &dx)) { return; } AG_LockView(); pDst = (Uint8 *)agView->v->pixels + (wid->rView.y1 + y)*agView->v->pitch + (wid->rView.x1 + x1); pEnd = pDst + dx; memset(pDst, c, pEnd-pDst); AG_UnlockView(); } static __inline__ int ClipVertLine(AG_Widget *wid, int *x, int *y1, int *y2, int *dy) { SDL_Rect *rd = &agView->v->clip_rect; if ((wid->rView.x1 + *x) < rd->x || (wid->rView.x1 + *x) >= rd->x+rd->w) { return (1); } if (*y1 > *y2) { *dy = *y2; *y2 = *y1; *y1 = *dy; } if (wid->rView.y1 + *y1 < rd->y) *y1 = rd->y - wid->rView.y1; if (wid->rView.y1 + *y2 >= rd->y+rd->h) *y2 = rd->y + rd->h - wid->rView.y1 - 1; *dy = *y2 - *y1; return (*dy <= 0); } static void LineV32(void *widget, int x, int y1, int y2, Uint32 c) { AG_Widget *wid = widget; Uint8 *pDst, *pEnd; int dy; if (ClipVertLine(wid, &x, &y1, &y2, &dy)) { return; } AG_LockView(); pDst = (Uint8 *)agView->v->pixels + (wid->rView.y1 + y1)*agView->v->pitch + ((wid->rView.x1 + x)<<2); pEnd = pDst + dy*agView->v->pitch; while (pDst < pEnd) { *(Uint32 *)pDst = c; pDst += agView->v->pitch; } AG_UnlockView(); } static void LineV24(void *widget, int x, int y1, int y2, Uint32 c) { AG_Widget *wid = widget; Uint8 *pDst, *pEnd; int dy; if (ClipVertLine(wid, &x, &y1, &y2, &dy)) { return; } AG_LockView(); pDst = (Uint8 *)agView->v->pixels + (wid->rView.y1 + y1)*agView->v->pitch + (wid->rView.x1 + x)*3; pEnd = pDst + dy*agView->v->pitch; while (pDst < pEnd) { #if AG_BYTEORDER == AG_BIG_ENDIAN pDst[0] = (c >>16) & 0xff; pDst[1] = (c >>8) & 0xff; pDst[2] = c & 0xff; #else pDst[2] = (c>>16) & 0xff; pDst[1] = (c>>8) & 0xff; pDst[0] = c & 0xff; #endif pDst += agView->v->pitch; } AG_UnlockView(); } static void LineV16(void *widget, int x, int y1, int y2, Uint32 c) { AG_Widget *wid = widget; Uint8 *pDst, *pEnd; int dy; if (ClipVertLine(wid, &x, &y1, &y2, &dy)) { return; } AG_LockView(); pDst = (Uint8 *)agView->v->pixels + (wid->rView.y1 + y1)*agView->v->pitch + ((wid->rView.x1 + x)<<1); pEnd = pDst + dy*agView->v->pitch; while (pDst < pEnd) { *(Uint16 *)pDst = c; pDst += agView->v->pitch; } AG_UnlockView(); } static void LineV8(void *widget, int x, int y1, int y2, Uint32 c) { AG_Widget *wid = widget; Uint8 *pDst, *pEnd; int dy; if (ClipVertLine(wid, &x, &y1, &y2, &dy)) { return; } AG_LockView(); pDst = (Uint8 *)agView->v->pixels + (wid->rView.y1 + y1)*agView->v->pitch + (wid->rView.x1 + x); pEnd = pDst + dy*agView->v->pitch; while (pDst < pEnd) { *(Uint8 *)pDst = c; pDst += agView->v->pitch; } AG_UnlockView(); } static void LineBlendedFB(void *widget, int x1, int y1, int x2, int y2, Uint8 c[4], AG_BlendFn func) { AG_Widget *wid = widget; int dx, dy; int inc1, inc2; int d, x, y; int xend, yend; int xdir, ydir; dx = abs(x2-x1); dy = abs(y2-y1); AG_LockView(); if (dy <= dx) { d = dy*2 - dx; inc1 = dy*2; inc2 = (dy-dx)*2; if (x1 > x2) { x = x2; y = y2; ydir = -1; xend = x1; } else { x = x1; y = y1; ydir = 1; xend = x2; } AG_WidgetBlendPixel(wid, x, y, c, func); if (((y2-y1)*ydir) > 0) { while (x < xend) { x++; if (d < 0) { d += inc1; } else { y++; d += inc2; } AG_WidgetBlendPixel(wid, x, y, c, func); } } else { while (x < xend) { x++; if (d < 0) { d += inc1; } else { y--; d += inc2; } AG_WidgetBlendPixel(wid, x, y, c, func); } } } else { d = dx*2 - dy; inc1 = dx*2; inc2 = (dx-dy)*2; if (y1 > y2) { y = y2; x = x2; yend = y1; xdir = -1; } else { y = y1; x = x1; yend = y2; xdir = 1; } AG_WidgetBlendPixel(wid, x, y, c, func); if (((x2-x1)*xdir) > 0) { while (y < yend) { y++; if (d < 0) { d += inc1; } else { x++; d += inc2; } AG_WidgetBlendPixel(wid, x, y, c, func); } } else { while (y < yend) { y++; if (d < 0) { d += inc1; } else { x--; d += inc2; } AG_WidgetBlendPixel(wid, x, y, c, func); } } } AG_UnlockView(); } /* Render a rectangle outline. */ static void RectOutline(void *p, AG_Rect r, Uint32 color) { AG_Widget *wid = p; int x2 = r.x+r.w-1; int y2 = r.y+r.h-1; AG_DrawLineH(wid, r.x, x2, r.y, color); AG_DrawLineH(wid, r.x, x2, y2, color); AG_DrawLineV(wid, r.x, r.y, y2, color); AG_DrawLineV(wid, x2, r.y, y2, color); } /* Render a filled rectangle. */ static void RectFilledFB(void *p, AG_Rect r, Uint32 color) { AG_Widget *wid = p; AG_Rect rd; rd.x = wid->rView.x1 + r.x; rd.y = wid->rView.y1 + r.y; rd.w = r.w; rd.h = r.h; AG_FillRect(agView->v, &rd, color); } /* Render an alpha blended rectangle. */ static void RectBlendedFB(void *p, AG_Rect r, Uint8 c[4], AG_BlendFn func) { AG_Widget *wid = p; int x, y; AG_LockView(); for (y = 0; y < r.h; y++) { for (x = 0; x < r.w; x++) { AG_BLEND_RGBA2_CLIPPED(agView->v, wid->rView.x1 + r.x + x, wid->rView.y1 + r.y + y, c[0], c[1], c[2], c[3], func); } } AG_UnlockView(); } /* Render a gimp-style background tiling. */ static void Tiling(void *p, AG_Rect r, int tsz, int offs, Uint32 c1, Uint32 c2) { AG_Widget *wid = p; int alt1 = 0, alt2 = 0; AG_Rect rt; rt.w = tsz; rt.h = tsz; /* XXX inelegant */ for (rt.y = r.y-tsz+offs; rt.y < r.y+r.h; rt.y += tsz) { for (rt.x = r.x-tsz+offs; rt.x < r.x+r.w; rt.x += tsz) { if (alt1++ == 1) { AG_DrawRectFilled(wid, rt, c1); alt1 = 0; } else { AG_DrawRectFilled(wid, rt, c2); } } if (alt2++ == 1) { alt2 = 0; } alt1 = alt2; } } /* Render a [+] sign. */ static void Plus(void *p, AG_Rect r, Uint8 c[4], AG_BlendFn func) { int xcen = r.x + r.w/2; int ycen = r.y + r.h/2; AG_DrawLineBlended(p, xcen, r.y, xcen, r.y+r.h, c, func); AG_DrawLineBlended(p, r.x, ycen, r.x+r.w, ycen, c, func); } /* Render a [-] sign. */ static void Minus(void *p, AG_Rect r, Uint8 c[4], AG_BlendFn func) { int ycen = r.y+r.h/2; AG_DrawLineBlended(p, r.x, ycen, r.x+r.w, ycen, c, func); } #ifdef HAVE_OPENGL /* * OpenGL versions of the primitives. */ static void LineGL(void *p, int px1, int py1, int px2, int py2, Uint32 color) { AG_Widget *wid = p; int x1 = wid->rView.x1 + px1; int y1 = wid->rView.y1 + py1; int x2 = wid->rView.x1 + px2; int y2 = wid->rView.y1 + py2; Uint8 r, g, b; AG_GetRGB(color, agVideoFmt, &r,&g,&b); glBegin(GL_LINES); glColor3ub(r, g, b); glVertex2s(x1, y1); glVertex2s(x2, y2); glEnd(); } static void LineHGL(void *p, int x1, int x2, int py, Uint32 color) { AG_Widget *wid = p; int y = wid->rView.y1 + py; Uint8 r, g, b; AG_GetRGB(color, agVideoFmt, &r,&g,&b); glBegin(GL_LINES); glColor3ub(r, g, b); glVertex2s(wid->rView.x1 + x1, y); glVertex2s(wid->rView.x1 + x2, y); glEnd(); } static void LineVGL(void *p, int px, int y1, int y2, Uint32 color) { AG_Widget *wid = p; int x = wid->rView.x1 + px; Uint8 r, g, b; AG_GetRGB(color, agVideoFmt, &r,&g,&b); glBegin(GL_LINES); glColor3ub(r, g, b); glVertex2s(x, wid->rView.y1 + y1); glVertex2s(x, wid->rView.y1 + y2); glEnd(); } static void LineBlendedGL(void *p, int px1, int py1, int px2, int py2, Uint8 c[4], AG_BlendFn func) { AG_Widget *wid = p; int x1 = wid->rView.x1 + px1; int y1 = wid->rView.y1 + py1; int x2 = wid->rView.x1 + px2; int y2 = wid->rView.y1 + py2; GLboolean blend_save; GLint sfac_save, dfac_save; if (c[3] < 255) { glGetBooleanv(GL_BLEND, &blend_save); glGetIntegerv(GL_BLEND_SRC, &sfac_save); glGetIntegerv(GL_BLEND_DST, &dfac_save); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } glBegin(GL_LINES); glColor4ub(c[0], c[1], c[2], c[3]); glVertex2s(x1, y1); glVertex2s(x2, y2); glEnd(); if (c[3] < 255) { if (blend_save) { glEnable(GL_BLEND); } else { glDisable(GL_BLEND); } glBlendFunc(sfac_save, dfac_save); } } static void CircleGL(void *p, int x, int y, int radius, Uint32 color) { AG_Widget *wid = p; int nedges = radius*2; int i; Uint8 r, g, b; AG_GetRGB(color, agVideoFmt, &r,&g,&b); glBegin(GL_LINE_LOOP); glColor3ub(r, g, b); for (i = 0; i < nedges; i++) { glVertex2f(wid->rView.x1 + x + radius*Cos((2*AG_PI*i)/nedges), wid->rView.y1 + y + radius*Sin((2*AG_PI*i)/nedges)); } glEnd(); } static void Circle2GL(void *p, int x, int y, int radius, Uint32 color) { AG_Widget *wid = p; int nedges = radius*2; Uint8 r, g, b; int x1 = wid->rView.x1 + x; int y1 = wid->rView.y1 + y; int i; AG_GetRGB(color, agVideoFmt, &r,&g,&b); glBegin(GL_LINE_LOOP); glColor3ub(r, g, b); for (i = 0; i < nedges; i++) { glVertex2f(x1 + radius*Cos((2*AG_PI*i)/nedges), y1 + radius*Sin((2*AG_PI*i)/nedges)); glVertex2f(x1 + (radius+1)*Cos((2*AG_PI*i)/nedges), y1 + (radius+1)*Sin((2*AG_PI*i)/nedges)); } glEnd(); } static void RectGL(void *p, AG_Rect r, Uint32 color) { AG_Widget *wid = p; Uint8 red, green, blue; int x1 = wid->rView.x1 + r.x; int y1 = wid->rView.y1 + r.y; int x2 = x1 + r.w - 1; int y2 = y1 + r.h - 1; #if 0 if (wid->flags & AG_WIDGET_CLIPPING) { if (x1 > wid->rView.x2 || y1 > wid->rView.y2) { return; } if (x1 < wid->rView.x1) { x1 = wid->rView.x1; } if (y1 < wid->rView.y1) { y1 = wid->rView.y1; } if (x2 > wid->rView.x2) { x2 = wid->rView.x2; } if (y2 > wid->rView.y2) { y2 = wid->rView.y2; } } #endif AG_GetRGB(color, agVideoFmt, &red,&green,&blue); glBegin(GL_POLYGON); glColor3ub(red, green, blue); glVertex2i(x1, y1); glVertex2i(x2, y1); glVertex2i(x2, y2); glVertex2i(x1, y2); glEnd(); } static void RectBlendedGL(void *p, AG_Rect r, Uint8 c[4], AG_BlendFn func) { AG_Widget *wid = p; int x1 = wid->rView.x1 + r.x; int y1 = wid->rView.y1 + r.y; int x2 = x1+r.w; int y2 = y1+r.h; GLboolean blend_save; GLint sfac_save, dfac_save; #if 0 if (wid->flags & AG_WIDGET_CLIPPING) { if (x1 > rView.x2 || y1 > rView.y2) { return; } if (x1 < wid->rView.x1) { x1 = wid->rView.x1; } if (y1 < wid->rView.y1) { y1 = wid->rView.y1; } if (x2 > wid->rView.x2) { x2 = wid->rView.x2; } if (y2 > wid->rView.y2) { y2 = wid->rView.y2; } } #endif if (c[3] < 255) { glGetBooleanv(GL_BLEND, &blend_save); glGetIntegerv(GL_BLEND_SRC, &sfac_save); glGetIntegerv(GL_BLEND_DST, &dfac_save); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } glBegin(GL_POLYGON); glColor4ub(c[0], c[1], c[2], c[3]); glVertex2i(x1, y1); glVertex2i(x2, y1); glVertex2i(x2, y2); glVertex2i(x1, y2); glEnd(); if (c[3] < 255) { if (blend_save) { glEnable(GL_BLEND); } else { glDisable(GL_BLEND); } glBlendFunc(sfac_save, dfac_save); } } static void BoxDisabledGL(void *p, AG_Rect r, int z, Uint32 c1, Uint32 c2) { AG_Widget *wid = p; int stippleEnabled = glIsEnabled(GL_POLYGON_STIPPLE); Uint32 cBg; glEnable(GL_POLYGON_STIPPLE); glPushAttrib(GL_POLYGON_STIPPLE_BIT); glPolygonStipple(DisabledStipple); if (AG_WidgetFocused(wid)) { cBg = ColorShift(c2, (z<0) ? agFocusSunkColorShift : agFocusRaisedColorShift); } else { cBg = ColorShift(c2, (z<0) ? agNofocusSunkColorShift : agNofocusRaisedColorShift); } AG_DrawRectFilled(wid, r, c1); AG_DrawFrame(wid, r, z, c1); glPopAttrib(); if (!stippleEnabled) { glDisable(GL_POLYGON_STIPPLE); } } /* Render a 3D-style box with rounded edges. */ static void BoxRoundedGL(void *p, AG_Rect r, int z, int rad, Uint32 cBg) { AG_Widget *wid = p; Uint8 red, green, blue; /* TODO */ glMatrixMode(GL_MODELVIEW); glPushMatrix(); glTranslatef(wid->rView.x1 + r.x, wid->rView.y1 + r.y, 0); glBegin(GL_POLYGON); { AG_GetRGB(cBg, agVideoFmt, &red,&green,&blue); glColor3ub(red, green, blue); glVertex2i(0, r.h); glVertex2i(0, rad); glVertex2i(rad, 0); glVertex2i(r.w-rad, 0); glVertex2i(r.w, rad); glVertex2i(r.w, r.h); } glEnd(); if (z >= 0) { glBegin(GL_LINE_STRIP); { AG_GetRGB(ColorShift(cBg, agHighColorShift), agVideoFmt, &red,&green,&blue); glColor3ub(red, green, blue); glVertex2i(0, r.h); glVertex2i(0, rad); glVertex2i(rad, 0); } glEnd(); glBegin(GL_LINES); { AG_GetRGB(ColorShift(cBg, agLowColorShift), agVideoFmt, &red,&green,&blue); glColor3ub(red, green, blue); glVertex2i(r.w-1, r.h); glVertex2i(r.w-1, rad); } glEnd(); } glPopMatrix(); } /* Render a 3D-style box with rounded top edges. */ static void BoxRoundedTopGL(void *p, AG_Rect r, int z, int rad, Uint32 cBg) { AG_Widget *wid = p; Uint8 red, green, blue; /* TODO */ glMatrixMode(GL_MODELVIEW); glPushMatrix(); glTranslatef(wid->rView.x1 + r.x, wid->rView.y1 + r.y, 0); glBegin(GL_POLYGON); { AG_GetRGB(cBg, agVideoFmt, &red,&green,&blue); glColor3ub(red, green, blue); glVertex2i(0, r.h); glVertex2i(0, rad); glVertex2i(rad, 0); glVertex2i(r.w-rad, 0); glVertex2i(r.w, rad); glVertex2i(r.w, r.h); } glEnd(); if (z >= 0) { glBegin(GL_LINE_STRIP); { AG_GetRGB(ColorShift(cBg, agHighColorShift), agVideoFmt, &red,&green,&blue); glColor3ub(red, green, blue); glVertex2i(0, r.h); glVertex2i(0, rad); glVertex2i(rad, 0); } glEnd(); glBegin(GL_LINES); { AG_GetRGB(ColorShift(cBg, agLowColorShift), agVideoFmt, &red,&green,&blue); glColor3ub(red, green, blue); glVertex2i(r.w-1, r.h); glVertex2i(r.w-1, rad); } glEnd(); } glPopMatrix(); } static void ArrowUpGL(void *p, int x, int y, int h, Uint32 c1, Uint32 c2) { AG_Widget *wid = p; Uint8 r, g, b; int h2 = h>>1; AG_GetRGB(c1, agVideoFmt, &r,&g,&b); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glTranslatef(wid->rView.x1, wid->rView.y1, 0); glBegin(GL_POLYGON); { glColor3ub(r, g, b); glVertex2i(x, y - h2); glVertex2i(x - h2, y + h2); glVertex2i(x + h2, y + h2); } glEnd(); glPopMatrix(); } static void ArrowDownGL(void *p, int x, int y, int h, Uint32 c1, Uint32 c2) { AG_Widget *wid = p; Uint8 r, g, b; int h2 = h>>1; AG_GetRGB(c1, agVideoFmt, &r,&g,&b); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glTranslatef(wid->rView.x1, wid->rView.y1, 0); glBegin(GL_POLYGON); { glColor3ub(r, g, b); glVertex2i(x - h2, y - h2); glVertex2i(x + h2, y - h2); glVertex2i(x, y + h2); } glEnd(); glPopMatrix(); } static void ArrowLeftGL(void *p, int x, int y, int h, Uint32 c1, Uint32 c2) { AG_Widget *wid = p; Uint8 r, g, b; int h2 = h>>1; AG_GetRGB(c1, agVideoFmt, &r,&g,&b); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glTranslatef(wid->rView.x1, wid->rView.y1, 0); glBegin(GL_POLYGON); { glColor3ub(r, g, b); glVertex2i(x - h2, y); glVertex2i(x + h2, y + h2); glVertex2i(x + h2, y - h2); } glEnd(); glPopMatrix(); } static void ArrowRightGL(void *p, int x, int y, int h, Uint32 c1, Uint32 c2) { AG_Widget *wid = p; Uint8 r, g, b; int h2 = h>>1; AG_GetRGB(c1, agVideoFmt, &r,&g,&b); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glTranslatef(wid->rView.x1, wid->rView.y1, 0); glBegin(GL_POLYGON); { glColor3ub(r, g, b); glVertex2i(x + h2, y); glVertex2i(x - h2, y + h2); glVertex2i(x - h2, y - h2); } glEnd(); glPopMatrix(); } #endif /* HAVE_OPENGL */ void AG_InitPrimitives(void) { #ifdef HAVE_OPENGL memset(DisabledStipple, 0xaa, sizeof(DisabledStipple)); #endif agPrim.Box = Box; agPrim.Frame = Frame; agPrim.FrameBlended = FrameBlended; agPrim.RectOutline = RectOutline; agPrim.Plus = Plus; agPrim.Minus = Minus; agPrim.Line2 = Line2; agPrim.Tiling = Tiling; #ifdef HAVE_OPENGL if (agView->opengl) { agPrim.Line = LineGL; agPrim.LineH = LineHGL; agPrim.LineV = LineVGL; agPrim.LineBlended = LineBlendedGL; agPrim.RectFilled = RectGL; agPrim.RectBlended = RectBlendedGL; agPrim.Circle = CircleGL; agPrim.Circle2 = Circle2GL; agPrim.BoxRounded = BoxRoundedGL; agPrim.BoxRoundedTop = BoxRoundedTopGL; agPrim.BoxDisabled = BoxDisabledGL; agPrim.ArrowUp = ArrowUpGL; agPrim.ArrowDown = ArrowDownGL; agPrim.ArrowLeft = ArrowLeftGL; agPrim.ArrowRight = ArrowRightGL; } else #endif { agPrim.Line = LineFB; agPrim.LineBlended = LineBlendedFB; agPrim.RectFilled = RectFilledFB; agPrim.RectBlended = RectBlendedFB; agPrim.Circle = CircleFB; agPrim.Circle2 = Circle2FB; agPrim.BoxRounded = BoxRoundedFB; agPrim.BoxRoundedTop = BoxRoundedTopFB; agPrim.BoxDisabled = BoxDisabledFB; agPrim.ArrowUp = ArrowUpFB; agPrim.ArrowDown = ArrowDownFB; agPrim.ArrowLeft = ArrowLeftFB; agPrim.ArrowRight = ArrowRightFB; switch (agVideoFmt->BytesPerPixel) { case 4: agPrim.LineH = LineH32; agPrim.LineV = LineV32; break; case 3: agPrim.LineH = LineH24; agPrim.LineV = LineV24; break; case 2: agPrim.LineH = LineH16; agPrim.LineV = LineV16; break; case 1: agPrim.LineH = LineH8; agPrim.LineV = LineV8; break; } } }