windmill-gint/src/windmill.cpp

1789 lines
50 KiB
C++
Raw Normal View History

2021-06-18 11:48:50 +02:00
//----------------------------------------------------------------------------------------------------
//
// 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);
}