/* ***************************************************************************** * render.c -- draw the triangles. * Copyright (C) 2017 Olivier "Ninestars" Lanneau * Copyright (C) 2017 Thomas "Cakeisalie5" Touhey * * 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 . * ************************************************************************** */ #include 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; } }