libwindmill/src/draw.c

192 lines
6.9 KiB
C

/* *****************************************************************************
* draw.c -- draw the scene.
* 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>
/* ************************************************************************** */
/* 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, &current_object->list_rect[j],
cosinus, sinus);
for (int j = 0; j < current_object->list_tri_size; j++)
render_triangle(scene, &current_object->list_tri[j],
cosinus, sinus);
}
}