clipping.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. /*
  2. * 3D Engine
  3. * clipping.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 11/03/2021.
  8. */
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <math.h>
  12. #include <assert.h>
  13. #include <display.h>
  14. #include <clipping.h>
  15. static plane_t frustum[TOTAL_PLANES];
  16. void initFrustumPlanes(double fov, double aspectRatio, double zNear, double zFar)
  17. {
  18. double radFOV_Y = (fov * M_PI) / 180.;
  19. double radFOV_X = atan(tan(radFOV_Y/2)* aspectRatio) * 2;
  20. frustum[LEFT_PLANE].point = vec3(0, 0, 0);
  21. frustum[LEFT_PLANE].normal = vec3( cos(radFOV_X / 2.0) , 0, sin(radFOV_X / 2.0));
  22. frustum[RIGHT_PLANE].point = vec3(0, 0, 0);
  23. frustum[RIGHT_PLANE].normal = vec3( -cos(radFOV_X / 2.0), 0, sin(radFOV_X / 2.0));
  24. frustum[TOP_PLANE].point = vec3(0, 0, 0);
  25. frustum[TOP_PLANE].normal = vec3(0, -cos(radFOV_Y / 2.0), sin(radFOV_Y / 2.0));
  26. frustum[BOTTOM_PLANE].point = vec3(0, 0, 0);
  27. frustum[BOTTOM_PLANE].normal = vec3(0, cos(radFOV_Y / 2.0), sin(radFOV_Y / 2.0));
  28. frustum[NEAR_PLANE].point = vec3(0, 0, zNear);
  29. frustum[NEAR_PLANE].normal = vec3(0, 0, 1);
  30. frustum[FAR_PLANE].point = vec3(0, 0, zFar);
  31. frustum[FAR_PLANE].normal = vec3(0, 0, -1);
  32. }
  33. void createTriangleFromPolygon(polygon_t *polygon, triangle_t *triangleList, uint32_t *outNumber)
  34. {
  35. int i;
  36. *outNumber = 0;
  37. for(i = 1; i < (polygon->num_vertices - 1); i++)
  38. {
  39. triangleList[i - 1].points[0] = vec4FromVec3(polygon->vertices[0]);
  40. triangleList[i - 1].points[1] = vec4FromVec3(polygon->vertices[i]);
  41. triangleList[i - 1].points[2] = vec4FromVec3(polygon->vertices[i + 1]);
  42. triangleList[i - 1].textureCoordinates[0] = polygon->textureCoords[0];
  43. triangleList[i - 1].textureCoordinates[1] = polygon->textureCoords[i];
  44. triangleList[i - 1].textureCoordinates[2] = polygon->textureCoords[i + 1];
  45. (*outNumber)++;
  46. assert(*outNumber < MAX_NUM_POLYGON_TRIANGLES);
  47. }
  48. }
  49. /* Linear interpolation */
  50. static inline double floatLerp(double a, double b, double t)
  51. {
  52. return a + t * (b - a);
  53. }
  54. static void clipPolygonAgainstPlane(polygon_t *poly, faceenum_t plane)
  55. {
  56. int i;
  57. vec3_t planePoint = frustum[plane].point;
  58. vec3_t planeNormal = frustum[plane].normal;
  59. vec3_t *currentVertex, *previousVertex;
  60. tex2_t *currentTexCoord, *previousTexCoord;
  61. double currentDot, previousDot;
  62. vec3_t newVertices[MAX_NUM_POLYGON_VERTICES];
  63. tex2_t newTexCoords[MAX_NUM_POLYGON_VERTICES];
  64. int newVerticesCount = 0;
  65. previousVertex = &poly->vertices[poly->num_vertices - 1];
  66. previousTexCoord = &poly->textureCoords[poly->num_vertices - 1];
  67. for(i = 0; i < poly->num_vertices; i++)
  68. {
  69. currentVertex = &poly->vertices[i];
  70. currentTexCoord = &poly->textureCoords[i];
  71. currentDot = vec3Dot(vec3SubVectors(*currentVertex, planePoint), planeNormal);
  72. previousDot = vec3Dot(vec3SubVectors(*previousVertex, planePoint), planeNormal);
  73. if ((currentDot * previousDot) < 0.0)
  74. {
  75. double t = previousDot / (previousDot - currentDot);
  76. /* we crossed the plane */
  77. vec3_t intersectionVertex =
  78. {
  79. .x = floatLerp(previousVertex->x, currentVertex->x, t),
  80. .y = floatLerp(previousVertex->y, currentVertex->y, t),
  81. .z = floatLerp(previousVertex->z, currentVertex->z, t),
  82. };
  83. newVertices[newVerticesCount] = intersectionVertex;
  84. tex2_t intersectionTexCoord =
  85. {
  86. .u = floatLerp(previousTexCoord->u, currentTexCoord->u, t),
  87. .v = floatLerp(previousTexCoord->v, currentTexCoord->v, t),
  88. };
  89. newTexCoords[newVerticesCount] = intersectionTexCoord;
  90. newVerticesCount++;
  91. }
  92. if (currentDot > 0.0)
  93. {
  94. newVertices[newVerticesCount] = *currentVertex;
  95. newTexCoords[newVerticesCount] = *currentTexCoord;
  96. newVerticesCount++;
  97. }
  98. /* Just to be sure, should never trigger */
  99. assert(newVerticesCount < MAX_NUM_POLYGON_VERTICES);
  100. previousVertex = currentVertex;
  101. previousTexCoord = currentTexCoord;
  102. }
  103. for(i = 0; i < newVerticesCount; i++)
  104. {
  105. poly->vertices[i] = newVertices[i];
  106. poly->textureCoords[i] = newTexCoords[i];
  107. }
  108. poly->num_vertices = newVerticesCount;
  109. }
  110. void clipPolygon(polygon_t *poly)
  111. {
  112. clipPolygonAgainstPlane(poly, LEFT_PLANE);
  113. clipPolygonAgainstPlane(poly, TOP_PLANE);
  114. clipPolygonAgainstPlane(poly, RIGHT_PLANE);
  115. clipPolygonAgainstPlane(poly, BOTTOM_PLANE);
  116. clipPolygonAgainstPlane(poly, NEAR_PLANE);
  117. clipPolygonAgainstPlane(poly, FAR_PLANE);
  118. }