258 lines
5.8 KiB
C++
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
|
||
|
}*/
|