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