1 /* SCCS Id: @(#)gr_rect.c 3.4 2001/12/10 */
2 /* Copyright (c) Christian Bressler, 2001 */
3 /* NetHack may be freely redistributed. See license for details. */
4 /* This is an almost exact copy of qt_clust.cpp */
10 dirty_rect *new_dirty_rect(int size){
13 new=(dirty_rect *)calloc(1L,sizeof(dirty_rect));
15 new->rects=(GRECT *)calloc((long)size,sizeof(GRECT));
25 void delete_dirty_rect(dirty_rect *this){
30 /* In case the Pointer is reused wrongly */
36 static int gc_inside(GRECT *frame,GRECT *test);
37 static int gc_touch(GRECT *frame,GRECT *test);
38 static void gc_combine(GRECT *frame,GRECT *test);
39 static long gc_area(GRECT *area);
40 int add_dirty_rect(dirty_rect *dr,GRECT *area){
42 long lowestcost=9999999L;
44 int cheapestmerge1=-1;
45 int cheapestmerge2=-1;
48 for (cursor=0; cursor<dr->used; cursor++) {
49 if (gc_inside(&dr->rects[cursor],area)) {
50 /* Wholly contained already. */
54 for (cursor=0; cursor<dr->used; cursor++) {
55 if (gc_touch(&dr->rects[cursor],area)) {
56 GRECT larger=dr->rects[cursor];
58 gc_combine(&larger,area);
59 cost=gc_area(&larger)-gc_area(&dr->rects[cursor]);
60 if (cost < lowestcost) {
62 for (c=0; c<dr->used && !bad; c++) {
63 bad=gc_touch(&dr->rects[c],&larger) && c!=cursor;
73 gc_combine(&dr->rects[cheapest],area);
76 if (dr->used < dr->max) {
77 dr->rects[dr->used++]=*area;
81 // add to closest cluster
82 // do cheapest cluster merge, add to new cluster
85 for (cursor=0; cursor<dr->used; cursor++) {
86 GRECT larger=dr->rects[cursor];
88 gc_combine(&larger,area);
89 cost=gc_area(&larger)-gc_area(&dr->rects[cursor]);
90 if (cost < lowestcost) {
92 for (c=0; c<dr->used && !bad; c++) {
93 bad=gc_touch(&dr->rects[c],&larger) && c!=cursor;
101 // XXX could make an heuristic guess as to whether we
102 // XXX need to bother looking for a cheap merge.
103 for (merge1=0; merge1<dr->used; merge1++) {
104 for (merge2=0; merge2<dr->used; merge2++) {
105 if (merge1!=merge2) {
106 GRECT larger=dr->rects[merge1];
108 gc_combine(&larger,&dr->rects[merge2]);
109 cost=gc_area(&larger)-gc_area(&dr->rects[merge1])-gc_area(&dr->rects[merge2]);
110 if (cost < lowestcost) {
112 for (c=0; c<dr->used && !bad; c++) {
113 bad=gc_touch(&dr->rects[c],&larger) && c!=cursor;
116 cheapestmerge1=merge1;
117 cheapestmerge2=merge2;
124 if (cheapestmerge1>=0) {
125 gc_combine(&dr->rects[cheapestmerge1],&dr->rects[cheapestmerge2]);
126 dr->rects[cheapestmerge2]=dr->rects[dr->used-1];
127 dr->rects[dr->used-1]=*area;
129 gc_combine(&dr->rects[cheapest],area);
131 // NB: clusters do not intersect (or intersection will
132 // overwrite). This is a result of the above algorithm,
133 // given the assumption that (x,y) are ordered topleft
137 int get_dirty_rect(dirty_rect* dr,GRECT *area){
138 if(dr==NULL || area==NULL || dr->rects==NULL || dr->used<=0 || dr->max<=0)
140 *area=dr->rects[--dr->used];
143 int clear_dirty_rect(dirty_rect *dr){
148 int resize_dirty_rect(dirty_rect *dr,int new_size){
151 static int gc_inside(GRECT *frame,GRECT *test){
152 if(frame && test && frame->g_x<=test->g_x && frame->g_y<=test->g_y &&
153 frame->g_x+frame->g_w>=test->g_x+test->g_w &&
154 frame->g_y+frame->g_h>=test->g_y+test->g_h
159 static int gc_touch(GRECT *frame,GRECT *test){
160 GRECT tmp={test->g_x-1,test->g_y-1,test->g_w+2,test->g_h+2};
161 return(rc_intersect(frame,&tmp));
163 static void gc_combine(GRECT *frame,GRECT *test){
166 if(frame->g_x>test->g_x){
167 frame->g_w+=frame->g_x-test->g_x;
168 frame->g_x=test->g_x;
170 if(frame->g_y>test->g_y){
171 frame->g_h+=frame->g_y-test->g_y;
172 frame->g_y=test->g_y;
174 if(frame->g_x+frame->g_w<test->g_x+test->g_w)
175 frame->g_w=test->g_x+test->g_w-frame->g_x;
176 if(frame->g_y+frame->g_h<test->g_y+test->g_h)
177 frame->g_h=test->g_y+test->g_h-frame->g_y;
179 static long gc_area(GRECT *area){
180 return((long)area->g_h*(long)area->g_w);