#include #include #include #include #include #include #include #include #include #include #include #include #include "hash.h" #include "structure.h" #include "base.h" #include "display.h" #include "triangles.h" double draw_incr = 0.0 ; int errno = 0; pt_2d* triangle_1 ; pt_2d* triangle_2 ; pt_2d* cube_t1 ; pt_2d* cube_t2 ; int* dOrder1 ; int* dOrder2 ; double* zdepths1 ; double* zdepths2 ; void trInit() { triangle_1 = malloc(sizeof(pt_2d)*3); triangle_2 = malloc(sizeof(pt_2d)*3); cube_t1 = malloc(sizeof(pt_2d)*6); cube_t2 = malloc(sizeof(pt_2d)*6); dOrder1 = malloc(sizeof(int)*6); dOrder2 = malloc(sizeof(int)*6); zdepths1 = malloc(sizeof(double)*4); zdepths2 = malloc(sizeof(double)*4); } double det2D(pt_2d* p1, pt_2d* p2, pt_2d* p3) { return p1->x * (p2->y - p3->y) + p2->x * (p3->y - p1->y) + p3->x * (p1->y - p2->y); } void checkTriWinding(pt_2d * p1, pt_2d * p2, pt_2d * p3, bool allowReversed) { double detTri = det2D(p1, p2, p3); if (detTri < 0.0) { if (allowReversed) { double t = p3->x; p3->x = p2->x; p2->x = t; t = p3->y; p3->y = p2->y; p2->y = t; } else { errno = 1; } } } bool boundaryCollideChk(pt_2d *p1, pt_2d *p2, pt_2d *p3, double eps) { return det2D(p1, p2, p3) < eps; } bool boundaryDoesntCollideChk(pt_2d *p1, pt_2d *p2, pt_2d *p3, double eps) { return det2D(p1, p2, p3) <= eps; } bool triTri2D(pt_2d* t1, pt_2d* t2, double eps, bool allowReversed, bool onBoundary) { bool(*chkEdge)(pt_2d*, pt_2d*, pt_2d*, double); int i; errno = 0; // Triangles must be expressed anti-clockwise checkTriWinding(&t1[0], &t1[1], &t1[2], allowReversed); if (errno != 0) { return false; } checkTriWinding(&t2[0], &t2[1], &t2[2], allowReversed); if (errno != 0) { return false; } if (onBoundary) { // pt_2ds on the boundary are considered as colliding chkEdge = boundaryCollideChk; } else { // pt_2ds on the boundary are not considered as colliding chkEdge = boundaryDoesntCollideChk; } //For edge E of trangle 1, for (i = 0; i < 3; ++i) { int j = (i + 1) % 3; //Check all points of trangle 2 lay on the external side of the edge E. If //they do, the triangles do not collide. if (chkEdge(&t1[i], &t1[j], &t2[0], eps) && chkEdge(&t1[i], &t1[j], &t2[1], eps) && chkEdge(&t1[i], &t1[j], &t2[2], eps)) { return false; } } //For edge E of trangle 2, for (i = 0; i < 3; i++) { int j = (i + 1) % 3; //Check all points of trangle 1 lay on the external side of the edge E. If //they do, the triangles do not collide. if (chkEdge(&t2[i], &t2[j], &t1[0], eps) && chkEdge(&t2[i], &t2[j], &t1[1], eps) && chkEdge(&t2[i], &t2[j], &t1[2], eps)) return false; } //The triangles collide return true; } bool triangleIntersection(pt_2d* tri1, pt_2d* tri2) { return triTri2D(tri1, tri2, 0.0, false, false); } bool triangleIntersectionDec(pt_2d t1_1, pt_2d t1_2, pt_2d t1_3, pt_2d t2_1, pt_2d t2_2, pt_2d t2_3) { triangle_1[0] = t1_1; triangle_1[1] = t1_2; triangle_1[2] = t1_3; triangle_2[0] = t2_1; triangle_2[1] = t2_2; triangle_2[2] = t2_3; return triangleIntersection(triangle_1, triangle_2); } bool multipleTrianglesIntersection(pt_2d* tri1, int len1, pt_2d* tri2, int len2, int* ret1, int* ret2) { for(int k1 = 0; k1 < len1; k1+=3) { for(int k2 = 0; k2 < len2; k2+=3) { if(triangleIntersection(&tri1[k1], &tri2[k2])) { if(ret1 != NULL) {*ret1 = k1;} if(ret2 != NULL) {*ret2 = k2;} return true; } } } return false ; } int visibleSurfaces(double x0, double y0, double z0, cube_0 cb, int* dOrd) { // returns the number of surfaces that should be drawn, as well as filling dOrd for said surfaces : // 0 = +x ; 1 = -x // 2 = +y ; 3 = -y // 4 = +z ; 5 = -z // align cube center to (0, 0, 0) double x = x0 - (cb.x + cb.w/2.0) ; double y = y0 - (cb.y + cb.h/2.0) ; double z = z0 - (cb.z + cb.d/2.0) ; // rotate (y) double xry = x*cos(cb.hz_angle) + z*sin(cb.hz_angle) ; double yry = y ; double zry = z*cos(cb.hz_angle) - x*sin(cb.hz_angle) ; // rotate (x) double xrx = xry ; double yrx = yry*cos(cb.vt_angle) + zry*sin(cb.vt_angle) ; double zrx = zry*cos(cb.vt_angle) - yry*sin(cb.vt_angle) ; // cube is centered and aligned int id = 0 ; if(xrx > cb.w/2.0) { dOrd[id] = 0 ; id += 1 ; } else if(xrx < -cb.w/2.0) { dOrd[id] = 1 ; id += 1 ; } if(yrx > cb.h/2.0) { dOrd[id] = 2 ; id += 1 ; } else if(yrx < -cb.h/2.0) { dOrd[id] = 3 ; id += 1 ; } if(zrx > cb.d/2.0) { dOrd[id] = 4 ; id += 1 ; } else if(zrx < -cb.d/2.0) { dOrd[id] = 5 ; id += 1 ; } if(id == 0) { // inside the cube for(int k = 0; k < 6; k++) { dOrd[k] = k ; } return 6; } else { return id ; } } bool noWT; double sign_triangle(pt_2d p1, pt_2d p2, pt_2d p3) { return (p1.x - p3.x) * (p2.y - p3.y) - (p2.x - p3.x) * (p1.y - p3.y); } pt_2d to_pt2d(double x0, double y0, double z0) { pt_2d res; res.x = x0; res.y = y0; res.z = z0; return res; } double dot_product_3D(pt_2d p1, pt_2d p2) { return p1.x*p2.x + p1.y*p2.y + p1.z*p2.z ; } double dot_product_2D(pt_2d p1, pt_2d p2) { return p1.x*p2.x + p1.y*p2.y ; } void return_barycentric(pt_2d p, pt_2d a, pt_2d b, pt_2d c, double* u, double* v, double* w) { // get barycentric coords of p inside ABC triangle pt_2d v0 = to_pt2d(b.x - a.x, b.y - a.y, b.z - a.z); pt_2d v1 = to_pt2d(c.x - a.x, c.y - a.y, c.z - a.z); pt_2d v2 = to_pt2d(p.x - a.x, p.y - a.y, p.z - a.z); double d00 = dot_product_2D(v0, v0); double d01 = dot_product_2D(v0, v1); double d11 = dot_product_2D(v1, v1); double d20 = dot_product_2D(v2, v0); double d21 = dot_product_2D(v2, v1); double denom = d00 * d11 - d01 * d01; if(v != NULL) {*v = (d11 * d20 - d01 * d21) / denom;} if(w != NULL) {*w = (d00 * d21 - d01 * d20) / denom;} if(u != NULL && v != NULL && w != NULL) {*u = 1.0 - *v - *w;} } bool point_in_triangle(pt_2d pt, pt_2d v1, pt_2d v2, pt_2d v3, double* thetaA, double* thetaB, double* thetaC) { double d1, d2, d3; bool has_neg, has_pos; d1 = sign_triangle(pt, v1, v2); d2 = sign_triangle(pt, v2, v3); d3 = sign_triangle(pt, v3, v1); has_neg = (d1 < 0) || (d2 < 0) || (d3 < 0); has_pos = (d1 > 0) || (d2 > 0) || (d3 > 0); if(!(has_neg && has_pos)) { return_barycentric(pt, v1, v2, v3, thetaA, thetaB, thetaC); return true; } return false; } bool seg_seg_inter(pt_2d p1, pt_2d p2, pt_2d p3, pt_2d p4, double* ret0, double* ret1) { double deno = (p4.x - p3.x)*(p2.y - p1.y) - (p4.y - p3.y)*(p2.x - p1.x); if(absf(deno) <= 0.0001) { return false; } //printf("%lf\n", deno); double alpha = ((p4.x - p3.x)*(p3.y - p1.y) - (p4.y - p3.y)*(p3.x - p1.x))/ (deno) ; double beta = ((p2.x - p1.x)*(p3.y - p1.y) - (p2.y - p1.y)*(p3.x - p1.x))/ (deno) ; if(ret0 != NULL) {*ret0 = alpha;} if(ret1 != NULL) {*ret1 = beta;} return (alpha >= 0.0 && alpha <= 1.0 && beta >= 0.0 && beta <= 1.0); } void get_barycentric(pt_2d p, pt_2d* tri, double* retu, double* retv, double* retw) { pt_2d a = tri[0] ; pt_2d b = tri[1] ; pt_2d c = tri[2] ; pt_2d v0 = vect_diff(b, a); pt_2d v1 = vect_diff(c, a); pt_2d v2 = vect_diff(p, a); double d00 = dot2D(v0, v0); double d01 = dot2D(v0, v1); double d11 = dot2D(v1, v1); double d20 = dot2D(v2, v0); double d21 = dot2D(v2, v1); double denom = d00 * d11 - d01 * d01; if(retv != NULL) { *retv = (d11 * d20 - d01 * d21) / denom; } if(retw != NULL) { *retw = (d00 * d21 - d01 * d20) / denom; } if(retu != NULL) { *retu = 1.0 - *retv - *retw ; } } bool pt_equal(pt_2d p1, pt_2d p2, double epsilon) { return (absf(p2.x - p1.x) <= epsilon && absf(p2.y - p1.y) <= epsilon && absf(p2.z - p1.z) <= epsilon) ; } bool is_hidden(SDL_Renderer* renderer, pt_2d p, pt_2d ogp, pt_2d* tri, pt_2d* og) { if(pt_equal(p, tri[0], 0.0001) || pt_equal(p, tri[1], 0.0001) || pt_equal(p, tri[2], 0.0001)) { return false; } double u = 0.0 ; double v = 0.0 ; double w = 0.0 ; get_barycentric(p, tri, &u, &v, &w); pt_2d mid = convex_pt2d_tri(og[0], u, og[1], v, og[2], w); if(renderer != NULL && (u >= 0.0) && (v >= 0.0) && (w >= 0.0) && (u+v+w <= 1.0)) { if(mid.z >= 0.4) { SDL_Rect r; r.x = (int)(1500.0 * (1.0 + (mid.x / (1.5 * mid.z * tan_fov))) / 2.0) -2; r.y = (int)(1000.0 * (1.0 + (mid.y / (mid.z * tan_fov))) / 2.0) -2; r.w = 4 ; r.h = 4 ; SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); SDL_RenderFillRect(renderer, &r); } } if((u >= 0.0) && (v >= 0.0) && (w >= 0.0) && (u+v+w <= 1.0)) { return (proj_pt_distance_to_camera(mid) <= proj_pt_distance_to_camera(ogp)); } return false; } bool nonzero(double tha, double thb, double thc, double epsilon) { return (absf(tha) > epsilon && absf(thb) > epsilon && absf(thc) > epsilon); } bool is_in_front(pt_2d* tri1, pt_2d* og1, pt_2d* tri2, pt_2d* og2) { for(int k = 0; k < 3; k++) { pt_2d p = tri1[k]; if(pt_equal(p, tri2[0], 0.0001) || pt_equal(p, tri2[1], 0.0001) || pt_equal(p, tri2[2], 0.0001)) { return false; } double u = 0.0 ; double v = 0.0 ; double w = 0.0 ; get_barycentric(p, tri2, &u, &v, &w); pt_2d mid = convex_pt2d_tri(og2[0], u, og2[1], v, og2[2], w); if(((u >= 0.0) && (v >= 0.0) && (w >= 0.0) && (u+v+w <= 1.0)) && nonzero(u, v, w, 0.0001)) { return !(proj_pt_distance_to_camera(mid) <= proj_pt_distance_to_camera(og1[k])); } } for(int k = 0; k < 3; k++) { pt_2d p = tri2[k]; if(pt_equal(p, tri1[0], 0.0001) || pt_equal(p, tri1[1], 0.0001) || pt_equal(p, tri1[2], 0.0001)) { return false; } double u = 0.0 ; double v = 0.0 ; double w = 0.0 ; get_barycentric(p, tri1, &u, &v, &w); pt_2d mid = convex_pt2d_tri(og1[0], u, og1[1], v, og1[2], w); if(((u >= 0.0) && (v >= 0.0) && (w >= 0.0) && (u+v+w <= 1.0)) && nonzero(u, v, w, 0.0001)) { return !(proj_pt_distance_to_camera(mid) >= proj_pt_distance_to_camera(og2[k])); } } for(int k1 = 0; k1 < 3; k1++) { for(int k2 = 0; k2 < 3; k2++) { double th1, th2; if(seg_seg_inter(tri1[k1], tri1[(k1+1)%3], tri2[k2], tri2[(k2+1)%3], &th1, &th2)) { pt_2d mid1 = convex_pt2d(tri1[k1], tri1[(k1+1)%3], th1); pt_2d mid2 = convex_pt2d(tri2[k2], tri2[(k2+1)%3], th2); return (proj_pt_distance_to_camera(mid1) <= proj_pt_distance_to_camera(mid2)); } } } return false; }