triangle.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. /*
  2. * 3D Engine
  3. * triangle.c:
  4. * Based on pikuma.com 3D software renderer in C
  5. * Copyright (c) 2021 986-Studio. All rights reserved.
  6. *
  7. * Created by Manoël Trapier on 04/03/2021.
  8. */
  9. #include <display.h>
  10. #include <triangle.h>
  11. void drawTriangle(int32_t x0, int32_t y0, int32_t x1, int32_t y1, int32_t x2, int32_t y2, colour_t colour)
  12. {
  13. drawLine(x0, y0, x1, y1, colour);
  14. drawLine(x1, y1, x2, y2, colour);
  15. drawLine(x2, y2, x0, y0, colour);
  16. }
  17. /* ----------------------------------- Filled triangles ----------------------------------- */
  18. /* This function expect Point 0 to be the top, 1 to be the bottom left, 2 to be the bottom right */
  19. static void drawFillBottomFlatTriangle(int32_t x0, int32_t y0, int32_t x1, int32_t y1, int32_t x2, int32_t y2, colour_t colour)
  20. {
  21. int i;
  22. int32_t deltaXL = x1 - x0;
  23. int32_t deltaXR = x2 - x0;
  24. int32_t deltaY = y1 - y0;
  25. int32_t sideLength = abs(deltaY);
  26. double incrementXL = deltaXL / (double)sideLength;
  27. double incrementXR = deltaXR / (double)sideLength;
  28. double incrementY = deltaY / (double)sideLength;
  29. double currentXL = x0;
  30. double currentXR = x0;
  31. double currentY = y0;
  32. for(i = 0; i < sideLength; i++)
  33. {
  34. drawHLine(round(currentXL), round(currentY), round(currentXR), colour);
  35. currentXL += incrementXL;
  36. currentXR += incrementXR;
  37. currentY += incrementY;
  38. }
  39. }
  40. /* This function expect Point 2 to be the bottom, 0 to be the top left, 1 to be the top right */
  41. static void drawFillTopFlatTriangle(int32_t x0, int32_t y0, int32_t x1, int32_t y1, int32_t x2, int32_t y2, colour_t colour)
  42. {
  43. int i;
  44. int32_t deltaXL = x0 - x2;
  45. int32_t deltaXR = x1 - x2;
  46. int32_t deltaY = y0 - y2;
  47. int32_t sideLength = abs(deltaY);
  48. if (sideLength == 0)
  49. {
  50. return;
  51. }
  52. double incrementXL = deltaXL / (double)sideLength;
  53. double incrementXR = deltaXR / (double)sideLength;
  54. double incrementY = deltaY / (double)sideLength;
  55. double currentXL = x2;
  56. double currentXR = x2;
  57. double currentY = y2;
  58. for(i = 0; i <= sideLength; i++)
  59. {
  60. drawHLine(round(currentXL), round(currentY), round(currentXR), colour);
  61. currentXL += incrementXL;
  62. currentXR += incrementXR;
  63. currentY += incrementY;
  64. }
  65. }
  66. void drawFilledTriangle(int32_t x0, int32_t y0, int32_t x1, int32_t y1, int32_t x2, int32_t y2, colour_t colour)
  67. {
  68. int32_t My, Mx;
  69. if (y0 > y1)
  70. {
  71. intSwap(&x0, &x1); intSwap(&y0, &y1);
  72. }
  73. if (y1 > y2)
  74. {
  75. intSwap(&x1, &x2); intSwap(&y1, &y2);
  76. }
  77. if (y0 > y1)
  78. {
  79. intSwap(&x0, &x1); intSwap(&y0, &y1);
  80. }
  81. /* Determine the mid intersection and point */
  82. My = y1;
  83. Mx = x0 + (double)((x2 - x0) * (y1 - y0)) / (double)(y2 - y0);
  84. /* Fill top */
  85. if (y0 != y1)
  86. {
  87. drawFillBottomFlatTriangle(x0, y0, x1, y1, Mx, My, colour);
  88. }
  89. /* Fill bottom */
  90. if (y1 != y2)
  91. {
  92. drawFillTopFlatTriangle(x1, y1, Mx, My, x2, y2, colour);
  93. }
  94. }
  95. /* ----------------------------------- Textured triangles ----------------------------------- */
  96. void drawTextureTriangle(struct triangle_t *t)
  97. {
  98. int32_t x, y;
  99. if (t->points[0].y > t->points[1].y)
  100. {
  101. doubleSwap(&t->points[0].x, &t->points[1].x); doubleSwap(&t->points[0].y, &t->points[1].y);
  102. doubleSwap(&t->textureCoordinates[0].u, &t->textureCoordinates[1].u);
  103. doubleSwap(&t->textureCoordinates[0].v, &t->textureCoordinates[1].v);
  104. }
  105. if (t->points[1].y > t->points[2].y)
  106. {
  107. doubleSwap(&t->points[1].x, &t->points[2].x); doubleSwap(&t->points[1].y, &t->points[2].y);
  108. doubleSwap(&t->textureCoordinates[1].u, &t->textureCoordinates[2].u);
  109. doubleSwap(&t->textureCoordinates[1].v, &t->textureCoordinates[2].v);
  110. }
  111. if (t->points[0].y > t->points[1].y)
  112. {
  113. doubleSwap(&t->points[0].x, &t->points[1].x); doubleSwap(&t->points[0].y, &t->points[1].y);
  114. doubleSwap(&t->textureCoordinates[0].u, &t->textureCoordinates[1].u);
  115. doubleSwap(&t->textureCoordinates[0].v, &t->textureCoordinates[1].v);
  116. }
  117. /* Render the top part */
  118. double inverseSlope1 = 0;
  119. double inverseSlope2 = 0;
  120. int32_t x0 = t->points[0].x, y0 = t->points[0].y;
  121. int32_t x1 = t->points[1].x, y1 = t->points[1].y;
  122. int32_t x2 = t->points[2].x, y2 = t->points[2].y;
  123. if ((y1 - y0) != 0) { inverseSlope1 = (double)(x1 - x0) / abs(y1 - y0); }
  124. if ((y2 - y0) != 0) { inverseSlope2 = (double)(x2 - x0) / abs(y2 - y0); }
  125. if ((y1 - y0) != 0)
  126. {
  127. for (y = y0 ; y <= y1 ; y++)
  128. {
  129. int32_t xStart = x1 + (y - y1) * inverseSlope1;
  130. int32_t xEnd = x0 + (y - y0) * inverseSlope2;
  131. if (xEnd < xStart)
  132. {
  133. intSwap(&xStart, &xEnd);
  134. }
  135. for (x = xStart ; x <= xEnd ; x++)
  136. {
  137. drawPixel(x, y, (x%2 == 0)?0xFFFF00FF:0xFF000000);
  138. }
  139. }
  140. }
  141. /* Render the bottom part */
  142. inverseSlope1 = 0;
  143. if ((y2 - y1) != 0) { inverseSlope1 = (double)(x2 - x1) / abs(y2 - y1); }
  144. if ((y2 - y1) != 0)
  145. {
  146. for (y = y1 ; y <= y2 ; y++)
  147. {
  148. int32_t xStart = x2 + (y - y2) * inverseSlope1;
  149. int32_t xEnd = x0 + (y - y0) * inverseSlope2;
  150. if (xEnd < xStart)
  151. {
  152. intSwap(&xStart, &xEnd);
  153. }
  154. for (x = xStart ; x <= xEnd ; x++)
  155. {
  156. drawPixel(x, y, (x%2 == 0)?0xFFFF00FF:0xFF000000);
  157. }
  158. }
  159. }
  160. }
  161. /* ---- Utility ---- */
  162. int compareTrianglesZOrder(const void *p1, const void *p2)
  163. {
  164. triangle_t *t1 = (struct triangle_t *)p1;
  165. triangle_t *t2 = (struct triangle_t *)p2;
  166. if (t1->averageDepth > t2->averageDepth)
  167. {
  168. return -1;
  169. }
  170. else if (t1->averageDepth < t2->averageDepth)
  171. {
  172. return 1;
  173. }
  174. return 0;
  175. }