From 4859abd118efbeb20d132db7ffcbd43a10c41da6 Mon Sep 17 00:00:00 2001 From: lecoanet Date: Fri, 12 Oct 2001 07:14:22 +0000 Subject: Suppression du code de dessin des gradients en X. Transformation de DoPolygonRelief pour qu'elle fonctionne avec des callbacks (g�n�ralisation). Ajout du code de gradients GL. Ajout de routines pour remplir une forme avec une tuile et pour dessiner une image et une bitmap en GL. --- generic/Draw.c | 1083 +++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 764 insertions(+), 319 deletions(-) (limited to 'generic/Draw.c') diff --git a/generic/Draw.c b/generic/Draw.c index cc5378c..ed8d3ce 100644 --- a/generic/Draw.c +++ b/generic/Draw.c @@ -42,15 +42,17 @@ #include "Geo.h" #include "List.h" #include "WidgetInfo.h" +#include "Image.h" #include #include #define POLYGON_RELIEF_DRAW 0 -#define POLYGON_RELIEF_DIST 1 -#define POLYGON_RELIEF_BBOX 2 -#define POLYGON_RELIEF_IN_BBOX 3 +#define POLYGON_RELIEF_RENDER 1 +#define POLYGON_RELIEF_DIST 2 +#define POLYGON_RELIEF_BBOX 3 +#define POLYGON_RELIEF_IN_BBOX 4 #define TOP_CONTRAST 13 #define BOTTOM_CONTRAST 6 @@ -73,31 +75,52 @@ ********************************************************************************** */ void -SetLineStyle(Display *display, - GC gc, +SetLineStyle(WidgetInfo *wi, LineStyle line_style) { - XGCValues values; - static const char dashed[] = { 8 }; - static const char dotted[] = { 2, 5 }; - static const char mixed[] = { 8, 5, 2, 5 }; - - values.line_style = LineOnOffDash; - switch (line_style) { - case LINE_DASHED : - XSetDashes(display, gc, 0, dashed, 1); - break; - case LINE_MIXED : - XSetDashes(display, gc, 0, mixed, 4); - break; - case LINE_DOTTED : - XSetDashes(display, gc, 0, dotted, 2); - break; + if (wi->render) { +#ifdef GLX + switch (line_style) { + case LINE_DASHED : + glLineStipple(1, 0xF0F0); + glEnable(GL_LINE_STIPPLE); + break; + case LINE_MIXED : + glLineStipple(1, 0x27FF); + glEnable(GL_LINE_STIPPLE); + break; + case LINE_DOTTED : + glLineStipple(1, 0x18C3); + glEnable(GL_LINE_STIPPLE); + break; + default: + glDisable(GL_LINE_STIPPLE); + } +#endif + } + else { + XGCValues values; + static const char dashed[] = { 8 }; + static const char dotted[] = { 2, 5 }; + static const char mixed[] = { 8, 5, 2, 5 }; + + values.line_style = LineOnOffDash; + switch (line_style) { + case LINE_DASHED : + XSetDashes(wi->dpy, wi->gc, 0, dashed, 1); + break; + case LINE_MIXED : + XSetDashes(wi->dpy, wi->gc, 0, mixed, 4); + break; + case LINE_DOTTED : + XSetDashes(wi->dpy, wi->gc, 0, dotted, 2); + break; default: values.line_style = LineSolid; break; + } + XChangeGC(wi->dpy, wi->gc, GCLineStyle, &values); } - XChangeGC(display, gc, GCLineStyle, &values); } @@ -290,7 +313,7 @@ DrawLineShape(WidgetInfo *wi, /* * Setup GC. */ - SetLineStyle(wi->dpy, wi->gc, line_style); + SetLineStyle(wi, line_style); values.foreground = ZnPixel(foreground); values.line_width = (line_width == 1) ? 0 : line_width; values.fill_style = FillSolid; @@ -311,7 +334,7 @@ DrawLineShape(WidgetInfo *wi, /* * ReliefIndexOfSegment -- */ -static long +static XColor * ReliefColorOfSegment(ZnReal x1, ZnReal y1, ZnReal x2, @@ -358,7 +381,7 @@ ReliefColorOfSegment(ZnReal x1, angle, RadianToDegrees(origin));*/ - return ZnPixel(ZnGetGradientColor(wi->win, gradient, position)); + return ZnGetGradientColor(wi->win, gradient, position, NULL); } @@ -420,8 +443,8 @@ DrawRectangleRelief(WidgetInfo *wi, bevel[2].x = bevel[1].x - line_width; bevel[3].x = bevel[0].x + line_width; XSetForeground(wi->dpy, wi->gc, - ReliefColorOfSegment(bevel[1].x, bevel[1].y, bevel[0].x, bevel[0].y, - relief, gradient, wi)); + ZnPixel(ReliefColorOfSegment(bevel[1].x, bevel[1].y, bevel[0].x, bevel[0].y, + relief, gradient, wi))); XFillPolygon(wi->dpy, wi->draw_buffer, wi->gc, bevel, 4, Convex, CoordModeOrigin); bevel[0] = bevel[1]; @@ -429,8 +452,8 @@ DrawRectangleRelief(WidgetInfo *wi, bevel[1].y += bbox->height; bevel[2].y = bevel[1].y - line_width; XSetForeground(wi->dpy, wi->gc, - ReliefColorOfSegment(bevel[1].x, bevel[1].y, bevel[0].x, bevel[0].y, - relief, gradient, wi)); + ZnPixel(ReliefColorOfSegment(bevel[1].x, bevel[1].y, bevel[0].x, bevel[0].y, + relief, gradient, wi))); XFillPolygon(wi->dpy, wi->draw_buffer, wi->gc, bevel, 4, Convex, CoordModeOrigin); bevel[0] = bevel[1]; @@ -438,8 +461,8 @@ DrawRectangleRelief(WidgetInfo *wi, bevel[1].x -= bbox->width; bevel[2].x = bevel[1].x + line_width; XSetForeground(wi->dpy, wi->gc, - ReliefColorOfSegment(bevel[1].x, bevel[1].y, bevel[0].x, bevel[0].y, - relief, gradient, wi)); + ZnPixel(ReliefColorOfSegment(bevel[1].x, bevel[1].y, bevel[0].x, bevel[0].y, + relief, gradient, wi))); XFillPolygon(wi->dpy, wi->draw_buffer, wi->gc, bevel, 4, Convex, CoordModeOrigin); bevel[0] = bevel[1]; @@ -449,58 +472,26 @@ DrawRectangleRelief(WidgetInfo *wi, bevel[2].x = bevel[3].x; bevel[2].y = bbox->y + line_width; XSetForeground(wi->dpy, wi->gc, - ReliefColorOfSegment(bevel[1].x, bevel[1].y, bevel[0].x, bevel[0].y, - relief, gradient, wi)); + ZnPixel(ReliefColorOfSegment(bevel[1].x, bevel[1].y, bevel[0].x, bevel[0].y, + relief, gradient, wi))); XFillPolygon(wi->dpy, wi->draw_buffer, wi->gc, bevel, 4, Convex, CoordModeOrigin); } static void -DoPolygonRelief(ZnPoint *p, - int num_points, - int line_width, - int what_to_do, - ...) +DoPolygon(ZnPoint *p, + int num_points, + int line_width, + ZnBool (*cb)(ZnPoint *bevels, int proc_points, void *closure), + void *closure) { - int i, j, processed_points, *result=NULL; + int i, processed_points; ZnPoint *p1, *p11=NULL, *p2; ZnPoint pp1, pp2, new_pp1, new_pp2; ZnPoint perp, c, shift1, shift2; ZnPoint bevel_points[4]; - XPoint bevel_xpoints[5]; ZnBool folded, closed, colinear; - WidgetInfo *wi = NULL; - ReliefStyle relief = 0; - ZnGradient *gradient = NULL; - ZnPoint *pp = NULL; - double *dist = NULL; - ZnBBox *bbox = NULL; - va_list var; -#if 0 - ZnBool toggle=True; -#endif ZnReal dx, dy; - - va_start(var, what_to_do); - if (what_to_do == POLYGON_RELIEF_DIST) { - pp = va_arg(var, ZnPoint *); - dist = va_arg(var, double *); - *dist = 1.0e40; - } - if (what_to_do == POLYGON_RELIEF_IN_BBOX) { - bbox = va_arg(var, ZnBBox *); - result = va_arg(var, int *); - } - else if (what_to_do == POLYGON_RELIEF_BBOX) { - bbox = va_arg(var, ZnBBox *); - ResetBBox(bbox); - } - else if (what_to_do == POLYGON_RELIEF_DRAW) { - wi = va_arg(var, WidgetInfo *); - relief = va_arg(var, int); - gradient = va_arg(var, ZnGradient *); - } - va_end(var); /* * If the polygon is closed (last point is the same as first) open it by @@ -644,73 +635,11 @@ DoPolygonRelief(ZnPoint *p, } if ((processed_points >= 2) || (!closed && (processed_points == 1))) { - if (what_to_do == POLYGON_RELIEF_DIST) { - double new_dist; - - new_dist = PolygonToPointDist(bevel_points, 4, pp); - if (new_dist < 0) { - new_dist = 0; - } - *dist = MIN(*dist, new_dist); - } - else if (what_to_do == POLYGON_RELIEF_IN_BBOX) { - if (processed_points <= 2) { - *result = PolygonInBBox(bevel_points, 4, bbox, NULL); - if (*result == 0) { - return; - } - } - else { - if (PolygonInBBox(bevel_points, 4, bbox, NULL) != *result) { - *result = 0; - return; - } - } - } - else if (what_to_do == POLYGON_RELIEF_BBOX) { - int i; - - for (i = 0; i < 4; i++) { - AddPointToBBox(bbox, bevel_points[i].x, bevel_points[i].y); - } - } - else if (what_to_do == POLYGON_RELIEF_DRAW) { - XGCValues gc_values; -#if 1 - gc_values.foreground = ReliefColorOfSegment(bevel_points[0].x, bevel_points[0].y, - bevel_points[3].x, bevel_points[3].y, - relief, gradient, wi); -#endif -#if 0 - gc_values.foreground = toggle ? WhitePixelOfScreen(wi->screen):BlackPixelOfScreen(wi->screen); -#endif -#if 0 - gc_values.foreground = colinear ? WhitePixelOfScreen(wi->screen):BlackPixelOfScreen(wi->screen); -#endif -#if 0 - toggle = !toggle; -#endif - gc_values.fill_style = FillSolid; - XChangeGC(wi->dpy, wi->gc, GCFillStyle|GCForeground, &gc_values); - - for (j = 0; j < 4; j++) { - bevel_xpoints[j].x = REAL_TO_INT(bevel_points[j].x); - bevel_xpoints[j].y = REAL_TO_INT(bevel_points[j].y); - } -#if 1 - XFillPolygon(wi->dpy, wi->draw_buffer, wi->gc, bevel_xpoints, 4, - Convex, CoordModeOrigin); -#endif -#if 0 - bevel_xpoints[4] = bevel_xpoints[0]; - gc_values.line_width = 0; - XChangeGC(wi->dpy, wi->gc, GCLineWidth, &gc_values); - XDrawLines(wi->dpy, wi->draw_buffer, wi->gc, bevel_xpoints, 5, - CoordModeOrigin); -#endif + if ((*cb)(bevel_points, processed_points, closure)) { + return; } } - + p11 = p1; p1 = p2; pp1 = new_pp1; @@ -727,6 +656,18 @@ DoPolygonRelief(ZnPoint *p, } } +typedef struct { + WidgetInfo *wi; + ZnPoint *pp; + double dist; + ZnBBox *bbox; + ReliefStyle relief; + ZnGradient *gradient; + int alpha; + ZnBool smooth; + int result; + ZnBool toggle; +} PolygonData; /* ********************************************************************************** @@ -736,13 +677,28 @@ DoPolygonRelief(ZnPoint *p, * ********************************************************************************** */ +static ZnBool +PolygonBBoxCB(ZnPoint *bevels, + int proc_points, + void *closure) +{ + ZnBBox *bbox = closure; + int i; + + for (i = 0; i < 4; i++) { + AddPointToBBox(bbox, bevels[i].x, bevels[i].y); + } + return 0; +} + void GetPolygonReliefBBox(ZnPoint *points, int num_points, int line_width, ZnBBox *bbox) { - DoPolygonRelief(points, num_points, line_width, POLYGON_RELIEF_BBOX, bbox); + ResetBBox(bbox); + DoPolygon(points, num_points, line_width, PolygonBBoxCB, bbox); } @@ -755,17 +711,40 @@ GetPolygonReliefBBox(ZnPoint *points, * ********************************************************************************** */ +static ZnBool +PolygonInBBoxCB(ZnPoint *bevels, + int proc_points, + void *closure) +{ + PolygonData *pd = closure; + + if (proc_points <= 2) { + pd->result = PolygonInBBox(bevels, 4, pd->bbox, NULL); + if (pd->result == 0) { + return 1; + } + } + else { + if (PolygonInBBox(bevels, 4, pd->bbox, NULL) != pd->result) { + pd->result = 0; + return 1; + } + } + return 0; +} + int PolygonReliefInBBox(ZnPoint *points, int num_points, int line_width, ZnBBox *area) { - int result; + PolygonData pd; - DoPolygonRelief(points, num_points, line_width, POLYGON_RELIEF_IN_BBOX, area, &result); + pd.bbox = area; + DoPolygon(points, num_points, line_width, PolygonInBBoxCB, &pd); - return result; + return pd.result; } @@ -778,17 +757,37 @@ PolygonReliefInBBox(ZnPoint *points, * ********************************************************************************** */ +static ZnBool +PolygonDistCB(ZnPoint *bevels, + int proc_points, + void *closure) +{ + PolygonData *pd = closure; + double new_dist; + + new_dist = PolygonToPointDist(bevels, 4, pd->pp); + if (new_dist < 0.0) { + new_dist = 0.0; + } + if (new_dist < pd->dist) { + pd->dist = new_dist; + } + return 0; +} + double PolygonReliefToPointDist(ZnPoint *points, int num_points, int line_width, ZnPoint *pp) { - double dist; + PolygonData pd; - DoPolygonRelief(points, num_points, line_width, POLYGON_RELIEF_DIST, pp, &dist); + pd.dist = 1.0e40; + pd.pp = pp; + DoPolygon(points, num_points, line_width, PolygonDistCB, &pd); - return dist; + return pd.dist; } @@ -800,6 +799,50 @@ PolygonReliefToPointDist(ZnPoint *points, * ********************************************************************************** */ +static ZnBool +PolygonDrawCB(ZnPoint *bevels, + int proc_points, + void *closure) +{ + PolygonData *pd = closure; + WidgetInfo *wi = pd->wi; + XPoint bevel_xpoints[5]; + XGCValues values; + int j; +#if 1 + values.foreground = ZnPixel(ReliefColorOfSegment(bevels[0].x, bevels[0].y, + bevels[3].x, bevels[3].y, + pd->relief, pd->gradient, pd->wi)); +#endif +#if 0 + values.foreground = toggle ? WhitePixelOfScreen(wi->screen):BlackPixelOfScreen(wi->screen); +#endif +#if 0 + values.foreground = colinear ? WhitePixelOfScreen(wi->screen):BlackPixelOfScreen(wi->screen); +#endif +#if 0 + toggle = !toggle; +#endif + values.fill_style = FillSolid; + XChangeGC(wi->dpy, wi->gc, GCFillStyle|GCForeground, &values); + + for (j = 0; j < 4; j++) { + bevel_xpoints[j].x = REAL_TO_INT(bevels[j].x); + bevel_xpoints[j].y = REAL_TO_INT(bevels[j].y); + } +#if 1 + XFillPolygon(wi->dpy, wi->draw_buffer, wi->gc, bevel_xpoints, 4, + Convex, CoordModeOrigin); +#endif +#if 0 + bevel_xpoints[4] = bevel_xpoints[0]; + values.line_width = 0; + XChangeGC(wi->dpy, wi->gc, GCLineWidth, &values); + XDrawLines(wi->dpy, wi->draw_buffer, wi->gc, bevel_xpoints, 5, CoordModeOrigin); +#endif + return 0; +} + void DrawPolygonRelief(WidgetInfo *wi, ReliefStyle relief, @@ -808,230 +851,632 @@ DrawPolygonRelief(WidgetInfo *wi, int num_points, int line_width) { + PolygonData pd; + + pd.wi = wi; + pd.gradient = gradient; /* * Grooves and ridges are drawn with two calls. The first * with the original width, the second with half the width. */ if ((relief == RELIEF_RIDGE) || (relief == RELIEF_GROOVE)) { - DoPolygonRelief(points, num_points, line_width, POLYGON_RELIEF_DRAW, wi, - (int) (relief==RELIEF_GROOVE)?RELIEF_BEVEL_OUT:RELIEF_BEVEL_IN, - gradient); - DoPolygonRelief(points, num_points, line_width/2, POLYGON_RELIEF_DRAW, wi, - (int) (relief==RELIEF_GROOVE)?RELIEF_BEVEL_IN:RELIEF_BEVEL_OUT, - gradient); + pd.relief = (relief==RELIEF_GROOVE)?RELIEF_BEVEL_OUT:RELIEF_BEVEL_IN; + DoPolygon(points, num_points, line_width, PolygonDrawCB, &pd); + pd.relief = (relief==RELIEF_GROOVE)?RELIEF_BEVEL_IN:RELIEF_BEVEL_OUT; + DoPolygon(points, num_points, line_width/2, PolygonDrawCB, &pd); } else { - DoPolygonRelief(points, num_points, line_width, POLYGON_RELIEF_DRAW, wi, - (int) relief, gradient); + pd.relief = relief; + DoPolygon(points, num_points, line_width, PolygonDrawCB, &pd); } } -static void -DrawRadialGradient(struct _WidgetInfo *wi, - ZnGradient *grad, - XRectangle *bbox) +/* + ********************************************************************************** + * + * RenderPolygonRelief -- + * Draw the bevels around path using alpha enabled rendering. + * + ********************************************************************************** + */ +#ifdef GLX +static ZnBool +PolygonRenderCB(ZnPoint *bevels, + int proc_points, + void *closure) { + PolygonData *pd = closure; + int i; + XColor *color = ReliefColorOfSegment(bevels[0].x, bevels[0].y, + bevels[3].x, bevels[3].y, + pd->relief, pd->gradient, pd->wi); + glColor4us(color->red, color->green, color->blue, pd->alpha*65535/100); + glBegin(GL_QUADS); + for (i = 0; i < 4; i++) { + glVertex2f(bevels[i].x, bevels[i].y); + } + glEnd(); + + return 0; } -static void -DrawAxialGradient(struct _WidgetInfo *wi, - ZnGradient *grad, - XRectangle *bbox) +void +RenderPolygonRelief(WidgetInfo *wi, + ReliefStyle relief, + ZnGradient *gradient, + int alpha, + ZnBool smooth, + ZnPoint *points, + int num_points, + int line_width) { -#define NUM_STENCILS 8 - static int s[NUM_STENCILS] = { 0, 1, 3, 5, 7, 9, 11, 13 }; - int angle = grad->g.angle; - int num_shades = grad->num_shades; - int num_shades_2 = num_shades /2; - int num_colors = grad->num_colors; - int x, y, span, stop, i, j, k, p; - int *startp, *widthp, width, height; - int position; - ZnReal pos, pos_span_bc, pos_span_ac, pos_span; - ZnReal stencil_step_bc, stencil_step_ac, stencil_step; - short origin, limit; - ZnBool dir; - ZnGradientColor *color, *next_color; - XColor *shade; + PolygonData pd; + + pd.wi = wi; + pd.gradient = gradient; + pd.alpha = alpha; + pd.smooth = smooth; + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); /* - * We can only handle 0, 90, 180, 270. + * Grooves and ridges are drawn with two calls. The first + * with the original width, the second with half the width. */ - angle = (angle / 90) * 90; + if ((relief == RELIEF_RIDGE) || (relief == RELIEF_GROOVE)) { + pd.relief = (relief==RELIEF_GROOVE)?RELIEF_BEVEL_OUT:RELIEF_BEVEL_IN; + DoPolygon(points, num_points, line_width, PolygonRenderCB, &pd); + pd.relief = (relief==RELIEF_GROOVE)?RELIEF_BEVEL_IN:RELIEF_BEVEL_OUT; + DoPolygon(points, num_points, line_width/2, PolygonRenderCB, &pd); + } + else { + pd.relief = relief; + DoPolygon(points, num_points, line_width, PolygonRenderCB, &pd); + } +} + +void +RenderImage(struct _WidgetInfo *wi, + ImageBits *image, /* ImageBits or BitmapBits */ + XColor *color, + int alpha, + ZnPoint *origin) +{ + ZnReal nx, ny; + + alpha = alpha*65535/100; + nx = origin->x + image->width; + ny = origin->y + image->height; + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, image->texture); + if (color) { + glColor4us(color->red, color->green, color->blue, alpha); + } + else { + glColor4us(65535, 65535, 65535, alpha); + } + glBegin(GL_QUADS); + glTexCoord2f(0.0, 0.0); + glVertex2f(origin->x, origin->y); + glTexCoord2f(0.0, image->t); + glVertex2f(origin->x, ny); + glTexCoord2f(image->s, image->t); + glVertex2f(nx, ny); + glTexCoord2f(image->s, 0.0); + glVertex2f(nx, origin->y); + glEnd(); + glDisable(GL_TEXTURE_2D); +} + +void +RenderTile(struct _WidgetInfo *wi, + ImageBits *tile, + ZnGradient *gradient, + void cb(void *), + void *closure, + ZnPoint *quad) /* Right now it's a ZnBBox */ +{ + ZnReal x, y, nx, ny, lx, ly, s, t; + int alpha, num_clips = ZnListSize(wi->clip_stack); - x = bbox->x; - y = bbox->y; - if ((angle == 0) || (angle == 180)) { - startp = &x; - origin = bbox->x; - limit = bbox->x+bbox->width; - height = bbox->height; - widthp = &width; + if (gradient) { + ZnGetGradientColor(wi->win, gradient, 0.0, &alpha); + alpha = alpha*65535/100; } else { - startp = &y; - origin = bbox->y; - limit = bbox->y+bbox->height; - width = bbox->width; - widthp = &height; + alpha = 65535; } - dir = True; - if ((angle == 180) || (angle == 270)) { - dir = False; + if (cb) { + /* + * Setup the stencil buffer with the shape to be drawn. + */ + if (!num_clips) { + glEnable(GL_STENCIL_TEST); + } + glStencilFunc(GL_EQUAL, num_clips, 0xFF); + glStencilOp(GL_KEEP, GL_INCR, GL_INCR); + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + (*cb)(closure); + + glStencilFunc(GL_EQUAL, num_clips+1, 0xFF); + glStencilOp(GL_KEEP, GL_DECR, GL_DECR); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); } - - span = limit - origin; /* - * External loop iterates over the gradient colors. + * Then texture map the quad through the shape. + * The rectangle is drawn using quads, each + * quad matching the size of the texture tile. */ - XSetTSOrigin(wi->dpy, wi->gc, bbox->x, bbox->y); - ZnRealizeGradient(grad, wi->win); - if (dir) { - *startp = origin; + glEnable(GL_TEXTURE_2D); + glColor4us(65535, 65535, 65535, alpha); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glBindTexture(GL_TEXTURE_2D, tile->texture); + + y = quad[0].y; + lx = quad[1].x; + ly = quad[1].y; + glBegin(GL_QUADS); + do { + x = quad[0].x; + t = 1.0; + ny = y + tile->height; + if (ny > ly) { + ny = ly; + t = (ly - y) / (ZnReal) tile->height; + } + t *= tile->t; + do { + s = 1.0; + nx = x + tile->width; + if (nx > lx) { + nx = lx; + s = (lx - x) / (ZnReal) tile->width; + } + s *= tile->s; + glTexCoord2f(0.0, 0.0); + glVertex2f(x, y); + glTexCoord2f(0.0, t); + glVertex2f(x, ny); + glTexCoord2f(s, t); + glVertex2f(nx, ny); + glTexCoord2f(s, 0.0); + glVertex2f(nx, y); + x = nx; + } + while (x != lx); + y = ny; } - else { - stop = limit; + while (y != ly); + glEnd(); + + if (cb) { + glStencilFunc(GL_EQUAL, num_clips, 0xFF); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + if (!num_clips) { + glDisable(GL_STENCIL_TEST); + } } - for (k = 0; k < num_colors-1; k++) { + glDisable(GL_TEXTURE_2D); +} + +void +RenderGradient(struct _WidgetInfo *wi, + ZnGradient *gradient, + void cb(void *), + void *closure, + ZnPoint *quad) +{ + int alpha, angle, i, j; + int type = gradient->type; + int num_shades = gradient->num_shades; + XColor *color; + ZnPoint p; + ZnPoint dposa, dposb, dposc, dposd; + ZnPoint dcontrol; + ZnReal npos, pos, control; + int num_clips = ZnListSize(wi->clip_stack); + ZnPoint iquad[4]; + + if (!cb) { /* Render an axial gradient in the quad */ + if (type != ZN_AXIAL_GRADIENT) { + type = ZN_AXIAL_GRADIENT; + angle = 0; + } + else { + angle = gradient->g.angle; + } /* - * Mid loop iterates over the current color shades. + * Adjust the quad for 90 180 and 270 degrees axial + * gradients. Other angles not supported. */ - color = grad->colors[k]; - next_color = grad->colors[k+1]; - position = color->position; - pos_span_bc = (next_color->position - position)*color->control/100.0; - pos_span_ac = (next_color->position - position)-pos_span_bc; - stencil_step_bc = pos_span_bc/(num_shades_2*NUM_STENCILS); - stencil_step_ac = pos_span_ac/(num_shades_2*NUM_STENCILS); - /*printf("span bc %g, span ac %g, stencil bc %g, stencil ac %g\n", - pos_span_bc, pos_span_ac, stencil_step_bc, stencil_step_ac);*/ - pos_span = pos_span_bc; - stencil_step = stencil_step_bc; - pos = position; - for (j = 0; j < num_shades; j++) { - p = j+1; - if (j >= num_shades_2) { - pos = position + pos_span_bc; - pos_span = pos_span_ac; - stencil_step = stencil_step_ac; - p -= num_shades_2; - } - if (dir) { - stop = origin + span*(pos + (pos_span*p/(num_shades_2)))/100; - } - else { - *startp = limit - span*(pos + (pos_span*p/(num_shades_2)))/100; - } - *widthp = stop - *startp; - XSetFillStyle(wi->dpy, wi->gc, FillSolid); - shade = color->shades[j]; - XSetForeground(wi->dpy, wi->gc, ZnPixel(shade)); - XFillRectangle(wi->dpy, wi->draw_buffer, wi->gc, x, y, width, height); -#if 1 - /* - * Inner loop iterates over the stencils used to - * smooth the current shade. - */ - p--; - if (dir) { - *startp = origin + span*(pos + (stencil_step*(p*NUM_STENCILS+1)))/100; - } - else { - stop = limit - span*(pos + (stencil_step*(p*NUM_STENCILS+1)))/100; - } - XSetFillStyle(wi->dpy, wi->gc, FillStippled); - if (j < num_shades-1) { - shade = color->shades[j+1]; - } - else { - shade = next_color->shades[0]; + switch (angle) { + case 90: + iquad[0] = quad[3]; + iquad[3] = quad[2]; + iquad[2] = quad[1]; + iquad[1] = quad[0]; + quad = iquad; + break; + case 180: + iquad[0] = quad[2]; + iquad[3] = quad[1]; + iquad[2] = quad[0]; + iquad[1] = quad[3]; + quad = iquad; + break; + case 270: + iquad[0] = quad[1]; + iquad[3] = quad[0]; + iquad[2] = quad[3]; + iquad[1] = quad[2]; + quad = iquad; + break; + } + } + + if (cb) { + /* + * Draw the gradient shape in the stencil using the provided + * callback. + */ + if (!num_clips) { + glEnable(GL_STENCIL_TEST); + } + glStencilFunc(GL_EQUAL, num_clips, 0xFF); + glStencilOp(GL_KEEP, GL_INCR, GL_INCR); + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + (*cb)(closure); + glStencilFunc(GL_EQUAL, num_clips+1, 0xFF); + glStencilOp(GL_KEEP, GL_DECR, GL_DECR); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + } + + if (type == ZN_AXIAL_GRADIENT) { + /* + * Then fill the axial gradient using the provided + * quad and colors. The stencil will be restored + * to its previous state in the process. + */ + glBegin(GL_QUAD_STRIP); + for (i = 0; i < gradient->num_colors; i++) { + color = gradient->colors[i]->shades[0]; + alpha = gradient->colors[i]->alpha*65535/100; + glColor4us(color->red, color->green, color->blue, alpha); + + pos = gradient->colors[i]->position; + control = gradient->colors[i]->control; + dposa.x = (quad[1].x - quad[0].x)*pos/100.0; + dposa.y = (quad[1].y - quad[0].y)*pos/100.0; + p.x = quad[0].x + dposa.x; + p.y = quad[0].y + dposa.y; + glVertex2f(p.x, p.y); + + dposb.x = (quad[2].x - quad[3].x)*pos/100.0; + dposb.y = (quad[2].y - quad[3].y)*pos/100.0; + p.x = quad[3].x + dposb.x; + p.y = quad[3].y + dposb.y; + glVertex2f(p.x, p.y); + + if ((control != 50.0) && (i != gradient->num_colors-1)) { + color = gradient->colors[i]->shades[num_shades/2]; + alpha = gradient->colors[i]->alpha*65535/100; + glColor4us(color->red, color->green, color->blue, alpha); + + npos = gradient->colors[i+1]->position; + dposc.x = (quad[1].x - quad[0].x)*npos/100.0; + dposc.y = (quad[1].y - quad[0].y)*npos/100.0; + dcontrol.x = (dposc.x - dposa.x)*control/100.0; + dcontrol.y = (dposc.y - dposa.y)*control/100.0; + p.x = quad[0].x + dposa.x + dcontrol.x; + p.y = quad[0].y + dposa.y + dcontrol.y; + glVertex2f(p.x, p.y); + + dposd.x = (quad[2].x - quad[3].x)*npos/100.0; + dposd.y = (quad[2].y - quad[3].y)*npos/100.0; + dcontrol.x = (dposd.x - dposb.x)*control/100.0; + dcontrol.y = (dposd.y - dposb.y)*control/100.0; + p.x = quad[3].x + dposb.x + dcontrol.x; + p.y = quad[3].y + dposb.y + dcontrol.y; + glVertex2f(p.x, p.y); } - XSetForeground(wi->dpy, wi->gc, ZnPixel(shade)); - for (i = 1; i < NUM_STENCILS; i++) { - if (dir) { - stop = origin + span*(pos + (stencil_step*(p*NUM_STENCILS+i+1)))/100; - } - else { - *startp = limit - span*(pos + (stencil_step*(p*NUM_STENCILS+i+1)))/100; - } - *widthp = stop - *startp; - XSetStipple(wi->dpy, wi->gc, wi->alpha_stipples[s[i]]); - XFillRectangle(wi->dpy, wi->draw_buffer, wi->gc, x, y, width, height); - if (dir) { - *startp = stop; - } - else { - stop = *startp; + + } + glEnd(); + } + else if (type == ZN_RADIAL_GRADIENT) { + ZnReal x, y, radius, radius2, radius3; + int num_p, alpha2; + ZnPoint *genarc; + XColor *color2; + + genarc = GetCirclePoints(3, ZN_CIRCLE_MEDIUM, 0, 360, &num_p, NULL); + radius = 0; + color = gradient->colors[0]->shades[0]; + alpha = gradient->colors[0]->alpha*65535/100; + control = gradient->colors[0]->control; + for (j = 1; j < gradient->num_colors; j++) { + radius2 = quad[1].x*gradient->colors[j]->position/100.0; + if ((control != 50) && (j != gradient->num_colors-1)) { + glBegin(GL_QUAD_STRIP); + color2 = gradient->colors[j-1]->shades[num_shades/2]; + alpha2 = gradient->colors[j-1]->alpha*65535/100; + radius3 = radius + (radius2-radius)*control/100.0; + for (i = 0; i < num_p; i++) { + x = quad[0].x+genarc[i].x*radius; + y = quad[0].y+genarc[i].y*radius; + glColor4us(color->red, color->green, color->blue, alpha); + glVertex2f(x, y); + x = quad[0].x+genarc[i].x*radius3; + y = quad[0].y+genarc[i].y*radius3; + glColor4us(color2->red, color2->green, color2->blue, alpha); + glVertex2f(x, y); } + radius = radius3; + color = color2; + alpha = alpha2; + glEnd(); } -#else - if (dir) { - *startp = stop; + glBegin(GL_QUAD_STRIP); + color2 = gradient->colors[j]->shades[0]; + alpha2 = gradient->colors[j]->alpha*65535/100; + for (i = 0; i < num_p; i++) { + x = quad[0].x+genarc[i].x*radius; + y = quad[0].y+genarc[i].y*radius; + glColor4us(color->red, color->green, color->blue, alpha); + glVertex2f(x, y); + x = quad[0].x+genarc[i].x*radius2; + y = quad[0].y+genarc[i].y*radius2; + glColor4us(color2->red, color2->green, color2->blue, alpha); + glVertex2f(x, y); } - else { - stop = *startp; - } -#endif + glEnd(); + radius = radius2; + color = color2; + alpha = alpha2; + control = gradient->colors[j]->control; + } + } + + if (cb) { + /* + * Restore the previous GL state. + */ + glStencilFunc(GL_EQUAL, num_clips, 0xFF); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + if (!num_clips) { + glDisable(GL_STENCIL_TEST); } } } + void -DrawPolygonGradient(struct _WidgetInfo *wi, - ZnGradient *gradient, - ZnPoly *poly, - ZnBBox *bbox) +RenderHollowDot(struct _WidgetInfo *wi, + ZnPoint *p, + ZnReal size) { - ZnBBox lbbox; - XRectangle r; - int i; - - /* - * The polygon has to be reduced for this to give meaningful - * results. - */ - if (!bbox) { - ResetBBox(&lbbox); - for (i = 0; i < poly->num_contours; i++) { - if (!poly->holes[i]) { - AddPointsToBBox(&lbbox, poly->contours[i].points, - poly->contours[i].num_points); + int num_clips = ZnListSize(wi->clip_stack); + + if (!num_clips) { + glEnable(GL_STENCIL_TEST); + } + glStencilFunc(GL_EQUAL, num_clips, 0xFF); + glStencilOp(GL_KEEP, GL_INCR, GL_INCR); + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + glPointSize(size-2); + glBegin(GL_POINTS); + glVertex2f(p->x, p->y); + glEnd(); + + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glPointSize(size); + glBegin(GL_POINTS); + glVertex2f(p->x, p->y); + glEnd(); + + glStencilFunc(GL_EQUAL, num_clips+1, 0xFF); + glStencilOp(GL_KEEP, GL_DECR, GL_DECR); + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + glPointSize(size-2); + glBegin(GL_POINTS); + glVertex2f(p->x, p->y); + glEnd(); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + + if (!num_clips) { + glDisable(GL_STENCIL_TEST); + } +} +#endif + + +#ifdef GLX +/* Copyright (c) Mark J. Kilgard, 1997. */ + +/* This program is freely distributable without licensing fees and is + provided without guarantee or warrantee expressed or implied. This + program is -not- in the public domain. */ + +#include + +static TexGlyphVertexInfo * +getTCVI(TexFont *txf, + int c) +{ + TexGlyphVertexInfo *tgvi; + + /* Automatically substitute uppercase letters with lowercase if not + uppercase available (and vice versa). */ + if ((c >= txf->min_glyph) && (c < txf->min_glyph + txf->range)) { + tgvi = txf->lut[c - txf->min_glyph]; + if (tgvi) { + return tgvi; + } + if (islower(c)) { + c = toupper(c); + if ((c >= txf->min_glyph) && (c < txf->min_glyph + txf->range)) { + return txf->lut[c - txf->min_glyph]; + } + } + if (isupper(c)) { + c = tolower(c); + if ((c >= txf->min_glyph) && (c < txf->min_glyph + txf->range)) { + return txf->lut[c - txf->min_glyph]; } } - bbox = &lbbox; - } - BBox2XRect(bbox, &r); - ITEM_P.PushClip(wi, poly, False, True); - if (gradient->type == ZN_AXIAL_GRADIENT) { - DrawAxialGradient(wi, gradient, &r); } - else if (gradient->type == ZN_RADIAL_GRADIENT) { - DrawRadialGradient(wi, gradient, &r); + /* ZnWarning("Tried to access unavailable texture font character");*/ + printf("Tried to access unavailable texture font character '%c'(%d)\n", c, c); + return txf->lut[(int)'!' - txf->min_glyph]; +} + + +void +txfRenderGlyph(TexFont *txf, + int c) +{ + TexGlyphVertexInfo *tgvi; + + tgvi = getTCVI(txf, c); + + glBegin(GL_QUADS); + glTexCoord2fv(tgvi->t0); + glVertex2sv(tgvi->v0); + glTexCoord2fv(tgvi->t1); + glVertex2sv(tgvi->v1); + glTexCoord2fv(tgvi->t2); + glVertex2sv(tgvi->v2); + glTexCoord2fv(tgvi->t3); + glVertex2sv(tgvi->v3); + glEnd(); + glTranslatef(tgvi->advance, 0.0, 0.0); +} + +void +txfRenderString(TexFont *txf, + unsigned char *string, + int len) +{ + int i; + + for (i = 0; i < len; i++) { + txfRenderGlyph(txf, string[i]); } - ITEM_P.PopClip(wi, True); } +enum { + MONO, TOP_BOTTOM, LEFT_RIGHT, FOUR +}; + void -DrawRectangleGradient(struct _WidgetInfo *wi, - ZnGradient *grad, - XRectangle *bbox) +txfRenderFancyString(TexFont *txf, + unsigned char *string, + int len) { - if (grad->type == ZN_AXIAL_GRADIENT) { - DrawAxialGradient(wi, grad, bbox); + TexGlyphVertexInfo *tgvi; + GLubyte c[4][3]; + int mode = MONO; + int i; + + for (i = 0; i < len; i++) { + if (string[i] == 27) { + switch (string[i + 1]) { + case 'M': + mode = MONO; + glColor3ubv((GLubyte *) & string[i + 2]); + i += 4; + break; + case 'T': + mode = TOP_BOTTOM; + memcpy(c, &string[i + 2], 6); + i += 7; + break; + case 'L': + mode = LEFT_RIGHT; + memcpy(c, &string[i + 2], 6); + i += 7; + break; + case 'F': + mode = FOUR; + memcpy(c, &string[i + 2], 12); + i += 13; + break; + } + } else { + switch (mode) { + case MONO: + txfRenderGlyph(txf, string[i]); + break; + case TOP_BOTTOM: + tgvi = getTCVI(txf, string[i]); + glBegin(GL_QUADS); + glColor3ubv(c[0]); + glTexCoord2fv(tgvi->t0); + glVertex2sv(tgvi->v0); + glTexCoord2fv(tgvi->t1); + glVertex2sv(tgvi->v1); + glColor3ubv(c[1]); + glTexCoord2fv(tgvi->t2); + glVertex2sv(tgvi->v2); + glTexCoord2fv(tgvi->t3); + glVertex2sv(tgvi->v3); + glEnd(); + glTranslatef(tgvi->advance, 0.0, 0.0); + break; + case LEFT_RIGHT: + tgvi = getTCVI(txf, string[i]); + glBegin(GL_QUADS); + glColor3ubv(c[0]); + glTexCoord2fv(tgvi->t0); + glVertex2sv(tgvi->v0); + glColor3ubv(c[1]); + glTexCoord2fv(tgvi->t1); + glVertex2sv(tgvi->v1); + glColor3ubv(c[1]); + glTexCoord2fv(tgvi->t2); + glVertex2sv(tgvi->v2); + glColor3ubv(c[0]); + glTexCoord2fv(tgvi->t3); + glVertex2sv(tgvi->v3); + glEnd(); + glTranslatef(tgvi->advance, 0.0, 0.0); + break; + case FOUR: + tgvi = getTCVI(txf, string[i]); + glBegin(GL_QUADS); + glColor3ubv(c[0]); + glTexCoord2fv(tgvi->t0); + glVertex2sv(tgvi->v0); + glColor3ubv(c[1]); + glTexCoord2fv(tgvi->t1); + glVertex2sv(tgvi->v1); + glColor3ubv(c[2]); + glTexCoord2fv(tgvi->t2); + glVertex2sv(tgvi->v2); + glColor3ubv(c[3]); + glTexCoord2fv(tgvi->t3); + glVertex2sv(tgvi->v3); + glEnd(); + glTranslatef(tgvi->advance, 0.0, 0.0); + break; + } + } } - else if (grad->type == ZN_RADIAL_GRADIENT) { - ZnPoly poly; - ZnPoint points[2]; - - points[0].x = bbox->x; - points[0].y = bbox->y; - points[1].x = bbox->x + bbox->width; - points[1].y = bbox->x + bbox->height; - POLY_CONTOUR1(&poly, points, 2); - ITEM_P.PushClip(wi, &poly, False, True); - DrawRadialGradient(wi, grad, bbox); - ITEM_P.PopClip(wi, True); +} + +int +txfInFont(TexFont * txf, int c) +{ + /* NOTE: No uppercase/lowercase substituion. */ + if ((c >= txf->min_glyph) && (c < txf->min_glyph + txf->range)) { + if (txf->lut[c - txf->min_glyph]) { + return 1; + } } + return 0; } +#endif -- cgit v1.1