192 lines
6.9 KiB
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, ¤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);
|
|
}
|
|
}
|