openblt

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

GraphicsContext.cpp (6131B)


      1 #include "Renderer.h"
      2 #include "Rect.h"
      3 #include "Region.h"
      4 #include "GraphicsContext.h"
      5 #include "util.h"
      6 #include "font.h"
      7 #include "Window.h"
      8 
      9 #define swap(a, b) { int temp = a; a = b; b = temp; }
     10 
     11 
     12 GraphicsContext::GraphicsContext()
     13 	:	fRenderer(0)
     14 {
     15 }
     16 
     17 void GraphicsContext::SetColor(char color)
     18 {
     19 	fCurrentColor = color;
     20 }
     21 
     22 const unsigned kBottom = 1;
     23 const unsigned kTop = 2;
     24 const unsigned kLeft = 4;
     25 const unsigned kRight = 8;
     26 
     27 inline unsigned clipmask(int x, int y, const Rect &rect) 
     28 {
     29 	unsigned mask = 0;
     30 	if (x < rect.left)
     31 		mask |= kLeft;
     32 	else if (x > rect.right)
     33 		mask |= kRight;
     34 	
     35 	if (y < rect.top)
     36 		mask |= kTop;
     37 	else if (y > rect.bottom)
     38 		mask |= kBottom;
     39 	
     40 	return mask;		
     41 }
     42 
     43 inline int vert_intersection(int x1, int y1, int x2, int y2, int x)
     44 {
     45 	return y1 + (y2 - y1) * (x - x1) / (x2 - x1);
     46 }
     47 
     48 inline int horz_intersection(int x1, int y1, int x2, int y2, int y)
     49 {
     50 	return x1 + (x2 - x1) * (y - y1) / (y2 - y1);
     51 }
     52 
     53 void GraphicsContext::DrawLine(int x1, int y1, int x2, int y2)
     54 {
     55 	x1 += fXOrigin;
     56 	x2 += fXOrigin;
     57 	y1 += fYOrigin;
     58 	y2 += fYOrigin;
     59 
     60 	for (int rect = 0; rect < fClipRegion.CountRects(); rect++) {
     61 		const Rect &clipRect = fClipRegion.RectAt(rect);
     62 		int clippedX1 = x1;
     63 		int clippedY1 = y1;
     64 		int clippedX2 = x2;
     65 		int clippedY2 = y2;
     66 		unsigned point1mask = clipmask(clippedX1, clippedY1, clipRect);
     67 		unsigned point2mask = clipmask(clippedX2, clippedY2, clipRect);
     68 			
     69 		bool rejected = false;
     70 		while (point1mask != 0 || point2mask != 0) {
     71 			if ((point1mask & point2mask) != 0) {
     72 				rejected = true;
     73 				break;
     74 			}
     75 
     76 			unsigned  mask = point1mask ? point1mask : point2mask;
     77 			int x = 0;
     78 			int y = 0;
     79 			if (mask & kBottom) {
     80 				y = clipRect.bottom;
     81 				x = horz_intersection(clippedX1, clippedY1, clippedX2, clippedY2, y);
     82 			} else if (mask & kTop) {
     83 				y = clipRect.top;
     84 				x = horz_intersection(clippedX1, clippedY1, clippedX2, clippedY2, y);
     85 			} else if (mask & kRight) {
     86 				x = clipRect.right;
     87 				y = vert_intersection(clippedX1, clippedY1, clippedX2, clippedY2, x);
     88 			} else if (mask & kLeft) {
     89 				x = clipRect.left;
     90 				y = vert_intersection(clippedX1, clippedY1, clippedX2, clippedY2, x);
     91 			}
     92 			
     93 			if (point1mask) {
     94 				// Clip point 1
     95 				point1mask = clipmask(x, y, clipRect);
     96 				clippedX1 = x;
     97 				clippedY1 = y;
     98 			} else {
     99 				// Clip point 2
    100 				point2mask = clipmask(x, y, clipRect);
    101 				clippedX2 = x;
    102 				clippedY2 = y;
    103 			}
    104 		}
    105 
    106 		if (!rejected)
    107 	 		fRenderer->DrawLine(clippedX1, clippedY1, clippedX2, clippedY2, fCurrentColor);
    108 	}
    109 }
    110 
    111 
    112 
    113 void GraphicsContext::FillRect(int x1, int y1, int x2, int y2)
    114 {
    115 	x1 += fXOrigin;
    116 	x2 += fXOrigin;
    117 	y1 += fYOrigin;
    118 	y2 += fYOrigin;
    119 
    120     if (x1 > x2) swap(x1, x2);
    121     if (y1 > y2) swap(y1, y2);
    122 
    123 	for (int rect = 0; rect < fClipRegion.CountRects(); rect++) {
    124 		const Rect &clipRect = fClipRegion.RectAt(rect);
    125 		int clipleft = max(x1, clipRect.left); 
    126 		int cliptop = max(y1, clipRect.top);
    127 		int clipright = min(x2, clipRect.right);
    128 		int clipbottom = min(y2, clipRect.bottom);
    129 
    130 		if (clipright >= clipleft && clipbottom >= cliptop) 
    131 			fRenderer->FillRect(clipleft, cliptop, clipright, clipbottom, 
    132 				fCurrentColor);
    133 	}
    134 }
    135 
    136 void GraphicsContext::Blit(int x, int y, char image[], int image_width,
    137 	int image_height, int img_bytes_per_row)
    138 {
    139 	x += fXOrigin;
    140 	y += fYOrigin;
    141 
    142 	for (int rect = 0; rect < fClipRegion.CountRects(); rect++) {
    143 		const Rect &clipRect = fClipRegion.RectAt(rect);
    144 		int clipleft = max(x, clipRect.left); 
    145 		int cliptop = max(y, clipRect.top);
    146 		int clipright = min(x + image_width - 1, clipRect.right);
    147 		int clipbottom = min(y + image_height - 1, clipRect.bottom);
    148 
    149 		if (clipright >= clipleft && clipbottom >= cliptop) {
    150 			fRenderer->Blit(clipleft, cliptop, image + (clipleft - x) + 
    151 				(cliptop - y) * img_bytes_per_row, clipright - clipleft + 1, 
    152 				clipbottom - cliptop + 1, img_bytes_per_row);
    153 		}
    154 	}
    155 }
    156 
    157 void GraphicsContext::StretchBlit(Rect imageRect, Rect screenRect, char image[], int img_bytes_per_row)
    158 {
    159 	screenRect.left += fXOrigin;
    160 	screenRect.top += fYOrigin;
    161 	screenRect.right += fXOrigin;
    162 	screenRect.bottom += fYOrigin;
    163 
    164 	for (int rect = 0; rect < fClipRegion.CountRects(); rect++) {
    165 		const Rect &clipRect = fClipRegion.RectAt(rect);
    166 		Rect clippedScreenRect;
    167 		clippedScreenRect.left = max(screenRect.left, clipRect.left);
    168 		clippedScreenRect.top = max(screenRect.top, clipRect.top);
    169 		clippedScreenRect.right = min(screenRect.right, clipRect.right);
    170 		clippedScreenRect.bottom = min(screenRect.bottom, clipRect.bottom);
    171 
    172 		if (clippedScreenRect.Width() > 0 && clippedScreenRect.Height() > 0) {
    173 			Rect clippedImageRect;
    174 			clippedImageRect.left = (clippedScreenRect.left - screenRect.left)
    175 				* imageRect.Width() / screenRect.Width();
    176 			clippedImageRect.right = (clippedScreenRect.right - screenRect.left)
    177 				 * imageRect.Width() / screenRect.Width();
    178 			clippedImageRect.top = (clippedScreenRect.top - screenRect.top)
    179 				* imageRect.Height() / screenRect.Height();		
    180 			clippedImageRect.bottom = (clippedScreenRect.bottom - screenRect.top)
    181 				* imageRect.Height() / screenRect.Height();
    182 	
    183 			fRenderer->StretchBlit(clippedImageRect, clippedScreenRect, image, img_bytes_per_row);
    184 		}
    185 	}
    186 }
    187 
    188 void GraphicsContext::CopyRect(Rect src, Rect dest, const Region &inCleanRegion,
    189 	Region &outNotCopied)
    190 {
    191 	src.OffsetBy(fXOrigin, fYOrigin);
    192 	dest.OffsetBy(fXOrigin, fYOrigin);
    193 
    194 	int dX = dest.left - src.left;
    195 	int dY = dest.top - src.top;
    196 	Region copyRegion = inCleanRegion;
    197 	copyRegion.ConstrainTo(dest);
    198 	copyRegion.Translate(-dX, -dY);
    199 	copyRegion.Intersect(inCleanRegion);
    200 	for (int rect = 0; rect < copyRegion.CountRects(); rect++) {
    201 		const Rect &srcRect = copyRegion.RectAt(rect);
    202 		Rect destRect(srcRect);
    203 		destRect.OffsetBy(dX, dY);
    204 		fRenderer->CopyRect(srcRect, destRect);
    205 	}
    206 	
    207 	copyRegion.Invert();
    208 	copyRegion.Intersect(fClipRegion);
    209 	outNotCopied = copyRegion;
    210 }
    211 
    212 void GraphicsContext::DrawString(int x, int y, const char *string)
    213 {
    214 	while (*string) {
    215 		Blit(x, y, (char*) &font5x8[*string++ * 40], 5, 8, 5);
    216 		x += 5;
    217 	}
    218 }
    219 
    220 Rect GraphicsContext::Bounds()
    221 {
    222 	Rect rect = fClipRegion.Bounds();
    223 	rect.OffsetBy(-fXOrigin, -fYOrigin);
    224 	return rect;
    225 }
    226 
    227 
    228