triangle.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  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 <stdint.h>
  10. #include <stdbool.h>
  11. #include <3dengine.h>
  12. #include <display.h>
  13. #include <triangle.h>
  14. #include <math.h>
  15. void drawTriangle(int32_t x0, int32_t y0, int32_t x1, int32_t y1, int32_t x2, int32_t y2, colour_t colour)
  16. {
  17. drawLine(x0, y0, x1, y1, colour);
  18. drawLine(x1, y1, x2, y2, colour);
  19. drawLine(x2, y2, x0, y0, colour);
  20. }
  21. /* ----------------------------------- Filled triangles ----------------------------------- */
  22. void drawFilledTriangle(struct triangle_t *t)
  23. {
  24. int32_t x, y;
  25. if (t->points[0].y > t->points[1].y)
  26. {
  27. doubleSwap(&t->points[0].x, &t->points[1].x); doubleSwap(&t->points[0].y, &t->points[1].y);
  28. doubleSwap(&t->points[0].z, &t->points[1].z); doubleSwap(&t->points[0].w, &t->points[1].w);
  29. }
  30. if (t->points[1].y > t->points[2].y)
  31. {
  32. doubleSwap(&t->points[1].x, &t->points[2].x); doubleSwap(&t->points[1].y, &t->points[2].y);
  33. doubleSwap(&t->points[1].z, &t->points[2].z); doubleSwap(&t->points[1].w, &t->points[2].w);
  34. }
  35. if (t->points[0].y > t->points[1].y)
  36. {
  37. doubleSwap(&t->points[0].x, &t->points[1].x); doubleSwap(&t->points[0].y, &t->points[1].y);
  38. doubleSwap(&t->points[0].z, &t->points[1].z); doubleSwap(&t->points[0].w, &t->points[1].w);
  39. }
  40. vec4_t a = t->points[0];
  41. vec4_t b = t->points[1];
  42. vec4_t c = t->points[2];
  43. /* Render the top part */
  44. double inverseSlope1 = 0;
  45. double inverseSlope2 = 0;
  46. int32_t x0 = a.x, y0 = a.y;
  47. int32_t x1 = b.x, y1 = b.y;
  48. int32_t x2 = c.x, y2 = c.y;
  49. if ((y1 - y0) != 0) { inverseSlope1 = (double)(x1 - x0) / abs(y1 - y0); }
  50. if ((y2 - y0) != 0) { inverseSlope2 = (double)(x2 - x0) / abs(y2 - y0); }
  51. if ((y1 - y0) != 0)
  52. {
  53. for (y = y0 ; y <= y1 ; y++)
  54. {
  55. int32_t xStart = x1 + (y - y1) * inverseSlope1;
  56. int32_t xEnd = x0 + (y - y0) * inverseSlope2;
  57. if (doZBuffer)
  58. {
  59. if (xEnd < xStart)
  60. {
  61. intSwap(&xStart, &xEnd);
  62. }
  63. for (x = xStart ; x <= xEnd ; x++)
  64. {
  65. drawZPixel(x, y, a, b, c,t->colour);
  66. }
  67. }
  68. else
  69. {
  70. drawHLine(xStart, y, xEnd, t->colour);
  71. }
  72. }
  73. }
  74. /* Render the bottom part */
  75. inverseSlope1 = 0;
  76. if ((y2 - y1) != 0) { inverseSlope1 = (double)(x2 - x1) / abs(y2 - y1); }
  77. if ((y2 - y1) != 0)
  78. {
  79. for (y = y1 ; y <= y2 ; y++)
  80. {
  81. int32_t xStart = x2 + (y - y2) * inverseSlope1;
  82. int32_t xEnd = x0 + (y - y0) * inverseSlope2;
  83. if (doZBuffer)
  84. {
  85. if (xEnd < xStart)
  86. {
  87. intSwap(&xStart, &xEnd);
  88. }
  89. for (x = xStart ; x <= xEnd ; x++)
  90. {
  91. drawZPixel(x, y, a, b, c,t->colour);
  92. }
  93. }
  94. else
  95. {
  96. drawHLine(xStart, y, xEnd, t->colour);
  97. }
  98. }
  99. }
  100. }
  101. /* ----------------------------------- Textured triangles ----------------------------------- */
  102. void drawTextureTriangle(struct triangle_t *t)
  103. {
  104. int32_t x, y;
  105. if (t->points[0].y > t->points[1].y)
  106. {
  107. doubleSwap(&t->points[0].x, &t->points[1].x); doubleSwap(&t->points[0].y, &t->points[1].y);
  108. doubleSwap(&t->points[0].z, &t->points[1].z); doubleSwap(&t->points[0].w, &t->points[1].w);
  109. doubleSwap(&t->textureCoordinates[0].u, &t->textureCoordinates[1].u);
  110. doubleSwap(&t->textureCoordinates[0].v, &t->textureCoordinates[1].v);
  111. }
  112. if (t->points[1].y > t->points[2].y)
  113. {
  114. doubleSwap(&t->points[1].x, &t->points[2].x); doubleSwap(&t->points[1].y, &t->points[2].y);
  115. doubleSwap(&t->points[1].z, &t->points[2].z); doubleSwap(&t->points[1].w, &t->points[2].w);
  116. doubleSwap(&t->textureCoordinates[1].u, &t->textureCoordinates[2].u);
  117. doubleSwap(&t->textureCoordinates[1].v, &t->textureCoordinates[2].v);
  118. }
  119. if (t->points[0].y > t->points[1].y)
  120. {
  121. doubleSwap(&t->points[0].x, &t->points[1].x); doubleSwap(&t->points[0].y, &t->points[1].y);
  122. doubleSwap(&t->points[0].z, &t->points[1].z); doubleSwap(&t->points[0].w, &t->points[1].w);
  123. doubleSwap(&t->textureCoordinates[0].u, &t->textureCoordinates[1].u);
  124. doubleSwap(&t->textureCoordinates[0].v, &t->textureCoordinates[1].v);
  125. }
  126. vec4_t a = t->points[0];
  127. vec4_t b = t->points[1];
  128. vec4_t c = t->points[2];
  129. /* Render the top part */
  130. double inverseSlope1 = 0;
  131. double inverseSlope2 = 0;
  132. int32_t x0 = a.x, y0 = a.y;
  133. int32_t x1 = b.x, y1 = b.y;
  134. int32_t x2 = c.x, y2 = c.y;
  135. if ((y1 - y0) != 0) { inverseSlope1 = (double)(x1 - x0) / abs(y1 - y0); }
  136. if ((y2 - y0) != 0) { inverseSlope2 = (double)(x2 - x0) / abs(y2 - y0); }
  137. if ((y1 - y0) != 0)
  138. {
  139. for (y = y0 ; y <= y1 ; y++)
  140. {
  141. int32_t xStart = x1 + (y - y1) * inverseSlope1;
  142. int32_t xEnd = x0 + (y - y0) * inverseSlope2;
  143. if (xEnd < xStart)
  144. {
  145. intSwap(&xStart, &xEnd);
  146. }
  147. for (x = xStart ; x <= xEnd ; x++)
  148. {
  149. drawTexel(x, y, a, b, c,
  150. t->textureCoordinates[0],
  151. t->textureCoordinates[1],
  152. t->textureCoordinates[2],
  153. t->texture);
  154. }
  155. }
  156. }
  157. /* Render the bottom part */
  158. inverseSlope1 = 0;
  159. if ((y2 - y1) != 0) { inverseSlope1 = (double)(x2 - x1) / abs(y2 - y1); }
  160. if ((y2 - y1) != 0)
  161. {
  162. for (y = y1 ; y <= y2 ; y++)
  163. {
  164. int32_t xStart = x2 + (y - y2) * inverseSlope1;
  165. int32_t xEnd = x0 + (y - y0) * inverseSlope2;
  166. if (xEnd < xStart)
  167. {
  168. intSwap(&xStart, &xEnd);
  169. }
  170. for (x = xStart ; x <= xEnd ; x++)
  171. {
  172. drawTexel(x, y, a, b, c,
  173. t->textureCoordinates[0],
  174. t->textureCoordinates[1],
  175. t->textureCoordinates[2],
  176. t->texture);
  177. }
  178. }
  179. }
  180. }
  181. /* ---- Utility ---- */
  182. int compareTrianglesZOrder(const void *p1, const void *p2)
  183. {
  184. triangle_t *t1 = (struct triangle_t *)p1;
  185. triangle_t *t2 = (struct triangle_t *)p2;
  186. if (t1->averageDepth > t2->averageDepth)
  187. {
  188. return -1;
  189. }
  190. else if (t1->averageDepth < t2->averageDepth)
  191. {
  192. return 1;
  193. }
  194. return 0;
  195. }