//---------------------------------------------------------------------------------------------------- // // WINDMILL // // version : 2.0 // Moteur de rendu 3D base sur la methode de rasterisation avec buffer de profondeur // // Cree par Olivier Lanneau, alias NineStars // Planet-casio.fr // //---------------------------------------------------------------------------------------------------- #include "windmill.hpp" void debug_pop(char const *fmt, ...); void debug_display(char const *fmt, ...); extern Texture tex_white; extern Texture tex_light; extern Texture tex_dark; extern Texture tex_black; //---------------------------------------------------------------------------------------------------- // CLIPPING //---------------------------------------------------------------------------------------------------- bool Windmill::object_in_frustrum(Object* object) { Vertex centre(object->sphere.x, object->sphere.y, object->sphere.z); std::vector vCentre = {centre}; // calcul des coordonnees dans le repère monde apres rotation et translation du centre de l objet transform_model_to_world(object, vCentre); // calcul des coordonnees du centre dans le repère camera apres rotation et translation de la camera transform_world_to_camera(vCentre); // si la camera est dans la sphere if (centre.x*centre.x + centre.y*centre.y + centre.z*centre.z < object->sphere.square_radius) { return true; } // si la sphere est dans le frustrum for (int p = 0; p<5 ; p++) { Plane plane = camera.frustrum.sides[p]; if (inside_frustrum(centre, plane, object->sphere.radius) == false) return false; } return true; // A GARDER CAR PAS MAL OPTI /* int cone_offset = sphere->radius * camera.sin_fov; int nx = camera.nx; int ny = camera.ny; int nz = camera.nz; Point3D cone; cone.x = int(camera.x) - (nx * cone_offset); cone.y = int(camera.y) - (ny * cone_offset); cone.z = int(camera.z) - (nz * cone_offset); int sx = sphere->x - cone.x; int sy = sphere->y - cone.y; int sz = sphere->z - cone.z; int ss = sx*sx + sy*sy + sz*sz; // si sommet du cone dans la sphere if (ss <= sphere->radius * sphere->radius) { return true; } // si sphere dans le cone int ns = ((nx * sx) >> 7) + ((ny * sy) >> 7) + ((nz * sz) >> 7); if (ns > 0 and ns*ns > camera.cos_fov_square * ss) { return true; } return false;*/ } void Windmill::clip_frustrum(WMesh &mesh) { //pour chaque plan for (int p = 0; p<5 ; p++) { Plane plane = camera.frustrum.sides[p]; int init_f_length = mesh.f.size(); // car sinon on va faire du clipping sur des points nouveaux issues du clipping... // pour chaque triangle for (int f=0; f on modifie la face en cours if (ok_indice >= 3) { Face edited_triangle; edited_triangle.texture_front = triangle.texture_front; edited_triangle.texture_back = triangle.texture_back; for (int i=0; i<3; i++) { edited_triangle.v[i] = v_ok[i]; edited_triangle.t[i] = t_ok[i]; } mesh.f[f] = edited_triangle; // pas de verif d'overflow } // 1 point en dehors = 2 triangles -> on modifie face en cours, et on ajoute une face if (ok_indice == 4) { // ajout triangle Face new_triangle; new_triangle.texture_front = triangle.texture_front; new_triangle.texture_back = triangle.texture_back; new_triangle.v[0] = v_ok[0]; new_triangle.t[0] = t_ok[0]; new_triangle.v[1] = v_ok[2]; new_triangle.t[1] = t_ok[2]; new_triangle.v[2] = v_ok[3]; new_triangle.t[2] = t_ok[3]; mesh.f.push_back(new_triangle); // pas de verif d'overflow } } /*debug_pop("FIN CYCLE\nplan %i\nil y a %i triangles\nil y a %i vertex", p, mesh->f_length, mesh->v_length); for (int i=0; if_length; i++) { debug_pop("f %i %i %i", mesh->f[i].v[0], mesh->f[i].v[1], mesh->f[i].v[2]); } for (int i=0; iv_length; i++) { debug_pop("v\nx %i\ny %i\nz %i", mesh->v[i].x, mesh->v[i].y, mesh->v[i].z); }*/ } } } bool Windmill::inside_frustrum(Vertex vertex, Plane plane, int offset) { /*if (plane.id == NEAR) { return vertex.z > camera.near; } if (plane.id == RIGHT) { return vertex.x * camera.scale_coef2 < vertex.z; // MULT float ! } if (plane.id == TOP) { return -vertex.y * camera.scale_coef2 / 2.0 < vertex.z; } if (plane.id == LEFT) { return -vertex.x * camera.scale_coef2 < vertex.z; } if (plane.id == BOTTOM) { return vertex.y * camera.scale_coef2 / 2.0 < vertex.z; }*/ int dot = vertex.x * plane.normal_x + vertex.y * plane.normal_y + vertex.z * plane.normal_z - plane.distance+ (offset * 1000); return dot > 0; } Vertex Windmill::clip_onto_plane(Vertex vertexA, Vertex vertexB, Plane plane) {/* int x, y, z, u, v; float t; if (plane == NEAR) { t = float(camera.near - vertexA->z) / float(vertexB->z - vertexA->z); //x = vertexA->x + t * (vertexB->x - vertexA->x); //y = vertexA->y + t * (vertexB->y - vertexA->y); //z = camera.near; } if (plane == RIGHT) { t = float(camera.near - vertexA->z) / float(vertexB->z - vertexA->z); } x = vertexA->x + t * (vertexB->x - vertexA->x); y = vertexA->y + t * (vertexB->y - vertexA->y); z = vertexA->z + t * (vertexB->z - vertexA->z); u = vertexA->u + t * (vertexB->u - vertexA->u); v = vertexA->v + t * (vertexB->v - vertexA->v); return Vertex(x, y, z, u, v);*/ //return Vertex(0, 0, 0, 0, 0); float dotA = vertexA.x * plane.normal_x + vertexA.y * plane.normal_y + vertexA.z * plane.normal_z - plane.distance; float dotB = vertexB.x * plane.normal_x + vertexB.y * plane.normal_y + vertexB.z * plane.normal_z - plane.distance; float t = dotA / (dotA - dotB); // intersection factor (between 0 and 1) int x = vertexA.x + t * (vertexB.x - vertexA.x); int y = vertexA.y + t * (vertexB.y - vertexA.y); int z = vertexA.z + t * (vertexB.z - vertexA.z); float u = vertexA.u + t * (vertexB.u - vertexA.u); float v = vertexA.v + t * (vertexB.v - vertexA.v); return Vertex(x, y, z, u, v); } bool Windmill::inside_viewport(int x, int y) { return (x < viewport.x2 and y >= viewport.y1 and x >= viewport.x1 and y < viewport.y2); } int Windmill::get_visible_face(Vertex* a, Vertex* b, Vertex* c) { return (c->x - a->x) * (b->y - a->y) - (c->y - a->y) * (b->x - a->x) > 0 ? FRONT : BACK; }