openblt

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

Renderer_8bpp.cpp (5670B)


      1 #include "Renderer_8bpp.h"
      2 #include "assert.h"
      3 
      4 Renderer_8bpp::Renderer_8bpp(char *baseAddress, int width, int height, int bytesPerRow)
      5 	:	Renderer(baseAddress, width, height, bytesPerRow)
      6 {
      7 }
      8 
      9 const unsigned kBottom = 1;
     10 const unsigned kTop = 2;
     11 const unsigned kLeft = 4;
     12 const unsigned kRight = 8;
     13 
     14 #define clipmask(x, y, rect) 		\
     15 	({	unsigned mask = 0;								\
     16 		if (x < rect.left) mask |= kLeft;			\
     17 		else if (x > rect.right) mask |= kRight;	\
     18 		if (y < rect.top) mask |= kTop;			\
     19 		else if (y > rect.bottom) mask |= kBottom;	\
     20 		mask;})											
     21 
     22 void Renderer_8bpp::DrawLine(int x1, int y1, int x2, int y2, char color)
     23 {
     24 	ASSERT(x1 >= 0 && x1 < BufferWidth());
     25 	ASSERT(x2 >= 0 && x2 < BufferWidth());
     26 	ASSERT(y1 >= 0 && y1 < BufferWidth());
     27 	ASSERT(y2 >= 0 && y2 < BufferWidth());
     28 
     29 	// Swap if necessary so we always draw top to bottom 
     30 	if (y1 > y2) {
     31 		int temp = y1;
     32 		y1 = y2;
     33 		y2 = temp;
     34 		
     35 		temp = x1;
     36 		x1 = x2;
     37 		x2 = temp;
     38 	}
     39 
     40 	int deltaY = y2 - y1;
     41 	int deltaX = x2 > x1 ? x2 - x1 : x1 - x2;
     42 	int xDir = x2 > x1 ? 1 : -1;
     43 	int error = 0;
     44 	char *ptr = BufferBaseAddress() + x1 + y1 * BufferBytesPerRow();
     45 
     46 	if (deltaX == 0) {
     47 		// Vertical line
     48 		for (int y = deltaY; y >= 0; y--) {
     49 			*ptr = color;
     50 			ptr += BufferBytesPerRow();
     51 		}
     52 	} else if (deltaY == 0) {
     53 		// Horizontal line
     54 		for (int x = deltaX; x >= 0; x--) {
     55 			*ptr = color;
     56 			ptr += xDir;
     57 		}
     58 	} else if (deltaX > deltaY) {
     59 		// Diagonal with horizontal major axis
     60 		x2 += xDir;	// Want to quit on pixel past last.  Ugly, I know.
     61 		for (int x = x1; x != x2; x += xDir) {
     62 			*ptr = color;
     63 
     64 			error += deltaY;
     65 			if (error > deltaX) {
     66 				ptr += BufferBytesPerRow();
     67 				error -= deltaX;	
     68 			}
     69 
     70 			ptr += xDir; 	
     71 		}
     72 	} else {
     73 		// Diagonal with vertical major axis
     74 		for (int y = y1; y <= y2; y++) {
     75 			*ptr = color;
     76 
     77 			error += deltaX;
     78 			if (error > deltaY) {
     79 				ptr += xDir;
     80 				error -= deltaY;	
     81 			}
     82 
     83 			ptr += BufferBytesPerRow();
     84 		}
     85 	}
     86 }
     87 
     88 void Renderer_8bpp::FillRect(int x1, int y1, int x2, int y2, char color)
     89 {
     90 	ASSERT(x1 >= 0 && x1 <= BufferWidth());
     91 	ASSERT(x2 >= 0 && x2 <= BufferWidth());
     92 	ASSERT(y1 >= 0 && y1 <= BufferWidth());
     93 	ASSERT(y2 >= 0 && y2 <= BufferWidth());
     94 	ASSERT(x2 >= x1);
     95 	ASSERT(y2 >= y1);
     96 
     97 	char *ptr = BufferBaseAddress() + x1 + y1 * BufferBytesPerRow();
     98 	unsigned int longcolor = (unsigned int)(unsigned char)color | ((unsigned int)(unsigned char)color << 8) |
     99 		((unsigned int)(unsigned char)color << 16) | ((unsigned int)(unsigned char)color << 24);
    100 
    101 	int wrap = BufferBytesPerRow() - (x2 - x1) - 1;
    102 	for (int y = y1; y <= y2; y++) {
    103 		int x = x1;
    104 		while (x <= x2 && (x & 3) != 0) {
    105 			*ptr++ = color;
    106 			x++;
    107 		}
    108 
    109 		while (x + 4 <= x2) {
    110 			*((long*) ptr) = longcolor;
    111 			ptr += 4;
    112 			x += 4;
    113 		}
    114 			
    115 		while (x <= x2) {
    116 			*ptr++ = color;				
    117 			x++;
    118 		}
    119 
    120 		ptr += wrap;
    121 	}
    122 }
    123 
    124 void Renderer_8bpp::Blit(int x, int y, char image[], int imageWidth,
    125     int imageHeight, int imageBytesPerRow)
    126 {
    127 	ASSERT(x >= 0 && x + imageWidth <= BufferWidth());
    128 	ASSERT(y >= 0 && y + imageHeight <= BufferWidth());
    129 
    130 	char *screen_ptr = BufferBaseAddress() + x + y * BufferBytesPerRow();
    131 	char *image_ptr = image;
    132 	int imageOffs = imageBytesPerRow - imageWidth;
    133 	int screenOffs = BufferBytesPerRow() - imageWidth;
    134 
    135 	for (int i = 0; i < imageHeight; i++) {
    136 		for (int j = 0; j < imageWidth; j++) {
    137 			if ((unsigned char) *image_ptr != 0xff)
    138 				*screen_ptr = *image_ptr;
    139 
    140 			screen_ptr++;
    141 			image_ptr++;
    142 		}
    143 
    144 		image_ptr += imageOffs;
    145 		screen_ptr += screenOffs;
    146 	}
    147 }
    148 
    149 void Renderer_8bpp::StretchBlit(const Rect &imageRect, const Rect &displayRect, char image[],
    150 	int imageBytesPerRow)
    151 {
    152 	ASSERT(imageRect.Valid());
    153 	ASSERT(displayRect.Valid());
    154 	ASSERT(imageRect.left >= 0);
    155 	ASSERT(imageRect.top >= 0);
    156 	ASSERT(imageRect.right < imageBytesPerRow);
    157 	
    158 	int verror = 0;
    159 	char *screen_ptr = BufferBaseAddress() + displayRect.left + displayRect.top
    160 		* BufferBytesPerRow();
    161 	char *current_image_line = image + imageRect.left + imageRect.top *
    162 		imageBytesPerRow;
    163 	int screenOffs = BufferBytesPerRow() - displayRect.Width() - 1;
    164 	
    165 	for (int y = displayRect.top; y <= displayRect.bottom; y++) {
    166 		char *image_ptr = current_image_line;
    167 		int herror = 0;
    168 		for (int x = displayRect.left; x <= displayRect.right; x++) {
    169 			if ((unsigned char) *image_ptr != 0xff)
    170 				*screen_ptr = *image_ptr;
    171 
    172 			herror += imageRect.Width();
    173 			while (herror >= displayRect.Width()) {
    174 				herror -= displayRect.Width();
    175  				image_ptr++;
    176 			}			
    177 	
    178 			screen_ptr++;
    179 		}
    180 
    181 		verror += imageRect.Height();
    182 		while (verror > displayRect.Height()) {
    183 			verror -= displayRect.Height();
    184 			current_image_line += imageBytesPerRow;
    185 		}
    186 		
    187 		screen_ptr += screenOffs;
    188 	}
    189 }
    190 
    191 void Renderer_8bpp::CopyRect(const Rect &source, const Rect &dest)
    192 {
    193 	ASSERT(source.Width() == dest.Width());
    194 	ASSERT(source.Height() == dest.Height());
    195 
    196 	int dX;
    197 	int dY;	
    198 	int startX;
    199 	int startY;	
    200 	if (dest.left > source.left && dest.left < source.right) {
    201 		// overlap left side, copy backward
    202 		dX = -1;
    203 		startX = source.right;
    204 	} else {
    205 		dX = 1;
    206 		startX = source.left;
    207 	}
    208 
    209 	if (dest.top > source.top && dest.top < source.bottom) {
    210 		// overlap bottom, copy top up
    211 		dY = -(BufferBytesPerRow() + dX * (source.Width() + 1));
    212 		startY = source.bottom;
    213 	} else {
    214 		dY = (BufferBytesPerRow() - dX * (source.Width() - 1));
    215 		startY = source.top;
    216 	}
    217 	
    218 	char *srcptr = BufferBaseAddress() + startX + startY * BufferBytesPerRow();
    219 	int offset =  (dest.left - source.left) + (dest.top - source.top)
    220 		* BufferBytesPerRow();
    221 	
    222 	for (int y = source.top; y <= source.bottom; y++) {
    223 		for (int x = source.left; x <= source.right; x++) {
    224 			*((char*) srcptr + offset) = *srcptr;
    225 			srcptr += dX;
    226 		}
    227 
    228 		srcptr += dY;
    229 	}
    230 }
    231 
    232 
    233