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