122 lines
4.4 KiB
C
122 lines
4.4 KiB
C
|
/* *****************************************************************************
|
||
|
* 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;
|
||
|
}
|
||
|
}
|