windmill-gint/src/windmill_load.cpp

258 lines
5.8 KiB
C++

//----------------------------------------------------------------------------------------------------
//
// 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;
//----------------------------------------------------------------------------------------------------
// INITIALISATION
//----------------------------------------------------------------------------------------------------
Windmill::Windmill()
{
camera2 = NULL;
map = NULL;
//object = NULL;
z_buffer = NULL;
set_viewport(0, 0, 128, 64);
sun = {0, 0, 100};
}
Windmill::~Windmill()
{
free(z_buffer);
//free(object);
}
void Windmill::set_camera(Camera* _camera)
{
camera2 = _camera;
}
void Windmill::set_viewport(int viewport_x1, int viewport_y1, int viewport_x2, int viewport_y2)
{
viewport.x1 = max(0, viewport_x1);
viewport.y1 = max(0, viewport_y1);
viewport.x2 = min(viewport_x2, DWIDTH);
viewport.y2 = min(viewport_y2, DHEIGHT);
//if (z_buffer != NULL) free(z_buffer);
free(z_buffer);
shift_x = (viewport.x1 + viewport.x2) / 2;
shift_y = (viewport.y1 + viewport.y2) / 2;
z_buffer_size = (viewport.x2 - viewport.x1) * (viewport.y2 - viewport.y1);
z_buffer = (unsigned short*) calloc(z_buffer_size, 2);
//if (z_buffer == NULL) debug_pop("ERROR ptr z_buffer NULL");
z_buffer_width = viewport.x2 - viewport.x1;
z_buffer_offset = - viewport.x1 - viewport.y1 * DWIDTH;
clear_z_buffer();
}
void Windmill::set_map(Map* _map)
{
loading = true;
if (map != _map)
{
// free les anciennes ombres
// ...
// attribution de la map
map = _map;
// enregistrement d'une liste triable
//set_objects();
// calcul des spheres englobantes de chaque objet
compute_bouding_sphere();
// calcul des ombres projetees au sol par chaque objet
//compute_shadows();
}
loading = false;
}
/*void Windmill::set_objects()
{
//objects = new Object* [map->object_length];
objects = (Object**) malloc(map->object_length * sizeof(Object));
if (objects == NULL) debug_pop("ERROR ptr object NULL");
for (int i = 0; i<map->object_length; i++)
{
objects[i] = map->object[i];
}
}*/
void Windmill::compute_bouding_sphere()
{
// calcul des spheres englobantes pour chaque objet
for (int i = 0; i<map->object_length; i++)
{
Object* object = map->object[i];
int nb_point = 0;
int barycenter_x = 0;
int barycenter_y = 0;
int barycenter_z = 0;
// calcul du barycentre
for (int v = 0; v<object->mesh->v_length; v++)
{
VertexPoint vp = object->mesh->v[v];
barycenter_x += vp.x;
barycenter_y += vp.y;
barycenter_z += vp.z;
nb_point++;
}
barycenter_x /= nb_point;
barycenter_y /= nb_point;
barycenter_z /= nb_point;
// recherche du point le plus eloigne du barycentre
int square_radius_max = 0;
for (int v = 0; v<object->mesh->v_length; v++)
{
VertexPoint vp = object->mesh->v[v];
int dx = vp.x - barycenter_x;
int dy = vp.y - barycenter_y;
int dz = vp.z - barycenter_z;
int square_radius = dx*dx + dy*dy + dz*dz;
if (square_radius > square_radius_max)
{
square_radius_max = square_radius;
}
}
// enregistrement
object->sphere.x = barycenter_x;
object->sphere.y = barycenter_y;
object->sphere.z = barycenter_z;
object->sphere.radius = sqrtf(square_radius_max) + 1;
object->sphere.square_radius = square_radius_max + 1;
}
}
/*WMesh Windmill::compute_shadows()
{
// pout chaque objet
for (int i = 0; i<map->object_length; i++)
{
Object* object = map->object[i];
list_shadows_length = get_points_size(object;
//debug_pop("sh %i", list_shadows_length);
shadows = (Point*) malloc(list_shadows_length * sizeof(Point));
int index = 0;
// pour chaque poly
for (int j = 0; j<object->modele_size; j++)
{
const Modele* current_poly = &object->modele[j];
for (int k = 0; k<current_poly->type; k++)
{
Point point = get_point(current_poly, k);
Point shadow_point = {(sun.x * point.z - sun.z * point.x) / (point.z - sun.z), (sun.y * point.z - sun.z * point.y) / (point.z - sun.z), 0};
shadows[index] = shadow_point;
index ++;
//debug_pop("p %i %i %i", point.x, point.y, point.z);
//debug_pop("s %i %i %i", shadow_point.x, shadow_point.y, shadow_point.z);
}
}
}
}
// Gift Wrapping algorithme
void Windmill::compute_shadows_hull(Point3D* points, int points_size)
{
if (points_size < 3) return;
Point3D* temp_hull = (Point3D*) malloc(list_shadows_length * sizeof(Point3D));
int temp_hull_length = 0;
// commencer par le point le plus a gauche
int left = 0;
for (int i = 1; i<points_size; i++)
{
if (points[i].x < points[left].x)
{
left = i;
}
}
// calcul de la coque
int p = left, q;
do
{
// conserver point p
temp_hull[temp_hull_length] = points[p];
temp_hull_length ++;
q = (p+1)%points_size;
for (int i = 0; i < points_size; i++)
{
if (compute_shadows_hull_orientation(points[p], points[i], points[q]) == 2) // clockwise
{
q = i;
}
p = q;
}
} while (p != left);
free(temp_hull);
int hull_length = temp_hull_length;
Point3D* hull = (Point3D*) malloc(hull_length * sizeof(Point3D));
memcpy(hull, temp_hull, hull_length * sizeof(Point3D));
for (int i = 0; i<temp_hull_length; i++)
{
//dprint(0, 8*i)
}
}
int Windmill::compute_shadows_hull_orientation(Point3D a, Point3D b, Point3D c)
{
int val = (b.y - a.y) * (c.x - b.x) - (b.x - a.x) * (c.y - b.y);
if (val == 0) return 0; // colineaire
return (val > 0)? 1 : 2; // clock ou counterclock wise
}*/