triangle.c 7.1 KB

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