merge latest public version from Ninestars

This commit is contained in:
Lephenixnoir 2023-01-01 21:32:11 +01:00
parent 5e45050e83
commit 0cf9a6c9af
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
18 changed files with 2720 additions and 3470 deletions

View File

@ -10,8 +10,13 @@ include(Fxconv)
find_package(Gint 2.1 REQUIRED)
set(SOURCES
src/Geometry.cpp
src/main.cpp
src/windmill.cpp
src/windmill_load.cpp
src/windmill_draw.cpp
src/windmill_clip.cpp
src/windmill_transform.cpp
src/windmill_utility.cpp
src/map.cpp
src/scene_map.cpp
src/camera.cpp

107
src/Geometry.cpp Normal file
View File

@ -0,0 +1,107 @@
#include "Geometry.hpp"
// VECTOR3D
Vector3D::Vector3D()
{
x = 0;
y = 0;
z = 0;
}
Vector3D::Vector3D(float _x, float _y, float _z)
{
x = _x;
y = _y;
z = _z;
}
Vector3D Vector3D::Add(Vector3D vector)
{
return Vector3D(x + vector.x, y + vector.y, z + vector.z);
}
Vector3D Vector3D::Substract(Vector3D vector)
{
return Vector3D(x - vector.x, y - vector.y, z - vector.z);
}
Vector3D Vector3D::Multiply(float value)
{
return Vector3D(x * value, y * value, z * value);
}
Vector3D Vector3D::Divide(float value)
{
float inv = 1 / value;
return Vector3D(x * inv, y * inv, z * inv);
}
float Vector3D::Dot(Vector3D vector)
{
return x * vector.x + y * vector.y + z * vector.z;
}
Vector3D Vector3D::Cross(Vector3D vector)
{
return Vector3D(x * vector.y - y * vector.x, y * vector.z - z * vector.y, z * vector.x - x * vector.z);
}
Point3D Vector3D::ToPoint3D()
{
return Point3D(x, y, z);
}
bool Vector3D::Null()
{
return (x == 0 and y == 0 and z == 0);
}
// POINT3D
Point3D::Point3D()
{
x = 0;
y = 0;
z = 0;
}
Point3D::Point3D(float _x, float _y, float _z)
{
x = _x;
y = _y;
z = _z;
}
Point3D Point3D::Add(Vector3D vector)
{
return Point3D(x + vector.x, y + vector.y, z + vector.z);
}
Point3D Point3D::Substract(Vector3D vector)
{
return Point3D(x - vector.x, y - vector.y, z - vector.z);
}

47
src/Geometry.hpp Normal file
View File

@ -0,0 +1,47 @@
#ifndef DEF_GEOMETRY
#define DEF_GEOMETRY
class Point3D;
class Vector3D;
class Vector3D
{
public:
Vector3D();
Vector3D(float _x, float _y, float _z);
Vector3D Add(Vector3D vector);
Vector3D Substract(Vector3D vector);
Vector3D Multiply(float value);
Vector3D Divide(float value);
float Dot(Vector3D vector);
Vector3D Cross(Vector3D vector);
Point3D ToPoint3D();
bool Null();
float x;
float y;
float z;
};
class Point3D
{
public:
Point3D();
Point3D(float _x, float _y, float _z);
Point3D Add(Vector3D vector);
Point3D Substract(Vector3D vector);
Point3D Rotate(Vector3D rotation, float angle);
float x;
float y;
float z;
};
#endif

View File

@ -10,19 +10,23 @@ Camera::Camera()
z = 0;
yaw = 0;
pitch = 0;
fov = 50;
near = 1;
fov = 50; // degrés
near = 5;
far = 1000;
float fov_rad = to_rad(fov);
scale_coef = 64 * near * tanf(fov_rad);
cos_fov = SCALE_AI * cosf(fov_rad);
scale_coef = 128 / 2 * tanf(to_rad(fov)); // = 64 * 1 * 1,19 = 76,27
//scale_coef2 = tanf(to_rad(fov)); // = 1 * 1,19 = 1.19
//cos_fov = SCALE_AI * cosf(fov_rad);
//sin_fov = SCALE_AI * sinf(fov_rad);
sin_fov = sinf(fov_rad);
cos_fov_square = cosf(fov_rad) * cosf(fov_rad);
//sin_fov = sinf(fov_rad);
//cos_fov_square = cosf(fov_rad) * cosf(fov_rad);
//near_coef = - far / float(far - near);
//far_coef = - far * near * 128 / (far - near);
setup_frustrum();
}
@ -52,11 +56,11 @@ void Camera::set(Camera* _camera)
//-----------------------------------------------------------------------------
void Camera::update()
{
if (look_at_duration)
/*if (look_at_duration)
{
yaw = (yaw * (look_at_duration - 1) + look_at_yaw) / look_at_duration;
look_at_duration -= 1;
}
}*/
cos_yaw = cosf(yaw);
sin_yaw = sinf(yaw);
@ -86,7 +90,7 @@ void Camera::update()
a9 = SCALE_AI * cos_pitch;
}
/*
//-----------------------------------------------------------------------------
// NORMAL_VECTOR
//-----------------------------------------------------------------------------
@ -169,4 +173,53 @@ void Camera::look_at(float look_at_x, float look_at_y, float look_at_z, float du
//look_at_pitch = atan2(look_at_z - z, look_at_x - x);
// calcule de sqrt ??
look_at_duration = duration;
}*/
void Camera::setup_frustrum()
{
float angle_horizontal = to_rad(fov);
float angle_vertical = to_rad(fov / 2);
int sh = sinf(angle_horizontal) * 1000;
int sv = sinf(angle_vertical) * 1000;
int ch = cosf(angle_horizontal) * 1000;
int cv = cosf(angle_vertical) * 1000;
// z-near clipping plane
frustrum.sides[0].normal_x = 0;
frustrum.sides[0].normal_y = 0;
frustrum.sides[0].normal_z = 1;
frustrum.sides[0].distance = -near * 1000;
// right
frustrum.sides[1].normal_x = -ch;
frustrum.sides[1].normal_y = 0;
frustrum.sides[1].normal_z = sh;
frustrum.sides[1].distance = 0;
// top
frustrum.sides[2].normal_x = 0;
frustrum.sides[2].normal_y = cv;
frustrum.sides[2].normal_z = sv;
frustrum.sides[2].distance = 0;
// left
frustrum.sides[3].normal_x = ch;
frustrum.sides[3].normal_y = 0;
frustrum.sides[3].normal_z = sh;
frustrum.sides[3].distance = 0;
// bottom
frustrum.sides[4].normal_x = 0;
frustrum.sides[4].normal_y = -cv;
frustrum.sides[4].normal_z = sv;
frustrum.sides[4].distance = 0;
// z-far clipping plane
//frustrum.z_far.normal.x = 0;
//frustrum.z_far.normal.y = 0;
//frustrum.z_far.normal.z = -1;
//frustrum.z_far.distance = 1000;
}

View File

@ -43,15 +43,37 @@
#include <math.h>
#include <gint/defs/util.h>
#include "Geometry.hpp"
//#define PI 3.1415
#define DEG 180.0
#define to_rad(x) M_PI / DEG * x
#define to_deg(x) DEG / M_PI * x
//#define DEG 180.0
#define to_rad(x) 3.1415f / 180.0f * x
#define to_deg(x) 180.0f / 3.1415f * x
#define SCALE_AI 128
class Plane
{
public:
int id;
//Vector3D normal;
int normal_x;
int normal_y;
int normal_z;
float distance;
};
class Frustrum
{
public:
Plane sides[5];
};
class Camera
{
public:
@ -77,6 +99,8 @@ public:
void turn(float _yaw, float _pitch);
void setup_frustrum();
//int min(int a, int b);
//int max(int a, int b);
@ -86,6 +110,9 @@ public:
float yaw, pitch;
public:
Frustrum frustrum;
int look_at_type;
float look_at_yaw;
float look_at_pitch;
@ -98,22 +125,25 @@ public:
float cos_pitch, sin_pitch;
float fov;
int cos_fov;
//int cos_fov;
//int sin_fov;
float sin_fov;
float cos_fov_square;
//float sin_fov;
//float cos_fov_square;
int scale_coef;
//float scale_coef2;
int near;
int far;
float near_coef;
int far_coef;
//float near_coef;
//int far_coef;
float normal_x, normal_y, normal_z;
//float normal_x, normal_y, normal_z;
int a1, a2, a3, a4, a5, a6, a7, a8, a9;
};
#endif

View File

@ -1,5 +1,8 @@
#include "game.hpp"
extern Map map_exemple;
extern Map map_moulin;
//-----------------------------------------------------------------------------
// GAME
//-----------------------------------------------------------------------------
@ -15,19 +18,6 @@ Game::Game()
void Game::new_game()
{
// pour exemple
//map = &map_exemple;
//map = &map_interieur_forgeron; // ICI LAUNCH GAME
player.teleport(0,0,0,0,0);
//player.dissociate_camera = true;
//scene_map.camera.set(-14,25,5,90,0); // de face
//player.teleport(25,-50,0,90,0);
//scene_map.camera.set(-14,1,5,-20,0); // de biais
//map = &map_village;
//scene_map.load_map();
//player.teleport(-85.7, -77.5, 0, 40, 0);
//player.teleport(0, -5, 0, 0, 0);
//player.teleport(250.7, -110.7, 0, 26.8, 15.4); // bug chevauchement clip depth
//player.teleport(250.7, -110.7, 0, 319.6, 53.55);
map = &map_moulin;
player.teleport(-100,0,player.height,0,10);
}

View File

@ -71,7 +71,6 @@ public:
//Object* get_object(int id);
//Collision_flag collision(float* new_x, float* new_y, float* new_z);
//bool CollisionDroiteSeg(Vecteur wall, Vecteur player);
Map *map;

View File

@ -1,61 +1,161 @@
#include "main.hpp"
/*
LISTE DES IDEES
O - objets dynamiques et statics
O - gérer la sphere qui chevauche pas pour simplifier le clipping
O - rotation n'importe quel axe
X - sprite de gint -> pas possible
O - compatibilité couleur
*/
#include "main.hpp"
#include <fxlibc/printf.h>
Game game;
Windmill windmill;
Scene_Map scene_map;
int main(void)
{
__printf_enable_fp();
// Ecran principal
extern bopti_image_t img_windmill;
dclear(C_WHITE);
dimage(16, 0, &img_windmill);
int key = 0;
while(key != KEY_EXE)
{
dupdate();
key = getkey().key;
}
dclear(C_BLACK);
dprint_opt(64, 40, C_BLACK, C_WHITE, DTEXT_MIDDLE, DTEXT_BOTTOM, "Jour 26");
int key = 0;
while(key != KEY_EXE)
{
dupdate();
key = getkey().key;
}
dclear(C_BLACK);
dupdate();
scene_map.launch();
while(1)
{
/* (LEPHE) */
clearevents();
if (keydown(KEY_EXIT))
break;
if (keydown(KEY_MENU))
gint_osmenu();
scene_map.draw();
scene_map.update();
}
scene_map.terminate();
// initialise le moteur de jeu
game.new_game();
scene_map.launch();
int timer = timer_configure(TIMER_ANY, 25*1000, GINT_CALL(callback_tick));
timer_start(timer);
scene_map.update();
// boucle principale
while (1)
{
clearevents();
if (keydown(KEY_EXIT))
break;
if (keydown(KEY_MENU))
gint_osmenu();
scene_map.draw();
}
timer_stop(timer);
scene_map.terminate();
getkey();
return 1;
}
static int callback_tick()
{
scene_map.update();
return TIMER_CONTINUE;
}
void debug_pop(char const *fmt, ...)
{
dclear(C_WHITE);
static int id = 0;
id ++;
va_list args;
va_start(args, fmt);
char str[256];
vsnprintf(str, 256, fmt, args);
va_end(args);
dclear(C_WHITE);
dtext(1, 1, C_BLACK, str);
dupdate();
getkey();
va_list args;
va_start(args, fmt);
char str[256];
vsnprintf(str, 256, fmt, args);
va_end(args);
char substr[256];
int line = 0;
int i = 0;
int subi = 0;
while (str[i] != '\0')
{
substr[subi] = str[i];
if (str[i] == '\n')
{
substr[subi] = '\0';
dprint(1, 1+9*line, C_BLACK, substr);
line ++;
subi = 0;
}
else
{
subi++;
}
i++;
}
substr[subi] = '\0';
dprint(1, 1+9*line, C_BLACK, substr);
dprint_opt(124, 60, C_BLACK, C_WHITE, DTEXT_RIGHT, DTEXT_BOTTOM, "%i", id);
dupdate();
getkey();
}
void debug_display(char const *fmt, ...)
{
va_list args;
va_start(args, fmt);
char str[256];
vsnprintf(str, 256, fmt, args);
va_end(args);
char substr[256];
int line = 0;
int i = 0;
int subi = 0;
while (str[i] != '\0')
{
substr[subi] = str[i];
if (str[i] == '\n')
{
substr[subi] = '\0';
dprint(1, 1+9*line, C_BLACK, substr);
line ++;
subi = 0;
}
else
{
subi++;
}
i++;
}
substr[subi] = '\0';
dprint(1, 1+9*line, C_BLACK, substr);
dupdate();
}

View File

@ -1,9 +1,15 @@
#include <gint/display.h>
#include <gint/keyboard.h>
#include <gint/gint.h>
#include <gint/clock.h>
#include <gint/timer.h>
#include <stdio.h>
#include "game.hpp"
#include "windmill.hpp"
#include "scene_map.hpp"
static int callback_tick();
void debug_pop(char const *fmt, ...);

File diff suppressed because it is too large Load Diff

View File

@ -1,18 +1,19 @@
#include "scene_map.hpp"
void debug_pop(char const *fmt, ...);
void debug_display(char const *fmt, ...);
extern Game game;
extern Windmill windmill;
// import des map
extern Map map_village;
extern Map map_interieur_forgeron;
extern Map map_exemple;
extern Map map_moulin;
// import des objets
extern Object chaumiere1;
extern Object panneau1;
extern Object forgeron1;
//----------------------------------------------------------------------------------------------------
// CONSTRUCTOR
@ -20,7 +21,7 @@ extern Object forgeron1;
Scene_Map::Scene_Map()
{
// debug
show_repere = false;
show_repere = true;
show_coordinates = false;
// histoire
vue_horloge = false;
@ -35,6 +36,8 @@ Scene_Map::Scene_Map()
//----------------------------------------------------------------------------------------------------
void Scene_Map::launch()
{
if (game.map == NULL) return;
time_scene = 0;
load_map();
@ -47,13 +50,11 @@ void Scene_Map::launch()
void Scene_Map::load_map()
{
// (LEPHE)
game.map = &map_village;
// mise a jour de la map pour la scene
windmill.load_map(game.map);
windmill.set_map(game.map);
// creation des bouding box 3D
/*
// creation des bouding box 3D pour les collisions
//delete bbox;
free(bbox);
//bbox = new Bbox3D[game.map->list_object_length];
@ -76,12 +77,12 @@ void Scene_Map::load_map()
for (int k=0; k<current_modele->type; k++)
{
Point point = windmill.get_point(current_modele, k);
current_bbox->x1 = min((int)current_bbox->x1, point.x);
current_bbox->y1 = min((int)current_bbox->y1, point.y);
current_bbox->z1 = min((int)current_bbox->z1, point.z);
current_bbox->x2 = max((int)current_bbox->x2, point.x);
current_bbox->y2 = max((int)current_bbox->y2, point.y);
current_bbox->z2 = max((int)current_bbox->z2, point.z);
current_bbox->x1 = min(current_bbox->x1, point.x);
current_bbox->y1 = min(current_bbox->y1, point.y);
current_bbox->z1 = min(current_bbox->z1, point.z);
current_bbox->x2 = max(current_bbox->x2, point.x);
current_bbox->y2 = max(current_bbox->y2, point.y);
current_bbox->z2 = max(current_bbox->z2, point.z);
}
}
if (current_object->axe == Z_BILLBOARD)
@ -89,7 +90,7 @@ void Scene_Map::load_map()
current_bbox->radius = max(current_bbox->y1, current_bbox->y2);
}
}
}*/
// mise a zero du temps sur la map
time_scene = 0;
@ -101,38 +102,10 @@ void Scene_Map::load_map()
//----------------------------------------------------------------------------------------------------
void Scene_Map::draw()
{
//ML_clear_vram();
dclear(C_WHITE);
windmill.draw();
// MAP VILLAGE
if (game.map == &map_village)
{
if (vue_panneau_moulin)
{
//ML_rectangle(34, 15, 95, 50, 0, ML_WHITE, ML_WHITE);
//PrintXY(34, 20, "MOULIN DES", 0);
//PrintXY(52, 30, "RIBES", 0);
//PrintMini(45, 45, "NineStars", 0);
}
}
// MAP INTERIEUR FORGERON
if (game.map == &map_interieur_forgeron)
{
if (parle_avec_forgeron)
{
//Point point_ancrage = windmill.get_point(&forgeron1.modele, 0);
//ML_rectangle(50, 10, 118, 54, 1, ML_BLACK, ML_WHITE);
}
}
if (show_repere) windmill.show_repere();
if (show_coordinates) windmill.show_coordinates();
//ML_display_vram();
dupdate();
}
@ -169,6 +142,11 @@ void Scene_Map::update()
show_coordinates = !show_coordinates;
}*/
if (keydown(KEY_LOG))
{
windmill.log = !windmill.log;
}
// action du joueur sur la map
player_action();
@ -186,75 +164,28 @@ void Scene_Map::update()
camera.set(game.player.x, game.player.y, game.player.z + game.player.height, game.player.yaw, game.player.pitch);
}
//debug_display(id(windmill.object_cursor), 3);
//debug_display(windmill.poly_cursor, 4);
}
void Scene_Map::player_action()
{
// MAP VILLAGE
if (game.map == &map_village)
{
/*if (input_trigger(K_EXE))
{
if (action_object(object(20)))
{
if (vue_panneau_moulin)
{
game.player.can_move = true;
game.player.dissociate_camera = false;
windmill.set_camera(&camera);
} else {
game.player.can_move = false;
game.player.dissociate_camera = true;
look(&panneau1, 0, 8, 17, 270, -10);
windmill.set_camera(&camera_look);
}
vue_panneau_moulin = not vue_panneau_moulin;
}
}*/
}
// MAP INTERIEUR FORGERON
if (game.map == &map_interieur_forgeron)
{
/*if (input_trigger(K_EXE))
{
// interaction avec le forgeron
if (parle_avec_forgeron)
{
parle_avec_forgeron = false;
game.player.can_move = true;
game.player.dissociate_camera = false;
} else {
if (action_object(&forgeron1))
{
parle_avec_forgeron = true;
game.player.can_move = false;
game.player.dissociate_camera = true;
camera.set(-23, 4, game.player.height, 198, 0);
}
}
}*/
}
}
void Scene_Map::animation()
{
// MAP VILLAGE
if (game.map == &map_village)
if (game.map == &map_moulin)
{
object(6)->angle -= 1;
game.map->object[1]->angle += 0.6;
game.map->object[2]->angle += 0.6;
game.map->object[3]->angle += 0.6;
game.map->object[4]->angle += 0.6;
game.map->object[5]->angle += 0.6;
}
}
void Scene_Map::player_move()
{
///////////// METTRE DANS PLAYER ET RETURN LE FLAG
@ -263,20 +194,15 @@ void Scene_Map::player_move()
float new_z = game.player.z;
// deplacement
float front, side;
/* (LEPHE) */
// input_move(&front, &side);
front = 2 * (keydown(KEY_5) != 0);
side = 2 * ((keydown(KEY_6) != 0) - (keydown(KEY_4) != 0));
// si des touches sont pressees
int front = (keydown(KEY_5) != 0) - (keydown(KEY_2) != 0);
int side = (keydown(KEY_4) != 0) - (keydown(KEY_6) != 0);
if (side != 0 or front != 0)
{
game.player.moving = true;
//game.player.translation_speed = min(game.player.translation_speed + 0.25, game.player.translation_speed_max);
// acceleration player
if (game.player.translation_speed < game.player.translation_speed_max)
{
game.player.translation_speed += game.player.translation_acceleration; // acceleration
game.player.translation_speed += game.player.translation_acceleration;
} else {
game.player.translation_speed = game.player.translation_speed_max;
}
@ -291,7 +217,15 @@ void Scene_Map::player_move()
game.player.translation_speed = 0;
}
// vole
int vertical = (keydown(KEY_PLUS) != 0) - (keydown(KEY_MINUS) != 0);
if (vertical != 0)
{
new_z += vertical;
}
// saut
/*
if (keydown(KEY_8) and not game.player.jumping)
{
game.player.jump_speed = game.player.jump_speed_max;
@ -299,8 +233,9 @@ void Scene_Map::player_move()
} else {
game.player.jump_speed -= 0.981; // gravite
}
new_z += game.player.jump_speed;
new_z += game.player.jump_speed;*/
/*
// collision
flag = collision(&new_x, &new_y, &new_z);
@ -314,8 +249,8 @@ void Scene_Map::player_move()
// hors terrain
if (flag.type == COLLISION_BOUND)
{
//debug_display("trop loin", 2);
}
// trop loin
}*/
game.player.x = new_x;
game.player.y = new_y;
@ -328,10 +263,10 @@ void Scene_Map::player_turn()
float yaw = 0;
float pitch = 0;
if (keydown(KEY_RIGHT)) yaw = -1;
if (keydown(KEY_LEFT)) yaw = 1;
if (keydown(KEY_DOWN)) pitch = -0.5;
if (keydown(KEY_UP)) pitch = 0.5;
if (keydown(KEY_RIGHT)) yaw = -0.5;
if (keydown(KEY_LEFT)) yaw = 0.5;
if (keydown(KEY_DOWN)) pitch = -0.25;
if (keydown(KEY_UP)) pitch = 0.25;
if (yaw != 0 or pitch != 0)
{
@ -367,7 +302,7 @@ void Scene_Map::player_turn()
// 4 z_billboard
// 5 hors terrain
//-----------------------------------------------------------------------------
Collision_flag Scene_Map::collision(float* new_x, float* new_y, float* new_z)
/*Collision_flag Scene_Map::collision(float* new_x, float* new_y, float* new_z)
{
Collision_flag flag;
@ -383,7 +318,7 @@ Collision_flag Scene_Map::collision(float* new_x, float* new_y, float* new_z)
flag.type = COLLISION_GROUND;
}
for (int i = 0; i<game.map->list_object_length; i++)
for (int i = 0; i<game.map->object_length; i++)
{
Object* current_object = game.map->object[i];
@ -536,7 +471,9 @@ Collision_flag Scene_Map::collision(float* new_x, float* new_y, float* new_z)
}
return flag;
}
}*/
/*Collision_flag Scene_Map::collision(float* new_x, float* new_y, float* new_z)
{
Collision_flag flag;
@ -711,7 +648,7 @@ Collision_flag Scene_Map::collision(float* new_x, float* new_y, float* new_z)
return flag;
}*/
/*
void Scene_Map::look(Object* object, float x, float y, float z, float yaw, float pitch)
{
Vertex vertex;
@ -762,9 +699,9 @@ int Scene_Map::id(Object* object)
}
debug_pop("ERROR object not found");
return -1;
}
}*/
/*
bool Scene_Map::action_object(Object* object, int poly_id)
{
if (look_object(object, poly_id) == false) return false;
@ -804,7 +741,7 @@ bool Scene_Map::look_object(Object* object, int poly_id)
return (object == windmill.object_cursor and poly_id == windmill.poly_cursor);
}
}
}*/
//----------------------------------------------------------------------------------------------------
@ -821,36 +758,3 @@ Scene_Map::~Scene_Map()
{
// rien
}

File diff suppressed because it is too large Load Diff

View File

@ -7,22 +7,32 @@
#include <stdlib.h>
#include <gint/defs/util.h>
#include "camera.hpp"
#include "Geometry.hpp"
#include <stdio.h>
#define get_vram_address() ((char *)gint_vram)
// parametrage de Windmill
#define MIN_AREA_CLIP 5
#define DECORATION_OFFSET 50
#define MAX_DEPTH_Z_BUFFER 0xffff
enum {N, X, Y, Z, Z_BILLBOARD};
enum {N, RX, RY, RZ, Z_BILLBOARD};
//#define N {0, 0, 0}
//#define RX {1, 0, 0}
//#define RY {0, 1, 0}
//#define RZ {0, 0, 1}
#define LB {0, 1}
#define RB {1, 1}
#define LT {0, 0}
#define RT {1, 0}
#define MB {0.5, 1}
#define MT {0.5, 0}
#define LM {0, 0.5}
#define RM {1, 0.5}
#define FRONT 1
#define BACK -1
#define RIEN 0
#define TRIANGLE 3
#define RECTANGLE 4
#define PARA 0
#define TRAP 1
#define INTERIEUR true
#define EXTERIEUR false
@ -37,36 +47,22 @@ enum {N, X, Y, Z, Z_BILLBOARD};
// definition des structures
struct Point
{
int x, y, z;
};
class Vecteur
{
public:
float x1, y1, x2, y2;
};
struct Sphere
{
int x, y, z;
int radius;
int x, y, z;
int radius;
int square_radius;
};
class Vertex
struct VertexPoint
{
public:
int x, y, z;
float w, h;
unsigned short z_normalized;
Vertex();
void set_xyz(int _x, int _y, int _z);
void set_wh(float _w, float _h);
float length(int x, int y, int z);
int x, y, z;
};
struct TexturePoint
{
float u, v;
};
struct Texture
{
@ -74,49 +70,85 @@ struct Texture
const unsigned char* mask;
const char pixel_width;
const char pixel_height;
const char real_width;
const char real_height;
const float offset;
const bool transparent;
const bool decoration;
const bool mirror;
const int real_height;
const int real_width;
};
struct Modele
struct Face
{
const int type;
const Texture* texture_front;
const Texture* texture_back;
const short x0, y0, z0;
const short x1, y1, z1;
const short x2, y2, z2;
const char option;
unsigned char v[3];
unsigned char t[3];
bool visible = true;
};
class Vertex
{
public:
int x, y, z;
float u, v;
int inv_z;
unsigned short z_normalized;
Vertex();
Vertex(int _x, int _y, int _z);
Vertex(int _x, int _y, int _z, float _u, float _v);
void set_texture(TexturePoint t);
void set_xyz(int _x, int _y, int _z);
};
struct Mesh
{
const VertexPoint* v;
const int v_length;
const TexturePoint* t;
const int t_length;
const Face* f;
const int f_length;
};
class WMesh
{
public:
Vertex* v;
int v_length;
int v_length_allocated;
TexturePoint* t;
int t_length;
int t_length_allocated;
Face* f;
int f_length;
int f_length_allocated;
void from_mesh(const Mesh* mesh, int margin);
void free_memory();
void add_vertex(Vertex vertex);
};
struct Object
{
short x, y, z;
// bool static = STATIC / DYNAMIC -> transform_model_to_world au chargement
const Mesh* mesh;
Point3D position;
//Vector3D rotation;
//short x, y, z;
char axe;
float angle;
const Modele* modele;
const int modele_size;
// ajouter ici
const char collision;
//const char for_collision;
//const char type_collision;
bool hidden;
bool on_screen;
Sphere sphere;
int distance_to_camera;
};
//Vector3D rotation;
char collision = ALL;
bool visible = true;
Sphere sphere;
WMesh* shadow;
//bool on_screen;
};
struct Map
{
Object** object;
int list_object_length;
int object_length;
bool horizon;
bool ground;
// ajouter ici
@ -128,65 +160,50 @@ struct Viewport
};
float distance(float dx, float dy, float dz);
int compare_object(void const *a, void const *b);
class Windmill
{
public:
// initialisation et parametrage
// initialisation, parametrage et pre calcul
Windmill();
void set_camera(Camera* _camera);
void set_viewport(int viewport_x1, int viewport_y1, int viewport_x2, int viewport_y2);
void load_map(Map* _map);
void set_map(Map* _map);
void set_objects();
void compute_bouding_sphere();
void compute_shadows();
void compute_shadows_hull(Point3D* points, int points_size);
int compute_shadows_hull_orientation(Point3D a, Point3D b, Point3D c);
// dessin
void draw();
void draw_horizon();
void draw_shadows();
void draw_ground();
void draw_objects();
void draw_post_treatment();
void draw_body();
// transformation 3D des vertex
void transform_model_to_world(Vertex vertex[], int vertex_length, Object* object, int cosinus, int sinus);
void transform_model_to_world(Object* object, Vertex vertex[], int vertex_length);
void transform_world_to_camera(Vertex vertex[], int vertex_length);
void transform_camera_to_screen(Vertex vertex[], int vertex_length);
void transform_camera_to_screen2(Vertex vertex[], int vertex_length);
// text visiblilite
bool fast_check(Vertex vertex_list[], int vertex_list_length);
// test visiblilite
bool object_in_frustrum(Object* object);
void clip_frustrum(WMesh* mesh);
bool inside_frustrum(Vertex vertex, Plane plane, int offset = 0);
Vertex clip_plane(Vertex vertex[], int vertex_length);
Vertex clip_onto_plane(Vertex vertexA, Vertex vertexB, Plane plane);
bool inside_viewport(int x, int y);
int visible_face(Vertex* a, Vertex* b, Vertex* c);
void clip_depth(Vertex vertex_list_input[], int* vertex_list_input_length);
void clip_depth_edge(Vertex* vertex_in, Vertex* vertex_out, Vertex* vertex_set);
bool clip_depth_inside_edge(Vertex* vertex);
void clip_viewport(Vertex vertex_list_input[], int* vertex_list_input_length);
void clip_viewport_edge(Vertex* vertex_in, Vertex* vertex_out, Vertex* vertex_set, int edge);
bool clip_viewport_inside_edge(Vertex* vertex, int edge);
int get_visible_face(Vertex* a, Vertex* b, Vertex* c);
// dessin des triangles
void render_triangle(Vertex* vertex1, Vertex* vertex2, Vertex* vertex3, const Texture *texture);
void render_triangles(WMesh mesh);
void render_triangle_texture(Vertex* vertex1, Vertex* vertex2, Vertex* vertex3, const Texture* texture);
void render_triangle_black(Vertex* vertex0, Vertex* vertex1, Vertex* vertex2);
void render_triangle_white(Vertex* vertex0, Vertex* vertex1, Vertex* vertex2);
void render_triangle_transparent(Vertex* vertex1, Vertex* vertex2, Vertex* vertex3, const Texture* texture);
// manipulation
Point get_point(const Modele* poly, int i);
Point get_center_poly(const Modele* poly);
void compute_object_angle(Object* object, int* cosinus, int* sinus);
void extract_vertex_from_poly(const Modele* poly, Vertex* vertex, int* vertex_length, int* width, int* height);
void texture_coordinates(const Modele* poly, Vertex* vertex, const Texture* texture, int visible, int width, int height);
void swap_vertex(Vertex* vertexA, Vertex* vertexB);
void copy_vertex(Vertex* vertex_source, Vertex* vertex_dest);
// sphere
Sphere transform_sphere_to_world(Sphere* sphere, Object* object, int cosinus, int sinus);
bool sphere_in_cone(Sphere* sphere);
void render_triangle_color(Vertex* vertex0, Vertex* vertex1, Vertex* vertex2, color_t color);
// divers
void copy_camera();
@ -196,14 +213,13 @@ public:
int edge_start(Vertex* a, Vertex* b, int px, int py);
int edge_step_x(Vertex* a, Vertex* b);
int edge_step_y(Vertex* a, Vertex* b);
float distance(float dx, float dy, float dz);
// utilitaires
void pixel_on_cursor(int x, int y);
void show_coordinates();
void show_repere();
//void show_fps();
// destructeurr
// destructeur
~Windmill();
private:
@ -215,8 +231,10 @@ private:
Map* map;
// liste objets triee
Object** object;
int list_object_length;
Object* objects;
// ombres
Point3D sun;
// z_buffer
int shift_x, shift_y;
@ -229,22 +247,14 @@ private:
int i;
int j;
// variables temporaire pour eviter de lire la valeur en cours de calcul
int temp_nb_object_on_screen;
Object* temp_object_cursor;
int temp_poly_cursor;
public:
// fenetre de visualisation
Viewport viewport;
// utilitaires
bool loading;
int nb_object_on_screen;
Object* object_cursor;
int poly_cursor;
int cursor_x;
int cursor_y;
bool log = false;
};

283
src/windmill_clip.cpp Normal file
View File

@ -0,0 +1,283 @@
//----------------------------------------------------------------------------------------------------
//
// WINDMILL
//
// version : 2.0
// Moteur de rendu 3D base sur la methode de rasterisation avec buffer de profondeur
//
// Cree par Olivier Lanneau, alias NineStars
// Planet-casio.fr
//
//----------------------------------------------------------------------------------------------------
#include "windmill.hpp"
void debug_pop(char const *fmt, ...);
void debug_display(char const *fmt, ...);
extern Texture tex_white;
extern Texture tex_light;
extern Texture tex_dark;
extern Texture tex_black;
//----------------------------------------------------------------------------------------------------
// CLIPPING
//----------------------------------------------------------------------------------------------------
bool Windmill::object_in_frustrum(Object* object)
{
Vertex centre(object->sphere.x, object->sphere.y, object->sphere.z);
// calcul des coordonnees dans le repère monde apres rotation et translation du centre de l objet
transform_model_to_world(object, &centre, 1);
// calcul des coordonnees du centre dans le repère camera apres rotation et translation de la camera
transform_world_to_camera(&centre, 1);
// si la camera est dans la sphere
if (centre.x*centre.x + centre.y*centre.y + centre.z*centre.z < object->sphere.square_radius)
{
return true;
}
// si la sphere est dans le frustrum
for (int p = 0; p<5 ; p++)
{
Plane plane = camera.frustrum.sides[p];
if (inside_frustrum(centre, plane, object->sphere.radius) == false) return false;
}
return true;
// A GARDER CAR PAS MAL OPTI
/*
int cone_offset = sphere->radius * camera.sin_fov;
int nx = camera.nx;
int ny = camera.ny;
int nz = camera.nz;
Point3D cone;
cone.x = int(camera.x) - (nx * cone_offset);
cone.y = int(camera.y) - (ny * cone_offset);
cone.z = int(camera.z) - (nz * cone_offset);
int sx = sphere->x - cone.x;
int sy = sphere->y - cone.y;
int sz = sphere->z - cone.z;
int ss = sx*sx + sy*sy + sz*sz;
// si sommet du cone dans la sphere
if (ss <= sphere->radius * sphere->radius)
{
return true;
}
// si sphere dans le cone
int ns = ((nx * sx) >> 7) + ((ny * sy) >> 7) + ((nz * sz) >> 7);
if (ns > 0 and ns*ns > camera.cos_fov_square * ss)
{
return true;
}
return false;*/
}
void Windmill::clip_frustrum(WMesh* mesh)
{
for (int p = 0; p<5 ; p++)
{
Plane plane = camera.frustrum.sides[p];
int init_f_length = mesh->f_length; // car sinon on va faire du clipping sur des points nouveaux issues du clipping...
// pour chaque triangle
for (int f=0; f<init_f_length; f++)
{
// triangle en cours
Face triangle = mesh->f[f];
if (triangle.visible)
{
int S = 3 - 1;
// indice vertex pour face
int v_ok[4];
int t_ok[4];
int ok_indice = 0;
// pour chaque segment
for (int E = 0; E<3; E++)
{
Vertex vertexE(mesh->v[triangle.v[E]].x, mesh->v[triangle.v[E]].y, mesh->v[triangle.v[E]].z, mesh->t[triangle.t[E]].u,mesh->t[triangle.t[E]].v);
Vertex vertexS(mesh->v[triangle.v[S]].x, mesh->v[triangle.v[S]].y, mesh->v[triangle.v[S]].z, mesh->t[triangle.t[S]].u,mesh->t[triangle.t[S]].v);
if (inside_frustrum(vertexE, plane) == true)
{
if (inside_frustrum(vertexS, plane) == false)
{
v_ok[ok_indice] = mesh->v_length;
t_ok[ok_indice] = mesh->t_length;
ok_indice++;
mesh->add_vertex(clip_onto_plane(vertexE, vertexS, plane));
}
v_ok[ok_indice] = triangle.v[E];
t_ok[ok_indice] = triangle.t[E];
ok_indice++;
}
else if (inside_frustrum(vertexS, plane) == true)
{
v_ok[ok_indice] = mesh->v_length;
t_ok[ok_indice] = mesh->t_length;
ok_indice++;
mesh->add_vertex(clip_onto_plane(vertexE, vertexS, plane));
}
S = E;
}
// aucun point dans le frustrum
if (ok_indice == 0)
{
mesh->f[f].visible = false;
}
// soit les 3 points à l'intérieur du triangle, soit 2 point ouside -> on modifie la face en cours
if (ok_indice >= 3)
{
Face edited_triangle;
edited_triangle.texture_front = triangle.texture_front;
edited_triangle.texture_back = triangle.texture_back;
for (int i=0; i<3; i++)
{
edited_triangle.v[i] = v_ok[i];
edited_triangle.t[i] = t_ok[i];
}
mesh->f[f] = edited_triangle; // pas de verif d'overflow
}
// 1 point en dehors = 2 triangles -> on modifie face en cours, et on ajoute une face
if (ok_indice == 4)
{
// ajout triangle
Face new_triangle;
new_triangle.texture_front = triangle.texture_front;
new_triangle.texture_back = triangle.texture_back;
new_triangle.v[0] = v_ok[0];
new_triangle.t[0] = t_ok[0];
new_triangle.v[1] = v_ok[2];
new_triangle.t[1] = t_ok[2];
new_triangle.v[2] = v_ok[3];
new_triangle.t[2] = t_ok[3];
mesh->f[mesh->f_length] = new_triangle; // pas de verif d'overflow
mesh->f_length++;
}
}
/*debug_pop("FIN CYCLE\nplan %i\nil y a %i triangles\nil y a %i vertex", p, mesh->f_length, mesh->v_length);
for (int i=0; i<mesh->f_length; i++)
{
debug_pop("f %i %i %i", mesh->f[i].v[0], mesh->f[i].v[1], mesh->f[i].v[2]);
}
for (int i=0; i<mesh->v_length; i++)
{
debug_pop("v\nx %i\ny %i\nz %i", mesh->v[i].x, mesh->v[i].y, mesh->v[i].z);
}*/
}
}
}
bool Windmill::inside_frustrum(Vertex vertex, Plane plane, int offset)
{
/*if (plane.id == NEAR)
{
return vertex.z > camera.near;
}
if (plane.id == RIGHT)
{
return vertex.x * camera.scale_coef2 < vertex.z; // MULT float !
}
if (plane.id == TOP)
{
return -vertex.y * camera.scale_coef2 / 2.0 < vertex.z;
}
if (plane.id == LEFT)
{
return -vertex.x * camera.scale_coef2 < vertex.z;
}
if (plane.id == BOTTOM)
{
return vertex.y * camera.scale_coef2 / 2.0 < vertex.z;
}*/
int dot = vertex.x * plane.normal_x + vertex.y * plane.normal_y + vertex.z * plane.normal_z - plane.distance+ (offset * 1000);
return dot > 0;
}
Vertex Windmill::clip_onto_plane(Vertex vertexA, Vertex vertexB, Plane plane)
{/*
int x, y, z, u, v;
float t;
if (plane == NEAR)
{
t = float(camera.near - vertexA->z) / float(vertexB->z - vertexA->z);
//x = vertexA->x + t * (vertexB->x - vertexA->x);
//y = vertexA->y + t * (vertexB->y - vertexA->y);
//z = camera.near;
}
if (plane == RIGHT)
{
t = float(camera.near - vertexA->z) / float(vertexB->z - vertexA->z);
}
x = vertexA->x + t * (vertexB->x - vertexA->x);
y = vertexA->y + t * (vertexB->y - vertexA->y);
z = vertexA->z + t * (vertexB->z - vertexA->z);
u = vertexA->u + t * (vertexB->u - vertexA->u);
v = vertexA->v + t * (vertexB->v - vertexA->v);
return Vertex(x, y, z, u, v);*/
//return Vertex(0, 0, 0, 0, 0);
float dotA = vertexA.x * plane.normal_x + vertexA.y * plane.normal_y + vertexA.z * plane.normal_z - plane.distance;
float dotB = vertexB.x * plane.normal_x + vertexB.y * plane.normal_y + vertexB.z * plane.normal_z - plane.distance;
float t = dotA / (dotA - dotB); // intersection factor (between 0 and 1)
int x = vertexA.x + t * (vertexB.x - vertexA.x);
int y = vertexA.y + t * (vertexB.y - vertexA.y);
int z = vertexA.z + t * (vertexB.z - vertexA.z);
float u = vertexA.u + t * (vertexB.u - vertexA.u);
float v = vertexA.v + t * (vertexB.v - vertexA.v);
return Vertex(x, y, z, u, v);
}
bool Windmill::inside_viewport(int x, int y)
{
return (x < viewport.x2 and y >= viewport.y1 and x >= viewport.x1 and y < viewport.y2);
}
int Windmill::get_visible_face(Vertex* a, Vertex* b, Vertex* c)
{
return (c->x - a->x) * (b->y - a->y) - (c->y - a->y) * (b->x - a->x) > 0 ? FRONT : BACK;
}

946
src/windmill_draw.cpp Normal file
View File

@ -0,0 +1,946 @@
//----------------------------------------------------------------------------------------------------
//
// WINDMILL
//
// version : 2.0
// Moteur de rendu 3D base sur la methode de rasterisation avec buffer de profondeur
//
// Cree par Olivier Lanneau, alias NineStars
// Planet-casio.fr
//
//----------------------------------------------------------------------------------------------------
#include "windmill.hpp"
void debug_pop(char const *fmt, ...);
void debug_display(char const *fmt, ...);
extern Texture tex_white;
extern Texture tex_light;
extern Texture tex_dark;
extern Texture tex_black;
//----------------------------------------------------------------------------------------------------
// DESSIN
//----------------------------------------------------------------------------------------------------
void Windmill::draw()
{
// quitte si pas de camera, de map, d objet ou de z_buffer
if(camera2 == NULL or map == NULL or/* object == NULL or */z_buffer == NULL) return;
// mets a jour les variables de la camera
camera2->update();
// cree une camera temporaire pour eviter les problemes de desynchronisation
copy_camera();
// fonction principale, l'ordre d'appel des fonctions suivantes est important
clear_z_buffer();
// trie les objets pour optimiser l affichage
sort_object();
// affiche le trait d'horizon
if (map->horizon) draw_horizon();
// affiche les ombres
// draw_shadows();
// affiche le sol
if (map->ground) draw_ground();
// affiche les objets de la scene
draw_objects();
// post traitement pour afficher les angles vifs
// draw_post_treatment();
// affiche le corps du personnage
//draw_body();
// affiche des informations debug
if (log)
{
//show_fps();
//show_coordinates();
show_repere();
}
}
void Windmill::draw_horizon()
{
int distance = 1000;
int hx = camera.x + distance * camera.cos_yaw;
int hy = camera.y + distance * camera.sin_yaw;
Vertex horizon = Vertex(hx, hy, 0);
transform_world_to_camera(&horizon, 1);
transform_camera_to_screen(&horizon, 1);
if (inside_viewport(horizon.x, horizon.y))
{
dline(viewport.x1, horizon.y, viewport.x2, horizon.y, C_BLACK);
}
}
void Windmill::draw_ground()
{
int distance = 50;
int esp = 20;
int nb = 6;
int nb2 = nb * nb;
float cx = camera.x + distance * camera.cos_yaw;
float cy = camera.y + distance * camera.sin_yaw;
int dx = int(cx) - int(cx)%esp;
int dy = int(cy) - int(cy)%esp;
for (int i=-nb; i<nb; i++)
{
for (int j=-nb; j<nb; j++)
{
if (i*i + j*j < nb2) // arrondi le carre en cercle
{
int x = dx + i*esp;
int y = dy + j*esp;
Vertex ground = Vertex(x, y, 0);
transform_world_to_camera(&ground, 1);
if (ground.z > 0)
{
transform_camera_to_screen(&ground, 1);
if (inside_viewport(ground.x, ground.y) == true)
{
dpixel(ground.x, ground.y, C_BLACK);
}
}
}
}
}
}
void Windmill::draw_objects()
{
for(i=0; i<map->object_length; i++)
{
// récupère l'objet en cours
Object* object = map->object[i];
//Object* object = objects[i];
//int f_visible = 0;
// si l'objet est totalement ou partie dans le frustrum
if (object-> visible && object_in_frustrum(object))
{
// copie le mesh avec plus de memoires disponible pour possiblement ajouter des points au clipping
WMesh mesh; mesh.from_mesh(object->mesh, 10);
// calcul des coordonnees dans le repère monde apres rotation et translation de l objet
transform_model_to_world(object, mesh.v, mesh.v_length);
// calcul des coordonnees dans le repère camera apres rotation et translation de la camera
transform_world_to_camera(mesh.v, mesh.v_length);
// coupe 3D selon le frustrum de la camera
clip_frustrum(&mesh); // SI OBJECT IN FRUSTRUM DIT QUE L'OBJET EST PARTEILLEMENT DANS FRUSTRUM
// calcul des coordonnes apres perspective et decalage au centre de l ecran
transform_camera_to_screen(mesh.v, mesh.v_length);
if (log)
{
for (int v = 0; v<mesh.v_length; v++)
{
dpixel(mesh.v[v].x, mesh.v[v].y, C_BLACK);
}
}
else
{
// dessine tous les triangles
render_triangles(mesh);
}
/*if (log)
{
debug_pop("LOG MODE\nf_length = %i", mesh.f_length);
for (int i=0; i<mesh.f_length; i++)
{
debug_pop("f%i\n%i %i %i\n%i %i %i", i, mesh.f[i].v[0], mesh.f[i].v[1], mesh.f[i].v[2], mesh.f[i].t[0], mesh.f[i].t[1],mesh.f[i].t[2]);
}
debug_pop("LOG MODE\nv_length = %i", mesh.v_length);
for (int i=0; i<mesh.v_length; i++)
{
debug_pop("v%i\nx %i\ny %i\nz %i", i, mesh.v[i].x, mesh.v[i].y, mesh.v[i].z);
}
debug_pop("LOG MODE\nt_length = %i", mesh.t_length);
for (int i=0; i<mesh.t_length; i++)
{
debug_pop("t%i\nu %f\nv %f", i, mesh.t[i].u, mesh.t[i].v);
}
log = false;
}*/
mesh.free_memory();
}
}
}
void Windmill::draw_post_treatment()
{
char* vram = get_vram_address();
unsigned char mask;
int current, right, bottom;
for (int y = viewport.y1; y<viewport.y2-1; y++)
{
for (int x = viewport.x1; x<viewport.x2-1; x++)
{
int address = x + y * z_buffer_width + z_buffer_offset;
current = z_buffer[address];
right = z_buffer[address + 1];
bottom = z_buffer[address + z_buffer_width];
if (current == MAX_DEPTH_Z_BUFFER)
{
if (right < MAX_DEPTH_Z_BUFFER)
{
mask = 128 >> ((x+1) & 7);
vram[address>>3] |= mask;
//ML_pixel(x+1, y, ML_BLACK);
}
if (bottom < MAX_DEPTH_Z_BUFFER)
{
dpixel(x, y+1, C_BLACK);
//ML_pixel(x, y+1, ML_BLACK);
}
} else {
if (right == MAX_DEPTH_Z_BUFFER or bottom == MAX_DEPTH_Z_BUFFER)
{
dpixel(x, y+1, C_BLACK);
//ML_pixel(x, y, ML_BLACK);
}
}
}
} // 21 fps 21,5 fps*/
/*left = z_buffer[0];
for (int i = 1; i<z_buffer_size; i++)
{
left = current;
current = z_buffer[i];
//bottom = z_buffer[i+128];
if (current < MAX_DEPTH_Z_BUFFER)
{
//left = z_buffer[i-1];
if (left == MAX_DEPTH_Z_BUFFER)
{
//ML_pixel((i+1)%128, (i+1)/128, ML_BLACK);
mask = 128 >> (i & 7);
vram[(i - z_buffer_offset)>>3] |= mask;
}
} else {
if (left < MAX_DEPTH_Z_BUFFER)
{
mask = 128 >> ((i-1) & 7);
vram[(i - 1 - z_buffer_offset)>>3] |= mask;
}
}
}
// sans rien 28 fps
// avec le i+1 : 24 fps
// avec le i : 25 fps
// calculer left = Z_buffer[i-1] dans if : 24 fps
// avec les deux cote : 24 fps ! */
bool flag = false;
for (int i = 0; i<z_buffer_size; i+=2)
{
current = z_buffer[i];
if (current == MAX_DEPTH_Z_BUFFER)
{
if (flag == true)
{
if (z_buffer[i-1] == MAX_DEPTH_Z_BUFFER)
{
// il y avait rien juste a gauche
mask = 128 >> ((i-2) & 7);
vram[(i - 2 - z_buffer_offset)>>3] |= mask;
flag = false;
} else {
// l objet commencait en fait 1 pixel a gauche
mask = 128 >> ((i-1) & 7);
vram[(i - 1 - z_buffer_offset)>>3] |= mask;
flag = false;
}
}
} else {
if (flag == false)
{
if (z_buffer[i-1] == MAX_DEPTH_Z_BUFFER)
{
// il y avait rien juste a gauche
mask = 128 >> (i & 7);
vram[(i - z_buffer_offset)>>3] |= mask;
flag = true;
} else {
// l objet commencait en fait 1 pixel a gauche
mask = 128 >> ((i-1) & 7);
vram[(i - 1 - z_buffer_offset)>>3] |= mask;
flag = true;
}
}
}
} // 24 fps
// avec astuce +=2 : 25 fps
/*bool flag = false;
char i_mod_8;
for (int i = 0; i<z_buffer_size; i++)
{
i_mod_8 = i & 7;
current = z_buffer[i];
if (current == MAX_DEPTH_Z_BUFFER)
{
if (flag == true)
{
mask |= 128 >> i_mod_8;//((i-1) & 7);
flag = false;
}
} else {
if (flag == false)
{
mask |= 128 >> i_mod_8;
flag = true;
}
}
if (i_mod_8 == 7)
{
//if (mask > 0)
vram[i>>3] |= mask;
mask = 0;
}
}*/
}
void Windmill::draw_body()
{
/*int x = camera.x;
int y = camera.y;
int z = camera.z;
Vertex v0, v1, v2, v3;
set_vertex_xyz()
METTRE DIRECT LES VERTEX DANS LE REPERE SCREEN PUIS RENDER...
*/
}
//----------------------------------------------------------------------------------------------------
// DESSIN DES TRIANGLES
//----------------------------------------------------------------------------------------------------
void Windmill::render_triangles(WMesh mesh)
{
for (int f = 0; f<mesh.f_length; f++)
{
Face triangle = mesh.f[f];
if (triangle.visible)
{
for (int i=0; i<3; i++)
{
mesh.v[triangle.v[i]].set_texture(mesh.t[triangle.t[i]]);
}
// determine quelle face du triangle est visible
int visible_face = get_visible_face(&mesh.v[triangle.v[0]], &mesh.v[triangle.v[1]], &mesh.v[triangle.v[2]]);
// choisi la texture visible
const Texture* visible_texture = (visible_face == FRONT) ? triangle.texture_front : triangle.texture_back;
// selectionne l'ordre d'affichage
int a = 0, b = 1, c = 2;
if (visible_face != FRONT) {b = 2; c = 1;}
// pour chaque type de texture
if (visible_texture == NULL)
{
// ne rien faire
}
else if (visible_texture == &tex_white)
{
render_triangle_color(&mesh.v[triangle.v[a]], &mesh.v[triangle.v[b]], &mesh.v[triangle.v[c]], C_WHITE);
}
else if (visible_texture == &tex_light)
{
render_triangle_color(&mesh.v[triangle.v[a]], &mesh.v[triangle.v[b]], &mesh.v[triangle.v[c]], C_LIGHT);
}
else if (visible_texture == &tex_dark)
{
render_triangle_color(&mesh.v[triangle.v[a]], &mesh.v[triangle.v[b]], &mesh.v[triangle.v[c]], C_DARK);
}
else if (visible_texture == &tex_black)
{
render_triangle_color(&mesh.v[triangle.v[a]], &mesh.v[triangle.v[b]], &mesh.v[triangle.v[c]], C_BLACK);
}
else
{
render_triangle_texture(&mesh.v[triangle.v[a]], &mesh.v[triangle.v[b]], &mesh.v[triangle.v[c]], visible_texture);
}
}
}
}
void Windmill::render_triangle_texture(Vertex* vertexA, Vertex* vertexB, Vertex* vertexC, const Texture* texture)
{
// calcul de l'aire du triangle
int area = edge(vertexA, vertexB, vertexC);
if (area <= MIN_AREA_CLIP) return;
// calcul du rectangle circonscrit au triangle
int min_x = max(viewport.x1, min(vertexA->x, min(vertexB->x, vertexC->x)));
int max_x = min(viewport.x2-1, max(vertexA->x, max(vertexB->x, vertexC->x)));
int min_y = max(viewport.y1, min(vertexA->y, min(vertexB->y, vertexC->y)));
int max_y = min(viewport.y2-1, max(vertexA->y, max(vertexB->y, vertexC->y)));
// ajustement des coordonnees des textures a la taille en pixel
vertexA->u *= texture->pixel_width;
vertexA->v *= texture->pixel_height;
vertexB->u *= texture->pixel_width;
vertexB->v *= texture->pixel_height;
vertexC->u *= texture->pixel_width;
vertexC->v *= texture->pixel_height;
// pre-calcul des coordonnees de la texture << 13 => tex_w * 8192 / x
int w0 = vertexA->u * vertexA->inv_z; int h0 = vertexA->v * vertexA->inv_z;
int w1 = vertexB->u * vertexB->inv_z; int h1 = vertexB->v * vertexB->inv_z;
int w2 = vertexC->u * vertexC->inv_z; int h2 = vertexC->v * vertexC->inv_z;
// calcul des produits vectoriels
int u0_start = edge_start(vertexB, vertexC, min_x, min_y);
int u0_step_x = edge_step_x(vertexB, vertexC);
int u0_step_y = edge_step_y(vertexB, vertexC);
int u1_start = edge_start(vertexC, vertexA, min_x, min_y);
int u1_step_x = edge_step_x(vertexC, vertexA);
int u1_step_y = edge_step_y(vertexC, vertexA);
int u2_start = edge_start(vertexA, vertexB, min_x, min_y);
int u2_step_x = edge_step_x(vertexA, vertexB);
int u2_step_y = edge_step_y(vertexA, vertexB);
// << 15
int z_num_start = (u0_start * vertexA->z_normalized + u1_start * vertexB->z_normalized + u2_start * vertexC->z_normalized) / area;
int z_num_step_x = (u0_step_x * vertexA->z_normalized + u1_step_x * vertexB->z_normalized + u2_step_x * vertexC->z_normalized) / area;
int z_num_step_y = (u0_step_y * vertexA->z_normalized + u1_step_y * vertexB->z_normalized + u2_step_y * vertexC->z_normalized) / area;
// << 13
int z_div_start = u0_start * vertexA->inv_z + u1_start * vertexB->inv_z + u2_start * vertexC->inv_z;
int z_div_step_x = u0_step_x * vertexA->inv_z + u1_step_x * vertexB->inv_z + u2_step_x * vertexC->inv_z;
int z_div_step_y = u0_step_y * vertexA->inv_z + u1_step_y * vertexB->inv_z + u2_step_y * vertexC->inv_z;
// rapprochement artificiel si texture de type decoration
int decoration = 0;//(texture->decoration ? DECORATION_OFFSET : 0);
// acces a la vram
//char* vram = get_vram_address();
unsigned char mask_vram, mask_w;
int offset_vram;
int address;
int u0, u1, u2;
int z_num, z_div;
int w, h;
// pre-calcul largeur en octet des tableaux
int nbw_tex = ((texture->pixel_width - 1) >> 3) + 1;
char loop_w_tex = texture->pixel_width-1;
char loop_h_tex = texture->pixel_height-1;
// parcours en ligne
for(int x=min_x; x<=max_x; x++)
{
u0 = u0_start; u1 = u1_start; u2 = u2_start;
z_num = z_num_start;
z_div = z_div_start;
offset_vram = x >> 3;
mask_vram = 128 >> (x & 7);
// parcours en colonne
for(int y=min_y; y<=max_y; y++)
{
// si le pixel (x;y) est dans le triangle
if ((u0 | u1 | u2) > 0)
{
// addresse du z-buffer
address = x + y * z_buffer_width + z_buffer_offset;
// si le pixel (x;y) est plus proche qu'avant
if (z_num <= z_buffer[address] + decoration)
{
// calcul des coordonnees pour la texture
w = ((u0 * w0 + u1 * w1 + u2 * w2) / z_div) & loop_w_tex;
h = ((u0 * h0 + u1 * h1 + u2 * h2) / z_div) & loop_h_tex;
// calcul du masque pour l'octet
mask_w = 128 >> (w & 7);
if (texture->mask == NULL)
{
// enregistre la profondeur du pixel dans le z buffer
z_buffer[address] = z_num;
if (texture->sprite[(w >> 3) + (h * nbw_tex)] & mask_w)
{
// afficher pixel noir
dpixel(x, y, C_BLACK);
//vram[(y << 4) + offset_vram] |= mask_vram;
}else{
// afficher pixel blanc
dpixel(x, y, C_WHITE);
//vram[(y << 4) + offset_vram] &= ~mask_vram;
}
// curseur
//pixel_on_cursor(x, y);
}/* else {
int alpha = (w >> 3) + (h * nbw_tex);
if ((texture->mask[alpha] & mask_w))
{
// enregistre la profondeur du pixel dans le z buffer
z_buffer[address] = z_num;
if ((texture->sprite[alpha] & mask_w))
{
// afficher pixel noir
vram[(y << 4) + offset_vram] |= mask_vram;
}else{
// afficher pixel blanc
vram[(y << 4) + offset_vram] &= ~mask_vram;
}
// curseur
//pixel_on_cursor(x, y);
}
}*/
}
}
u0 += u0_step_y; u1 += u1_step_y; u2 += u2_step_y;
z_num += z_num_step_y;
z_div += z_div_step_y;
}
u0_start += u0_step_x; u1_start += u1_step_x; u2_start += u2_step_x;
z_num_start += z_num_step_x;
z_div_start += z_div_step_x;
}
}
void Windmill::render_triangle_color(Vertex* vertexA, Vertex* vertexB, Vertex* vertexC, color_t color)
{
// calcul de l'aire du triangle
int area = edge(vertexA, vertexB, vertexC);
if (area <= MIN_AREA_CLIP) return;
// calcul du rectangle circonscrit au triangle
int min_x = max(viewport.x1, min(vertexA->x, min(vertexB->x, vertexC->x)));
int max_x = min(viewport.x2-1, max(vertexA->x, max(vertexB->x, vertexC->x)));
int min_y = max(viewport.y1, min(vertexA->y, min(vertexB->y, vertexC->y)));
int max_y = min(viewport.y2-1, max(vertexA->y, max(vertexB->y, vertexC->y)));
// calcul des produits vectoriels
int u0_start = edge_start(vertexB, vertexC, min_x, min_y);
int u0_step_x = edge_step_x(vertexB, vertexC);
int u0_step_y = edge_step_y(vertexB, vertexC);
int u1_start = edge_start(vertexC, vertexA, min_x, min_y);
int u1_step_x = edge_step_x(vertexC, vertexA);
int u1_step_y = edge_step_y(vertexC, vertexA);
int u2_start = edge_start(vertexA, vertexB, min_x, min_y);
int u2_step_x = edge_step_x(vertexA, vertexB);
int u2_step_y = edge_step_y(vertexA, vertexB);
int z_num_start = (u0_start * vertexA->z_normalized + u1_start * vertexB->z_normalized + u2_start * vertexC->z_normalized) / area;
int z_num_step_x = (u0_step_x * vertexA->z_normalized + u1_step_x * vertexB->z_normalized + u2_step_x * vertexC->z_normalized) / area;
int z_num_step_y = (u0_step_y * vertexA->z_normalized + u1_step_y * vertexB->z_normalized + u2_step_y * vertexC->z_normalized) / area;
// acces a la vram
char* vram = get_vram_address();
unsigned char mask_vram;
int offset_vram;
int address;
int u0, u1, u2;
int z_num;
// parcours en ligne
for(int x=min_x; x<=max_x; x++)
{
u0 = u0_start; u1 = u1_start; u2 = u2_start;
z_num = z_num_start;
offset_vram = x >> 3;
mask_vram = 128 >> (x & 7);
// parcours en colonne
for(int y=min_y; y<=max_y; y++)
{
// si le pixel (x;y) est dans le triangle
if ((u0 | u1 | u2) > 0)
{
// addresse du z-buffer
address = x + y * z_buffer_width + z_buffer_offset;
// si le pixel (x;y) est plus proche qu'avant
if (z_num <= z_buffer[address])
{
// enregistre la profondeur du pixel dans le z buffer
z_buffer[address] = z_num;
// afficher pixel
dpixel(x, y, color);
}
}
u0 += u0_step_y; u1 += u1_step_y; u2 += u2_step_y;
z_num += z_num_step_y;
}
u0_start += u0_step_x; u1_start += u1_step_x; u2_start += u2_step_x;
z_num_start += z_num_step_x;
}
}
/*void Windmill::render_triangle_black(Vertex* vertexA, Vertex* vertexB, Vertex* vertexC)
{
// calcul du rectangle circonscrit au triangle
int min_x = max(viewport.x1, min(vertexA->x, min(vertexB->x, vertexC->x)));
int max_x = min(viewport.x2-1, max(vertexA->x, max(vertexB->x, vertexC->x)));
int min_y = max(viewport.y1, min(vertexA->y, min(vertexB->y, vertexC->y)));
int max_y = min(viewport.y2-1, max(vertexA->y, max(vertexB->y, vertexC->y)));
// calcul de l'aire du triangle
int area = edge(vertexA, vertexB, vertexC);
// termine si la taille du triangle est trop petite
if (area <= MIN_AREA_CLIP) return;
// calcul des produits vectoriels
int u0_start = edge_start(vertexB, vertexC, min_x, min_y);
int u0_step_x = edge_step_x(vertexB, vertexC);
int u0_step_y = edge_step_y(vertexB, vertexC);
int u1_start = edge_start(vertexC, vertexA, min_x, min_y);
int u1_step_x = edge_step_x(vertexC, vertexA);
int u1_step_y = edge_step_y(vertexC, vertexA);
int u2_start = edge_start(vertexA, vertexB, min_x, min_y);
int u2_step_x = edge_step_x(vertexA, vertexB);
int u2_step_y = edge_step_y(vertexA, vertexB);
int z_num_start = (u0_start * vertexA->z_normalized + u1_start * vertexB->z_normalized + u2_start * vertexC->z_normalized) / area;
int z_num_step_x = (u0_step_x * vertexA->z_normalized + u1_step_x * vertexB->z_normalized + u2_step_x * vertexC->z_normalized) / area;
int z_num_step_y = (u0_step_y * vertexA->z_normalized + u1_step_y * vertexB->z_normalized + u2_step_y * vertexC->z_normalized) / area;
// acces a la vram
char* vram = get_vram_address();
unsigned char mask_vram;
int offset_vram;
int address;
int u0, u1, u2;
int z_num;
// parcours en ligne
for(int x=min_x; x<=max_x; x++)
{
u0 = u0_start; u1 = u1_start; u2 = u2_start;
z_num = z_num_start;
offset_vram = x >> 3;
mask_vram = 128 >> (x & 7);
// parcours en colonne
for(int y=min_y; y<=max_y; y++)
{
// si le pixel (x;y) est dans le triangle
if ((u0 | u1 | u2) > 0)
{
// addresse du z-buffer
address = x + y * z_buffer_width + z_buffer_offset;
// si le pixel (x;y) est plus proche qu'avant
if (z_num <= z_buffer[address])
{
// enregistre la profondeur du pixel dans le z buffer
z_buffer[address] = z_num;
// afficher pixel noir
vram[(y << 4) + offset_vram] |= mask_vram;
// curseur
pixel_on_cursor(x, y);
}
}
u0 += u0_step_y; u1 += u1_step_y; u2 += u2_step_y;
z_num += z_num_step_y;
}
u0_start += u0_step_x; u1_start += u1_step_x; u2_start += u2_step_x;
z_num_start += z_num_step_x;
}
}*/
/*
void Windmill::render_triangle_black(Vertex* vertexA, Vertex* vertexB, Vertex* vertexC)
{
// calcul du rectangle circonscrit au triangle
int min_x = max(viewport.x1, min(vertexA->x, min(vertexB->x, vertexC->x)));
int max_x = min(viewport.x2-1, max(vertexA->x, max(vertexB->x, vertexC->x)));
int min_y = max(viewport.y1, min(vertexA->y, min(vertexB->y, vertexC->y)));
int max_y = min(viewport.y2-1, max(vertexA->y, max(vertexB->y, vertexC->y)));
// calcul de l'aire du triangle
int area = edge(vertexA, vertexB, vertexC);
// termine si la taille du triangle est trop petite
if (area <= MIN_AREA_CLIP) return;
// calcul des produits vectoriels
int u0_start = edge_start(vertexB, vertexC, min_x, min_y);
int u0_step_x = edge_step_x(vertexB, vertexC);
int u0_step_y = edge_step_y(vertexB, vertexC);
int u1_start = edge_start(vertexC, vertexA, min_x, min_y);
int u1_step_x = edge_step_x(vertexC, vertexA);
int u1_step_y = edge_step_y(vertexC, vertexA);
int u2_start = edge_start(vertexA, vertexB, min_x, min_y);
int u2_step_x = edge_step_x(vertexA, vertexB);
int u2_step_y = edge_step_y(vertexA, vertexB);
int z_num_start = (u0_start * vertexA->z_normalized + u1_start * vertexB->z_normalized + u2_start * vertexC->z_normalized) / area;
int z_num_step_x = (u0_step_x * vertexA->z_normalized + u1_step_x * vertexB->z_normalized + u2_step_x * vertexC->z_normalized) / area;
int z_num_step_y = (u0_step_y * vertexA->z_normalized + u1_step_y * vertexB->z_normalized + u2_step_y * vertexC->z_normalized) / area;
// acces a la vram
// char* vram = get_vram_address();
unsigned char mask_vram;
int offset_vram;
int address;
int u0, u1, u2;
int z_num;
// parcours en ligne
for(int x=min_x; x<=max_x; x++)
{
u0 = u0_start; u1 = u1_start; u2 = u2_start;
z_num = z_num_start;
offset_vram = x >> 3;
mask_vram = 128 >> (x & 7);
// parcours en colonne
for(int y=min_y; y<=max_y; y++)
{
// si le pixel (x;y) est dans le triangle
if ((u0 | u1 | u2) > 0)
{
// addresse du z-buffer
address = x + y * z_buffer_width + z_buffer_offset;
// si le pixel (x;y) est plus proche qu'avant
if (z_num <= z_buffer[address])
{
// enregistre la profondeur du pixel dans le z buffer
z_buffer[address] = z_num;
// afficher pixel noir
// vram[(y << 4) + offset_vram] |= mask_vram;
// curseur
pixel_on_cursor(x, y);
}
}
u0 += u0_step_y; u1 += u1_step_y; u2 += u2_step_y;
z_num += z_num_step_y;
}
u0_start += u0_step_x; u1_start += u1_step_x; u2_start += u2_step_x;
z_num_start += z_num_step_x;
}
}
*/
/*void Windmill::render_triangle_white(Vertex* vertexA, Vertex* vertexB, Vertex* vertexC)
{
// calcul du rectangle circonscrit au triangle
int min_x = max(viewport.x1, min(vertexA->x, min(vertexB->x, vertexC->x)));
int max_x = min(viewport.x2-1, max(vertexA->x, max(vertexB->x, vertexC->x)));
int min_y = max(viewport.y1, min(vertexA->y, min(vertexB->y, vertexC->y)));
int max_y = min(viewport.y2-1, max(vertexA->y, max(vertexB->y, vertexC->y)));
// calcul de l'aire du triangle
int area = edge(vertexA, vertexB, vertexC);
// termine si la taille du triangle est trop petite
if (area <= MIN_AREA_CLIP) return;
// calcul des produits vectoriels
int u0_start = edge_start(vertexB, vertexC, min_x, min_y);
int u0_step_x = edge_step_x(vertexB, vertexC);
int u0_step_y = edge_step_y(vertexB, vertexC);
int u1_start = edge_start(vertexC, vertexA, min_x, min_y);
int u1_step_x = edge_step_x(vertexC, vertexA);
int u1_step_y = edge_step_y(vertexC, vertexA);
int u2_start = edge_start(vertexA, vertexB, min_x, min_y);
int u2_step_x = edge_step_x(vertexA, vertexB);
int u2_step_y = edge_step_y(vertexA, vertexB);
int z_num_start = (u0_start * vertexA->z_normalized + u1_start * vertexB->z_normalized + u2_start * vertexC->z_normalized) / area;
int z_num_step_x = (u0_step_x * vertexA->z_normalized + u1_step_x * vertexB->z_normalized + u2_step_x * vertexC->z_normalized) / area;
int z_num_step_y = (u0_step_y * vertexA->z_normalized + u1_step_y * vertexB->z_normalized + u2_step_y * vertexC->z_normalized) / area;
// acces a la vram
char* vram = get_vram_address();
unsigned char mask_vram;
int offset_vram;
int address;
int u0, u1, u2;
int z_num;
// parcours en ligne
for(int x=min_x; x<=max_x; x++)
{
u0 = u0_start; u1 = u1_start; u2 = u2_start;
z_num = z_num_start;
offset_vram = x >> 3;
mask_vram = 128 >> (x & 7);
// parcours en colonne
for(int y=min_y; y<=max_y; y++)
{
// si le pixel (x;y) est dans le triangle
if ((u0 | u1 | u2) > 0)
{
// addresse du z-buffer
address = x + y * z_buffer_width + z_buffer_offset;
// si le pixel (x;y) est plus proche qu'avant
if (z_num <= z_buffer[address])
{
// enregistre la profondeur du pixel dans le z buffer
z_buffer[address] = z_num;
// afficher pixel blanc
vram[(y << 4) + offset_vram] &= ~mask_vram;
// curseur
pixel_on_cursor(x, y);
}
}
u0 += u0_step_y; u1 += u1_step_y; u2 += u2_step_y;
z_num += z_num_step_y;
}
u0_start += u0_step_x; u1_start += u1_step_x; u2_start += u2_step_x;
z_num_start += z_num_step_x;
}
}*/
/*void Windmill::render_triangle_transparent(Vertex* vertexA, Vertex* vertexB, Vertex* vertexC, const Texture* texture)
{
// calcul du rectangle circonscrit au triangle
int min_x = max(viewport.x1, min(vertexA->x, min(vertexB->x, vertexC->x)));
int max_x = min(viewport.x2-1, max(vertexA->x, max(vertexB->x, vertexC->x)));
int min_y = max(viewport.y1, min(vertexA->y, min(vertexB->y, vertexC->y)));
int max_y = min(viewport.y2-1, max(vertexA->y, max(vertexB->y, vertexC->y)));
// calcul de l'aire du triangle
int area = edge(vertexA, vertexB, vertexC);
// termine si la taille du triangle est trop petite
if (area <= MIN_AREA_CLIP) return;
// pre-calcul des coordonnees de la texture
int w0 = vertexA->w * vertexA->z; int h0 = vertexA->h * vertexA->z;
int w1 = vertexB->w * vertexB->z; int h1 = vertexB->h * vertexB->z;
int w2 = vertexC->w * vertexC->z; int h2 = vertexC->h * vertexC->z;
// calcul des produits vectoriels
int u0_start = edge_start(vertexB, vertexC, min_x, min_y);
int u0_step_x = edge_step_x(vertexB, vertexC);
int u0_step_y = edge_step_y(vertexB, vertexC);
int u1_start = edge_start(vertexC, vertexA, min_x, min_y);
int u1_step_x = edge_step_x(vertexC, vertexA);
int u1_step_y = edge_step_y(vertexC, vertexA);
int u2_start = edge_start(vertexA, vertexB, min_x, min_y);
int u2_step_x = edge_step_x(vertexA, vertexB);
int u2_step_y = edge_step_y(vertexA, vertexB);
int z_num_start = (u0_start * vertexA->z_normalized + u1_start * vertexB->z_normalized + u2_start * vertexC->z_normalized) / area;
int z_num_step_x = (u0_step_x * vertexA->z_normalized + u1_step_x * vertexB->z_normalized + u2_step_x * vertexC->z_normalized) / area;
int z_num_step_y = (u0_step_y * vertexA->z_normalized + u1_step_y * vertexB->z_normalized + u2_step_y * vertexC->z_normalized) / area;
int z_div_start = u0_start * vertexA->z + u1_start * vertexB->z + u2_start * vertexC->z;
int z_div_step_x = u0_step_x * vertexA->z + u1_step_x * vertexB->z + u2_step_x * vertexC->z;
int z_div_step_y = u0_step_y * vertexA->z + u1_step_y * vertexB->z + u2_step_y * vertexC->z;
// acces a la vram
char* vram = get_vram_address();
// pre-calcul largeur en octet des tableaux
int nbw_tex = ((texture->pixel_width - 1) >> 3) + 1;
char loop_w_tex = texture->pixel_width-1;
char loop_h_tex = texture->pixel_height-1;
// parcours en ligne
for(int x=min_x; x<=max_x; x++)
{
int u0 = u0_start; int u1 = u1_start; int u2 = u2_start;
int z_num = z_num_start;
int z_div = z_div_start;
int offset_vram = x >> 3;
char mask_vram = 128 >> (x & 7);
// parcours en colonne
for(int y=min_y; y<=max_y; y++)
{
// si le pixel (x;y) est dans le triangle
if ((u0 | u1 | u2) > 0)
{
// addresse du z-buffer
int address = x + y * z_buffer_width + z_buffer_offset;
// si le pixel (x;y) est plus proche qu'avant
if (z_num <= z_buffer[address])
{
// calcul des coordonnees pour la texture
unsigned int w = ((u0 * w0 + u1 * w1 + u2 * w2) / z_div) & loop_w_tex;
unsigned int h = ((u0 * h0 + u1 * h1 + u2 * h2) / z_div) & loop_h_tex;
// calcul du masque pour l'octet
unsigned char mask_w = 128 >> (w & 7);
if ((texture->sprite[(w >> 3) + (h * nbw_tex)] & mask_w))
{
// afficher pixel noir
vram[(y << 4) + offset_vram] |= mask_vram;
// enregistre la profondeur du pixel dans le z buffer
z_buffer[address] = z_num;
}
}
}
u0 += u0_step_y; u1 += u1_step_y; u2 += u2_step_y;
z_num += z_num_step_y;
z_div += z_div_step_y;
}
u0_start += u0_step_x; u1_start += u1_step_x; u2_start += u2_step_x;
z_num_start += z_num_step_x;
z_div_start += z_div_step_x;
}
}*/
//----------------------------------------------------------------------------------------------------
// UTILITAIRES
//----------------------------------------------------------------------------------------------------
int Windmill::edge(Vertex* a, Vertex* b, Vertex* c)
{
return (c->x - a->x) * (b->y - a->y) - (c->y - a->y) * (b->x - a->x);
}
int Windmill::edge_start(Vertex* a, Vertex* b, int px, int py)
{
return (b->y - a->y) * (px - a->x) - (b->x - a->x) * (py - a->y);
}
int Windmill::edge_step_x(Vertex* a, Vertex* b)
{
return b->y - a->y;
}
int Windmill::edge_step_y(Vertex* a, Vertex* b)
{
return a->x - b->x;
}

257
src/windmill_load.cpp Normal file
View File

@ -0,0 +1,257 @@
//----------------------------------------------------------------------------------------------------
//
// WINDMILL
//
// version : 2.0
// Moteur de rendu 3D base sur la methode de rasterisation avec buffer de profondeur
//
// Cree par Olivier Lanneau, alias NineStars
// Planet-casio.fr
//
//----------------------------------------------------------------------------------------------------
#include "windmill.hpp"
void debug_pop(char const *fmt, ...);
void debug_display(char const *fmt, ...);
extern Texture tex_white;
extern Texture tex_light;
extern Texture tex_dark;
extern Texture tex_black;
//----------------------------------------------------------------------------------------------------
// INITIALISATION
//----------------------------------------------------------------------------------------------------
Windmill::Windmill()
{
camera2 = NULL;
map = NULL;
//object = NULL;
z_buffer = NULL;
set_viewport(0, 0, 128, 64);
sun = {0, 0, 100};
}
Windmill::~Windmill()
{
free(z_buffer);
//free(object);
}
void Windmill::set_camera(Camera* _camera)
{
camera2 = _camera;
}
void Windmill::set_viewport(int viewport_x1, int viewport_y1, int viewport_x2, int viewport_y2)
{
viewport.x1 = max(0, viewport_x1);
viewport.y1 = max(0, viewport_y1);
viewport.x2 = min(viewport_x2, DWIDTH);
viewport.y2 = min(viewport_y2, DHEIGHT);
//if (z_buffer != NULL) free(z_buffer);
free(z_buffer);
shift_x = (viewport.x1 + viewport.x2) / 2;
shift_y = (viewport.y1 + viewport.y2) / 2;
z_buffer_size = (viewport.x2 - viewport.x1) * (viewport.y2 - viewport.y1);
z_buffer = (unsigned short*) calloc(z_buffer_size, 2);
//if (z_buffer == NULL) debug_pop("ERROR ptr z_buffer NULL");
z_buffer_width = viewport.x2 - viewport.x1;
z_buffer_offset = - viewport.x1 - viewport.y1 * DWIDTH;
clear_z_buffer();
}
void Windmill::set_map(Map* _map)
{
loading = true;
if (map != _map)
{
// free les anciennes ombres
// ...
// attribution de la map
map = _map;
// enregistrement d'une liste triable
//set_objects();
// calcul des spheres englobantes de chaque objet
compute_bouding_sphere();
// calcul des ombres projetees au sol par chaque objet
//compute_shadows();
}
loading = false;
}
/*void Windmill::set_objects()
{
//objects = new Object* [map->object_length];
objects = (Object**) malloc(map->object_length * sizeof(Object));
if (objects == NULL) debug_pop("ERROR ptr object NULL");
for (int i = 0; i<map->object_length; i++)
{
objects[i] = map->object[i];
}
}*/
void Windmill::compute_bouding_sphere()
{
// calcul des spheres englobantes pour chaque objet
for (int i = 0; i<map->object_length; i++)
{
Object* object = map->object[i];
int nb_point = 0;
int barycenter_x = 0;
int barycenter_y = 0;
int barycenter_z = 0;
// calcul du barycentre
for (int v = 0; v<object->mesh->v_length; v++)
{
VertexPoint vp = object->mesh->v[v];
barycenter_x += vp.x;
barycenter_y += vp.y;
barycenter_z += vp.z;
nb_point++;
}
barycenter_x /= nb_point;
barycenter_y /= nb_point;
barycenter_z /= nb_point;
// recherche du point le plus eloigne du barycentre
int square_radius_max = 0;
for (int v = 0; v<object->mesh->v_length; v++)
{
VertexPoint vp = object->mesh->v[v];
int dx = vp.x - barycenter_x;
int dy = vp.y - barycenter_y;
int dz = vp.z - barycenter_z;
int square_radius = dx*dx + dy*dy + dz*dz;
if (square_radius > square_radius_max)
{
square_radius_max = square_radius;
}
}
// enregistrement
object->sphere.x = barycenter_x;
object->sphere.y = barycenter_y;
object->sphere.z = barycenter_z;
object->sphere.radius = sqrtf(square_radius_max) + 1;
object->sphere.square_radius = square_radius_max + 1;
}
}
/*WMesh Windmill::compute_shadows()
{
// pout chaque objet
for (int i = 0; i<map->object_length; i++)
{
Object* object = map->object[i];
list_shadows_length = get_points_size(object;
//debug_pop("sh %i", list_shadows_length);
shadows = (Point*) malloc(list_shadows_length * sizeof(Point));
int index = 0;
// pour chaque poly
for (int j = 0; j<object->modele_size; j++)
{
const Modele* current_poly = &object->modele[j];
for (int k = 0; k<current_poly->type; k++)
{
Point point = get_point(current_poly, k);
Point shadow_point = {(sun.x * point.z - sun.z * point.x) / (point.z - sun.z), (sun.y * point.z - sun.z * point.y) / (point.z - sun.z), 0};
shadows[index] = shadow_point;
index ++;
//debug_pop("p %i %i %i", point.x, point.y, point.z);
//debug_pop("s %i %i %i", shadow_point.x, shadow_point.y, shadow_point.z);
}
}
}
}
// Gift Wrapping algorithme
void Windmill::compute_shadows_hull(Point3D* points, int points_size)
{
if (points_size < 3) return;
Point3D* temp_hull = (Point3D*) malloc(list_shadows_length * sizeof(Point3D));
int temp_hull_length = 0;
// commencer par le point le plus a gauche
int left = 0;
for (int i = 1; i<points_size; i++)
{
if (points[i].x < points[left].x)
{
left = i;
}
}
// calcul de la coque
int p = left, q;
do
{
// conserver point p
temp_hull[temp_hull_length] = points[p];
temp_hull_length ++;
q = (p+1)%points_size;
for (int i = 0; i < points_size; i++)
{
if (compute_shadows_hull_orientation(points[p], points[i], points[q]) == 2) // clockwise
{
q = i;
}
p = q;
}
} while (p != left);
free(temp_hull);
int hull_length = temp_hull_length;
Point3D* hull = (Point3D*) malloc(hull_length * sizeof(Point3D));
memcpy(hull, temp_hull, hull_length * sizeof(Point3D));
for (int i = 0; i<temp_hull_length; i++)
{
//dprint(0, 8*i)
}
}
int Windmill::compute_shadows_hull_orientation(Point3D a, Point3D b, Point3D c)
{
int val = (b.y - a.y) * (c.x - b.x) - (b.x - a.x) * (c.y - b.y);
if (val == 0) return 0; // colineaire
return (val > 0)? 1 : 2; // clock ou counterclock wise
}*/

133
src/windmill_transform.cpp Normal file
View File

@ -0,0 +1,133 @@
//----------------------------------------------------------------------------------------------------
//
// WINDMILL
//
// version : 2.0
// Moteur de rendu 3D base sur la methode de rasterisation avec buffer de profondeur
//
// Cree par Olivier Lanneau, alias NineStars
// Planet-casio.fr
//
//----------------------------------------------------------------------------------------------------
#include "windmill.hpp"
void debug_pop(char const *fmt, ...);
extern Texture tex_white;
extern Texture tex_light;
extern Texture tex_dark;
extern Texture tex_black;
//----------------------------------------------------------------------------------------------------
// TRANSFORMATION 3D
//----------------------------------------------------------------------------------------------------
void Windmill::transform_model_to_world(Object* object, Vertex vertex[], int vertex_length)
{
int cos = 0, sin = 0;
// precalcul de cos et sin
// /!\ CHANGEMENT D'ECHELLE : cos et sin << 10
/*if (object->axe == Z_BILLBOARD)
{
float angle_look_at_camera = atan2f(camera.y - object->y, camera.x - object->x);
float angle_rad = angle_look_at_camera + 3.1415 * object->angle / 180.0;
cosinus = 1024 * cosf(angle_rad);
sinus = 1024 * sinf(angle_rad);
}*/
//if (object->rotation.Null() == false)
if (object->axe == N)
{
float angle_rad = 3.1415 * object->angle / 180.0;
cos = 1024 * cosf(angle_rad);
sin = 1024 * sinf(angle_rad);
}
// transformation de chaque vertex
for (int k = 0; k<vertex_length; k++)
{
int vertex_x = vertex[k].x;
int vertex_y = vertex[k].y;
int vertex_z = vertex[k].z;
//if (cos == 0 and sin == 0)
if(object->axe == N)
{
vertex[k].x = vertex_x + object->position.x;
vertex[k].y = vertex_y + object->position.y;
vertex[k].z = vertex_z + object->position.z;
}
/*else
{
int a1 = object->rotation.x * object->rotation.x * (1024 - cos) + cos;
int a2 = object->rotation.x * object->rotation.y * (1024 - cos) - object->rotation.z * sin;
int a3 = object->rotation.x * object->rotation.y * (1024 - cos) + object->rotation.y * sin;
int a4 = object->rotation.x * object->rotation.y * (1024 - cos) + object->rotation.z * sin;
int a5 = object->rotation.y * object->rotation.y * (1024 - cos) + cos;
int a6 = object->rotation.y * object->rotation.z * (1024 - cos) - object->rotation.x * sin;
int a7 = object->rotation.x * object->rotation.z * (1024 - cos) - object->rotation.y * sin;
int a8 = object->rotation.y * object->rotation.z * (1024 - cos) + object->rotation.x * sin;
int a9 = object->rotation.z * object->rotation.z * (1024 - cos) + cos;
vertex[k].x = (a1 * vertex_x + a2 * vertex_y + a3 * vertex_z) / 1024 + object->position.x;
vertex[k].y = (a4 * vertex_x + a5 * vertex_y + a6 * vertex_z) / 1024 + object->position.y;
vertex[k].z = (a7 * vertex_x + a8 * vertex_y + a9 * vertex_z) / 1024 + object->position.z;
//vertex[k].x = ((vertex_x * cosinus - vertex_z * sinus) >> 10) + object->position.x;
//vertex[k].y = ((vertex_y * cosinus - vertex_z * sinus) >> 10) + object->position.y;
//vertex[k].z = ((vertex_y * sinus + vertex_z * cosinus) >> 10) + object->position.z;
}*/
if (object->axe == RX)
{
vertex[k].x = vertex_x + object->position.x;
vertex[k].y = ((vertex_y * cos - vertex_z * sin) / 1024) + object->position.y;
vertex[k].z = ((vertex_y * sin + vertex_z * cos) / 1024) + object->position.z;
}
if (object->axe == RY)
{
vertex[k].x = ((vertex_x * cos - vertex_z * sin) / 1024) + object->position.x;
vertex[k].y = vertex_y + object->position.y;
vertex[k].z = ((vertex_x * sin + vertex_z * cos) / 1024) + object->position.z;
}
if (object->axe == RZ)// or object->axe == Z_BILLBOARD)
{
vertex[k].x = ((vertex_x * cos - vertex_y * sin) / 1024) + object->position.x;
vertex[k].y = ((vertex_x * sin + vertex_y * cos) / 1024) + object->position.y;
vertex[k].z = vertex_z + object->position.z;
}
}
}
void Windmill::transform_world_to_camera(Vertex vertex[], int vertex_length)
{
for (int k = 0; k<vertex_length; k++)
{
// translation
int vertex_x = int(camera.x) - vertex[k].x;
int vertex_y = int(camera.y) - vertex[k].y;
int vertex_z = int(camera.z) - vertex[k].z;
// rotation
vertex[k].z = (-(camera.a1 * vertex_x + camera.a2 * vertex_y + camera.a3 * vertex_z) ) / SCALE_AI;
vertex[k].x = (camera.a4 * vertex_x + camera.a5 * vertex_y + camera.a6 * vertex_z ) / SCALE_AI;
vertex[k].y = (camera.a7 * vertex_x + camera.a8 * vertex_y + camera.a9 * vertex_z ) / SCALE_AI;
}
}
void Windmill::transform_camera_to_screen(Vertex vertex[], int vertex_length)
{
for (int k = 0; k<vertex_length; k++)
{
// perspective
vertex[k].x = (vertex[k].x * camera.scale_coef) / vertex[k].z + shift_x;
vertex[k].y = (vertex[k].y * camera.scale_coef) / vertex[k].z + shift_y;
// pre calcul
vertex[k].inv_z = (1<<13) / vertex[k].z;
vertex[k].z_normalized = (1<<15) * ( float(vertex[k].z - camera.near) / float(camera.far) );
}
}

240
src/windmill_utility.cpp Normal file
View File

@ -0,0 +1,240 @@
//----------------------------------------------------------------------------------------------------
//
// WINDMILL
//
// version : 2.0
// Moteur de rendu 3D base sur la methode de rasterisation avec buffer de profondeur
//
// Cree par Olivier Lanneau, alias NineStars
// Planet-casio.fr
//
//----------------------------------------------------------------------------------------------------
#include "windmill.hpp"
void debug_pop(char const *fmt, ...);
extern Texture tex_white;
extern Texture tex_light;
extern Texture tex_dark;
extern Texture tex_black;
//----------------------------------------------------------------------------------------------------
// DIVERS
//----------------------------------------------------------------------------------------------------
/*void WMesh::from_mesh(const Mesh* mesh, int margin)
{
// Double allocated memory because 3D clipping could generate more vertices and copy mesh into working mesh
WMesh wmesh;
v_length = mesh->v_length;
v_length_allocated = mesh->v_length * margin;
v = (Vertex*) malloc(v_length_allocated * sizeof(Vertex));
for (int i = 0; i < mesh->v_length; i++)
{
//v[i].FromVertexPoint(mesh->v[i])
v[i].x = mesh->v[i].x;
v[i].y = mesh->v[i].y;
v[i].z = mesh->v[i].z;
}
t_length = mesh->t_length;
t_length_allocated = mesh->t_length * margin;
t = (TexturePoint*) malloc(t_length_allocated * sizeof(TexturePoint));
memcpy(t, mesh->t, mesh->t_length * sizeof(TexturePoint));
f_length = mesh->f_length;
f_length_allocated = mesh->f_length * margin;
f = (Face*) malloc(f_length_allocated * sizeof(Face));
memcpy(f, mesh->f, mesh->f_length * sizeof(Face));
return wmesh;
}*/
/*WMesh Windmill::create_working_mesh(const WMesh* wmesh)
{
WMesh output_wmesh;
output_v_length = 0;
output_v_length_allocated = wmesh->v_length_allocated;
output_v = (Vertex*) malloc(output_v_length_allocated * sizeof(Vertex));
output_t_length = 0;
output_t_length_allocated = wmesh->t_length_allocated;
output_t = (TexturePoint*) malloc(output_t_length_allocated * sizeof(TexturePoint));
output_f_length = 0;
output_f_length_allocated = wmesh->f_length_allocated;
output_f = (Face*) malloc(output_f_length_allocated * sizeof(Face));
return output_wmesh;
}*/
void Windmill::copy_camera()
{
memcpy(&camera, camera2, sizeof(Camera)); // a supprimer cf remarque lephe
}
void Windmill::sort_object()
{
qsort(map->object, map->object_length, sizeof(Object*), compare_object);
}
int compare_object(void const *a, void const *b)
{
Object* object_a = *(Object **) a;
Object* object_b = *(Object **) b;
return (object_a->position.z - object_b->position.z);
}
void Windmill::clear_z_buffer()
{
memset(z_buffer, MAX_DEPTH_Z_BUFFER, z_buffer_size * sizeof(short));
}
float Windmill::distance(float dx, float dy, float dz)
{
return sqrtf(dx*dx + dy*dy + dz*dz);
}
//----------------------------------------------------------------------------------------------------
// DEBUG
//----------------------------------------------------------------------------------------------------
void Windmill::show_coordinates()
{
// coordonnees
float tab_coordinates[5] = {camera.x, camera.y, camera.z, to_deg(camera.yaw), to_deg(camera.pitch)};
for (int i = 0; i < 5; i++)
{
dprint_opt(1, 1+8*i, C_BLACK, C_WHITE, 0, 0, "%i", (int)(tab_coordinates[i]));
}
}
void Windmill::show_repere()
{
// repere
int repere_x = 112;
int repere_y = 55;
int repere_size = -12;
// repere
Vertex v[3];
const char* letter[] = {"x", "y", "z"};
v[0].set_xyz(repere_size, 0 , 0 );
v[1].set_xyz(0 , repere_size, 0 );
v[2].set_xyz(0 , 0 , repere_size);
for (int i = 0; i < 3; i++)
{
float x3D = (camera.a4 * v[i].x + camera.a5 * v[i].y + camera.a6 * v[i].z) / 128;
float y3D = (camera.a7 * v[i].x + camera.a8 * v[i].y + camera.a9 * v[i].z) / 128;
//float z3D = (-(camera.a1 * v[i].x + camera.a2 * v[i].y + camera.a3 * v[i].z)) / 128;
float x2D = x3D;
float y2D = y3D;
//int color = (z3D < 0 ? C_BLACK : C_LIGHT);
dline(repere_x, repere_y, x2D + repere_x, y2D + repere_y, C_BLACK);
dtext(x2D + repere_x, y2D + repere_y-2, C_BLACK, letter[i]);
}
}
//----------------------------------------------------------------------------------------------------
// VERTEX
//----------------------------------------------------------------------------------------------------
Vertex::Vertex(){}
Vertex::Vertex(int _x, int _y, int _z)
{
x = _x;
y = _y;
z = _z;
}
Vertex::Vertex(int _x, int _y, int _z, float _u, float _v)
{
x = _x;
y = _y;
z = _z;
u = _u;
v = _v;
}
void Vertex::set_texture(TexturePoint t)
{
u = t.u;
v = t.v;
}
void Vertex::set_xyz(int _x, int _y, int _z)
{
x = _x;
y = _y;
z = _z;
}
//----------------------------------------------------------------------------------------------------
// WMESH
//----------------------------------------------------------------------------------------------------
void WMesh::from_mesh(const Mesh* mesh, int margin)
{
// Double allocated memory because 3D clipping could generate more vertices and copy mesh into working mesh
v_length = mesh->v_length;
v_length_allocated = mesh->v_length * margin;
v = (Vertex*) malloc(v_length_allocated * sizeof(Vertex));
for (int i = 0; i < mesh->v_length; i++)
{
//v[i].FromVertexPoint(mesh->v[i])
v[i].x = mesh->v[i].x;
v[i].y = mesh->v[i].y;
v[i].z = mesh->v[i].z;
}
t_length = mesh->t_length;
t_length_allocated = mesh->t_length * margin;
t = (TexturePoint*) malloc(t_length_allocated * sizeof(TexturePoint));
memcpy(t, mesh->t, mesh->t_length * sizeof(TexturePoint));
f_length = mesh->f_length;
f_length_allocated = mesh->f_length * margin;
f = (Face*) malloc(f_length_allocated * sizeof(Face));
memcpy(f, mesh->f, mesh->f_length * sizeof(Face));
}
void WMesh::free_memory()
{
free(v);
free(t);
free(f);
}
void WMesh::add_vertex(Vertex vertex)
{
v[v_length].x = vertex.x;
v[v_length].y = vertex.y;
v[v_length].z = vertex.z;
t[t_length].u = vertex.u;
t[t_length].v = vertex.v;
if (v_length < v_length_allocated) v_length++;
if (t_length < t_length_allocated) t_length++;
}