From 0ba9e4cec7018cf7d5dd5a7e6bcfd00846f313c6 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Fri, 11 Dec 2009 09:59:36 +0000 Subject: [PATCH] Fixed X11 line implementation - clip lines that are going to go outside the window. --- src/video/x11/SDL_x11render.c | 132 +++++++++++++++++++++++++++++++--- src/video/x11/SDL_x11sym.h | 1 + 2 files changed, 122 insertions(+), 11 deletions(-) diff --git a/src/video/x11/SDL_x11render.c b/src/video/x11/SDL_x11render.c index fa974df67..4b75d0c82 100644 --- a/src/video/x11/SDL_x11render.c +++ b/src/video/x11/SDL_x11render.c @@ -23,6 +23,8 @@ #if SDL_VIDEO_RENDER_X11 +#include /* For INT_MIN and INT_MAX */ + #include "SDL_x11video.h" #include "../SDL_rect_c.h" #include "../SDL_pixels_c.h" @@ -647,26 +649,134 @@ X11_RenderLines(SDL_Renderer * renderer, const SDL_Point * points, int count) SDL_Window *window = SDL_GetWindowFromID(renderer->window); SDL_Rect clip, rect; unsigned long foreground; + XPoint *xpoints, *xpoint; + int i, xcount; + int minx, miny; + int maxx, maxy; clip.x = 0; clip.y = 0; clip.w = window->w; clip.h = window->h; - if (data->makedirty) { - /* Get the smallest rectangle that contains everything */ - SDL_EnclosePoints(points, count, NULL, &rect); - if (!SDL_IntersectRect(&rect, &clip, &rect)) { - /* Nothing to draw */ - return 0; + foreground = renderdrawcolor(renderer, 1); + XSetForeground(data->display, data->gc, foreground); + + xpoint = xpoints = SDL_stack_alloc(XPoint, count); + xcount = 0; + minx = INT_MAX; + miny = INT_MAX; + maxx = INT_MIN; + maxy = INT_MIN; + for (i = 0; i < count; ++i) { + int x = points[i].x; + int y = points[i].y; + + /* If the point is inside the window, add it to the list */ + if (x >= 0 && x < window->w && y >= 0 && y < window->h) { + if (x < minx) { + minx = x; + } else if (x > maxx) { + maxx = x; + } + if (y < miny) { + miny = y; + } else if (y > maxy) { + maxy = y; + } + xpoint->x = (short)x; + xpoint->y = (short)y; + ++xpoint; + ++xcount; + continue; + } + + /* We need to clip the line segments joined by this point */ + if (xcount > 0) { + int x1 = xpoint[-1].x; + int y1 = xpoint[-1].y; + int x2 = x; + int y2 = y; + if (SDL_IntersectRectAndLine(&clip, &x1, &y1, &x2, &y2)) { + if (x2 < minx) { + minx = x2; + } else if (x2 > maxx) { + maxx = x2; + } + if (y2 < miny) { + miny = y2; + } else if (y2 > maxy) { + maxy = y2; + } + xpoint->x = (short)x2; + xpoint->y = (short)y2; + ++xpoint; + ++xcount; + } + XDrawLines(data->display, data->drawable, data->gc, + xpoints, xcount, CoordModeOrigin); + if (xpoints[0].x != x2 || xpoints[0].y != y2) { + XDrawPoint(data->display, data->drawable, data->gc, x2, y2); + } + if (data->makedirty) { + SDL_Rect rect; + + rect.x = minx; + rect.y = miny; + rect.w = (maxx - minx) + 1; + rect.h = (maxy - miny) + 1; + SDL_AddDirtyRect(&data->dirty, &rect); + } + xpoint = xpoints; + xcount = 0; + minx = INT_MAX; + miny = INT_MAX; + maxx = INT_MIN; + maxy = INT_MIN; + } + if (i < (count-1)) { + int x1 = x; + int y1 = y; + int x2 = points[i+1].x; + int y2 = points[i+1].y; + if (SDL_IntersectRectAndLine(&clip, &x1, &y1, &x2, &y2)) { + if (x1 < minx) { + minx = x1; + } else if (x1 > maxx) { + maxx = x1; + } + if (y1 < miny) { + miny = y1; + } else if (y1 > maxy) { + maxy = y1; + } + xpoint->x = (short)x1; + xpoint->y = (short)y1; + ++xpoint; + ++xcount; + } } - SDL_AddDirtyRect(&data->dirty, &rect); } + if (xcount > 1) { + int x2 = xpoint[-1].x; + int y2 = xpoint[-1].y; + XDrawLines(data->display, data->drawable, data->gc, xpoints, xcount, + CoordModeOrigin); + if (xpoints[0].x != x2 || xpoints[0].y != y2) { + XDrawPoint(data->display, data->drawable, data->gc, x2, y2); + } + if (data->makedirty) { + SDL_Rect rect; + + rect.x = minx; + rect.y = miny; + rect.w = (maxx - minx) + 1; + rect.h = (maxy - miny) + 1; + SDL_AddDirtyRect(&data->dirty, &rect); + } + } + SDL_stack_free(xpoints); - foreground = renderdrawcolor(renderer, 1); - XSetForeground(data->display, data->gc, foreground); - /* FIXME: Can we properly handle lines that extend beyond visible space? */ - //XDrawLine(data->display, data->drawable, data->gc, x1, y1, x2, y2); return 0; } diff --git a/src/video/x11/SDL_x11sym.h b/src/video/x11/SDL_x11sym.h index b63fdf2c3..c529f5ef7 100644 --- a/src/video/x11/SDL_x11sym.h +++ b/src/video/x11/SDL_x11sym.h @@ -95,6 +95,7 @@ SDL_X11_SYM(int,XPeekEvent,(Display* a,XEvent* b),(a,b),return) SDL_X11_SYM(int,XPending,(Display* a),(a),return) SDL_X11_SYM(int,XPutImage,(Display* a,Drawable b,GC c,XImage* d,int e,int f,int g,int h,unsigned int i,unsigned int j),(a,b,c,d,e,f,g,h,i,j),return) SDL_X11_SYM(int,XDrawLines,(Display* a, Drawable b, GC c, XPoint* d, int e, int f),(a,b,c,d,e,f),return) +SDL_X11_SYM(int,XDrawPoint,(Display* a, Drawable b, GC c, int d, int e),(a,b,c,d,e),return) SDL_X11_SYM(int,XDrawPoints,(Display* a, Drawable b, GC c, XPoint* d, int e, int f),(a,b,c,d,e,f),return) SDL_X11_SYM(int,XQueryColors,(Display* a,Colormap b,XColor* c,int d),(a,b,c,d),return) SDL_X11_SYM(int,XQueryKeymap,(Display* a,char *b),(a,b),return)