graphics.cc 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. // -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
  2. // Copyright (C) 2014 Henner Zeller <h.zeller@acm.org>
  3. //
  4. // This program is free software; you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation version 2.
  7. //
  8. // This program is distributed in the hope that it will be useful,
  9. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. // GNU General Public License for more details.
  12. //
  13. // You should have received a copy of the GNU General Public License
  14. // along with this program. If not, see <http://gnu.org/licenses/gpl-2.0.txt>
  15. #include "graphics.h"
  16. #include "utf8-internal.h"
  17. #include <stdlib.h>
  18. #include <functional>
  19. #include <algorithm>
  20. namespace rgb_matrix {
  21. bool SetImage(Canvas *c, int canvas_offset_x, int canvas_offset_y,
  22. const uint8_t *buffer, size_t size,
  23. const int width, const int height,
  24. bool is_bgr) {
  25. if (3 * width * height != (int)size) // Sanity check
  26. return false;
  27. int image_display_w = width;
  28. int image_display_h = height;
  29. size_t skip_start_row = 0; // Bytes to skip before each row
  30. if (canvas_offset_x < 0) {
  31. skip_start_row = -canvas_offset_x * 3;
  32. image_display_w += canvas_offset_x;
  33. if (image_display_w <= 0) return false; // Done. outside canvas.
  34. canvas_offset_x = 0;
  35. }
  36. if (canvas_offset_y < 0) {
  37. // Skip buffer to the first row we'll be showing
  38. buffer += 3 * width * -canvas_offset_y;
  39. image_display_h += canvas_offset_y;
  40. if (image_display_h <= 0) return false; // Done. outside canvas.
  41. canvas_offset_y = 0;
  42. }
  43. const int w = std::min(c->width(), canvas_offset_x + image_display_w);
  44. const int h = std::min(c->height(), canvas_offset_y + image_display_h);
  45. // Bytes to skip for wider than canvas image at the end of a row
  46. const size_t skip_end_row = (canvas_offset_x + image_display_w > w)
  47. ? (canvas_offset_x + image_display_w - w) * 3
  48. : 0;
  49. // Let's make this a combined skip per row and ajust where we start.
  50. const size_t next_row_skip = skip_start_row + skip_end_row;
  51. buffer += skip_start_row;
  52. if (is_bgr) {
  53. for (int y = canvas_offset_y; y < h; ++y) {
  54. for (int x = canvas_offset_x; x < w; ++x) {
  55. c->SetPixel(x, y, buffer[2], buffer[1], buffer[0]);
  56. buffer += 3;
  57. }
  58. buffer += next_row_skip;
  59. }
  60. } else {
  61. for (int y = canvas_offset_y; y < h; ++y) {
  62. for (int x = canvas_offset_x; x < w; ++x) {
  63. c->SetPixel(x, y, buffer[0], buffer[1], buffer[2]);
  64. buffer += 3;
  65. }
  66. buffer += next_row_skip;
  67. }
  68. }
  69. return true;
  70. }
  71. int DrawText(Canvas *c, const Font &font,
  72. int x, int y, const Color &color,
  73. const char *utf8_text) {
  74. return DrawText(c, font, x, y, color, NULL, utf8_text);
  75. }
  76. int DrawText(Canvas *c, const Font &font,
  77. int x, int y, const Color &color, const Color *background_color,
  78. const char *utf8_text, int extra_spacing) {
  79. const int start_x = x;
  80. while (*utf8_text) {
  81. const uint32_t cp = utf8_next_codepoint(utf8_text);
  82. x += font.DrawGlyph(c, x, y, color, background_color, cp);
  83. x += extra_spacing;
  84. }
  85. return x - start_x;
  86. }
  87. // There used to be a symbol without the optional extra_spacing parameter. Let's
  88. // define this here so that people linking against an old library will still
  89. // have their code usable. Now: 2017-06-04; can probably be removed in a couple
  90. // of months.
  91. int DrawText(Canvas *c, const Font &font,
  92. int x, int y, const Color &color, const Color *background_color,
  93. const char *utf8_text) {
  94. return DrawText(c, font, x, y, color, background_color, utf8_text, 0);
  95. }
  96. int VerticalDrawText(Canvas *c, const Font &font, int x, int y,
  97. const Color &color, const Color *background_color,
  98. const char *utf8_text, int extra_spacing) {
  99. const int start_y = y;
  100. while (*utf8_text) {
  101. const uint32_t cp = utf8_next_codepoint(utf8_text);
  102. font.DrawGlyph(c, x, y, color, background_color, cp);
  103. y += font.height() + extra_spacing;
  104. }
  105. return y - start_y;
  106. }
  107. void DrawCircle(Canvas *c, int x0, int y0, int radius, const Color &color) {
  108. int x = radius, y = 0;
  109. int radiusError = 1 - x;
  110. while (y <= x) {
  111. c->SetPixel(x + x0, y + y0, color.r, color.g, color.b);
  112. c->SetPixel(y + x0, x + y0, color.r, color.g, color.b);
  113. c->SetPixel(-x + x0, y + y0, color.r, color.g, color.b);
  114. c->SetPixel(-y + x0, x + y0, color.r, color.g, color.b);
  115. c->SetPixel(-x + x0, -y + y0, color.r, color.g, color.b);
  116. c->SetPixel(-y + x0, -x + y0, color.r, color.g, color.b);
  117. c->SetPixel(x + x0, -y + y0, color.r, color.g, color.b);
  118. c->SetPixel(y + x0, -x + y0, color.r, color.g, color.b);
  119. y++;
  120. if (radiusError<0){
  121. radiusError += 2 * y + 1;
  122. } else {
  123. x--;
  124. radiusError+= 2 * (y - x + 1);
  125. }
  126. }
  127. }
  128. void DrawLine(Canvas *c, int x0, int y0, int x1, int y1, const Color &color) {
  129. int dy = y1 - y0, dx = x1 - x0, gradient, x, y, shift = 0x10;
  130. if (abs(dx) > abs(dy)) {
  131. // x variation is bigger than y variation
  132. if (x1 < x0) {
  133. std::swap(x0, x1);
  134. std::swap(y0, y1);
  135. }
  136. gradient = (dy << shift) / dx ;
  137. for (x = x0 , y = 0x8000 + (y0 << shift); x <= x1; ++x, y += gradient) {
  138. c->SetPixel(x, y >> shift, color.r, color.g, color.b);
  139. }
  140. } else if (dy != 0) {
  141. // y variation is bigger than x variation
  142. if (y1 < y0) {
  143. std::swap(x0, x1);
  144. std::swap(y0, y1);
  145. }
  146. gradient = (dx << shift) / dy;
  147. for (y = y0 , x = 0x8000 + (x0 << shift); y <= y1; ++y, x += gradient) {
  148. c->SetPixel(x >> shift, y, color.r, color.g, color.b);
  149. }
  150. } else {
  151. c->SetPixel(x0, y0, color.r, color.g, color.b);
  152. }
  153. }
  154. }//namespace