diff --git a/include/QF/Makefile.am b/include/QF/Makefile.am index 398bcbee8..67a6425ad 100644 --- a/include/QF/Makefile.am +++ b/include/QF/Makefile.am @@ -8,8 +8,8 @@ nobase_pkginclude_HEADERS = \ pakfile.h pcx.h png.h plugin.h pr_comp.h pr_debug.h pr_obj.h progs.h \ qargs.h qdefs.h qendian.h qfplist.h qtypes.h quakefs.h quakeio.h render.h \ riff.h ruamoko.h screen.h script.h sizebuf.h skin.h sound.h spritegn.h \ - sys.h teamplay.h tga.h uint32.h va.h ver_check.h vid.h view.h wad.h \ - wadfile.h winding.h zone.h \ + sys.h teamplay.h tga.h uint32.h va.h ver_check.h vid.h vrect.h view.h \ + wad.h wadfile.h winding.h zone.h \ \ GL/ati.h GL/defines.h GL/extensions.h GL/funcs.h GL/qf_explosions.h \ GL/qf_funcs_list.h GL/qf_lightmap.h GL/qf_noisetextures.h \ diff --git a/include/QF/vid.h b/include/QF/vid.h index 058266858..257cbcfe3 100644 --- a/include/QF/vid.h +++ b/include/QF/vid.h @@ -30,6 +30,7 @@ #define __vid_h_ #include "QF/qtypes.h" +#include "QF/vrect.h" #define VID_CBITS 6 #define VID_GRADES (1 << VID_CBITS) @@ -44,11 +45,6 @@ extern struct cvar_s *vid_width; extern struct cvar_s *vid_height; extern struct cvar_s *vid_bitdepth; -typedef struct vrect_s { - int x,y,width,height; - struct vrect_s *pnext; -} vrect_t; - typedef struct { qboolean initialized; void *buffer; // invisible buffer diff --git a/include/QF/vrect.h b/include/QF/vrect.h new file mode 100644 index 000000000..e26e1f739 --- /dev/null +++ b/include/QF/vrect.h @@ -0,0 +1,140 @@ +/* + vrect.h + + Rectangle manipulation + + Copyright (C) 2012 Bill Currie + + Author: Bill Currie + Date: 2012/1/6 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + + $Id$ +*/ + +#ifndef __QF_vrect_h +#define __QF_vrect_h + +typedef struct vrect_s { + int x; + int y; + int width; + int height; + struct vrect_s *next; +} vrect_t; + +#define VRect_MinX(vr) ((vr)->x) +#define VRect_MinY(vr) ((vr)->y) +#define VRect_MaxX(vr) ((vr)->x + (vr)->width) +#define VRect_MaxY(vr) ((vr)->y + (vr)->height) +#define VRect_IsEmpty(vr) ((vr)->width <= 0 || (vr)->height <= 0) + +/** Create a new rectangle of the specified shape. + + Other VRect functions will return a rectangle (or chain of rectangles) + created by this function. + + \param x The X coordinate of the top-left corner. + \param y The Y coordinate of the top-left corner. + \param width The width of the rectangle. + \param height The height of the rectangle. + \return The newly created rectangle. +*/ +vrect_t *VRect_New (int x, int y, int width, int height); + +/** Free one rectangle. + + This function will not free any other rectangles linked to the specified + rectangle. + + \param rect The rectangle to be freed. +*/ +void VRect_Delete (vrect_t *rect); + +/** Return a rectangle representing the intersection of \a r1 and \a r2. + + The returned rectangle may be empty. Use VRect_IsEmpty to check. + + \param r1 The first rectangle. + \param r2 The second rectangle. + \return The single (possibly empty) rectangle representing the + intersection of \a r1 and \a r2. + \note It is the caller's responsibility to delete the returned rectangle. +*/ +vrect_t *VRect_Intersect (const vrect_t *r1, const vrect_t *r2); + +/** Return two rectangles representing the portions of \a r above and below + \a y. + + One of the returned rectangles may be empty. Use VRect_IsEmpty to check. + The first rectangle represents the portion of \a r that is above \a y, and + the second rectangle repesents the portion of \a r that is below \a y. The + second rectangle is linked to the first via the first's vrect_t::next + pointer. + + \param r The rectangle to split. + \param y The horizontal line by which \r will be split. + \return The two linked rectangles representing the portions above + and below \a y. The returned pointer points to the first + (above) rectangle, which links to the second (below) + rectangle. + \note It is the caller's responsibility to delete the returned + rectangles. +*/ +vrect_t *VRect_HSplit (const vrect_t *r, int y); + +/** Return two rectangles representing the portions of \a r to the left and + right of \a y. + + One of the returned rectangles may be empty. Use VRect_IsEmpty to check. + The first rectangle represents the portion of \a r that is to the left of + \a y, and the second rectangle repesents the portion of \a r that is to + the right of \a y. The second rectangle is linked to the first via the + first's vrect_t::next pointer. + + \param r The rectangle to split. + \param x The vertical line by which \r will be split. + \return The two linked rectangles representing the portions to the + left and right of \a y. The returned pointer points to the + first (left) rectangle, which links to the second (right) + rectangle. + \note It is the caller's responsibility to delete the returned + rectangles. +*/ +vrect_t *VRect_VSplit (const vrect_t *r, int x); + +/** Return up to four rectangles representing the result of carving rectangle + \a s out of rectangle \a r. + + None of the returned rectangles will be empty. If the difference is empty, + null will be returned. + + \param r The rectangle to be carved. + \param s The rectangle used to carve \a r. + \return Up to four linked rectangles representing the portions of + \a r after carving out the portion represented by \a s, or + null if the result is empty. A new rectangle that is a copy + of \a r will be returned if \a r and \a s do not intersect. + \note It is the caller's responsibility to delete the returned + rectangles. +*/ +vrect_t *VRect_Difference (const vrect_t *r, const vrect_t *s); + +#endif//__QF_vrect_h diff --git a/libs/util/Makefile.am b/libs/util/Makefile.am index 97804d64c..f6ef79fff 100644 --- a/libs/util/Makefile.am +++ b/libs/util/Makefile.am @@ -42,6 +42,6 @@ libQFutil_la_SOURCES= \ fendian.c hash.c idparse.c info.c link.c llist.c \ mathlib.c mdfour.c msg.c pakfile.c plugin.c qargs.c qendian.c \ qfplist.c quakefs.c quakeio.c riff.c script.c sizebuf.c string.c sys.c \ - va.c ver_check.c wad.c wadfile.c zone.c $(fnmatch) $(getopt) + va.c ver_check.c vrect.c wad.c wadfile.c zone.c $(fnmatch) $(getopt) EXTRA_DIST= $(fnmatch_src) $(getopt_src) diff --git a/libs/util/vrect.c b/libs/util/vrect.c new file mode 100644 index 000000000..1dadf5a26 --- /dev/null +++ b/libs/util/vrect.c @@ -0,0 +1,178 @@ +/* + vrect.c + + Rectangle manipulation + + Copyright (C) 2012 Bill Currie + + Author: Bill Currie + Date: 2012/1/6 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +static __attribute__ ((used)) const char rcsid[] = "$Id$"; + +#include + +#include "QF/mathlib.h" +#include "QF/vrect.h" + +#define RECT_BLOCK 128 +static vrect_t *free_rects; + +VISIBLE vrect_t * +VRect_New (int x, int y, int width, int height) +{ + vrect_t *r; + + if (!free_rects) { + int i; + + free_rects = malloc (RECT_BLOCK * sizeof (vrect_t)); + for (i = 0; i < RECT_BLOCK - 1; i++) + free_rects[i].next = &free_rects[i + 1]; + free_rects[i].next = 0; + } + r = free_rects; + free_rects = free_rects->next; + r->next = 0; + r->x = x; + r->y = y; + r->width = width; + r->height = height; + return r; +} + +VISIBLE void +VRect_Delete (vrect_t *rect) +{ + rect->next = free_rects; + free_rects = rect; +} + +VISIBLE vrect_t * +VRect_Intersect (const vrect_t *r1, const vrect_t *r2) +{ + int minx = max (VRect_MinX (r1), VRect_MinX (r2)); + int miny = max (VRect_MinY (r1), VRect_MinY (r2)); + int maxx = min (VRect_MaxX (r1), VRect_MaxX (r2)); + int maxy = min (VRect_MaxY (r1), VRect_MaxY (r2)); + return VRect_New (minx, miny, maxx - minx, maxy - miny); +} + +VISIBLE vrect_t * +VRect_HSplit (const vrect_t *r, int y) +{ + vrect_t *r1, *r2; + int r1miny = VRect_MinY (r); + int r1maxy = min (VRect_MaxY (r), y); + int r2miny = max (VRect_MinY (r), y); + int r2maxy = VRect_MaxY (r); + r1 = VRect_New (VRect_MinX (r), r1miny, r->width, r1maxy - r1miny); + r2 = VRect_New (VRect_MinX (r), r2miny, r->width, r2maxy - r2miny); + r1->next = r2; + return r1; +} + +VISIBLE vrect_t * +VRect_VSplit (const vrect_t *r, int x) +{ + vrect_t *r1, *r2; + int r1minx = VRect_MinX (r); + int r1maxx = min (VRect_MaxX (r), x); + int r2minx = max (VRect_MinX (r), x); + int r2maxx = VRect_MaxX (r); + r1 = VRect_New (r1minx, VRect_MinY (r), r1maxx - r1minx, r->height); + r2 = VRect_New (r2minx, VRect_MinY (r), r2maxx - r2minx, r->height); + r1->next = r2; + return r1; +} + +VISIBLE vrect_t * +VRect_Difference (const vrect_t *r, const vrect_t *s) +{ + vrect_t *i, *t, *_r; + vrect_t *rects = 0; +#define STASH(t) \ + do { \ + if (!VRect_IsEmpty (t)) { \ + t->next = rects; \ + rects = t; \ + } else { \ + VRect_Delete (t); \ + } \ + } while (0) + + // Find the intersection of r (original rect) and s (the rect being + // subtracted from r). The intersection rect is used to carve the original + // rect. If there is no intersection (the intersection rect is empty), + // then there is nothing to subtract and the original rect (actually, a + // copy of it) is returned. + i = VRect_Intersect (r, s); + if (VRect_IsEmpty (i)) { + // copy r's shape to i, and return i. + i->x = r->x; + i->y = r->y; + i->width = r->width; + i->height = r->height; + return i; + } + + // Split r along the top of the intersection rect and stash the top + // section if it is not empty. + t = VRect_HSplit (r, VRect_MinY (i)); + // can't delete r: we don't own it + _r = t->next; + STASH (t); // maybe stash the top section + // r now represents the portion of the original rect below the top of + // the intersection rect. + + // Split r along the bottom of the intersection rect and stash the bottom + // section if it is not empty. + t = VRect_HSplit (_r, VRect_MaxY (i)); + VRect_Delete (_r); // finished with that copy of _r + _r = t; + STASH (t->next); // maybe stash the bottom section + // r now represents the horizontal section that is common with the + // intersection rect. + + // Split r along the left side of tht intersection rect and stash the + // left section if it is not empty. + t = VRect_VSplit (_r, VRect_MinX (i)); + VRect_Delete (_r); // finished with that copy of _r + _r = t->next; + STASH (t); // maybe stash the left section + // r now represets the section of the original rect that is between the + // top and bottom, and to the right of the left side of the intersection + // rect. + + // Split r along the right side of the intersection rect and stash the + // right section if it is not empty. The left section is discarded. + t = VRect_VSplit (_r, VRect_MaxX (i)); + VRect_Delete (_r); // finished with that copy of _r + STASH (t->next); // maybe stash the right section + VRect_Delete (t); // discard the left section + + return rects; +} diff --git a/libs/video/renderer/sw/screen.c b/libs/video/renderer/sw/screen.c index 46b57ee1d..bfe5b4db5 100644 --- a/libs/video/renderer/sw/screen.c +++ b/libs/video/renderer/sw/screen.c @@ -286,7 +286,7 @@ SCR_UpdateScreen (double realtime, SCR_Func *scr_funcs) vrect.y = 0; vrect.width = vid.width; vrect.height = vid.height; - vrect.pnext = 0; + vrect.next = 0; VID_Update (&vrect); } else if (scr_copytop) { @@ -294,7 +294,7 @@ SCR_UpdateScreen (double realtime, SCR_Func *scr_funcs) vrect.y = 0; vrect.width = vid.width; vrect.height = vid.height - r_lineadj; - vrect.pnext = 0; + vrect.next = 0; VID_Update (&vrect); } else { @@ -302,7 +302,7 @@ SCR_UpdateScreen (double realtime, SCR_Func *scr_funcs) vrect.y = scr_vrect.y; vrect.width = scr_vrect.width; vrect.height = scr_vrect.height; - vrect.pnext = 0; + vrect.next = 0; VID_Update (&vrect); } diff --git a/libs/video/renderer/sw/sw_rmisc.c b/libs/video/renderer/sw/sw_rmisc.c index 8db884d6a..d3eebf432 100644 --- a/libs/video/renderer/sw/sw_rmisc.c +++ b/libs/video/renderer/sw/sw_rmisc.c @@ -75,7 +75,7 @@ R_TimeRefresh_f (void) vr.y = r_refdef.vrect.y; vr.width = r_refdef.vrect.width; vr.height = r_refdef.vrect.height; - vr.pnext = NULL; + vr.next = NULL; VID_Update (&vr); } stop = Sys_DoubleTime (); diff --git a/libs/video/renderer/sw32/screen.c b/libs/video/renderer/sw32/screen.c index 58d04cae1..28fc6f064 100644 --- a/libs/video/renderer/sw32/screen.c +++ b/libs/video/renderer/sw32/screen.c @@ -307,7 +307,7 @@ SCR_UpdateScreen (double realtime, SCR_Func *scr_funcs) vrect.y = 0; vrect.width = vid.width; vrect.height = vid.height; - vrect.pnext = 0; + vrect.next = 0; VID_Update (&vrect); } else if (scr_copytop) { @@ -315,7 +315,7 @@ SCR_UpdateScreen (double realtime, SCR_Func *scr_funcs) vrect.y = 0; vrect.width = vid.width; vrect.height = vid.height - r_lineadj; - vrect.pnext = 0; + vrect.next = 0; VID_Update (&vrect); } else { @@ -323,7 +323,7 @@ SCR_UpdateScreen (double realtime, SCR_Func *scr_funcs) vrect.y = scr_vrect.y; vrect.width = scr_vrect.width; vrect.height = scr_vrect.height; - vrect.pnext = 0; + vrect.next = 0; VID_Update (&vrect); } diff --git a/libs/video/renderer/sw32/sw32_rmisc.c b/libs/video/renderer/sw32/sw32_rmisc.c index 9dd894293..3c7363227 100644 --- a/libs/video/renderer/sw32/sw32_rmisc.c +++ b/libs/video/renderer/sw32/sw32_rmisc.c @@ -75,7 +75,7 @@ R_TimeRefresh_f (void) vr.y = r_refdef.vrect.y; vr.width = r_refdef.vrect.width; vr.height = r_refdef.vrect.height; - vr.pnext = NULL; + vr.next = NULL; VID_Update (&vr); } stop = Sys_DoubleTime (); diff --git a/libs/video/targets/vid_fbdev.c b/libs/video/targets/vid_fbdev.c index 318f676ad..2ff05dcfe 100644 --- a/libs/video/targets/vid_fbdev.c +++ b/libs/video/targets/vid_fbdev.c @@ -518,7 +518,7 @@ VID_Update (vrect_t *rects) d += lineskip; s += lineskip; } - rects = rects->pnext; + rects = rects->next; } } } diff --git a/libs/video/targets/vid_sdl.c b/libs/video/targets/vid_sdl.c index 86f63d8a3..b5d96e74d 100644 --- a/libs/video/targets/vid_sdl.c +++ b/libs/video/targets/vid_sdl.c @@ -147,14 +147,14 @@ VID_Update (vrect_t *rects) // First, count the number of rectangles n = 0; - for (rect = rects; rect; rect = rect->pnext) + for (rect = rects; rect; rect = rect->next) ++n; // Second, copy them to SDL rectangles and update if (!(sdlrects = (SDL_Rect *) calloc (1, n * sizeof (SDL_Rect)))) Sys_Error ("Out of memory!"); i = 0; - for (rect = rects; rect; rect = rect->pnext) { + for (rect = rects; rect; rect = rect->next) { sdlrects[i].x = rect->x; sdlrects[i].y = rect->y; sdlrects[i].w = rect->width; diff --git a/libs/video/targets/vid_sdl32.c b/libs/video/targets/vid_sdl32.c index a7d741872..670c3be2e 100644 --- a/libs/video/targets/vid_sdl32.c +++ b/libs/video/targets/vid_sdl32.c @@ -197,7 +197,7 @@ VID_Update (vrect_t *rects) // update display SDL_UpdateRect (screen, rects->x, rects->y, rects->width, rects->height); - rects = rects->pnext; + rects = rects->next; } } diff --git a/libs/video/targets/vid_svgalib.c b/libs/video/targets/vid_svgalib.c index 3839a309f..32cf6cd20 100644 --- a/libs/video/targets/vid_svgalib.c +++ b/libs/video/targets/vid_svgalib.c @@ -457,7 +457,7 @@ VID_Update (vrect_t *rects) } offset += vid.rowbytes; } - rects = rects->pnext; + rects = rects->next; } } } diff --git a/libs/video/targets/vid_x11.c b/libs/video/targets/vid_x11.c index bcecb4e09..1715492a1 100644 --- a/libs/video/targets/vid_x11.c +++ b/libs/video/targets/vid_x11.c @@ -615,7 +615,7 @@ VID_Update (vrect_t *rects) oktodraw = false; while (!oktodraw) X11_ProcessEvent (); - rects = rects->pnext; + rects = rects->next; current_framebuffer = !current_framebuffer; } else { @@ -624,7 +624,7 @@ VID_Update (vrect_t *rects) rects->width, rects->height)) { Sys_Error ("VID_Update: XPutImage failed"); } - rects = rects->pnext; + rects = rects->next; } } XSync (x_disp, False);