Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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 != 0) { 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 != 0) { 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 21:38:03 by
1.7.2