948 lines
29 KiB
C++
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;
|
|
}
|