libwindmill/src/render.c

122 lines
4.4 KiB
C
Raw Normal View History

/* *****************************************************************************
* render.c -- draw the triangles.
* Copyright (C) 2017 Olivier "Ninestars" Lanneau
* Copyright (C) 2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
*
* This file is part of libwindmill.
* libwindmill is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3.0 of the License,
* or (at your option) any later version.
*
* libwindmill is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with libwindmill; if not, see <http://www.gnu.org/licenses/>.
* ************************************************************************** */
#include <libwindmill/internals.h>
void wml_render_triangle(wml_scene_t *scene,
wml_vertex_t *vertex1, wml_vertex_t *vertex2, wml_vertex_t *vertex3,
wml_texture_t *texture)
{
/* calcul du rectangle circonscrit au triangle */
int min_x = max(scene->viewport_x1 - 64,
min(vertex0->x, min(vertex1->x, vertex2->x)));
int max_x = min(scene->viewport_x2 - 64,
max(vertex0->x, max(vertex1->x, vertex2->x)));
int min_y = max(scene->viewport_y1 - 32,
min(vertex0->y, min(vertex1->y, vertex2->y)));
int max_y = min(scene->viewport_y2 - 32,
max(vertex0->y, max(vertex1->y, vertex2->y)));
/* pré-calcul des coordonnées de la texture */
int tx0 = vertex0->tx * vertex0->z;
int ty0 = vertex0->ty * vertex0->z;
int tx1 = vertex1->tx * vertex1->z;
int ty1 = vertex1->ty * vertex1->z;
int tx2 = vertex2->tx * vertex2->z;
int tx2 = vertex2->ty * vertex2->z;
/* calcul des produits vectoriels */
int px = min_x, py = min_y;
int w0_start = wml_edge_start(vertex1, vertex2, px, py);
int w0_step_x = wml_edge_step_x(vertex1, vertex2);
int w0_step_y = wml_edge_step_y(vertex1, vertex2);
int w1_start = wml_edge_start(vertex2, vertex0, px, py);
int w1_step_x = wml_edge_step_x(vertex2, vertex0);
int w1_step_y = wml_edge_step_y(vertex2, vertex0);
int w2_start = wml_edge_start(vertex0, vertex1, px, py);
int w2_step_x = wml_edge_step_x(vertex0, vertex1);
int w2_step_y = wml_edge_step_y(vertex0, vertex1);
/* calcul de l'aire du triangle */
int area = wml_edge(vertex0, vertex1, vertex2);
/* ? */
int z_num_start = (w0_start * vertex0->z_normalized
+ w1_start * vertex1->z_normalized
+ w2_start * vertex2->z_normalized) / area;
int z_num_step_x = (w0_step_x * vertex0->z_normalized
+ w1_step_x * vertex1->z_normalized
+ w2_step_x * vertex2->z_normalized) / area;
int z_num_step_y = (w0_step_y * vertex0->z_normalized
+ w1_step_y * vertex1->z_normalized
+ w2_step_y * vertex2->z_normalized) / area;
/* ? */
int z_div_start = w0_start * vertex0->z
+ w1_start * vertex1->z
+ w2_start * vertex2->z;
int z_div_step_x = w0_step_x * vertex0->z
+ w1_step_x * vertex1->z
+ w2_step_x * vertex2->z;
int z_div_step_y = w0_step_y * vertex0->z
+ w1_step_y * vertex1->z
+ w2_step_y * vertex2->z;
/* pré-calcul largeur en octet des tableaux */
int nbw_tex = (texture->width - 1) / 8 + 1;
for (int x = min_x; x <= max_x; x++) {
int w0 = w0_start, w1 = w1_start, w2 = w2_start;
int z_num = z_num_start, z_div = z_div_start;
int offset_vram = (x >> 3) + 520;
char mask_vram = 128 >> (x & 7);
/* parcours en colonne */
for (int y = min_y; y <= max_y; y++) {
if (w0 >= 0 && w1 >= 0 && w2 >= 0 && z_num > 0) {
int address = x + y * z_buffer_width + z_buffer_offset;
if (z_num <= z_buffer[address]) {
z_buffer[address] = z_num;
/* calcul des coordonnées pour la texture */
int f_tx = (w0 * tx0 + w1 * tx1 + w2 * tx2) / z_div;
int f_ty = (w0 * ty0 + w1 * ty1 + w2 * ty2) / z_div;
/* calcul du masque pour l'octet */
char mask_tx = 128 >> (f_tx & 7);
int black = texture->sprite[(f_tx >> 3) + (f_ty * nbw_tex)]
& mask_tx;
/* affichage du pixel */
if (black) vram[(y << 4) + offset_vram] |= mask_vram;
else vram[(y << 4) + offset_vram] &= ~mask_vram;
}
}
w0 += w0_step_y;
w1 += w1_step_y;
w2 += w2_step_y;
z_num += z_num_step_y;
z_div += z_div_step_y;
}
w0_start += w0_step_x;
w1_start += w1_step_x;
w2_start += w2_step_x;
z_num_start += z_num_step_x;
z_div_start += z_div_step_x;
}
}