openblt

a hobby OS from the late 90s
git clone http://frotz.net/git/openblt.git
Log | Files | Refs | LICENSE

Region.cpp (7422B)


      1 #include <stdlib.h>
      2 #include <stdio.h>
      3 #include <string.h>
      4 #include "Region.h"
      5 #include "util.h"
      6 
      7 const int kRectAllocSize = 16;
      8 
      9 Region::Region()
     10 	:	fRects(0),
     11 		fNumRects(0),
     12 		fOpLevel(0)
     13 {
     14 }
     15 
     16 Region::Region(const Region &copyRegion)
     17 	:	fRects(0),
     18 		fNumRects(0),
     19 		fOpLevel(0)
     20 {
     21 	SetTo(copyRegion);
     22 }
     23 
     24 Region::~Region()
     25 {
     26 	free(fRects);
     27 }
     28 
     29 Region& Region::SetTo(const Region &copyRegion)
     30 {
     31 	AllocSpace(copyRegion.fNumRects);
     32 	fNumRects = copyRegion.fNumRects;
     33 	memcpy(fRects, copyRegion.fRects, fNumRects * sizeof(Rect));
     34 	return *this;
     35 }
     36 
     37 Region& Region::operator=(const Region &copyRegion)
     38 {
     39 	return SetTo(copyRegion);
     40 }
     41 
     42 Rect Region::Bounds() const
     43 {
     44 	Rect bounds(COORD_MAX, COORD_MAX, -COORD_MAX, -COORD_MAX);
     45 	for (int i = 0; i < fNumRects; i++) {
     46 		const Rect &rect = RectAt(i);
     47 		bounds.left = min(bounds.left, rect.left);
     48 		bounds.right = max(bounds.right, rect.right);
     49 		bounds.top = min(bounds.top, rect.top);
     50 		bounds.bottom = max(bounds.bottom, rect.bottom);
     51 	}
     52 
     53 	return bounds;
     54 }
     55 
     56 Region& Region::Include(const Rect &rect)
     57 {
     58 	Region temp;
     59 
     60 	BeginOperation();
     61 	// Make sure that there are no overlaps
     62 	temp.AddRect(rect);
     63 	for (int i = 0; i < fNumRects; i++)
     64 		temp.Exclude(RectAt(i));
     65 
     66 	AddRegionRects(temp);
     67 	EndOperation();
     68 	return *this;
     69 }
     70 
     71 Region& Region::Include(const Region &region)
     72 {
     73 	BeginOperation();
     74 	for (int i = 0; i < region.CountRects(); i++)
     75 		Include(region.RectAt(i));
     76 	EndOperation();
     77 
     78 	return *this;
     79 }
     80 
     81 #define SPLIT_TEST(rect1, rect2)											\
     82 	(max(rect1.left, rect2.left) < min(rect1.right, rect2.right)			\
     83 		&& max(rect1.top, rect2.top) < min(rect1.bottom, rect2.bottom))
     84 
     85 Region& Region::Exclude(const Rect &excludeRect)
     86 {
     87 	BeginOperation();
     88 	int index = 0;
     89 	int rectsToCheck = fNumRects;
     90 	while (index < rectsToCheck) {
     91 		Rect &clipRect = fRects[index];
     92 
     93 		if (!excludeRect.Intersects(clipRect)) {
     94 			index++;
     95 			continue;
     96 		}
     97 
     98 		// This clip rect intersects the excluded rect, and could be divided into
     99 		// as many as eight pieces.  Test for each case.  Note that none of these
    100 		// rectangles overlap!!!!
    101 		Rect quad1(clipRect.left, clipRect.top, excludeRect.left - 1, excludeRect.top - 1);
    102 		if (SPLIT_TEST(clipRect, quad1)) {
    103 			quad1.Intersect(clipRect);
    104 			AddRect(quad1);
    105 		}
    106 
    107 		Rect quad2(excludeRect.left, clipRect.top, excludeRect.right, excludeRect.top - 1);
    108 		if (SPLIT_TEST(clipRect, quad2)) {
    109 			quad2.Intersect(clipRect);
    110 			AddRect(quad2);
    111 		}
    112 
    113 		Rect quad3(excludeRect.right + 1, clipRect.top, clipRect.right, excludeRect.top - 1);
    114 		if (SPLIT_TEST(clipRect, quad3)) {
    115 			quad3.Intersect(clipRect);
    116 			AddRect(quad3);
    117 		}
    118 
    119 		Rect quad4(clipRect.left, excludeRect.top, excludeRect.left - 1, excludeRect.bottom);
    120 		if (SPLIT_TEST(clipRect, quad4)) {
    121 			quad4.Intersect(clipRect);
    122 			AddRect(quad4);
    123 		}
    124 
    125 		Rect quad5(excludeRect.right + 1, excludeRect.top, clipRect.right, excludeRect.bottom);
    126 		if (SPLIT_TEST(clipRect, quad5)) {
    127 			quad5.Intersect(clipRect);
    128 			AddRect(quad5);
    129 		}
    130 
    131 		Rect quad6(clipRect.left, excludeRect.bottom + 1, excludeRect.left - 1, clipRect.bottom);
    132 		if (SPLIT_TEST(clipRect, quad6)) {
    133 			quad6.Intersect(clipRect);
    134 			AddRect(quad6);
    135 		}
    136 
    137 		Rect quad7(excludeRect.left, excludeRect.bottom + 1, excludeRect.right, clipRect.bottom);
    138 		if (SPLIT_TEST(clipRect, quad7)) {
    139 			quad7.Intersect(clipRect);
    140 			AddRect(quad7);
    141 		}
    142 
    143 		Rect quad8(excludeRect.right + 1, excludeRect.bottom + 1, clipRect.right, clipRect.bottom);
    144 		if (SPLIT_TEST(clipRect, quad8)) {
    145 			quad8.Intersect(clipRect);
    146 			AddRect(quad8);	
    147 		}
    148 
    149 		// This rect has been split, remove it.  Note we don't
    150 		// change the index
    151 		RemoveRect(index);		
    152 		rectsToCheck--;
    153 	}
    154 	EndOperation();
    155 	return *this;
    156 }
    157 
    158 Region& Region::Exclude(const Region &ex)
    159 {
    160 	BeginOperation();
    161 	Region temp(ex);
    162 	temp.Invert();
    163 	Intersect(temp);
    164 	EndOperation();
    165 	return *this;
    166 }
    167 
    168 
    169 
    170 Region& Region::Clear()
    171 {
    172 	fNumRects = 0;
    173 	AllocSpace(0);
    174 	return *this;
    175 }
    176 
    177 Region& Region::ConstrainTo(const Rect &rect)
    178 {
    179 	BeginOperation();
    180 	for (int i = fNumRects - 1; i >= 0; i--) {
    181 		fRects[i].left = max(rect.left, fRects[i].left);
    182 		fRects[i].right = min(rect.right, fRects[i].right);
    183 		fRects[i].top = max(rect.top, fRects[i].top);
    184 		fRects[i].bottom = min(rect.bottom, fRects[i].bottom);
    185 		if (!fRects[i].Valid())
    186 			RemoveRect(i);
    187 	}
    188 	
    189 	EndOperation();
    190 	return *this;
    191 }
    192 
    193 Region& Region::Translate(int x, int y)
    194 {
    195 	for (int i = 0; i < fNumRects; i++) {
    196 		fRects[i].left += x;
    197 		fRects[i].right += x;
    198 		fRects[i].top += y;
    199 		fRects[i].bottom += y;
    200 	}
    201 
    202 	return *this;
    203 }
    204 
    205 Region& Region::Intersect(const Region &intersectRegion)
    206 {
    207 	BeginOperation();
    208 	Region newRegion;
    209 	for (int i = 0; i < fNumRects; i++) {
    210 		for (int j = 0; j < intersectRegion.fNumRects; j++) {
    211 			if (RectAt(i).Intersects(intersectRegion.RectAt(j))) {
    212 				Rect temp(RectAt(i));
    213 				temp.Intersect(intersectRegion.RectAt(j));
    214 				newRegion.AddRect(temp);
    215 			}
    216 		}
    217 	}
    218 	
    219 	SetTo(newRegion);
    220 	EndOperation();
    221 	return *this;
    222 }
    223 
    224 Region& Region::Invert()
    225 {
    226 	BeginOperation();
    227 	Region temp;
    228 	temp.Include(Rect(-COORD_MAX, -COORD_MAX, COORD_MAX, COORD_MAX));
    229 	for (int i = 0; i < fNumRects; i++)
    230 		temp.Exclude(fRects[i]);
    231 
    232 	SetTo(temp);
    233 	EndOperation();
    234 	return *this;
    235 }
    236 
    237 const bool Region::FindRect(int x, int y, Rect &outRect) const
    238 {
    239 	for (int i = 0; i < CountRects(); i++) {
    240 		if (RectAt(i).Contains(x, y)) {
    241 			outRect = RectAt(i);
    242 			return true;
    243 		}
    244 	}
    245 
    246 	return false;
    247 }
    248 
    249 void Region::AddRect(const Rect &rect)
    250 {
    251 	AllocSpace(fNumRects + 1);
    252 	fRects[fNumRects++] = rect;
    253 }
    254 
    255 void Region::RemoveRect(int index)
    256 {
    257 	fNumRects--;
    258 	memcpy(fRects + index, fRects + index + 1, (fNumRects - index) * sizeof(Rect));
    259 	AllocSpace(fNumRects);
    260 }
    261 
    262 void Region::AddRegionRects(const Region &region)
    263 {
    264 	for (int i = 0; i < region.fNumRects; i++)
    265 		AddRect(region.RectAt(i));
    266 }
    267 
    268 void Region::Consolidate()
    269 {
    270 	// Optimize region by consolidating adjacent rectangles.
    271 	for (int i = 0; i < fNumRects; i++) {
    272 		for (int j = fNumRects - 1; j > i; j--) {
    273 			Rect &rect1 = fRects[i];
    274 			Rect &rect2 = fRects[j];
    275 			if (rect1.top == rect2.top && rect1.bottom == rect2.bottom) {
    276 				if (rect1.right + 1 == rect2.left) {
    277 					rect1.right = rect2.right;
    278 					RemoveRect(j);				
    279 				} else if (rect2.right + 1 == rect1.left) {
    280 					rect1.left = rect2.left;
    281 					RemoveRect(j);
    282 				}
    283 			} else if (rect1.left == rect2.left && rect1.right == rect2.right) {
    284 				if (rect1.top == rect2.bottom + 1) {
    285 					rect1.top = rect2.top;
    286 					RemoveRect(j);
    287 				} else if (rect1.bottom + 1 == rect2.top) {
    288 					rect1.bottom = rect2.bottom;
    289 					RemoveRect(j);
    290 				}
    291 			}
    292 		}
    293 	}
    294 }
    295 
    296 void Region::AllocSpace(int numRects)
    297 {
    298 	int currentAlloc = ((fNumRects + kRectAllocSize - 1) / kRectAllocSize)
    299 		* kRectAllocSize;
    300 	int sizeWanted = ((numRects + kRectAllocSize - 1) / kRectAllocSize)
    301 		* kRectAllocSize;
    302 
    303 	if (sizeWanted != currentAlloc) {
    304 		if (fRects == 0 && sizeWanted > 0)
    305 			fRects = (Rect*) malloc(sizeWanted * sizeof(Rect));
    306 		else if (sizeWanted == 0 && fRects != 0) {
    307 			free(fRects);
    308 			fRects = 0;
    309 		} else
    310 			fRects = (Rect*) realloc(fRects, sizeWanted * sizeof(Rect));
    311 	}
    312 }
    313 
    314 
    315 void Region::BeginOperation()
    316 {
    317 	fOpLevel++;
    318 }
    319 
    320 void Region::EndOperation()
    321 {
    322 	if (--fOpLevel == 0)
    323 		Consolidate();
    324 		
    325 	ASSERT(fOpLevel >= 0);
    326 }
    327 
    328 
    329 
    330 void Region::Dump() const
    331 {
    332 	printf("Region:  ");
    333 	for (int i = 0; i < fNumRects; i++) { 
    334 		if ((i % 6) == 5)
    335 			printf("\n");
    336 		printf("(%d %d %d %d)   ", fRects[i].left, fRects[i].top, fRects[i].right,
    337 			fRects[i].bottom);
    338 	}
    339 
    340 	printf("\n");
    341 }