windmill-gint/src/windmill_draw.cpp

948 lines
29 KiB
C++

//----------------------------------------------------------------------------------------------------
//
// WINDMILL
//
// version : 2.0
// Moteur de rendu 3D base sur la methode de rasterisation avec buffer de profondeur
//
// Cree par Olivier Lanneau, alias NineStars
// Planet-casio.fr
//
//----------------------------------------------------------------------------------------------------
#include "windmill.hpp"
void debug_pop(char const *fmt, ...);
void debug_display(char const *fmt, ...);
extern Texture tex_white;
extern Texture tex_light;
extern Texture tex_dark;
extern Texture tex_black;
//----------------------------------------------------------------------------------------------------
// 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 les ombres
// draw_shadows();
// 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 debug
if (log)
{
//show_fps();
//show_coordinates();
show_repere();
}
}
void Windmill::draw_horizon()
{
int distance = 1000;
int hx = camera.x + distance * camera.cos_yaw;
int hy = camera.y + distance * camera.sin_yaw;
std::vector<Vertex> horizon = {Vertex(hx, hy, 0)};
transform_world_to_camera(horizon);
transform_camera_to_screen(horizon);
if (inside_viewport(horizon[0].x, horizon[0].y))
{
dline(viewport.x1, horizon[0].y, viewport.x2, horizon[0].y, C_BLACK);
}
}
void Windmill::draw_ground()
{
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;
std::vector<Vertex> ground = {Vertex(x, y, 0)};
transform_world_to_camera(ground);
if (ground[0].z > 0)
{
transform_camera_to_screen(ground);
if (inside_viewport(ground[0].x, ground[0].y) == true)
{
dpixel(ground[0].x, ground[0].y, C_BLACK);
}
}
}
}
}
}
void Windmill::draw_objects()
{
// pour chaque objet
for(i=0; i<map->object_length; i++)
{
// récupère l'objet en cours
Object* object = map->object[i];
//Object* object = objects[i];
//int f_visible = 0;
// si l'objet est totalement ou partie dans le frustrum
if (object-> visible && object_in_frustrum(object))
{
// copie le mesh avec plus de memoires disponible pour possiblement ajouter des points au clipping
WMesh mesh;
mesh.from_mesh(object->mesh);
// calcul des coordonnees dans le repère monde apres rotation et translation de l objet
transform_model_to_world(object, mesh.v);
// calcul des coordonnees dans le repère camera apres rotation et translation de la camera
transform_world_to_camera(mesh.v);
// coupe 3D selon le frustrum de la camera
clip_frustrum(mesh); // SI OBJECT IN FRUSTRUM DIT QUE L'OBJET EST PARTEILLEMENT DANS FRUSTRUM
// calcul des coordonnes apres perspective et decalage au centre de l ecran
transform_camera_to_screen(mesh.v);
if (log)
{
for (int v = 0; v<mesh.v.size(); v++)
{
dpixel(mesh.v[v].x, mesh.v[v].y, C_BLACK);
}
}
else
{
// dessine tous les triangles
render_triangles(mesh);
}
/*if (log)
{
debug_pop("LOG MODE\nf_length = %i", mesh.f_length);
for (int i=0; i<mesh.f_length; i++)
{
debug_pop("f%i\n%i %i %i\n%i %i %i", i, mesh.f[i].v[0], mesh.f[i].v[1], mesh.f[i].v[2], mesh.f[i].t[0], mesh.f[i].t[1],mesh.f[i].t[2]);
}
debug_pop("LOG MODE\nv_length = %i", mesh.v_length);
for (int i=0; i<mesh.v_length; i++)
{
debug_pop("v%i\nx %i\ny %i\nz %i", i, mesh.v[i].x, mesh.v[i].y, mesh.v[i].z);
}
debug_pop("LOG MODE\nt_length = %i", mesh.t_length);
for (int i=0; i<mesh.t_length; i++)
{
debug_pop("t%i\nu %f\nv %f", i, mesh.t[i].u, mesh.t[i].v);
}
log = false;
}*/
mesh.free_memory();
}
}
}
void Windmill::draw_post_treatment()
{
char* vram = get_vram_address();
unsigned char mask;
int current, right, bottom;
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[(y << 4) + ((x+1) >> 3)] |= mask;
}
if (bottom < MAX_DEPTH_Z_BUFFER)
{
mask = 128 >> (x & 7);
vram[(y << 4) + (x >> 3) + 16] |= mask;
}
} else {
if (right == MAX_DEPTH_Z_BUFFER or bottom == MAX_DEPTH_Z_BUFFER)
{
mask = 128 >> (x & 7);
vram[(y << 4) + (x >> 3) + 16] |= mask;
}
}
}
} // 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...
*/
}
//----------------------------------------------------------------------------------------------------
// DESSIN DES TRIANGLES
//----------------------------------------------------------------------------------------------------
void Windmill::render_triangles(WMesh &mesh)
{
for (int f = 0; f<mesh.f.size(); f++)
{
Face triangle = mesh.f[f];
if (triangle.visible)
{
for (int i=0; i<3; i++)
{
mesh.v[triangle.v[i]].set_texture(mesh.t[triangle.t[i]]);
}
// determine quelle face du triangle est visible
int visible_face = get_visible_face(&mesh.v[triangle.v[0]], &mesh.v[triangle.v[1]], &mesh.v[triangle.v[2]]);
// choisi la texture visible
const Texture* visible_texture = (visible_face == FRONT) ? triangle.texture_front : triangle.texture_back;
// selectionne l'ordre d'affichage
int a = 0, b = 1, c = 2;
if (visible_face != FRONT) {b = 2; c = 1;}
// pour chaque type de texture
if (visible_texture == NULL)
{
// ne rien faire
}
else if (visible_texture == &tex_white)
{
render_triangle_color(&mesh.v[triangle.v[a]], &mesh.v[triangle.v[b]], &mesh.v[triangle.v[c]], C_WHITE);
}
else if (visible_texture == &tex_light)
{
render_triangle_color(&mesh.v[triangle.v[a]], &mesh.v[triangle.v[b]], &mesh.v[triangle.v[c]], C_LIGHT);
}
else if (visible_texture == &tex_dark)
{
render_triangle_color(&mesh.v[triangle.v[a]], &mesh.v[triangle.v[b]], &mesh.v[triangle.v[c]], C_DARK);
}
else if (visible_texture == &tex_black)
{
render_triangle_color(&mesh.v[triangle.v[a]], &mesh.v[triangle.v[b]], &mesh.v[triangle.v[c]], C_BLACK);
}
else
{
render_triangle_texture(&mesh.v[triangle.v[a]], &mesh.v[triangle.v[b]], &mesh.v[triangle.v[c]], visible_texture);
}
}
}
}
void Windmill::render_triangle_texture(Vertex* vertexA, Vertex* vertexB, Vertex* vertexC, const Texture* texture)
{
// calcul de l'aire du triangle
int area = edge(vertexA, vertexB, vertexC);
if (area <= MIN_AREA_CLIP) return;
// 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)));
// ajustement des coordonnees des textures a la taille en pixel
vertexA->u *= texture->pixel_width;
vertexA->v *= texture->pixel_height;
vertexB->u *= texture->pixel_width;
vertexB->v *= texture->pixel_height;
vertexC->u *= texture->pixel_width;
vertexC->v *= texture->pixel_height;
// pre-calcul des coordonnees de la texture << 13 => tex_w * 8192 / x
int w0 = vertexA->u * vertexA->inv_z; int h0 = vertexA->v * vertexA->inv_z;
int w1 = vertexB->u * vertexB->inv_z; int h1 = vertexB->v * vertexB->inv_z;
int w2 = vertexC->u * vertexC->inv_z; int h2 = vertexC->v * vertexC->inv_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);
// << 15
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;
// << 13
int z_div_start = u0_start * vertexA->inv_z + u1_start * vertexB->inv_z + u2_start * vertexC->inv_z;
int z_div_step_x = u0_step_x * vertexA->inv_z + u1_step_x * vertexB->inv_z + u2_step_x * vertexC->inv_z;
int z_div_step_y = u0_step_y * vertexA->inv_z + u1_step_y * vertexB->inv_z + u2_step_y * vertexC->inv_z;
// rapprochement artificiel si texture de type decoration
int decoration = 0;//(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
dpixel(x, y, C_BLACK);
//vram[(y << 4) + offset_vram] |= mask_vram;
}else{
// afficher pixel blanc
dpixel(x, y, C_WHITE);
//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_color(Vertex* vertexA, Vertex* vertexB, Vertex* vertexC, color_t color)
{
// calcul de l'aire du triangle
int area = edge(vertexA, vertexB, vertexC);
if (area <= MIN_AREA_CLIP) return;
// 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 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
dpixel(x, y, color);
}
}
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_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;
}
}*/
//----------------------------------------------------------------------------------------------------
// UTILITAIRES
//----------------------------------------------------------------------------------------------------
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;
}