A simple yet powerful library for controlling graphical displays. Multiple display controllers are supported using inheritance.
Dependents: mbed_rifletool Hexi_Bubble_Game Hexi_Catch-the-dot_Game Hexi_Acceleromagnetic_Synth
Canvas.cpp
00001 /* NeatGUI Library 00002 * Copyright (c) 2013 Neil Thiessen 00003 * 00004 * Licensed under the Apache License, Version 2.0 (the "License"); 00005 * you may not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an "AS IS" BASIS, 00012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00017 #include "Canvas.h" 00018 00019 Canvas::Canvas(int w, int h) 00020 { 00021 m_Width = w; 00022 m_Height = h; 00023 } 00024 00025 void Canvas::clear(unsigned int c) 00026 { 00027 fillRect(0, 0, m_Width, m_Height, c); 00028 } 00029 00030 void Canvas::drawLine(int x0, int y0, int x1, int y1, unsigned int c) 00031 { 00032 int steep = abs(y1 - y0) > abs(x1 - x0); 00033 if (steep) { 00034 int temp = x0; 00035 x0 = y0; 00036 y0 = temp; 00037 00038 temp = x1; 00039 x1 = y1; 00040 y1 = temp; 00041 } 00042 00043 if (x0 > x1) { 00044 int temp = x0; 00045 x0 = x1; 00046 x1 = temp; 00047 00048 temp = y0; 00049 y0 = y1; 00050 y1 = temp; 00051 } 00052 00053 int dx, dy; 00054 dx = x1 - x0; 00055 dy = abs(y1 - y0); 00056 00057 int err = dx / 2; 00058 int ystep; 00059 00060 if (y0 < y1) { 00061 ystep = 1; 00062 } else { 00063 ystep = -1; 00064 } 00065 00066 for (; x0 <= x1; x0++) { 00067 if (steep) { 00068 drawPixel(y0, x0, c); 00069 } else { 00070 drawPixel(x0, y0, c); 00071 } 00072 err -= dy; 00073 if (err < 0) { 00074 y0 += ystep; 00075 err += dx; 00076 } 00077 } 00078 } 00079 00080 void Canvas::drawHLine(int x, int y, int w, unsigned int c) 00081 { 00082 drawLine(x, y, x + w - 1, y, c); 00083 } 00084 00085 void Canvas::drawVLine(int x, int y, int h, unsigned int c) 00086 { 00087 drawLine(x, y, x, y + h - 1, c); 00088 } 00089 00090 void Canvas::drawRect(int x, int y, int w, int h, unsigned int c) 00091 { 00092 drawHLine(x, y, w, c); 00093 drawHLine(x, y + h - 1, w, c); 00094 drawVLine(x, y, h, c); 00095 drawVLine(x + w - 1, y, h, c); 00096 } 00097 00098 void Canvas::fillRect(int x, int y, int w, int h, unsigned int c) 00099 { 00100 for (int i = x; i < x + w; i++) { 00101 drawVLine(i, y, h, c); 00102 } 00103 } 00104 00105 void Canvas::drawTriangle(int x0, int y0, int x1, int y1, int x2, int y2, unsigned int c) 00106 { 00107 drawLine(x0, y0, x1, y1, c); 00108 drawLine(x1, y1, x2, y2, c); 00109 drawLine(x2, y2, x0, y0, c); 00110 } 00111 00112 void Canvas::fillTriangle(int x0, int y0, int x1, int y1, int x2, int y2, unsigned int c) 00113 { 00114 int a, b, y, last; 00115 00116 //Sort coordinates by Y order (y2 >= y1 >= y0) 00117 if (y0 > y1) { 00118 int temp = y0; 00119 y0 = y1; 00120 y1 = temp; 00121 00122 temp = x0; 00123 x0 = x1; 00124 x1 = temp; 00125 } 00126 if (y1 > y2) { 00127 int temp = y1; 00128 x1 = y2; 00129 y2 = temp; 00130 00131 temp = x1; 00132 x1 = x2; 00133 x2 = temp; 00134 } 00135 if (y0 > y1) { 00136 int temp = y0; 00137 y0 = y1; 00138 y1 = temp; 00139 00140 temp = x0; 00141 x0 = x1; 00142 x1 = temp; 00143 } 00144 00145 //Handle awkward all-on-same-line case as its own thing 00146 if(y0 == y2) { 00147 a = b = x0; 00148 if(x1 < a) 00149 a = x1; 00150 else if(x1 > b) 00151 b = x1; 00152 if(x2 < a) 00153 a = x2; 00154 else if(x2 > b) 00155 b = x2; 00156 00157 drawHLine(a, y0, b - a + 1, c); 00158 00159 return; 00160 } 00161 00162 int dx01 = x1 - x0; 00163 int dy01 = y1 - y0; 00164 int dx02 = x2 - x0; 00165 int dy02 = y2 - y0; 00166 int dx12 = x2 - x1; 00167 int dy12 = y2 - y1; 00168 int sa = 0; 00169 int sb = 0; 00170 00171 //For upper part of triangle, find scanline crossings for segments 00172 //0-1 and 0-2. If y1=y2 (flat-bottomed triangle), the scanline y1 00173 //is included here (and second loop will be skipped, avoiding a /0 00174 //error there), otherwise scanline y1 is skipped here and handled 00175 //in the second loop...which also avoids a /0 error here if y0=y1 00176 //(flat-topped triangle). 00177 if(y1 == y2) 00178 last = y1; //Include y1 scanline 00179 else 00180 last = y1 - 1; //Skip it 00181 00182 for(y = y0; y <= last; y++) { 00183 a = x0 + sa / dy01; 00184 b = x0 + sb / dy02; 00185 sa += dx01; 00186 sb += dx02; 00187 00188 if(a > b) { 00189 int temp = a; 00190 a = b; 00191 b = temp; 00192 } 00193 drawHLine(a, y, b - a + 1, c); 00194 } 00195 00196 //For lower part of triangle, find scanline crossings for segments 00197 //0-2 and 1-2. This loop is skipped if y1=y2. 00198 sa = dx12 * (y - y1); 00199 sb = dx02 * (y - y0); 00200 for(; y <= y2; y++) { 00201 a = x1 + sa / dy12; 00202 b = x0 + sb / dy02; 00203 sa += dx12; 00204 sb += dx02; 00205 00206 if(a > b) { 00207 int temp = a; 00208 a = b; 00209 b = temp; 00210 } 00211 drawHLine(a, y, b - a + 1, c); 00212 } 00213 } 00214 00215 void Canvas::drawCircle(int x, int y, int r, unsigned int c) 00216 { 00217 int f = 1 - r; 00218 int ddF_x = 1; 00219 int ddF_y = -2 * r; 00220 int i = 0; 00221 int j = r; 00222 00223 drawPixel(x, y + r, c); 00224 drawPixel(x, y - r, c); 00225 drawPixel(x + r, y, c); 00226 drawPixel(x - r, y, c); 00227 00228 while(i < j) { 00229 if(f >= 0) { 00230 j--; 00231 ddF_y += 2; 00232 f += ddF_y; 00233 } 00234 i++; 00235 ddF_x += 2; 00236 f += ddF_x; 00237 drawPixel(x + i, y + j, c); 00238 drawPixel(x - i, y + j, c); 00239 drawPixel(x + i, y - j, c); 00240 drawPixel(x - i, y - j, c); 00241 drawPixel(x + j, y + i, c); 00242 drawPixel(x - j, y + i, c); 00243 drawPixel(x + j, y - i, c); 00244 drawPixel(x - j, y - i, c); 00245 } 00246 } 00247 00248 void Canvas::fillCircle(int x, int y, int r, unsigned int c) 00249 { 00250 drawVLine(x, y - r, 2 * r + 1, c); 00251 fillCircleHelper(x, y, r, 3, 0, c); 00252 } 00253 00254 void Canvas::drawRoundRect(int x, int y, int w, int h, int r, unsigned int c) 00255 { 00256 //Draw the four lines 00257 drawHLine(x + r, y, w - 2 * r, c); //Top 00258 drawHLine(x + r, y + h - 1, w - 2 * r, c); //Bottom 00259 drawVLine(x, y + r, h - 2 * r, c); //Left 00260 drawVLine(x + w - 1, y + r, h - 2 * r, c); //Right 00261 00262 //Draw the four corners 00263 drawCircleHelper(x + r, y + r, r, 1, c); 00264 drawCircleHelper(x + w - r - 1, y + r, r, 2, c); 00265 drawCircleHelper(x + w - r - 1, y + h - r - 1, r, 4, c); 00266 drawCircleHelper(x + r, y + h - r - 1, r, 8, c); 00267 } 00268 00269 void Canvas::fillRoundRect(int x, int y, int w, int h, int r, unsigned int c) 00270 { 00271 //Draw the body 00272 fillRect(x + r, y, w - 2 * r, h, c); 00273 00274 //Draw the four corners 00275 fillCircleHelper(x + w - r - 1, y + r, r, 1, h - 2 * r - 1, c); 00276 fillCircleHelper(x+r, y + r, r, 2, h - 2 * r - 1, c); 00277 } 00278 00279 void Canvas::drawImage(Image* img, int x, int y) 00280 { 00281 for (int j = 0; j < img->height(); j++) { 00282 for (int i = 0; i < img->width(); i++) { 00283 drawPixel(i + x, j + y, img->pixel(i, j)); 00284 } 00285 } 00286 } 00287 00288 int Canvas::drawChar(char c, Font* fnt, int x, int y) 00289 { 00290 //Get the character glyph 00291 BitmapImage glyph = fnt->glyph(c); 00292 00293 //Draw the character glyph 00294 drawImage(&glyph, x, y); 00295 00296 //Return the width of the glyph 00297 return glyph.width(); 00298 } 00299 00300 void Canvas::drawString(const char* str, Font* fnt, int x, int y) 00301 { 00302 int cursX = 0; 00303 int cursY = 0; 00304 00305 while(*str != NULL) { 00306 //Check for a new line character 00307 if (*str == '\n') { 00308 //Go to a new line 00309 cursX = 0; 00310 cursY += fnt->height(); 00311 00312 //We're done for this character 00313 str++; 00314 continue; 00315 } 00316 00317 //Check for a carriage return character 00318 if (*str == '\r') { 00319 //Ignore it, we're done for this character 00320 str++; 00321 continue; 00322 } 00323 00324 //Draw the character 00325 cursX += drawChar(*str++, fnt, x + cursX, y + cursY); 00326 } 00327 } 00328 00329 void Canvas::drawString(const char* str, Font* fnt, int x, int y, int w, int h) 00330 { 00331 int cursX = 0; 00332 int cursY = 0; 00333 00334 while(*str != NULL) { 00335 //Check for a new line character 00336 if (*str == '\n') { 00337 //Check if we can fit another line 00338 if ((cursY + 2 * fnt->height()) < h) { 00339 //Yes we can 00340 cursX = 0; 00341 cursY += fnt->height(); 00342 00343 //We're done for this character 00344 str++; 00345 continue; 00346 } else { 00347 //Nope, we can't print any more so return 00348 return; 00349 } 00350 } 00351 00352 //Check for a carriage return character 00353 if (*str == '\r') { 00354 //Ignore it, we're done for this character 00355 str++; 00356 continue; 00357 } 00358 00359 //Check for entire words first 00360 if ((*str > ' ') && (*str <= 0x7E)) { 00361 //Draw entire word on canvas with correct wrapping 00362 //int i = 0; 00363 int wlen; 00364 00365 //Determine the length of the next word 00366 wlen = fnt->measureWord(str); 00367 00368 //Will the length of the next word exceed the margins? 00369 if ((wlen + cursX) > w) { 00370 //Only do a newline if the word will fit on it 00371 if (wlen <= w) { 00372 //Check if we can fit another line 00373 if ((cursY + 2 * fnt->height()) < h) { 00374 //Yes we can 00375 cursX = 0; 00376 cursY += fnt->height(); 00377 } else { 00378 //Nope, we can't print any more so return 00379 return; 00380 } 00381 } 00382 } 00383 00384 //Put just the word characters on the display up to the next non-whitespace character or the end of the string 00385 while ((*str > ' ') && (*str <= 0x7E)) { 00386 //Check if the character will fit on the screen 00387 if ((fnt->glyph(*str).width() + cursX) > w) { 00388 //Check if we can fit another line 00389 if ((cursY + 2 * fnt->height()) < h) { 00390 //Yes we can 00391 cursX = 0; 00392 cursY += fnt->height(); 00393 } else { 00394 //Nope, we can't print any more so return 00395 return; 00396 } 00397 } 00398 00399 //Draw the character 00400 cursX += drawChar(*str++, fnt, x + cursX, y + cursY); 00401 } 00402 } else { 00403 //Check if the character will fit on the screen 00404 if ((fnt->glyph(*str).width() + cursX) > w) { 00405 //Check if we can fit another line 00406 if ((cursY + 2 * fnt->height()) < h) { 00407 //Yes we can 00408 cursX = 0; 00409 cursY += fnt->height(); 00410 } else { 00411 //Nope, we can't print any more so return 00412 return; 00413 } 00414 } 00415 00416 //Draw the character 00417 cursX += drawChar(*str++, fnt, x + cursX, y + cursY); 00418 } 00419 } 00420 } 00421 00422 int Canvas::width() 00423 { 00424 return m_Width; 00425 } 00426 00427 int Canvas::height() 00428 { 00429 return m_Height; 00430 } 00431 00432 void Canvas::drawCircleHelper(int x, int y, int r, unsigned int corner, unsigned int c) 00433 { 00434 int f = 1 - r; 00435 int ddF_x = 1; 00436 int ddF_y = -2 * r; 00437 int i = 0; 00438 int j = r; 00439 00440 while (i < j) { 00441 if (f >= 0) { 00442 j--; 00443 ddF_y += 2; 00444 f += ddF_y; 00445 } 00446 i++; 00447 ddF_x += 2; 00448 f += ddF_x; 00449 if (corner & 0x4) { 00450 drawPixel(x + i, y + j, c); 00451 drawPixel(x + j, y + i, c); 00452 } 00453 if (corner & 0x2) { 00454 drawPixel(x + i, y - j, c); 00455 drawPixel(x + j, y - i, c); 00456 } 00457 if (corner & 0x8) { 00458 drawPixel(x - j, y + i, c); 00459 drawPixel(x - i, y + j, c); 00460 } 00461 if (corner & 0x1) { 00462 drawPixel(x - j, y - i, c); 00463 drawPixel(x - i, y - j, c); 00464 } 00465 } 00466 } 00467 00468 void Canvas::fillCircleHelper(int x, int y, int r, unsigned int corner, int delta, unsigned int c) 00469 { 00470 int f = 1 - r; 00471 int ddF_x = 1; 00472 int ddF_y = -2 * r; 00473 int i = 0; 00474 int j = r; 00475 00476 while (i < j) { 00477 if (f >= 0) { 00478 j--; 00479 ddF_y += 2; 00480 f += ddF_y; 00481 } 00482 i++; 00483 ddF_x += 2; 00484 f += ddF_x; 00485 00486 if (corner & 0x1) { 00487 drawVLine(x + i, y - j, 2 * j + 1 + delta, c); 00488 drawVLine(x + j, y - i, 2 * i + 1 + delta, c); 00489 } 00490 if (corner & 0x2) { 00491 drawVLine(x - i, y - j, 2 * j + 1 + delta, c); 00492 drawVLine(x - j, y - i, 2 * i + 1 + delta, c); 00493 } 00494 } 00495 }
Generated on Tue Jul 12 2022 20:26:18 by 1.7.2