/* ***************************************************************************** * draw.c -- draw the scene. * 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 /* ************************************************************************** */ /* Rectangle */ /* ************************************************************************** */ static void render_rectangle_part(wml_scene_t *scene, wml_texture_t *texture, wml_vertex_t *vertex0, wml_vertex_t *vertex1, wml_vertex_t *vertex2, wml_vertex_t *vertex3) { if (texture == hidden) { /* do nothing */ } else if (texture == scene->black) { wml_render_triangle_black(scene, vertex0, vertex1, vertex2); wml_render_triangle_black(scene, vertex1, vertex3, vertex2); } else if (texture == scene->white) { wml_render_triangle_white(scene, vertex0, vertex1, vertex2); wml_render_triangle_white(scene, vertex1, vertex3, vertex2); } else { wml_set_vertex_txy(vertex0, 0, texture->height); wml_set_vertex_txy(vertex1, texture->width, texture->height); wml_set_vertex_txy(vertex2, 0, 0); wml_set_vertex_txy(vertex3, texture->width, 0); wml_render_triangle(scene, vertex0, vertex1, vertex2, texture); wml_render_triangle(scene, vertex1, vertex3, vertex2, texture); } } static void render_rectangle(wml_scene_t *scene, wml_polygon_t *polygon, float cosinus, float sinus) { wml_vertex_t vertex0, vertex1, vertex2, vertex3; int x0 = polygon->x0, y0 = polygon->y0, z0 = polygon->z0; int x1 = polygon->x1, y1 = polygon->y1, z1 = polygon->z1; int x2 = polygon->x2, y2 = polygon->y2, z2 = polygon->z2; int x3 = x1 + x2 - x0, y3 = y1 + y2 - y0, z3 = z1 + z2 - z0; wml_set_vertex_xyz(&vertex0, x0, y0, z0); wml_set_vertex_xyz(&vertex1, x1, y1, z1); wml_set_vertex_xyz(&vertex2, x2, y2, z2); wml_set_vertex_xyz(&vertex3, x3, y3, z3); /* object dynamique */ wml_dynamic(&vertex0, polygon->axe, current_object->x, polygon->y, cosinus, sinus); wml_dynamic(&vertex1, polygon->axe, current_object->x, polygon->y, cosinus, sinus); wml_dynamic(&vertex2, polygon->axe, current_object->x, polygon->y, cosinus, sinus); wml_dynamic(&vertex3, polygon->axe, current_object->x, polygon->y, cosinus, sinus); /* calcul des coordonnées après rotation de la caméra et projection * des coordonnées 3D sur l'écran */ wml_transform(&vertex0); wml_transform(&vertex1); wml_transform(&vertex2); wml_transform(&vertex3); /* si devant la caméra */ if (vertex0.z < 0 && vertex1.z < 0 && vertex2.z < 0 && vertex3.z < 0) { int area = wml_edge(&vertex0, &vertex1, &vertex2); if (area > 0) render_rectangle_part(scene, current_rect->texture_front, &vertex0, &vertex1, &vertex2, &vertex3); if (area < 0) render_rectangle_part(scene, current_rect->texture_back, &vertex0, &vertex2, &vertex1, &vertex3); } } /* ************************************************************************** */ /* Triangle */ /* ************************************************************************** */ static void render_triangle_part(wml_scene_t *scene, wml_texture_t *texture, wml_vertex_t *vertex0, wml_vertex_t *vertex1, wml_vertex_t *vertex2) { if (texture == hidden) { /* do nothing */ } else if (texture == scene->black) { wml_render_triangle_black(scene, vertex0, vertex1, vertex2); } else if (texture == scene->white) { wml_render_triangle_white(scene, vertex0, vertex1, vertex2); } else { wml_set_vertex_txy(vertex0, 0, texture->height); wml_set_vertex_txy(vertex1, texture->width, texture->height); wml_set_vertex_txy(vertex2, texture->width, 0); wml_render_triangle(scene, vertex0, vertex1, vertex2, texture); } } static void render_triangle(wml_scene_t *scene, wml_object_t *object, wml_triangle_t *triangle, float cosinus, float sinus) { wml_vertex_t vertex0, vertex1, vertex2; int x0 = triangle->x0, y0 = triangle->y0, z0 = triangle->z0; int x1 = triangle->x1, y1 = triangle->y1, z1 = triangle->z1; int x2 = triangle->x2, y2 = triangle->y2, z2 = triangle->z2; wml_set_vertex_xyz(&vertex0, x0, y0, z0); wml_set_vertex_xyz(&vertex1, x1, y1, z1); wml_set_vertex_xyz(&vertex2, x2, y2, z2); /* object dynamique */ wml_dynamic(&vertex0, triangle->axe, object->x, object->y, cosinus, sinus); wml_dynamic(&vertex1, polygon->axe, object->x, object->y, cosinus, sinus); wml_dynamic(&vertex2, polygon->axe, object->x, object->y, cosinus, sinus); /* calcul des coordonnées après rotation de la caméra et projection * des coordonnées 3D sur l'écran */ wml_transform(&vertex0); wml_transform(&vertex1); wml_transform(&vertex2); /* si devant la caméra */ if (vertex0.z < 0 && vertex1.z < 0 && vertex2.z < 0) { int area = wml_edge(&vertex0, &vertex1, &vertex2); if (area > 4) render_triangle_part(scene, current_rect->texture_front, &vertex0, &vertex1, &vertex2, &vertex3); if (area < 4) render_triangle_part(scene, current_rect->texture_back, &vertex0, &vertex2, &vertex1, &vertex3); } } /* ************************************************************************** */ /* Main function */ /* ************************************************************************** */ /** * wml_render_draw: * Render. * * @arg scene the scene to render. */ void wml_render_draw(wml_scene_t *scene) { wml_update_camera(scene); memset(scene->z_buffer, 0xFF, scene->z_buffer_size * 2); for (int i = 0; i < scene->map.list_object_size; i++) { wml_object_t *current_object = scene->map.list_object[i]; /* object dynamique */ float cosinus, sinus; if (current_object->axe == N) { cosinus = 0; sinus = 1; } else { cosinus = cosf(current_object->angle); sinus = sinf(current_object->angle); } for (int j = 0; j < current_object->list_rect_size; j++) render_rectangle(scene, ¤t_object->list_rect[j], cosinus, sinus); for (int j = 0; j < current_object->list_tri_size; j++) render_triangle(scene, ¤t_object->list_tri[j], cosinus, sinus); } }