Split out vrect_t to its own file and add support functions.

The rest is cleanup after removing a wart from one of the field names.
This commit is contained in:
Bill Currie 2012-01-06 09:52:14 +09:00
parent 42266cddd5
commit 2ae044effd
14 changed files with 337 additions and 23 deletions

View file

@ -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 \

View file

@ -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

140
include/QF/vrect.h Normal file
View file

@ -0,0 +1,140 @@
/*
vrect.h
Rectangle manipulation
Copyright (C) 2012 Bill Currie <bill@taniwha.org>
Author: Bill Currie <bill@taniwha.org>
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

View file

@ -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)

178
libs/util/vrect.c Normal file
View file

@ -0,0 +1,178 @@
/*
vrect.c
Rectangle manipulation
Copyright (C) 2012 Bill Currie <bill@taniwha.org>
Author: Bill Currie <bill@taniwha.org>
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 <stdlib.h>
#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;
}

View file

@ -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);
}

View file

@ -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 ();

View file

@ -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);
}

View file

@ -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 ();

View file

@ -518,7 +518,7 @@ VID_Update (vrect_t *rects)
d += lineskip;
s += lineskip;
}
rects = rects->pnext;
rects = rects->next;
}
}
}

View file

@ -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;

View file

@ -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;
}
}

View file

@ -457,7 +457,7 @@ VID_Update (vrect_t *rects)
}
offset += vid.rowbytes;
}
rects = rects->pnext;
rects = rects->next;
}
}
}

View file

@ -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);