/* * 3D Engine * clipping.c: * Based on pikuma.com 3D software renderer in C * Copyright (c) 2021 986-Studio. All rights reserved. * * Created by Manoƫl Trapier on 11/03/2021. */ #include #include #include #include #include #include static plane_t frustum[TOTAL_PLANES]; void initFrustumPlanes(double fov, double aspectRatio, double zNear, double zFar) { double radFOV_Y = (fov * M_PI) / 180.; double radFOV_X = atan(tan(radFOV_Y/2)* aspectRatio) * 2; frustum[LEFT_PLANE].point = vec3(0, 0, 0); frustum[LEFT_PLANE].normal = vec3( cos(radFOV_X / 2.0) , 0, sin(radFOV_X / 2.0)); frustum[RIGHT_PLANE].point = vec3(0, 0, 0); frustum[RIGHT_PLANE].normal = vec3( -cos(radFOV_X / 2.0), 0, sin(radFOV_X / 2.0)); frustum[TOP_PLANE].point = vec3(0, 0, 0); frustum[TOP_PLANE].normal = vec3(0, -cos(radFOV_Y / 2.0), sin(radFOV_Y / 2.0)); frustum[BOTTOM_PLANE].point = vec3(0, 0, 0); frustum[BOTTOM_PLANE].normal = vec3(0, cos(radFOV_Y / 2.0), sin(radFOV_Y / 2.0)); frustum[NEAR_PLANE].point = vec3(0, 0, zNear); frustum[NEAR_PLANE].normal = vec3(0, 0, 1); frustum[FAR_PLANE].point = vec3(0, 0, zFar); frustum[FAR_PLANE].normal = vec3(0, 0, -1); } void createTriangleFromPolygon(polygon_t *polygon, triangle_t *triangleList, uint32_t *outNumber) { int i; *outNumber = 0; for(i = 1; i < (polygon->num_vertices - 1); i++) { triangleList[i - 1].points[0] = vec4FromVec3(polygon->vertices[0]); triangleList[i - 1].points[1] = vec4FromVec3(polygon->vertices[i]); triangleList[i - 1].points[2] = vec4FromVec3(polygon->vertices[i + 1]); triangleList[i - 1].textureCoordinates[0] = polygon->textureCoords[0]; triangleList[i - 1].textureCoordinates[1] = polygon->textureCoords[i]; triangleList[i - 1].textureCoordinates[2] = polygon->textureCoords[i + 1]; (*outNumber)++; assert(*outNumber < MAX_NUM_POLYGON_TRIANGLES); } } /* Linear interpolation */ static inline double floatLerp(double a, double b, double t) { return a + t * (b - a); } static void clipPolygonAgainstPlane(polygon_t *poly, faceenum_t plane) { int i; vec3_t planePoint = frustum[plane].point; vec3_t planeNormal = frustum[plane].normal; vec3_t *currentVertex, *previousVertex; tex2_t *currentTexCoord, *previousTexCoord; double currentDot, previousDot; vec3_t newVertices[MAX_NUM_POLYGON_VERTICES]; tex2_t newTexCoords[MAX_NUM_POLYGON_VERTICES]; int newVerticesCount = 0; previousVertex = &poly->vertices[poly->num_vertices - 1]; previousTexCoord = &poly->textureCoords[poly->num_vertices - 1]; for(i = 0; i < poly->num_vertices; i++) { currentVertex = &poly->vertices[i]; currentTexCoord = &poly->textureCoords[i]; currentDot = vec3Dot(vec3SubVectors(*currentVertex, planePoint), planeNormal); previousDot = vec3Dot(vec3SubVectors(*previousVertex, planePoint), planeNormal); if ((currentDot * previousDot) < 0.0) { double t = previousDot / (previousDot - currentDot); /* we crossed the plane */ vec3_t intersectionVertex = { .x = floatLerp(previousVertex->x, currentVertex->x, t), .y = floatLerp(previousVertex->y, currentVertex->y, t), .z = floatLerp(previousVertex->z, currentVertex->z, t), }; newVertices[newVerticesCount] = intersectionVertex; tex2_t intersectionTexCoord = { .u = floatLerp(previousTexCoord->u, currentTexCoord->u, t), .v = floatLerp(previousTexCoord->v, currentTexCoord->v, t), }; newTexCoords[newVerticesCount] = intersectionTexCoord; newVerticesCount++; } if (currentDot > 0.0) { newVertices[newVerticesCount] = *currentVertex; newTexCoords[newVerticesCount] = *currentTexCoord; newVerticesCount++; } /* Just to be sure, should never trigger */ assert(newVerticesCount < MAX_NUM_POLYGON_VERTICES); previousVertex = currentVertex; previousTexCoord = currentTexCoord; } for(i = 0; i < newVerticesCount; i++) { poly->vertices[i] = newVertices[i]; poly->textureCoords[i] = newTexCoords[i]; } poly->num_vertices = newVerticesCount; } void clipPolygon(polygon_t *poly) { clipPolygonAgainstPlane(poly, LEFT_PLANE); clipPolygonAgainstPlane(poly, TOP_PLANE); clipPolygonAgainstPlane(poly, RIGHT_PLANE); clipPolygonAgainstPlane(poly, BOTTOM_PLANE); clipPolygonAgainstPlane(poly, NEAR_PLANE); clipPolygonAgainstPlane(poly, FAR_PLANE); }