windmill-gint/src/windmill.cpp

1789 lines
50 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//----------------------------------------------------------------------------------------------------
//
// 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"
//const Texture tex_black = {};
//const Texture tex_white = {};
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);
nb_object_on_screen = 0;
temp_object_cursor = NULL;
temp_poly_cursor = -1;
}
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();
cursor_x = shift_x;
cursor_y = shift_y;
}
void Windmill::load_map(Map* _map)
{
loading = true;
if (map != _map)
{
// attribution de la map
map = _map;
// enregistrement des objets de la map dans un tableau
// ceci permet de trier les objets pour les afficher du plus
// pres au plus loin
list_object_length = map->list_object_length;
//delete[] object;
free(object);
//object = new Object* [list_object_length];
object = (Object**) malloc(list_object_length * sizeof(Object));
//if (object == NULL) debug_pop("ERROR ptr object NULL");
for (int i = 0; i<list_object_length; i++)
{
object[i] = map->object[i];
}
// generation des spheres englobantes
// pour chaque objet
for (int i = 0; i<map->list_object_length; i++)
{
Object* current_object = map->object[i];
int nb_point = 0;
int center_x = 0;
int center_y = 0;
int center_z = 0;
// pour chaque poly
for (int j = 0; j<current_object->modele_size; j++)
{
const Modele* current_poly = &current_object->modele[j];
// pour chaque point
for (int k = 0; k<current_poly->type; k++)
{
Point point = get_point(current_poly, k);
center_x += point.x;
center_y += point.y;
center_z += point.z;
nb_point++;
}
}
// barycentre
center_x /= nb_point;
center_y /= nb_point;
center_z /= nb_point;
// recherche du point le plus eloigne du centre
int radius_max = 0;
for (int j = 0; j<current_object->modele_size; j++)
{
const Modele* current_poly = &current_object->modele[j];
for (int k = 0; k<current_poly->type; k++)
{
Point point = get_point(current_poly, k);
int dx = point.x - center_x;
int dy = point.y - center_y;
int dz = point.z - center_z;
int radius = dx*dx + dy*dy + dz*dz;
//int rr = sqrtf(radius);
if (radius > radius_max)
{
radius_max = radius;
}
}
}
radius_max = sqrtf(radius_max) + 1;
current_object->sphere.x = center_x;
current_object->sphere.y = center_y;
current_object->sphere.z = center_z;
current_object->sphere.radius = radius_max;
}
}
loading = false;
}
//----------------------------------------------------------------------------------------------------
// DESSIN
//----------------------------------------------------------------------------------------------------
void Windmill::draw()
{
// quitte si pas de camera, de map, d objet ou de z_buffer
if(camera2 == NULL or map == NULL or object == NULL or z_buffer == NULL) return;
// mets a jour les variables de la camera
camera2->update();
// cree une camera temporaire pour eviter les problemes de desynchronisation
copy_camera();
// fonction principale, l'ordre d'appel des fonctions suivantes est important
clear_z_buffer();
// trie les objets pour optimiser l affichage
sort_object();
// affiche le trait d'horizon
if (map->horizon) draw_horizon();
// affiche le sol
if (map->ground) draw_ground();
// affiche les objets de la scene
draw_objects();
// post traitement pour afficher les angles vifs
draw_post_treatment();
// affiche le corps du personnage
draw_body();
// affiche des informations
//show_fps();
//show_coordinates();
//show_repere();
}
void Windmill::draw_horizon()
{
Vertex horizon;
char* vram = get_vram_address();
int distance = 1000;
int hx = camera.x + distance * camera.cos_yaw;
int hy = camera.y + distance * camera.sin_yaw;
horizon.set_xyz(hx, hy, 0);
transform_world_to_camera(&horizon, 1);
transform_camera_to_screen(&horizon, 1);
if (inside_viewport(horizon.x, horizon.y))
{
dline(viewport.x1, horizon.y, viewport.x2, horizon.y, C_BLACK);
//ML_line(viewport.x1, horizon.y, viewport.x2, horizon.y, ML_BLACK);
}
}
void Windmill::draw_ground()
{
Vertex ground;
char* vram = get_vram_address();
unsigned char mask;
int distance = 50;
int esp = 20;
int nb = 6;
int nb2 = nb * nb;
float cx = camera.x + distance * camera.cos_yaw;
float cy = camera.y + distance * camera.sin_yaw;
int dx = int(cx) - int(cx)%esp;
int dy = int(cy) - int(cy)%esp;
for (int i=-nb; i<nb; i++)
{
for (int j=-nb; j<nb; j++)
{
if (i*i + j*j < nb2) // arrondi le carre en cercle
{
int x = dx + i*esp;
int y = dy + j*esp;
ground.set_xyz(x, y, 0);
transform_world_to_camera(&ground, 1);
if (ground.z > 0)
{
transform_camera_to_screen(&ground, 1);
if (inside_viewport(ground.x, ground.y) == true)
{
mask = 128 >> (ground.x & 7);
vram[(ground.y << 4) + (ground.x>>3)] |= mask;
}
}
}
}
}
}
void Windmill::draw_objects()
{
nb_object_on_screen = 0;
temp_object_cursor = NULL;
temp_poly_cursor = -1;
Vertex vertex[10];
int vertex_length;
int width, height;
int cosinus, sinus;
for(i=0; i<map->list_object_length; i++)
{
//Object* current_object = map->object[i];
Object* current_object = object[i];
if (current_object->hidden == false)
{
// angle de l objet
compute_object_angle(current_object, &cosinus, &sinus);
// transforme la sphere dans le repere monde
Sphere current_sphere = transform_sphere_to_world(&current_object->sphere, current_object, cosinus, sinus);
// verifie si la sphere englobante est dans le champs de vision de la camera
if (sphere_in_cone(&current_sphere))
{
temp_nb_object_on_screen ++;
current_object->on_screen = true;
current_object->distance_to_camera = current_sphere.z;
for(j=0; j<current_object->modele_size; j++)
{
const Modele* current_poly = &current_object->modele[j];
// creation des vertex a partir du poly
extract_vertex_from_poly(current_poly, vertex, &vertex_length, &width, &height);
// calcul des coordonnees dans le repère monde apres rotation et translation de l objet
transform_model_to_world(vertex, vertex_length, current_object, cosinus, sinus);
// calcul des coordonnees dans le repère camera apres rotation et translation de la camera
transform_world_to_camera(vertex, vertex_length);
// verifie si au moins 1 point peut etre visible
if (fast_check(vertex, vertex_length))
{
// calcul de l'aire du rectangle pour connaitre sa face visible
int visible = visible_face(&vertex[0], &vertex[1], &vertex[2]);
// choisi la texture visible
const Texture* texture;
texture = (visible == FRONT) ? current_poly->texture_front : current_poly->texture_back;
// si le rectangle est visible
if (texture != NULL)
{
// si le rectangle a une texture
if (texture != &tex_black && texture != &tex_white)
{
texture_coordinates(current_poly, vertex, texture, visible, width, height);
}
// tronque le polygon devant le plan avant de la camera
clip_depth(vertex, &vertex_length);
// calcul des coordonnes apres perspective et decalage au centre de l ecran
transform_camera_to_screen(vertex, vertex_length);
// tronque le polygon sur les bords de l ecran
clip_viewport(vertex, &vertex_length);
// calcul des coordonnees de profondeur
transform_camera_to_screen2(vertex, vertex_length);
// affiche les triangles
if (visible == FRONT)
{
for (int k = 1; k<vertex_length-1; k++)
{
render_triangle(&vertex[0], &vertex[k], &vertex[k+1], texture);
}
} else {
for (int k = vertex_length-1; k>1; k--)
{
render_triangle(&vertex[0], &vertex[k], &vertex[k-1], texture);
}
}
}
}
}
} else {
current_object->on_screen = false;
}
}
}
nb_object_on_screen = temp_nb_object_on_screen;
object_cursor = temp_object_cursor;
poly_cursor = temp_poly_cursor;
}
void Windmill::draw_post_treatment()
{
char* vram = get_vram_address();
unsigned char mask;
int current, right, bottom, left;
for (int y = viewport.y1; y<viewport.y2-1; y++)
{
for (int x = viewport.x1; x<viewport.x2-1; x++)
{
int address = x + y * z_buffer_width + z_buffer_offset;
current = z_buffer[address];
right = z_buffer[address + 1];
bottom = z_buffer[address + z_buffer_width];
if (current == MAX_DEPTH_Z_BUFFER)
{
if (right < MAX_DEPTH_Z_BUFFER)
{
mask = 128 >> ((x+1) & 7);
vram[address<<3] |= mask;
//ML_pixel(x+1, y, ML_BLACK);
}
if (bottom < MAX_DEPTH_Z_BUFFER)
{
dpixel(x, y+1, C_BLACK);
//ML_pixel(x, y+1, ML_BLACK);
}
} else {
if (right == MAX_DEPTH_Z_BUFFER or bottom == MAX_DEPTH_Z_BUFFER)
{
dpixel(x, y+1, C_BLACK);
//ML_pixel(x, y, ML_BLACK);
}
}
}
} // 21 fps 21,5 fps*/
/*left = z_buffer[0];
for (int i = 1; i<z_buffer_size; i++)
{
left = current;
current = z_buffer[i];
//bottom = z_buffer[i+128];
if (current < MAX_DEPTH_Z_BUFFER)
{
//left = z_buffer[i-1];
if (left == MAX_DEPTH_Z_BUFFER)
{
//ML_pixel((i+1)%128, (i+1)/128, ML_BLACK);
mask = 128 >> (i & 7);
vram[(i - z_buffer_offset)>>3] |= mask;
}
} else {
if (left < MAX_DEPTH_Z_BUFFER)
{
mask = 128 >> ((i-1) & 7);
vram[(i - 1 - z_buffer_offset)>>3] |= mask;
}
}
}
// sans rien 28 fps
// avec le i+1 : 24 fps
// avec le i : 25 fps
// calculer left = Z_buffer[i-1] dans if : 24 fps
// avec les deux cote : 24 fps ! */
bool flag = false;
for (int i = 0; i<z_buffer_size; i+=2)
{
current = z_buffer[i];
if (current == MAX_DEPTH_Z_BUFFER)
{
if (flag == true)
{
if (z_buffer[i-1] == MAX_DEPTH_Z_BUFFER)
{
// il y avait rien juste a gauche
mask = 128 >> ((i-2) & 7);
vram[(i - 2 - z_buffer_offset)>>3] |= mask;
flag = false;
} else {
// l objet commencait en fait 1 pixel a gauche
mask = 128 >> ((i-1) & 7);
vram[(i - 1 - z_buffer_offset)>>3] |= mask;
flag = false;
}
}
} else {
if (flag == false)
{
if (z_buffer[i-1] == MAX_DEPTH_Z_BUFFER)
{
// il y avait rien juste a gauche
mask = 128 >> (i & 7);
vram[(i - z_buffer_offset)>>3] |= mask;
flag = true;
} else {
// l objet commencait en fait 1 pixel a gauche
mask = 128 >> ((i-1) & 7);
vram[(i - 1 - z_buffer_offset)>>3] |= mask;
flag = true;
}
}
}
} // 24 fps
// avec astuce +=2 : 25 fps
/*bool flag = false;
char i_mod_8;
for (int i = 0; i<z_buffer_size; i++)
{
i_mod_8 = i & 7;
current = z_buffer[i];
if (current == MAX_DEPTH_Z_BUFFER)
{
if (flag == true)
{
mask |= 128 >> i_mod_8;//((i-1) & 7);
flag = false;
}
} else {
if (flag == false)
{
mask |= 128 >> i_mod_8;
flag = true;
}
}
if (i_mod_8 == 7)
{
//if (mask > 0)
vram[i>>3] |= mask;
mask = 0;
}
}*/
}
void Windmill::draw_body()
{
/*int x = camera.x;
int y = camera.y;
int z = camera.z;
Vertex v0, v1, v2, v3;
set_vertex_xyz()
METTRE DIRECT LES VERTEX DANS LE REPERE SCREEN PUIS RENDER...
*/
}
//----------------------------------------------------------------------------------------------------
// TRANSFORMATION 3D
//----------------------------------------------------------------------------------------------------
void Windmill::transform_model_to_world(Vertex vertex[], int vertex_length, Object* object, int cosinus, int sinus)
{
for (int k = 0; k<vertex_length; k++)
{
int vertex_x = vertex[k].x;
int vertex_y = vertex[k].y;
int vertex_z = vertex[k].z;
if (object->axe == N)
{
vertex[k].x = vertex_x + object->x;
vertex[k].y = vertex_y + object->y;
vertex[k].z = vertex_z + object->z;
}
if (object->axe == X)
{
vertex[k].x = vertex_x + object->x;
vertex[k].y = ((vertex_y * cosinus - vertex_z * sinus) >> 10) + object->y;
vertex[k].z = ((vertex_y * sinus + vertex_z * cosinus) >> 10) + object->z;
}
if (object->axe == Y)
{
vertex[k].x = ((vertex_x * cosinus - vertex_z * sinus) >> 10) + object->x;
vertex[k].y = vertex_y + object->y;
vertex[k].z = ((vertex_x * sinus + vertex_z * cosinus) >> 10) + object->z;
}
if (object->axe == Z or object->axe == Z_BILLBOARD)
{
vertex[k].x = ((vertex_x * cosinus - vertex_y * sinus) >> 10) + object->x;
vertex[k].y = ((vertex_x * sinus + vertex_y * cosinus) >> 10) + object->y;
vertex[k].z = vertex_z + object->z;
}
}
}
void Windmill::transform_world_to_camera(Vertex vertex[], int vertex_length)
{
for (int k = 0; k<vertex_length; k++)
{
// translation
int vertex_x = int(camera.x) - vertex[k].x;
int vertex_y = int(camera.y) - vertex[k].y;
int vertex_z = int(camera.z) - vertex[k].z;
// rotation
vertex[k].z = -(camera.a1 * vertex_x + camera.a2 * vertex_y + camera.a3 * vertex_z);
vertex[k].x = camera.a4 * vertex_x + camera.a5 * vertex_y + camera.a6 * vertex_z;
vertex[k].y = camera.a7 * vertex_x + camera.a8 * vertex_y + camera.a9 * vertex_z;
}
}
void Windmill::transform_camera_to_screen(Vertex vertex[], int vertex_length)
{
for (int k = 0; k<vertex_length; k++)
{
// perspective
vertex[k].x = (vertex[k].x * camera.scale_coef) / vertex[k].z + shift_x;
vertex[k].y = (vertex[k].y * camera.scale_coef) / vertex[k].z + shift_y;
}
}
void Windmill::transform_camera_to_screen2(Vertex vertex[], int vertex_length)
{
for (int k = 0; k<vertex_length; k++)
{
// calcul du z normalise entre les deux plans de clipping
//vertex[k].z_normalized = (1<<15) * ( float(vertex[k].z * camera.far - SCALE_AI * camera.far * camera.near) / float(vertex[k].z * (camera.far - camera.near)) );
vertex[k].z_normalized = (1<<15) * ( float(vertex[k].z - SCALE_AI * camera.near) / float(SCALE_AI * camera.far) );
//vertex[k].z_normalized = vertex[k].z;
//vertex->z_normalized = (1<<15) * (vertex->z * camera.far - SCALE_AI * camera.far * camera.near) / (vertex->z * (camera.far - camera.near));
// precalcul de 1/z
vertex[k].z = (1<<20) / vertex[k].z;
}
}
//----------------------------------------------------------------------------------------------------
// TEST VISIBILITE
//----------------------------------------------------------------------------------------------------
bool Windmill::fast_check(Vertex vertex[], int vertex_length)
{
int near = camera.near * SCALE_AI;
int far = camera.far * SCALE_AI;
for (int i = 0; i<vertex_length; i++)
{
if (vertex[i].z >= near and vertex[i].z < far) return true;
}
return false;
}
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::visible_face(Vertex* a, Vertex* b, Vertex* c)
{
int nx = ((b->y - a->y) * (c->z - a->z) - (b->z - a->z) * (c->y - a->y)) >> 15;
int ny = ((b->z - a->z) * (c->x - a->x) - (b->x - a->x) * (c->z - a->z)) >> 15;
int nz = ((b->x - a->x) * (c->y - a->y) - (b->y - a->y) * (c->x - a->x)) >> 15;
return (nx*a->x + ny*a->y + nz*a->z > 0) ? BACK : FRONT;
}
// SutherlandHodgman algorithm
void Windmill::clip_depth(Vertex vertex_input[], int* vertex_input_length)
{
Vertex vertex_temp;
Vertex vertex_output[10];
int vertex_output_length = 0;
int S = *vertex_input_length-1;
for (int E = 0; E<*vertex_input_length; E++)
{
if (clip_depth_inside_edge(&vertex_input[E]) == true)
{
if (clip_depth_inside_edge(&vertex_input[S]) == false)
{
clip_depth_edge(&vertex_input[E], &vertex_input[S], &vertex_temp);
copy_vertex(&vertex_temp, &vertex_output[vertex_output_length]);
vertex_output_length += 1;
}
copy_vertex(&vertex_input[E], &vertex_output[vertex_output_length]);
vertex_output_length += 1;
} else if (clip_depth_inside_edge(&vertex_input[S]) == true)
{
clip_depth_edge(&vertex_input[S], &vertex_input[E], &vertex_temp);
copy_vertex(&vertex_temp, &vertex_output[vertex_output_length]);
vertex_output_length += 1;
}
S = E;
}
*vertex_input_length = vertex_output_length;
for (int i = 0; i<*vertex_input_length; i++)
{
copy_vertex(&vertex_output[i], &vertex_input[i]);
}
}
void Windmill::clip_depth_edge(Vertex* vertex_in, Vertex* vertex_out, Vertex* vertex_set)
{
int near, x_near, y_near, z_near, w_near, h_near;
float t;
near = camera.near * SCALE_AI;
t = float(near - vertex_in->z) / float(vertex_out->z - vertex_in->z);
x_near = (vertex_out->x - vertex_in->x) * t + vertex_in->x;
y_near = (vertex_out->y - vertex_in->y) * t + vertex_in->y;
z_near = near;
w_near = (vertex_out->w - vertex_in->w) * t + vertex_in->w;
h_near = (vertex_out->h - vertex_in->h) * t + vertex_in->h;
vertex_set->set_xyz(x_near, y_near, z_near);
vertex_set->set_wh(w_near, h_near);
}
bool Windmill::clip_depth_inside_edge(Vertex* vertex)
{
return (vertex->z >= camera.near * SCALE_AI) ? true : false;
}
// SutherlandHodgman algorithm
void Windmill::clip_viewport(Vertex vertex_input[], int* vertex_input_length)
{
Vertex vertex_temp;
Vertex vertex_output[10];
int vertex_output_length = *vertex_input_length;
for (int i = 0; i<*vertex_input_length; i++)
{
copy_vertex(&vertex_input[i], &vertex_output[i]);
}
for (int edge = 0; edge < 4; edge++)
{
for (int i = 0; i<vertex_output_length; i++)
{
copy_vertex(&vertex_output[i], &vertex_input[i]);
}
*vertex_input_length = vertex_output_length;
vertex_output_length = 0;
int S = *vertex_input_length-1;
for (int E = 0; E<*vertex_input_length; E++)
{
if (clip_viewport_inside_edge(&vertex_input[E], edge) == true)
{
if (clip_viewport_inside_edge(&vertex_input[S], edge) == false)
{
clip_viewport_edge(&vertex_input[E], &vertex_input[S], &vertex_temp, edge);
copy_vertex(&vertex_temp, &vertex_output[vertex_output_length]);
vertex_output_length += 1;
}
copy_vertex(&vertex_input[E], &vertex_output[vertex_output_length]);
vertex_output_length += 1;
} else if (clip_viewport_inside_edge(&vertex_input[S], edge) == true)
{
clip_viewport_edge(&vertex_input[S], &vertex_input[E], &vertex_temp, edge);
copy_vertex(&vertex_temp, &vertex_output[vertex_output_length]);
vertex_output_length += 1;
}
S = E;
}
}
*vertex_input_length = vertex_output_length;
for (int i = 0; i<*vertex_input_length; i++)
{
copy_vertex(&vertex_output[i], &vertex_input[i]);
}
}
void Windmill::clip_viewport_edge(Vertex* vertex_in, Vertex* vertex_out, Vertex* vertex_set, int edge)
{
float x_set, y_set, z_set, w_set, h_set;
float t; // t = 0 si edge proche de in et = 1 si proche de out
if (edge == 0)
{
t = float(viewport.x2 - 1 - vertex_in->x) / float(vertex_out->x - vertex_in->x);
x_set = viewport.x2-1;
y_set = (vertex_out->y - vertex_in->y) * t + vertex_in->y;
}
if (edge == 1)
{
t = float(viewport.y1 - vertex_in->y) / float(vertex_out->y - vertex_in->y);
x_set = (vertex_out->x - vertex_in->x) * t + vertex_in->x;
y_set = viewport.y1;
}
if (edge == 2)
{
t = float(viewport.x1 - vertex_in->x) / float(vertex_out->x - vertex_in->x);
x_set = viewport.x1;
y_set = (vertex_out->y - vertex_in->y) * t + vertex_in->y;
}
if (edge == 3)
{
t = float(viewport.y2 - 1 - vertex_in->y) / float(vertex_out->y - vertex_in->y);
x_set = (vertex_out->x - vertex_in->x) * t + vertex_in->x;
y_set = viewport.y2-1;
}
z_set = 0.5 + float(1) / (float(1-t)/float(vertex_in->z) + float(t)/float(vertex_out->z));
w_set = z_set * ( (1.0-t) * vertex_in->w / float(vertex_in->z) + t * vertex_out->w / float(vertex_out->z) );
h_set = z_set * ( (1.0-t) * vertex_in->h / float(vertex_in->z) + t * vertex_out->h / float(vertex_out->z) );
vertex_set->set_xyz(x_set, y_set, z_set);
vertex_set->set_wh(w_set, h_set);
}
bool Windmill::clip_viewport_inside_edge(Vertex* vertex, int edge)
{
// 0 : RIGHT 1 : UP 2: LEFT 3 : DOWN
if (edge == 0 and vertex->x < viewport.x2-1) return true;
if (edge == 1 and vertex->y > viewport.y1) return true;
if (edge == 2 and vertex->x > viewport.x1) return true;
if (edge == 3 and vertex->y < viewport.y2-1) return true;
return false;
}
//----------------------------------------------------------------------------------------------------
// DESSIN DES TRIANGLES
//----------------------------------------------------------------------------------------------------
void Windmill::render_triangle(Vertex* vertexA, Vertex* vertexB, Vertex* vertexC, const Texture *texture)//, bool billboard)
{
//render_triangle_black(vertexA, vertexB, vertexC);
if (texture == NULL) return;
if (texture == &tex_black)
{
render_triangle_black(vertexA, vertexB, vertexC);
}
else if (texture == &tex_white)
{
render_triangle_white(vertexA, vertexB, vertexC);
}
else if (texture->transparent == true)
{
render_triangle_transparent(vertexA, vertexB, vertexC, texture);
}
else
{
render_triangle_texture(vertexA, vertexB, vertexC, texture);
}
}
void Windmill::render_triangle_texture(Vertex* vertexA, Vertex* vertexB, Vertex* vertexC, const Texture* texture)
{
// calcul du rectangle circonscrit au triangle
int min_x = max(viewport.x1, min(vertexA->x, min(vertexB->x, vertexC->x)));
int max_x = min(viewport.x2-1, max(vertexA->x, max(vertexB->x, vertexC->x)));
int min_y = max(viewport.y1, min(vertexA->y, min(vertexB->y, vertexC->y)));
int max_y = min(viewport.y2-1, max(vertexA->y, max(vertexB->y, vertexC->y)));
// calcul de l'aire du triangle
int area = edge(vertexA, vertexB, vertexC);
// determine si la taille du triangle est trop petite
if (area <= MIN_AREA_CLIP) return;
// pre-calcul des coordonnees de la texture
int w0 = vertexA->w * vertexA->z; int h0 = vertexA->h * vertexA->z;
int w1 = vertexB->w * vertexB->z; int h1 = vertexB->h * vertexB->z;
int w2 = vertexC->w * vertexC->z; int h2 = vertexC->h * vertexC->z;
// calcul des produits vectoriels
int u0_start = edge_start(vertexB, vertexC, min_x, min_y);
int u0_step_x = edge_step_x(vertexB, vertexC);
int u0_step_y = edge_step_y(vertexB, vertexC);
int u1_start = edge_start(vertexC, vertexA, min_x, min_y);
int u1_step_x = edge_step_x(vertexC, vertexA);
int u1_step_y = edge_step_y(vertexC, vertexA);
int u2_start = edge_start(vertexA, vertexB, min_x, min_y);
int u2_step_x = edge_step_x(vertexA, vertexB);
int u2_step_y = edge_step_y(vertexA, vertexB);
int z_num_start = (u0_start * vertexA->z_normalized + u1_start * vertexB->z_normalized + u2_start * vertexC->z_normalized) / area;
int z_num_step_x = (u0_step_x * vertexA->z_normalized + u1_step_x * vertexB->z_normalized + u2_step_x * vertexC->z_normalized) / area;
int z_num_step_y = (u0_step_y * vertexA->z_normalized + u1_step_y * vertexB->z_normalized + u2_step_y * vertexC->z_normalized) / area;
int z_div_start = u0_start * vertexA->z + u1_start * vertexB->z + u2_start * vertexC->z;
int z_div_step_x = u0_step_x * vertexA->z + u1_step_x * vertexB->z + u2_step_x * vertexC->z;
int z_div_step_y = u0_step_y * vertexA->z + u1_step_y * vertexB->z + u2_step_y * vertexC->z;
// rapprochement artificiel si texture de type decoration
int decoration = (texture->decoration ? DECORATION_OFFSET : 0);
// acces a la vram
char* vram = get_vram_address();
unsigned char mask_vram, mask_w;
int offset_vram;
int address;
int u0, u1, u2;
int z_num, z_div;
int w, h;
// pre-calcul largeur en octet des tableaux
int nbw_tex = ((texture->pixel_width - 1) >> 3) + 1;
char loop_w_tex = texture->pixel_width-1;
char loop_h_tex = texture->pixel_height-1;
// parcours en ligne
for(int x=min_x; x<=max_x; x++)
{
u0 = u0_start; u1 = u1_start; u2 = u2_start;
z_num = z_num_start;
z_div = z_div_start;
offset_vram = x >> 3;
mask_vram = 128 >> (x & 7);
// parcours en colonne
for(int y=min_y; y<=max_y; y++)
{
// si le pixel (x;y) est dans le triangle
if ((u0 | u1 | u2) > 0)
{
// addresse du z-buffer
address = x + y * z_buffer_width + z_buffer_offset;
// si le pixel (x;y) est plus proche qu'avant
if (z_num <= z_buffer[address] + decoration)
{
// calcul des coordonnees pour la texture
w = ((u0 * w0 + u1 * w1 + u2 * w2) / z_div) & loop_w_tex;
h = ((u0 * h0 + u1 * h1 + u2 * h2) / z_div) & loop_h_tex;
// calcul du masque pour l'octet
mask_w = 128 >> (w & 7);
if (texture->mask == NULL)
{
// enregistre la profondeur du pixel dans le z buffer
z_buffer[address] = z_num;
if ((texture->sprite[(w >> 3) + (h * nbw_tex)] & mask_w))
{
// afficher pixel noir
vram[(y << 4) + offset_vram] |= mask_vram;
}else{
// afficher pixel blanc
vram[(y << 4) + offset_vram] &= ~mask_vram;
}
// curseur
pixel_on_cursor(x, y);
} else {
int alpha = (w >> 3) + (h * nbw_tex);
if ((texture->mask[alpha] & mask_w))
{
// enregistre la profondeur du pixel dans le z buffer
z_buffer[address] = z_num;
if ((texture->sprite[alpha] & mask_w))
{
// afficher pixel noir
vram[(y << 4) + offset_vram] |= mask_vram;
}else{
// afficher pixel blanc
vram[(y << 4) + offset_vram] &= ~mask_vram;
}
// curseur
pixel_on_cursor(x, y);
}
}
}
}
u0 += u0_step_y; u1 += u1_step_y; u2 += u2_step_y;
z_num += z_num_step_y;
z_div += z_div_step_y;
}
u0_start += u0_step_x; u1_start += u1_step_x; u2_start += u2_step_x;
z_num_start += z_num_step_x;
z_div_start += z_div_step_x;
}
}
void Windmill::render_triangle_black(Vertex* vertexA, Vertex* vertexB, Vertex* vertexC)
{
// calcul du rectangle circonscrit au triangle
int min_x = max(viewport.x1, min(vertexA->x, min(vertexB->x, vertexC->x)));
int max_x = min(viewport.x2-1, max(vertexA->x, max(vertexB->x, vertexC->x)));
int min_y = max(viewport.y1, min(vertexA->y, min(vertexB->y, vertexC->y)));
int max_y = min(viewport.y2-1, max(vertexA->y, max(vertexB->y, vertexC->y)));
// calcul de l'aire du triangle
int area = edge(vertexA, vertexB, vertexC);
// termine si la taille du triangle est trop petite
if (area <= MIN_AREA_CLIP) return;
// calcul des produits vectoriels
int u0_start = edge_start(vertexB, vertexC, min_x, min_y);
int u0_step_x = edge_step_x(vertexB, vertexC);
int u0_step_y = edge_step_y(vertexB, vertexC);
int u1_start = edge_start(vertexC, vertexA, min_x, min_y);
int u1_step_x = edge_step_x(vertexC, vertexA);
int u1_step_y = edge_step_y(vertexC, vertexA);
int u2_start = edge_start(vertexA, vertexB, min_x, min_y);
int u2_step_x = edge_step_x(vertexA, vertexB);
int u2_step_y = edge_step_y(vertexA, vertexB);
int z_num_start = (u0_start * vertexA->z_normalized + u1_start * vertexB->z_normalized + u2_start * vertexC->z_normalized) / area;
int z_num_step_x = (u0_step_x * vertexA->z_normalized + u1_step_x * vertexB->z_normalized + u2_step_x * vertexC->z_normalized) / area;
int z_num_step_y = (u0_step_y * vertexA->z_normalized + u1_step_y * vertexB->z_normalized + u2_step_y * vertexC->z_normalized) / area;
// acces a la vram
char* vram = get_vram_address();
unsigned char mask_vram;
int offset_vram;
int address;
int u0, u1, u2;
int z_num;
// parcours en ligne
for(int x=min_x; x<=max_x; x++)
{
u0 = u0_start; u1 = u1_start; u2 = u2_start;
z_num = z_num_start;
offset_vram = x >> 3;
mask_vram = 128 >> (x & 7);
// parcours en colonne
for(int y=min_y; y<=max_y; y++)
{
// si le pixel (x;y) est dans le triangle
if ((u0 | u1 | u2) > 0)
{
// addresse du z-buffer
address = x + y * z_buffer_width + z_buffer_offset;
// si le pixel (x;y) est plus proche qu'avant
if (z_num <= z_buffer[address])
{
// enregistre la profondeur du pixel dans le z buffer
z_buffer[address] = z_num;
// afficher pixel noir
vram[(y << 4) + offset_vram] |= mask_vram;
// curseur
pixel_on_cursor(x, y);
}
}
u0 += u0_step_y; u1 += u1_step_y; u2 += u2_step_y;
z_num += z_num_step_y;
}
u0_start += u0_step_x; u1_start += u1_step_x; u2_start += u2_step_x;
z_num_start += z_num_step_x;
}
}
/*
void Windmill::render_triangle_black(Vertex* vertexA, Vertex* vertexB, Vertex* vertexC)
{
// calcul du rectangle circonscrit au triangle
int min_x = max(viewport.x1, min(vertexA->x, min(vertexB->x, vertexC->x)));
int max_x = min(viewport.x2-1, max(vertexA->x, max(vertexB->x, vertexC->x)));
int min_y = max(viewport.y1, min(vertexA->y, min(vertexB->y, vertexC->y)));
int max_y = min(viewport.y2-1, max(vertexA->y, max(vertexB->y, vertexC->y)));
// calcul de l'aire du triangle
int area = edge(vertexA, vertexB, vertexC);
// termine si la taille du triangle est trop petite
if (area <= MIN_AREA_CLIP) return;
// calcul des produits vectoriels
int u0_start = edge_start(vertexB, vertexC, min_x, min_y);
int u0_step_x = edge_step_x(vertexB, vertexC);
int u0_step_y = edge_step_y(vertexB, vertexC);
int u1_start = edge_start(vertexC, vertexA, min_x, min_y);
int u1_step_x = edge_step_x(vertexC, vertexA);
int u1_step_y = edge_step_y(vertexC, vertexA);
int u2_start = edge_start(vertexA, vertexB, min_x, min_y);
int u2_step_x = edge_step_x(vertexA, vertexB);
int u2_step_y = edge_step_y(vertexA, vertexB);
int z_num_start = (u0_start * vertexA->z_normalized + u1_start * vertexB->z_normalized + u2_start * vertexC->z_normalized) / area;
int z_num_step_x = (u0_step_x * vertexA->z_normalized + u1_step_x * vertexB->z_normalized + u2_step_x * vertexC->z_normalized) / area;
int z_num_step_y = (u0_step_y * vertexA->z_normalized + u1_step_y * vertexB->z_normalized + u2_step_y * vertexC->z_normalized) / area;
// acces a la vram
// char* vram = get_vram_address();
unsigned char mask_vram;
int offset_vram;
int address;
int u0, u1, u2;
int z_num;
// parcours en ligne
for(int x=min_x; x<=max_x; x++)
{
u0 = u0_start; u1 = u1_start; u2 = u2_start;
z_num = z_num_start;
offset_vram = x >> 3;
mask_vram = 128 >> (x & 7);
// parcours en colonne
for(int y=min_y; y<=max_y; y++)
{
// si le pixel (x;y) est dans le triangle
if ((u0 | u1 | u2) > 0)
{
// addresse du z-buffer
address = x + y * z_buffer_width + z_buffer_offset;
// si le pixel (x;y) est plus proche qu'avant
if (z_num <= z_buffer[address])
{
// enregistre la profondeur du pixel dans le z buffer
z_buffer[address] = z_num;
// afficher pixel noir
// vram[(y << 4) + offset_vram] |= mask_vram;
// curseur
pixel_on_cursor(x, y);
}
}
u0 += u0_step_y; u1 += u1_step_y; u2 += u2_step_y;
z_num += z_num_step_y;
}
u0_start += u0_step_x; u1_start += u1_step_x; u2_start += u2_step_x;
z_num_start += z_num_step_x;
}
}
*/
void Windmill::render_triangle_white(Vertex* vertexA, Vertex* vertexB, Vertex* vertexC)
{
// calcul du rectangle circonscrit au triangle
int min_x = max(viewport.x1, min(vertexA->x, min(vertexB->x, vertexC->x)));
int max_x = min(viewport.x2-1, max(vertexA->x, max(vertexB->x, vertexC->x)));
int min_y = max(viewport.y1, min(vertexA->y, min(vertexB->y, vertexC->y)));
int max_y = min(viewport.y2-1, max(vertexA->y, max(vertexB->y, vertexC->y)));
// calcul de l'aire du triangle
int area = edge(vertexA, vertexB, vertexC);
// termine si la taille du triangle est trop petite
if (area <= MIN_AREA_CLIP) return;
// calcul des produits vectoriels
int u0_start = edge_start(vertexB, vertexC, min_x, min_y);
int u0_step_x = edge_step_x(vertexB, vertexC);
int u0_step_y = edge_step_y(vertexB, vertexC);
int u1_start = edge_start(vertexC, vertexA, min_x, min_y);
int u1_step_x = edge_step_x(vertexC, vertexA);
int u1_step_y = edge_step_y(vertexC, vertexA);
int u2_start = edge_start(vertexA, vertexB, min_x, min_y);
int u2_step_x = edge_step_x(vertexA, vertexB);
int u2_step_y = edge_step_y(vertexA, vertexB);
int z_num_start = (u0_start * vertexA->z_normalized + u1_start * vertexB->z_normalized + u2_start * vertexC->z_normalized) / area;
int z_num_step_x = (u0_step_x * vertexA->z_normalized + u1_step_x * vertexB->z_normalized + u2_step_x * vertexC->z_normalized) / area;
int z_num_step_y = (u0_step_y * vertexA->z_normalized + u1_step_y * vertexB->z_normalized + u2_step_y * vertexC->z_normalized) / area;
// acces a la vram
char* vram = get_vram_address();
unsigned char mask_vram;
int offset_vram;
int address;
int u0, u1, u2;
int z_num;
// parcours en ligne
for(int x=min_x; x<=max_x; x++)
{
u0 = u0_start; u1 = u1_start; u2 = u2_start;
z_num = z_num_start;
offset_vram = x >> 3;
mask_vram = 128 >> (x & 7);
// parcours en colonne
for(int y=min_y; y<=max_y; y++)
{
// si le pixel (x;y) est dans le triangle
if ((u0 | u1 | u2) > 0)
{
// addresse du z-buffer
address = x + y * z_buffer_width + z_buffer_offset;
// si le pixel (x;y) est plus proche qu'avant
if (z_num <= z_buffer[address])
{
// enregistre la profondeur du pixel dans le z buffer
z_buffer[address] = z_num;
// afficher pixel blanc
vram[(y << 4) + offset_vram] &= ~mask_vram;
// curseur
pixel_on_cursor(x, y);
}
}
u0 += u0_step_y; u1 += u1_step_y; u2 += u2_step_y;
z_num += z_num_step_y;
}
u0_start += u0_step_x; u1_start += u1_step_x; u2_start += u2_step_x;
z_num_start += z_num_step_x;
}
}
void Windmill::render_triangle_transparent(Vertex* vertexA, Vertex* vertexB, Vertex* vertexC, const Texture* texture)
{
// calcul du rectangle circonscrit au triangle
int min_x = max(viewport.x1, min(vertexA->x, min(vertexB->x, vertexC->x)));
int max_x = min(viewport.x2-1, max(vertexA->x, max(vertexB->x, vertexC->x)));
int min_y = max(viewport.y1, min(vertexA->y, min(vertexB->y, vertexC->y)));
int max_y = min(viewport.y2-1, max(vertexA->y, max(vertexB->y, vertexC->y)));
// calcul de l'aire du triangle
int area = edge(vertexA, vertexB, vertexC);
// termine si la taille du triangle est trop petite
if (area <= MIN_AREA_CLIP) return;
// pre-calcul des coordonnees de la texture
int w0 = vertexA->w * vertexA->z; int h0 = vertexA->h * vertexA->z;
int w1 = vertexB->w * vertexB->z; int h1 = vertexB->h * vertexB->z;
int w2 = vertexC->w * vertexC->z; int h2 = vertexC->h * vertexC->z;
// calcul des produits vectoriels
int u0_start = edge_start(vertexB, vertexC, min_x, min_y);
int u0_step_x = edge_step_x(vertexB, vertexC);
int u0_step_y = edge_step_y(vertexB, vertexC);
int u1_start = edge_start(vertexC, vertexA, min_x, min_y);
int u1_step_x = edge_step_x(vertexC, vertexA);
int u1_step_y = edge_step_y(vertexC, vertexA);
int u2_start = edge_start(vertexA, vertexB, min_x, min_y);
int u2_step_x = edge_step_x(vertexA, vertexB);
int u2_step_y = edge_step_y(vertexA, vertexB);
int z_num_start = (u0_start * vertexA->z_normalized + u1_start * vertexB->z_normalized + u2_start * vertexC->z_normalized) / area;
int z_num_step_x = (u0_step_x * vertexA->z_normalized + u1_step_x * vertexB->z_normalized + u2_step_x * vertexC->z_normalized) / area;
int z_num_step_y = (u0_step_y * vertexA->z_normalized + u1_step_y * vertexB->z_normalized + u2_step_y * vertexC->z_normalized) / area;
int z_div_start = u0_start * vertexA->z + u1_start * vertexB->z + u2_start * vertexC->z;
int z_div_step_x = u0_step_x * vertexA->z + u1_step_x * vertexB->z + u2_step_x * vertexC->z;
int z_div_step_y = u0_step_y * vertexA->z + u1_step_y * vertexB->z + u2_step_y * vertexC->z;
// acces a la vram
char* vram = get_vram_address();
// pre-calcul largeur en octet des tableaux
int nbw_tex = ((texture->pixel_width - 1) >> 3) + 1;
char loop_w_tex = texture->pixel_width-1;
char loop_h_tex = texture->pixel_height-1;
// parcours en ligne
for(int x=min_x; x<=max_x; x++)
{
int u0 = u0_start; int u1 = u1_start; int u2 = u2_start;
int z_num = z_num_start;
int z_div = z_div_start;
int offset_vram = x >> 3;
char mask_vram = 128 >> (x & 7);
// parcours en colonne
for(int y=min_y; y<=max_y; y++)
{
// si le pixel (x;y) est dans le triangle
if ((u0 | u1 | u2) > 0)
{
// addresse du z-buffer
int address = x + y * z_buffer_width + z_buffer_offset;
// si le pixel (x;y) est plus proche qu'avant
if (z_num <= z_buffer[address])
{
// calcul des coordonnees pour la texture
unsigned int w = ((u0 * w0 + u1 * w1 + u2 * w2) / z_div) & loop_w_tex;
unsigned int h = ((u0 * h0 + u1 * h1 + u2 * h2) / z_div) & loop_h_tex;
// calcul du masque pour l'octet
unsigned char mask_w = 128 >> (w & 7);
if ((texture->sprite[(w >> 3) + (h * nbw_tex)] & mask_w))
{
// afficher pixel noir
vram[(y << 4) + offset_vram] |= mask_vram;
// enregistre la profondeur du pixel dans le z buffer
z_buffer[address] = z_num;
}
}
}
u0 += u0_step_y; u1 += u1_step_y; u2 += u2_step_y;
z_num += z_num_step_y;
z_div += z_div_step_y;
}
u0_start += u0_step_x; u1_start += u1_step_x; u2_start += u2_step_x;
z_num_start += z_num_step_x;
z_div_start += z_div_step_x;
}
}
/*
//-----------------------------------------------------------------------------
// load_map
// Ritter's bounding sphere
//-----------------------------------------------------------------------------
void Windmill::load_map(Map* _map)
{
if (map != _map)
{
map = _map;
delete[] sphere;
sphere = new Bounding_Sphere [map->list_object_length];
for (int i = 0; i<map->list_object_length; i++)
{
Object* current_object = map->object[i];
int nb_point;
for (int j = 0; j<current_object->modele_size; j++)
{
nb_point += current_object->modele[j].type;
}
Point* point = get_point(current_object, 0);
int min_x = point->x;
int min_y = point->y;
int min_z = point->z;
int max_x = min_x;
int max_y = min_y;
int max_z = min_z;
for (int j = 0; j<nb_point)
{
point = get_point(j);
if(point->x < min_x)
min_x = point->x;
if(point->y < min_y)
min_y = point->y;
if(point->z < min_z)
min_z = point->z;
if(point->x > max_x)
max_x = point->x;
if(point->y > max_y)
max_y = point->y;
if(point->z > max_z)
max_z = point->z;
}
int xdiff = max_x - min_x;
int ydiff = max_y - min_y;
int zdiff = max_z - min_y;
int diameter = max(xdiff, max(ydiff, zdiff)); //take max as diameter
glm::vec3 centre = (vmax+vmin)*(0.5f);
float radius = diameter/2;
float sq_radius = radius*radius;
for(int i=0; i<num_vertices; i++)
{
glm::vec3 point = vertices[i];
glm::vec3 direction = point - centre;
float sq_distance = glm::length2(direction);
if(sq_distance > sq_radius)
{
float distance = sqrt(sq_distance);
float difference = distance - radius;
float new_diameter = 2 * radius + difference;
sq_radius = radius * radius;
difference /= 2;
centre += difference * direction;
}
}
}
}
}*/
//----------------------------------------------------------------------------------------------------
// MANIPULATION
//----------------------------------------------------------------------------------------------------
Point Windmill::get_point(const Modele* poly, int i)
{
Point point;
if (i == 0)
{
point.x = poly->x0; point.y = poly->y0; point.z = poly->z0;
}
if (i == 1)
{
point.x = poly->x1; point.y = poly->y1; point.z = poly->z1;
}
if (i == 2)
{
point.x = poly->x2; point.y = poly->y2; point.z = poly->z2;
}
if (i == 3)
{
if (poly->option == PARA)
{
point.x = poly->x2 + poly->x1 - poly->x0;
point.y = poly->y2 + poly->y1 - poly->y0;
point.z = poly->z2 + poly->z1 - poly->z0;
} else if (poly->option == TRAP)
{
point.x = poly->x2 - poly->x1 + poly->x0;
point.y = poly->y2 - poly->y1 + poly->y0;
point.z = poly->z2 - poly->z1 + poly->z0;
}
}
return point;
}
Point Windmill::get_center_poly(const Modele* poly)
{
Point point;
point.x = 0; point.y = 0; point.z = 0;
for (int i = 0; i < poly->type; i++)
{
point.x += get_point(poly, i).x;
point.y += get_point(poly, i).y;
point.z += get_point(poly, i).z;
}
point.x /= poly->type;
point.y /= poly->type;
point.z /= poly->type;
return point;
}
void Windmill::compute_object_angle(Object* object, int* cosinus, int* sinus)
{
if (object->axe == Z_BILLBOARD)
{
float angle_look_at_camera = atan2f(camera.y - object->y, camera.x - object->x);
float angle_rad = angle_look_at_camera + 3.1415 * object->angle / 180.0;
*cosinus = 1024 * cosf(angle_rad);
*sinus = 1024 * sinf(angle_rad);
}
if (object->axe == X or object->axe == Y or object->axe == Z)
{
float angle_rad = 3.1415 * object->angle / 180.0;
*cosinus = 1024 * cosf(angle_rad);
*sinus = 1024 * sinf(angle_rad);
}
}
void Windmill::extract_vertex_from_poly(const Modele* poly, Vertex* vertex, int* vertex_length, int* width, int* height)
{
int x0, y0, z0, x1, y1, z1, x2, y2, z2, x3, y3, z3;
if (poly->type == TRIANGLE)
{
*vertex_length = 3;
x0 = poly->x0; y0 = poly->y0; z0 = poly->z0;
x1 = poly->x1; y1 = poly->y1; z1 = poly->z1;
x2 = poly->x2; y2 = poly->y2; z2 = poly->z2;
vertex[0].set_xyz(x0, y0, z0);
vertex[1].set_xyz(x1, y1, z1);
vertex[2].set_xyz(x2, y2, z2);
*width = distance(x0-x1, y0-y1, z0-z1);
*height = distance(x0-x2, y0-y2, z0-z2);
}
if (poly->type == RECTANGLE)
{
*vertex_length = 4;
x0 = poly->x0; y0 = poly->y0; z0 = poly->z0;
x1 = poly->x1; y1 = poly->y1; z1 = poly->z1;
x3 = poly->x2; y3 = poly->y2; z3 = poly->z2;
if (poly->option == PARA)
{
x2 = x3 + x1 - x0; y2 = y3 + y1 - y0; z2 = z3 + z1 - z0;
} else if (poly->option == TRAP)
{
//x2 = x3 - x1 + x0; y2 = y3 - y1 + y0; z2 = z3 - z1 + z0;
}
vertex[0].set_xyz(x0, y0, z0);
vertex[1].set_xyz(x1, y1, z1);
vertex[2].set_xyz(x2, y2, z2);
vertex[3].set_xyz(x3, y3, z3);
*width = distance(x0-x1, y0-y1, z0-z1);
*height = distance(x0-x3, y0-y3, z0-z3);
}
}
void Windmill::texture_coordinates(const Modele* poly, Vertex* vertex, const Texture* texture, int visible, int width, int height)
{
int w = (texture->real_width > 0) ? width * texture->pixel_width / texture->real_width : texture->pixel_width;
int h = (texture->real_height > 0) ? height * texture->pixel_height / texture->real_height : texture->pixel_height;
if (poly->type == TRIANGLE)
{
int offset = w * texture->offset;
if (visible == FRONT or texture->mirror == true)
{
vertex[0].set_wh(0, texture->pixel_height);
vertex[1].set_wh(w, texture->pixel_height);
vertex[2].set_wh(offset, texture->pixel_height-h);
// vertex[0].set_wh(0, h);
// vertex[1].set_wh(w, h);
// vertex[2].set_wh(offset, 0);
} else {
vertex[0].set_wh(w, h);
vertex[1].set_wh(0, h);
vertex[2].set_wh(w-offset, 0);
}
}
else if (poly->type == RECTANGLE)
{
if (visible == FRONT or texture->mirror == true)
{
vertex[0].set_wh(0, texture->pixel_height);
vertex[1].set_wh(w, texture->pixel_height);
vertex[2].set_wh(w, texture->pixel_height-h);
vertex[3].set_wh(0, texture->pixel_height-h);
// vertex[0].set_wh(0, h);
// vertex[1].set_wh(w, h);
// vertex[2].set_wh(w, 0);
// vertex[3].set_wh(0, 0);
} else {
vertex[0].set_wh(w, h);
vertex[1].set_wh(0, h);
vertex[2].set_wh(0, 0);
vertex[3].set_wh(w, 0);
}
}
}
void Windmill::swap_vertex(Vertex* vertexA, Vertex* vertexB)
{
Vertex vertex_temp;
memcpy(&vertex_temp, vertexA, sizeof(Vertex));
memcpy(vertexA, vertexB, sizeof(Vertex));
memcpy(vertexB, &vertex_temp, sizeof(Vertex));
}
void Windmill::copy_vertex(Vertex* vertex_source, Vertex* vertex_dest)
{
memcpy(vertex_dest, vertex_source, sizeof(Vertex));
}
//----------------------------------------------------------------------------------------------------
// SPHERE
//----------------------------------------------------------------------------------------------------
Sphere Windmill::transform_sphere_to_world(Sphere* sphere_input, Object* object, int cosinus, int sinus)
{
Vertex vertex;
vertex.set_xyz(sphere_input->x, sphere_input->y, sphere_input->z);
transform_model_to_world(&vertex, 1, object, cosinus, sinus);
transform_world_to_camera(&vertex, 1);
Sphere sphere_output;
sphere_output.x = vertex.x >> 7;
sphere_output.y = vertex.y >> 7;
sphere_output.z = vertex.z >> 7;
sphere_output.radius = sphere_input->radius;
return sphere_output;
}
/*
bool Windmill::sphere_in_cone(Sphere* sphere)
{
//return true;
int cone_offset = sphere->radius * camera.sin_fov;
int nx = camera.nx;
int ny = camera.ny;
int nz = camera.nz;
Point cone;
cone.x = int(camera.x) - ((nx * cone_offset) >> 14);
cone.y = int(camera.y) - ((ny * cone_offset) >> 14);
cone.z = int(camera.z) - ((nz * cone_offset) >> 14);
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;
}*/
bool Windmill::sphere_in_cone(Sphere* sphere)
{
//return true;
sphere->z += sphere->radius;
if (sphere->z > 0)
{
int sphere_z = int(sphere->z * camera.scale_coef) >> 6;
int xr = 0;
if (sphere->x > 0) xr = sphere->x - sphere->radius;
if (sphere->x < 0) xr = - sphere->x - sphere->radius;
if (xr <= sphere_z) return true;
}
return false;
}
//----------------------------------------------------------------------------------------------------
// DIVERS
//----------------------------------------------------------------------------------------------------
void Windmill::copy_camera()
{
memcpy(&camera, camera2, sizeof(Camera));
}
void Windmill::sort_object()
{
//qsort(object, list_object_length, sizeof(Object*), compare_object);
}
int compare_object(void const *a, void const *b)
{
Object* object_a = *(Object **) a;
Object* object_b = *(Object **) b;
return (object_a->distance_to_camera - object_b->distance_to_camera);
}
void Windmill::clear_z_buffer()
{
memset(z_buffer, MAX_DEPTH_Z_BUFFER, z_buffer_size * sizeof(short));
}
int Windmill::edge(Vertex* a, Vertex* b, Vertex* c)
{
return (c->x - a->x) * (b->y - a->y) - (c->y - a->y) * (b->x - a->x);
}
int Windmill::edge_start(Vertex* a, Vertex* b, int px, int py)
{
return (b->y - a->y) * (px - a->x) - (b->x - a->x) * (py - a->y);
}
int Windmill::edge_step_x(Vertex* a, Vertex* b)
{
return b->y - a->y;
}
int Windmill::edge_step_y(Vertex* a, Vertex* b)
{
return a->x - b->x;
}
//----------------------------------------------------------------------------------------------------
// UTILITAIRE
//----------------------------------------------------------------------------------------------------
void Windmill::pixel_on_cursor(int x, int y)
{
if (x == cursor_x and y == cursor_y)
{
temp_object_cursor = object[i];
temp_poly_cursor = j;
}
}
void Windmill::show_coordinates()
{
// coordonnees
float tab_coordinates[5] = {camera.x, camera.y, camera.z, to_deg(camera.yaw), to_deg(camera.pitch)};
for (int i = 0; i < 5; i++)
{
/*
char str[20];
sprintf(str, "%f", tab_coordinates[i]);
int j;
for(j= 0; j < 16; j++)
{
if (str[j] == '.')
{
str[j+2] = '\0';
break;
}
}
PrintMini(127-4*(j+2), 1+6*i, (unsigned char*)str, MINI_OVER);*/
dprint(0, 1+6*i, C_BLACK, "%f", tab_coordinates[i]); // need Gint
}
}
void Windmill::show_repere()
{/*
// repere
int repere_x = 112;
int repere_y = 55;
int repere_size = 12;
float camera_yaw_rad = -camera.yaw;//- 3.1415 * camera.yaw / 180.0;
float camera_pitch_rad = camera.pitch;//3.1415 * camera.pitch / 180.0;
float cos_yaw = cosf(camera_yaw_rad);
float sin_yaw = sinf(camera_yaw_rad);
float cos_pitch = cosf(camera_pitch_rad);
float sin_pitch = sinf(camera_pitch_rad);
float aa4 = sin_yaw;
float aa5 = cos_yaw;
float aa6 = 0;
float aa7 = -sin_pitch * cos_yaw;
float aa8 = sin_pitch * sin_yaw;
float aa9 = cos_pitch;
// repere
Vertex v[3];
//const unsigned char* cx = "x";
//const unsigned char* cy = "y";
//const unsigned char* cz = "z";
const char* letter[] = {"x", "y", "z"};
v[0].set_xyz(repere_size, 0 , 0 );
v[1].set_xyz(0 , repere_size, 0 );
v[2].set_xyz(0 , 0 , repere_size);
for (int i = 0; i < 3; i++)
{
float y = (aa4 * v[i].x + aa5 * v[i].y + aa6 * v[i].z);
float z = (aa7 * v[i].x + aa8 * v[i].y + aa9 * v[i].z);
v[i].x = -y;
v[i].y = -z;
//ML_line(repere_x, repere_y, v[i].x + repere_x, v[i].y + repere_y, ML_BLACK);
//PrintMini(v[i].x + repere_x, v[i].y + repere_y-2, letter[i], MINI_OVER);
}
*/
}
/*void Windmill::show_fps()
{
char str[20];
sprintf(str, "%i", time_get_fps());
PrintMini(1, 58, (unsigned char*)str, MINI_OVER);
}*/
//----------------------------------------------------------------------------------------------------
// DESTRUCTEUR
//----------------------------------------------------------------------------------------------------
Windmill::~Windmill()
{
free(z_buffer);
free(object);
//delete[] object;
}
float distance(float dx, float dy, float dz)
{
return sqrtf(dx*dx + dy*dy + dz*dz);
}
Vertex::Vertex(){}
void Vertex::set_xyz(int _x, int _y, int _z)
{
x = _x;
y = _y;
z = _z;
}
void Vertex::set_wh(float _w, float _h)
{
w = _w;
h = _h;
}
float Vertex::length(int x, int y, int z)
{
return sqrtf(x*x + y*y + z*z);
}