summaryrefslogtreecommitdiff
path: root/sys/src/cmd/vnc/rlist.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/vnc/rlist.c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/vnc/rlist.c')
-rwxr-xr-xsys/src/cmd/vnc/rlist.c283
1 files changed, 283 insertions, 0 deletions
diff --git a/sys/src/cmd/vnc/rlist.c b/sys/src/cmd/vnc/rlist.c
new file mode 100755
index 000000000..dddad64fc
--- /dev/null
+++ b/sys/src/cmd/vnc/rlist.c
@@ -0,0 +1,283 @@
+#include "vnc.h"
+#include "vncs.h"
+
+static int tot;
+static void rprint(Rlist*);
+
+static void
+growrlist(Rlist *rlist, int n)
+{
+ int old;
+
+ if(rlist->nrect+n <= rlist->maxrect)
+ return;
+
+ old = rlist->maxrect;
+ while(rlist->nrect+n > rlist->maxrect){
+ if(rlist->maxrect == 0)
+ rlist->maxrect = 16;
+ else
+ rlist->maxrect *= 2;
+ }
+
+ tot += rlist->maxrect - old;
+ if(tot > 10000)
+ sysfatal("too many rectangles");
+
+ rlist->rect = realloc(rlist->rect, rlist->maxrect*sizeof(rlist->rect[0]));
+ if(rlist->rect == nil)
+ sysfatal("realloc failed in growrlist");
+}
+
+static void
+rappend(Rlist *rl, Rectangle r)
+{
+ growrlist(rl, 1);
+ rl->rect[rl->nrect++] = r;
+}
+
+/* remove rectangle i from the list */
+static int
+rtrim(Rlist *r, int i)
+{
+ if(i < 0 || i >= r->nrect)
+ return 0;
+ if(i == r->nrect-1){
+ r->nrect--;
+ return 1;
+ }
+ r->rect[i] = r->rect[--r->nrect];
+ return 1;
+}
+
+static int
+rectadjacent(Rectangle r, Rectangle s)
+{
+ return r.min.x<=s.max.x && s.min.x<=r.max.x &&
+ r.min.y<=s.max.y && s.min.y<=r.max.y;
+}
+
+/*
+ * If s shares three edges with r, compute the
+ * rectangle r - s and return 1.
+ * Else return 0.
+ */
+static int
+rectubr(Rectangle *r, Rectangle s)
+{
+ if(r->min.y==s.min.y && r->max.y==s.max.y){
+ if(r->min.x == s.min.x){
+ r->min.x = s.max.x;
+ assert(r->max.x > r->min.x);
+ return 1;
+ }
+ if(r->max.x == s.max.x){
+ r->max.x = s.min.x;
+ assert(r->max.x > r->min.x);
+ return 1;
+ }
+ }
+ if(r->min.x==s.min.x && r->max.x==s.max.x){
+ if(r->min.y == s.min.y){
+ r->min.y = s.max.y;
+ assert(r->max.y > r->min.y);
+ return 1;
+ }
+ if(r->max.y == s.max.y){
+ r->max.y = s.min.y;
+ assert(r->max.y > r->min.y);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * If s is a corner of r, remove s from r, yielding
+ * two rectangles r and rr. R holds the part with
+ * smaller coordinates.
+ */
+static int
+rectcornersubr(Rectangle *r, Rectangle s, Rectangle *rr)
+{
+# define UPRIGHT(r) Pt((r).max.x, (r).min.y)
+# define LOWLEFT(r) Pt((r).min.x, (r).max.y)
+
+ *rr = *r;
+
+ if(s.min.x == r->min.x){
+ if(s.min.y == r->min.y){ // upper left
+ *rr = Rpt(UPRIGHT(s), r->max);
+ *r = Rpt(LOWLEFT(s), LOWLEFT(*rr));
+ return 1;
+ }
+ if(s.max.y == r->max.y){ // lower left
+ *rr = Rpt(Pt(s.max.x, r->min.y), r->max);
+ *r = Rpt(r->min, UPRIGHT(s));
+ return 1;
+ }
+ }
+ if(s.max.x == r->max.x){
+ if(s.max.y == r->max.y){ // lower right
+ *rr = Rpt(Pt(s.min.x, r->min.y), UPRIGHT(s));
+ *r = Rpt(r->min, LOWLEFT(s));
+ return 1;
+ }
+ if(s.min.y == r->min.y){ // upper right
+ *rr = Rpt(LOWLEFT(s), r->max);
+ *r = Rpt(r->min, LOWLEFT(*rr));
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * If s is a band cutting r into two pieces, set r to one piece
+ * and rr to the other.
+ */
+static int
+recttridesubr(Rectangle *nr, Rectangle s, Rectangle *rr)
+{
+ *rr = *nr;
+ if((nr->min.x == s.min.x && nr->max.x == s.max.x) &&
+ (nr->min.y < s.min.y && s.max.y < nr->max.y)){
+ nr->max.y = s.min.y;
+ rr->min.y = s.max.y;
+ return 1;
+ }
+
+ if((nr->min.y == s.min.y && nr->max.y == s.max.y) &&
+ (nr->min.x < s.min.x && s.max.x < nr->max.x)){
+ nr->max.x = s.min.x;
+ rr->min.x = s.max.x;
+ return 1;
+ }
+ return 0;
+}
+
+void
+addtorlist(Rlist *rlist, Rectangle r)
+{
+ int i, j;
+ Rectangle ir, cr, rr;
+ Rlist tmp;
+
+ if(r.min.x >= r.max.x || r.min.y >= r.max.y)
+ return;
+
+ memset(&tmp, 0, sizeof tmp);
+ rappend(&tmp, r);
+
+ if(verbose > 5)
+ fprint(2, "region union add %R:\n", r);
+
+ combinerect(&rlist->bbox, r); // must do this first
+ for(j = 0; j < tmp.nrect; j++){
+ r = tmp.rect[j];
+
+ for(i=0; i < rlist->nrect; i++){
+ ir = rlist->rect[i];
+
+ if(verbose > 5)
+ fprint(2, "checking %R against %R\n", r, ir);
+ if(!rectadjacent(ir, r))
+ continue;
+
+ /* r is covered by ir? */
+ if(rectinrect(r, ir))
+ break;
+
+ /* r covers ir? */
+ if(rectinrect(ir, r)){
+ rtrim(rlist, i);
+ i--;
+ continue;
+ }
+
+ /* aligned and overlapping? */
+ if((ir.min.y == r.min.y && ir.max.y == r.max.y) ||
+ (ir.min.x == r.min.x && ir.max.x == r.max.x)){
+ combinerect(&r, ir);
+ rtrim(rlist, i);
+ i--;
+ continue;
+ }
+
+ /* not aligned */
+ if(verbose > 5)
+ fprint(2, "break up rect %R and %R\n", ir, r);
+ /* 2->2 breakup */
+ cr = ir;
+ if (!rectclip(&cr, r)) /* share only one point */
+ continue;
+
+ if(rectubr(&r, cr))
+ continue;
+
+ if(rectubr(&rlist->rect[i], cr))
+ continue;
+
+ /* 2 -> 3 breakup */
+ /* stride across */
+ if(recttridesubr(&r, cr, &rr)){
+ rappend(&tmp, rr);
+ continue;
+ }
+
+ /* corner overlap */
+ if(rectcornersubr(&r, cr, &rr)){
+ rappend(&tmp, rr);
+ continue;
+ }
+ abort();
+ }
+ if(i == rlist->nrect)
+ rappend(rlist, r);
+ }
+ freerlist(&tmp);
+ if(verbose > 5)
+ rprint(rlist);
+}
+
+void
+freerlist(Rlist *r)
+{
+ free(r->rect);
+ tot -= r->maxrect;
+ r->nrect = 0;
+ r->maxrect = 0;
+ r->rect = nil;
+}
+
+static void
+rprint(Rlist *r)
+{
+ int i;
+
+ fprint(2, "rlist %p:", r);
+ for(i=0; i<r->nrect; i++)
+ fprint(2, " %R", r->rect[i]);
+ fprint(2, "\n");
+}
+
+
+#ifdef REGION_DEBUG
+
+int verbose = 10;
+
+void main(int argc, char * argv[])
+{
+ Rectangle r1 = Rect(0, 0, 300, 200);
+ Rectangle r2 = Rect(100, 100, 400, 300);
+ Rectangle r3 = Rect(200, 100, 500, 300);
+ Region reg;
+
+ initdraw(0, 0, "vncviewer");
+ region_init(&reg);
+ region_union(&reg, r1, r1);
+ region_union(&reg, r2, r2);
+ region_union(&reg, r3, r3);
+}
+
+#endif