You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

116 lines
3.7 KiB

  1. // Copyright 2021 Paul Cotter (@gr1mr3aver)
  2. // Copyright 2021 Nick Brassel (@tzarc)
  3. // SPDX-License-Identifier: GPL-2.0-or-later
  4. #include "qp_internal.h"
  5. #include "qp_comms.h"
  6. #include "qp_draw.h"
  7. // Utilize 4-way symmetry to draw an ellipse
  8. static bool qp_ellipse_helper_impl(painter_device_t device, uint16_t centerx, uint16_t centery, uint16_t offsetx, uint16_t offsety, bool filled) {
  9. /*
  10. Ellipses have the property of 4-way symmetry, so four pixels can be drawn
  11. for each computed [offsetx,offsety] given the center coordinates
  12. represented by [centerx,centery].
  13. For filled ellipses, we can draw horizontal lines between each pair of
  14. pixels with the same final value of y.
  15. When offsetx == 0 only two pixels can be drawn for filled or unfilled ellipses
  16. */
  17. int16_t xpx = ((int16_t)centerx) + ((int16_t)offsetx);
  18. int16_t xmx = ((int16_t)centerx) - ((int16_t)offsetx);
  19. int16_t ypy = ((int16_t)centery) + ((int16_t)offsety);
  20. int16_t ymy = ((int16_t)centery) - ((int16_t)offsety);
  21. if (offsetx == 0) {
  22. if (!qp_internal_setpixel_impl(device, xpx, ypy)) {
  23. return false;
  24. }
  25. if (!qp_internal_setpixel_impl(device, xpx, ymy)) {
  26. return false;
  27. }
  28. } else if (filled) {
  29. if (!qp_internal_fillrect_helper_impl(device, xpx, ypy, xmx, ypy)) {
  30. return false;
  31. }
  32. if (offsety > 0 && !qp_internal_fillrect_helper_impl(device, xpx, ymy, xmx, ymy)) {
  33. return false;
  34. }
  35. } else {
  36. if (!qp_internal_setpixel_impl(device, xpx, ypy)) {
  37. return false;
  38. }
  39. if (!qp_internal_setpixel_impl(device, xpx, ymy)) {
  40. return false;
  41. }
  42. if (!qp_internal_setpixel_impl(device, xmx, ypy)) {
  43. return false;
  44. }
  45. if (!qp_internal_setpixel_impl(device, xmx, ymy)) {
  46. return false;
  47. }
  48. }
  49. return true;
  50. }
  51. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  52. // Quantum Painter External API: qp_ellipse
  53. bool qp_ellipse(painter_device_t device, uint16_t x, uint16_t y, uint16_t sizex, uint16_t sizey, uint8_t hue, uint8_t sat, uint8_t val, bool filled) {
  54. qp_dprintf("qp_ellipse: entry\n");
  55. struct painter_driver_t *driver = (struct painter_driver_t *)device;
  56. if (!driver->validate_ok) {
  57. qp_dprintf("qp_ellipse: fail (validation_ok == false)\n");
  58. return false;
  59. }
  60. int16_t aa = ((int16_t)sizex) * ((int16_t)sizex);
  61. int16_t bb = ((int16_t)sizey) * ((int16_t)sizey);
  62. int16_t fa = 4 * ((int16_t)aa);
  63. int16_t fb = 4 * ((int16_t)bb);
  64. int16_t dx = 0;
  65. int16_t dy = ((int16_t)sizey);
  66. qp_internal_fill_pixdata(device, QP_MAX(sizex, sizey), hue, sat, val);
  67. if (!qp_comms_start(device)) {
  68. qp_dprintf("qp_ellipse: fail (could not start comms)\n");
  69. return false;
  70. }
  71. bool ret = true;
  72. for (int16_t delta = (2 * bb) + (aa * (1 - (2 * sizey))); bb * dx <= aa * dy; dx++) {
  73. if (!qp_ellipse_helper_impl(device, x, y, dx, dy, filled)) {
  74. ret = false;
  75. break;
  76. }
  77. if (delta >= 0) {
  78. delta += fa * (1 - dy);
  79. dy--;
  80. }
  81. delta += bb * (4 * dx + 6);
  82. }
  83. dx = sizex;
  84. dy = 0;
  85. for (int16_t delta = (2 * aa) + (bb * (1 - (2 * sizex))); aa * dy <= bb * dx; dy++) {
  86. if (!qp_ellipse_helper_impl(device, x, y, dx, dy, filled)) {
  87. ret = false;
  88. break;
  89. }
  90. if (delta >= 0) {
  91. delta += fb * (1 - dx);
  92. dx--;
  93. }
  94. delta += aa * (4 * dy + 6);
  95. }
  96. qp_dprintf("qp_ellipse: %s\n", ret ? "ok" : "fail");
  97. qp_comms_stop(device);
  98. return ret;
  99. }