Vous êtes sur la page 1sur 26

Windmill

Manuel d'utilisation V3.0

Moteur graphique 3D
Casio fx-9860G
Olivier Lanneau - NineStars

01/05/2019
Lien vers planète casio :

https://www.planet-casio.com/Fr/forums/lecture_sujet.php?id=14525


Windmill Page 1 sur 26


Introduction
Ce document présente Windmill, un moteur 3D programmé en C++ et compilé avec
le SDK CASIO pour les calculatrices graphiques de type graph75+ et graph35+USB.
La documentation qui suit présente la façon d’exploiter Windmill pour créer un
jeu. Windmill a été programmé dans le but d’être au maximum modulaire afin de
créer rapidement un jeu ou même d’être ajouté à un projet existant.

A l'origine Windmill était uniquement un moteur graphique 3D. Désormais, Windmill


est un projet bien plus large qui englobe de nombreuses autres fonctionnalités et
lui a donc donné son nom. Ainsi dans ce document, Windmill fera à la fois
référence au moteur graphique en lui-même, qu'au projet dans sa globalité.
Si vous ne souhaitez utiliser que le moteur graphique Windmill, rdv dans la section
associée.

Le moteur graphique Windmill est doté des fonctionnalités suivantes :


- Gestion d'objets 3D maillé en triangles
- Déplacement de caméra et rotation selon deux axes
- Translation et rotation de points
- Rastérisation de triangles texturés
- Rastérisation de triangles optimisés
- Buffer de profondeur
- Gestion d’objets dynamiques pouvant tourner selon les 3 axes
- Post traitement du rendu
- Gestion simplifiée des maillages et des textures
- Gestion des fenêtres d’affichages

Les autres fonctionnalités de Windmill :


- Gestion du clavier
- Gestion du jeu en scène
- Timer
- Moteur physique de collision simplifié
- Compatibilité SH3 et SH4

Note des versions :


v1.0 : version originale
v2.0 : refonte totale du document
v2.1 : ajout du moteur physique
v2.2 : ajout post traitement du rendu
V3.0 : refonte du document et ajout de plus de détails


Windmill Page 2 sur 26


Introduction ..................................................................2
Structure de Windmill ...................................................... 4
Scene........................................................................... 5
Windmill .......................................................................6
Notion sur les repères .........................................................6
Créer une carte .................................................................7
Définition d'une carte ..........................................................8
Définition d'une liste d'objets ................................................9
Définition d'un objet ........................................................... 9
Définition d'une liste de polygones ..........................................10
Zoom sur la définition d'un polygone poly .................................13
Retour sur la définition d'une liste de polygones ........................ 16
Définition d'une image sprite .................................................17
Définition d’une texture texture ............................................18
Bilan ...............................................................................21
Amélioration .....................................................................23

Scene Debug ..................................................................25


Windmill seul .................................................................26

Windmill Page 3 sur 26


Structure de Windmill
La structure de Windmill est articulée autour de 4 axes : Windmill, Game, Scene et
Map.

• Main initialise l'ensemble des variables, et gère le fonctionnement du jeu dans


son aspect général.
• Windmill est le moteur graphique 3D, l'origine du projet. Il regroupe tout ce à
trait à la 3D.
• Game est l'ensemble des informations sauvegardée d'une partie à l'autre.
• Scene est le coeur du jeu, c’est là que sont codés les parties gameplay.
• Map est le fichier renseignant l’ensemble des données 3D.

Main

Windmill Game Scene Map

Scene A

Scene B

...

Windmill Page 4 sur 26


Scene
Windmill est articulé autour de la notion de scènes. Une scène correspond à une
partie du jeu, une partie ayant sa propre façon de jouer ou interagir. Chaque scène
est composée de deux fonction : update et draw.
update est le moteur physique et de gestion du jeu. C'est la fonction servant à
gérer l'environnement du jeu : déplacement de la caméra, du personnage, du
curseur, ... Cette fonction est appelée à intervalle régulier.
draw est le moteur graphique. C'est la fonction servant à l'affichage, elle met
notamment à jour le moteur 3D Windmill.

Scene A

draw update
fps max fps constants

Cette distinction isole le moteur graphique du reste du jeu afin d’éviter une
dépendance entre la partie graphique et physique. Ainsi on profite d'un maximum
d’images par seconde tout en ayant une physique contrôlée.

On retrouve ainsi dans chaque scène les fonctions suivantes :

void launch();
void update();
void draw();
void terminate();

La fonction launch est appelé au lancement de la scène, ou du passage d’une scène


à une autre.
La fonction update est, comme expliqué au dessus, appelée à intervalles
régulières.
La fonction draw est appelé autant de fois que possible.
La fonction terminale est appelé à la fermeture d’une scène, ou du passage d’une
scène à une autre.

Etant donné que passer d’une scène à autre déclenche l’appel de launch et
terminate, les scènes ne doivent contenir aucune information à sauvegarder.
Toutes les information à sauvegarder se trouvent dans game.


Windmill Page 5 sur 26


Windmill
Le moteur graphique ne modifie pas l’écran, il se contente de dessiner dans la
vram, c’est à l’utilisateur de donner l’instruction de dessiner la vram à l’écran.

Avant de créer une nouvelle, il est nécessaire d’aborder des notions sur le
fonctionnement de Windmill : Les repères et les scènes.

Notion sur les repères

Il existe trois repères différents dans Windmill.


Z

Le repère propre :
Y
C'est dans ce repère que sont définis les triangles et
rectangles composants un objet.
X

Z monde
Le repère monde :

C’est le repère intuitif, celui dans lequel la caméra se Y monde


déplace et où les objets et la caméra sont placés.

Par défaut, la caméra regarde selon X, avec Y à sa X monde


gauche et Z vers le haut.

Le repère écran :
Z écran
C'est le repère propre à l'écran. Il possède un X écran
troisième axe perpendiculaire à l’écran
représentant la distance du pixel par rapport Y écran
à la caméra

Windmill Page 6 sur 26


Créer une carte

Voici l'arborescence de la structure des données nécessaires pour créer une carte.

Coordonnées Type

Image
Axe de
Poly 1 Textures
rotation
Paramètres de
Objet 1
la texture
Modèle Poly 2 Coordonnées

Liste d'objets Objet 2


Paramètres de
Carte collision
...
Paramètres de
la map
...

Cette arborescence parait lourde, mais une fois que les textures et les polygones
sont crées, la création d'une carte est très rapide puisqu'il suffit de les réutiliser.

La suite va décrire comment créer toutes ces parties

Windmill Page 7 sur 26


Dans ce tutoriel, nous allons obtenir le rendu suivant

Définition d'une carte

La première étape est de définir une carte, c’est à dire, un ensemble d’objets à
afficher dans le monde virtuel, avec quelques options supplémentaires.

Une carte se définie par les arguments suivants :

Map map_exemple = {objets, nb_objets, horizon, sol};

objets est un pointeur sur une liste d'objets et nb_objets le nombre d'objets dans
cette liste.
Horizon indique si la ligne d'horizon est affichée sur cette carte.
Sol indique si le motif du sol est affiché sur cette carte.

Pour cet exemple, nous allons créer la carte de la façon suivante :

Map map_exemple = {objets_exemple, 2, true, true};

Il y a donc 2 objets sur cette carte, ces objets sont définies dans le tableau
objets_exemple, la ligne d’horizon ainsi que le sol sont affichés.

Windmill Page 8 sur 26


Définition d'une liste d'objets
Rien de plus simple pour définir une liste d’objets, il suffit de donner faire la liste
des objets. Sur la carte map_exemple, il y aura donc les objets objet_exemple1 et
objet_exemple2.
Object* liste_exemple[] = {
&maison1, &maison2
};

Définition d'un objet

Un objet est unique, il est défini comme suit :

Object objet_exemple = {x, y, z, angle, axe, modèle,


modèle_taille};

Les coordonnées x, y, z et angle définissent son emplacement et sa position dans le


repère monde.
Le paramètre axe définie l’axe de rotation de l’objet. L'objet tourne d'un angle
exprimé en degrés par rapport à son propre repère, et non par rapport au repère
monde, soit X, Y ou Z. Si l'objet ne tourne pas il faut indiquer N, cela permet
d’optimiser certains calculs.
Il existe un axe particulier : Z_BILLBOARD. Avec cette valeur, l'objet tourne autour
de Z pour toujours faire face à la caméra. La technique des billboard est utilisée
pour simplifier les modèle 3D. Au lieu de modéliser en 3D un personnage, il suffit
que le personnage soit un simple rectangle faisant toujours face à la caméra. Cette
astuce peut aussi être utilisée pour les arbres.

Un objet est constitué d’un ensemble de polygones : un modèle. Un modèle est


composé des triangles et des rectangles positionnées dans l’espace sur lesquels
sont appliqués des textures. Nous allons voir juste après comment définir ce
modèle

modèle est un pointeur sur un modèle et modèle_taille est le nombre de polygones


composant le modèle.

Définissons les deux objets de cette façon :

Object maison1 = { 33,-50, 0, 0, N, modele_maison, 8};


Object maison2 = {100, 12, 0, 90, Z, modele_maison, 8};

Remarque :
Les deux objets font références au même modèle modele_exemple. Les deux
objets vont donc être basés sur les mêmes polygones, cependant il seront
positionnés différemment sur la carte. Il n’est pas nécessaire de modéliser deux
fois le même objet.

Windmill Page 9 sur 26


Définition d'une liste de polygones

Maintenant que nous avons vu comment créer un objet, passons à l’étape suivante.
Le modèle 3D !
Pour des soucis de mémoire, de performance et de simplicité, la création d’un
modèle 3D est réduite à l’utilisation de triangles et de rectangles, créés de façon
indépendantes. Il ne s’agit pas d’un réseau maillé de points.

Dans le cadre de cet exemple, notre modèle modele_exemple représentera une


maison à 4 murs, simple, mais regroupant l’ensemble des problèmes usuels.

D'abord :
- Quelle est la taille de la maison ?
- Comment décomposer la maison en triangles et rectangles ?
- Où mettre l'origine de son repère propre ?

Taille de la maison
On choisit une maison de 5m de long (sur X) par 2.5m de large (sur Y) par 3m de
haut (sur Z).
Le toit fera 1m de haut (sur Z).

Remarque : Quand il faut choisir les dimensions d'un modèle, il ne faut pas
raisonner en pixel mais en mètres. Les pixels n'ont rien à voir avec les dimensions
d'un modèle et le jeu ne sera pas plus rapide si la maison fait 16x8x4 ou 153x17x13.

Décomposition
Elle sera composée de 4 rectangles oranges, 2 rectangles verts et 2 triangles bleus.

Remarque : Chaque polygone consomme des performances. Il est important de


diminuer au maximum le nombre de polygone pour avoir un rendu fluide.

Origine
L'origine de son repère sera dans un coin.

Remarque : L’objet tourne autour du point 0, c’est à dire l’origine de son repère
propre. Ici le coin de la maison.

Il est important d’avoir une réponse à ces trois question avant de commencer un
modèle.


Windmill Page 10 sur 26


Ainsi, on obtient le modèle schématisé ci dessous :

1m
Z

3m Y

2.5m
X

5m

Pour un soucis de performance, les coordonnées des points d'un polygone sont des
entiers. Si l'on indiquait les coordonnées des polygones directement en mètres il ne
serait pas possible de faire des détails inférieurs au mètre (car il faudrait un
nombre entre 0 et 1)
Ainsi on pose une convention d'échelle entre les coordonnées réelles et les
coordonnées des points des polygones. Un bon compromis est :

1 mètre réel = 10 monde


10 centimètre réel = 1 monde
Le détail le plus fin est alors de 1 monde, soit 10 cm réel.

Ainsi en suivant cette convention, les dimensions de la maison, exprimées en


coordonnées monde sont :

10
Z

30 Y

25
X

50

Windmill Page 11 sur 26


Maintenant que le modèle est fixé, nous allons créer tous les polygones (triangles
et rectangles) composant ce modèle.
Commençons par le rectangle orange face à nous :

30 Y

50
Il est conseillé pour chaque polygone de s’imaginer face à lui, et de dessiner un
petit repère xyz avec les côte de largeur et hauteur.
Il est important de noter que de ce point de vue est à l’extérieur de la maison. On
regarde le mur depuis l’extérieur.

En se plaçant à l’intérieur de la maison nous aurions vu le rectangle de cette


façon :
Z

30

50
Y
Cependant, ce côté là du rectangle ne nous intéresse pas, seul l’extérieur nous
intéresse donc on se place sur le premier point de vue.

Windmill Page 12 sur 26


Zoom sur la définition d'un polygone poly

Reprenons un peu de recul. Un polygone est soit un triangle, soit un rectangle.

Le triangle

Un triangle est défini par une texture pour la face avant, une texture pour la face
arrière, et 3 points dans l'espace.

{TRIANGLE, tex_front, tex_back, x0,y0,z0, x1,y1,z1, x2,y2,z2 }

Le repère dans lequel sont définie ces points est le repère propre de l'objet.

2
Pour définir une face, l’ordre de déclaration des
points est important afin d’afficher la texture de
devant et pas celle de dos.

En tournant dans le sens trigo, c’est la texture avant
tex_front qui est affichée.


0 1

Le rectangle

Un rectangle est défini de la même manière que le triangle, il suffit de changer le


premier paramètre.

{RECTANGLE, tex_front, tex_back, x0,y0,z0, x1,y1,z1, x2,y2,z2 }

Le repère dans lequel sont définie ces points est le 2 3


repère propre de l'objet.

Dans le cas d'un rectangle, le quatrième point est


automatiquement calculé, c'est pourquoi il n'est pas à
indiquer manuellement.
Ce quatrième point est calculé pour former un triangle
(en vert), le tout formant un parallélogramme.

0 1

Remarque : Afin d’optimiser la vitesse du rendu, il faut indiquer la valeur NULL à


tex_back pour les faces arrières des objets qui n’ont pas vocation à être regardé de
dos. C’est le cas pour le mur de la maison.


Windmill Page 13 sur 26


Regardons comment appliquer cela à notre mur de maison :

{RECTANGLE, &tex_exemple, NULL, 0,0,0, 50,0,0, 0,0,30}


2
Z

30

0 X 1

50
On applique la texture tex_exemple sur la face avant, aucune texture sur la face
arrière, et les 3 point sont définis. Pour rappel, le fait d’avoir stipulé via le premier
paramètre que le polygone est un rectangle, a automatiquement crée le dernier
point.

Remarque : les textures ne sont pas encore définies, notamment la texture


tex_exemple. Le chapitre concernant les textures est abordé plus bas.

Pour simplifier la création des polygones, il est recommandé de créer des variables
de compilateur :
#define L 50// longueur X
#define H 30// hauteur Z

{RECTANGLE, &tex_exemple, NULL, 0,0,0, L,0,0, 0,0,H}

Faisons de même avec le triangle bleu à droite de la maison.

10
Z

30 Y

25
X

50

Windmill Page 14 sur 26


On se place avec le triangle face à soit, en étant à l’extérieur de la maison :

10
0 1

30

Y
25
Le tout est décalé sur X de 50.
{TRIANGLE, &tex_exemple, NULL, 50,0,30, 50,25,30, 50,12,40}

Même logique que pour le rectangle. Une remarque toutefois sur le dernier point.
Sa coordonnées sur Y est 12 et non 25/2=12.5 car les coordonnées doivent être des
nombres entiers. Dans notre cas, on pourrait très bien changer les dimensions de la
maison et imposer une largeur de 2,6m soit 26. Cela garantit la symétrie, mais
restons comme cela.

Windmill Page 15 sur 26


Retour sur la définition d'une liste de polygones

En poursuivant avec la même logique, on obtient la liste des polygones suivants.

#define L 50 // longueur X
#define W 25 // largueur Y
#define W2 12 // largeur divise par deux
#define H 30 // hauteur mur Z
#define HT 40 // hauteur toit Z
const Poly modele_maison[] = {
// les murs
{RECTANGLE, &tex_exemple, NULL, 0,0,0, L,0,0, 0,0,H},
{RECTANGLE, &tex_exemple, NULL, L,0,0, L,W,0, L,0,H},
{RECTANGLE, &tex_exemple, NULL, L,W,0, 0,W,0, L,W,H},
{RECTANGLE, &tex_exemple, NULL, 0,W,0, 0,0,0, 0,W,H},
// prolongement mur jusqu au toit
{TRIANGLE, &tex_exemple, NULL, L,0,H, L,W,H, L,W2,HT},
{TRIANGLE, &tex_exemple, NULL, 0,W,H, 0,0,H, 0,W2,HT},
// le toit
{RECTANGLE, &tex_exemple, NULL, L,W,H, 0,W,H, L,W2,HT},
{RECTANGLE, &tex_exemple, NULL, 0,0,H, L,0,H, 0,W2,HT},
};

Ensuite, il faut créer les objets en tant que tel, au dessus, il ne s’agit que d’un
modèle.

Object maison1 = { 33,-50, 0, 0, N, modele_maison, 8};


Object maison2 = {100, 12, 0, 90, Z, modele_maison, 8};

Et l’ajouter dans liste les objets à afficher sur cette map

Object* liste_exemple[] = {
&maison1, &maison2
};

Et le tout dans la map

Map map_exemple = {liste_exemple, 2, false, false};

Nous avons fait l’étape la plus délicate. Elle demande une bonne vision dans
l'espace et de l'habitude. Ne pas hésiter à griffonner sur papier, marquer les axes,
et commenter chaque poly pour noter son utilité.
Le plus difficile a été fait ! Maintenant tout va aller très vite.

Windmill Page 16 sur 26


Voici où nous en sommes rendu vis-à-vis de l’arborescence des choses à réaliser :

Coordonnées Type

Image
Axe de
Poly 1 Textures
rotation
Paramètres de
Objet 1
la texture
Modèle Poly 2 Coordonnées
Liste d'objets Objet 2
Paramètres de
Carte
collision
...
Paramètres de
la map
...

Il reste à définir les textures et les images, voyons ça de suite :

Définition d'une image sprite

Une image est codée en binaire à l'aide d'un logiciel de type Sprite Coder, la
largeur et la hauteur de l’image doivent être une puissance de deux (2, 4, 8, 16,
32, ...). La largeur et la hauteur peuvent être différentes.

const unsigned char sprite_exemple[]={


0xff,0xff,0xff,0xff,
0x87,0xff,0xfc,0x01,
...
};

La texture prise en exemple fait 32x32 pixels :

La texture choisie en exemple est, je vous l’accorde, très étrange. C’est par contre
un bon exemple car elle est asymétrique, ce sera davantage parlant pour la suite
des exemples.

Windmill Page 17 sur 26


Définition d’une texture texture

Général
Une texture se compose d'une image, un masque, des dimensions en pixel de
l'image, des dimensions réelles, du décalage et trois marqueurs pour la
transparence, un marqueur de décoration et le mode miroir.

struct Texture
{
const unsigned char* sprite;
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;
};
Les attributes pixels_height et pixel_width correspondent à la taille en pixel du
sprite, soit 32 et 32 dans notre cas. Ces tailles peuvent être différentes l’une de
l’autre mais doivent impérativement être des multiples de 2.

Taille réelle
Prenons le premier mur de notre maison (soit selon la convention choisie un mur de
5x3 mètres, explication plus haut), vu de face, sur lequel on applique
tex_exemple.

En définissant tex_exemple comme cela :


const Texture tex_exemple = {sprite_exemple, NULL, 32, 32, 0, 0,
0, false, false, false};

Le paramétrage de real_width et real_height à 0 étire la texture sur toute la


surface, peu importe ses dimensions réelles. C’est pourquoi elle apparait étirée en
largeur.

Windmill Page 18 sur 26


Mais on peut définir la taille réelle de la texture à l'aide des paramètres real_width
et real_height.
En définissant tex_exemple comme cela :
const Texture tex_exemple = {sprite_exemple, NULL, 32, 32, 12,
12, 0, false, false, false};

Le paramétrage de real_width et real_height indique que la texture fait 12 par 12


dans le repère monde (soit selon la convention choisie 1.2x1.2 mètres). Comme le
rectangle fait 50 par 30, la texture est plus petite et boucle pour occuper toute la
surface du rectangle.
A l’inverse du paramétrage :
const Texture tex_exemple = {sprite_exemple, NULL, 32, 32, 60,
60, 0, false, false, false};

Offset
L’exemple du dessus est appliqué à un rectangle, voyons maintenant comment cela
se passe avec un triangle.

Le paramètre offset est un nombre compris entre 0 et 1 permettant de définir la


partie de la texture utilisée si elle est appliquée sur un triangle.
La zone rouge montre quelle partie de la texture est utilisée dans le cas de
l'affichage d'un triangle.

const Texture tex_exemple = {sprite_exemple, 32, 32, 0, 0, 0.0,


false, false, false};

Windmill Page 19 sur 26


Offset = 0.0

Offset = 0.5

Offset = 1.0

Ce paramètre sera utilisé sur les deux triangles bleu de notre exemple.

Masque de transparence
Le masque de transparence permet d’afficher une texture uniquement quand le
même pixel du masque est noir.

Autres attributs
Le paramètre transparent indique que les pixels blancs de l'image sont
transparents.
Le paramètre decoration permet d’afficher la texture en priorité. Il s’affichera au
dessus de tout autre polygone avec le quel il devrait se confondre.
Le paramètre mirror indique si la texture est affichée en mode miroir sur la face
arrière.

Windmill Page 20 sur 26


Textures spéciales
Il existe aussi les textures spéciales permettant d’optimiser l’affichage : tex_black
et tex_white pour des textures unies noires ou blanches, et NULL pour aucune
texture.

Remarque : Les dimensions réelles d'une texture n'ont aucune raison d'être les
mêmes que les dimensions en pixels.

Remarque : Privilégier toujours l’utilisation des textures spéciales. L’algorithme


utilisé améliore considérablement les performances.

Remarque : Dû à la faible résolution de l’écran, et à la limitation bicolore. Il est


recommandé d’alterner les faces (par exemple les murs de maisons) entre une face
blanche et une face texturée. Cela offre une meilleure compréhension des
volumes.

Bilan

Tout les éléments de la chaine sont maitrisés, voici le code final pour dessiner la
maison :

// TEXTURES
const unsigned char sprite_exemple[]={
0xff,0xff,0xff,0xff,
0x87,0xff,0xfc,0x01,
0xb4,0x00,0x05,0xfd,
0xb4,0x00,0x05,0xfd,
0x84,0x00,0x04,0x01,
0xfc,0x00,0x07,0xff,
0xc0,0x00,0x00,0x01,
0xc0,0xfc,0x00,0x01,
0xc3,0x86,0x00,0x01,
0xcc,0x03,0x00,0x01,
0xc9,0x99,0x00,0x01,
0xc9,0x99,0x07,0xff,
0xc8,0x01,0x04,0x01,
0xc8,0x01,0x04,0x01,
0xc8,0xf1,0x04,0x01,
0xcc,0x62,0xff,0xff,
0xc6,0x06,0x80,0x21,
0xc3,0xfc,0x80,0x21,
0xc0,0x00,0x80,0x21,
0xc0,0x00,0xff,0xff,
0xc0,0x00,0x04,0x01,
0xc0,0x00,0x04,0x01,
0xc0,0x00,0x04,0x01,
0xc0,0x00,0x07,0xff,
0xc0,0x00,0x00,0x01,
0xc0,0x00,0x80,0x01,
0xfc,0x01,0xc0,0x3f,
0xc4,0x03,0xe0,0x3f,
0xa4,0x07,0x70,0x33,
0x94,0x0e,0x38,0x33,
0x8f,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,
};

Windmill Page 21 sur 26


const Texture tex_exemple = {sprite_exemple, NULL, 32, 32, 0, 0,
1, false, false, false};

// MODELE
#define L 50 // longueur X
#define W 25 // largueur Y
#define W2 12 // largeur divise par deux
#define H 30 // hauteur mur Z
#define HT 40 // hauteur toit Z

const Poly modele_maison_exemple[] = {


// les murs
{RECTANGLE, &tex_exemple, NULL, 0,0,0, L,0,0, 0,0,H},
{RECTANGLE, &tex_exemple, NULL, L,0,0, L,W,0, L,0,H},
{RECTANGLE, &tex_exemple, NULL, L,W,0, 0,W,0, L,W,H},
{RECTANGLE, &tex_exemple, NULL, 0,W,0, 0,0,0, 0,W,H},
// prolongement mur jusqu au toit
{TRIANGLE, &tex_exemple, NULL, L,0,H, L,W,H, L,W2,HT},
{TRIANGLE, &tex_exemple, NULL, 0,W,H, 0,0,H, 0,W2,HT},
// le toit
{RECTANGLE, &tex_exemple, NULL, L,W,H, 0,W,H, L,W2,HT},
{RECTANGLE, &tex_exemple, NULL, 0,0,H, L,0,H, 0,W2,HT},
};

// OBJET
Object maison1 = { 33,-50, 0, 0, N, modele_maison, 8};
Object maison2 = {100, 12, 0, 90, Z, modele_maison, 8};

Object* liste_exemple[] = {
&maison1, &maison2
};

// CARTE
Map map_exemple = {liste_exemple, 2, true, true};

Pour simplifier la lecture et garantir une certaine cohérence, il est conseillé


d’utiliser les préfixes normalisés suivants :
• sprite_ pour les images
• tex_ pour les textures
• modele_ pour les modèles
• liste_ pour les listes d’objets
• map_ pour les cartes

On obtient le rendu suivant :

Windmill Page 22 sur 26


Amélioration

En ajoutant différentes textures, comme une texture de brique pour les murs et de
paille pour le toit, on obtient un rendu plus réaliste :

Les murs en longueur sont bien vides. Nous allons voir comment ajouter des
détails.

Pour cela nous ajoutons deux rectangles sur chaque façade représentant des
fenêtres.
On utilise l’image suivante :

Avec la texture suivante :

const Texture tex_fenetre_simple = {sprite_fenetre_simple, NULL,


16, 16, 0, 0, 0, false, true, false};

L’image fait 16x16 pixels, on l’étale sur notre rectangle, et le paramètre


decoration est activé. C’est ce paramètre qui va permettre d’afficher par dessus
les murs les fenêtres.
On ajoute deux poly à notre modèle :

#define F 20 // position fenetre sur x
const Poly modele_maison[] = {

// fenetre
{RECTANGLE, &tex_fenetre_simple, NULL, F,0,7, F+9,0,7, F,
0,25},
{RECTANGLE, &tex_fenetre_simple, NULL, F,W,7, F-9,W,7, F,W,
25},
};

Windmill Page 23 sur 26


On remarque que les fenêtres sont sur le même plan yz que les murs, à 0 et à W.
Les fenêtres et les murs sont confondus, c’est le paramètre decoration qui va
permettre d’afficher en priorité les fenêtres.

Remarque :
Pour s’assurer un meilleur rendu, il faut placer les poly avec une texture de type
décoration en dernier dans la liste des polygones du modèle.

Nous venons de rajouter 2 polygones à notre modèle, il faut penser à mettre à jour
la taille du modèle dans les objets :

Object maison1 = { 33,-50, 0, 0, N, modele_maison, 10};


Object maison2 = {100, 12, 0, 90, Z, modele_maison, 10};

Et voici le rendu final :

Windmill Page 24 sur 26


Scene Debug
La scène debug est une scène spéciale qui permet de placer facilement les objets
créer sur la carte.
Cette scène est accessible via la touche : F1
Pour sélectionner l’objet suivant : F2
Pour sélectionner l’objet précédent : F3
Pour placer l’objet sur la position actuelle de la caméra : F4
Pour déplacer la caméra sur l’objet sélectionné : F5

Déplacer la caméra : REPLAY, COS et TAN

Les touches du pavé numérique : 1 à 9 permettent de déplacer un objet.

Une fois un objet placé comme souhaité, noter ses coordonnées x, y, z ainsi que
son angle puis reportez en dur dans le fichier.

Après la prochaine compilation, les objets seront là où vous venez de les placer.

Windmill Page 25 sur 26


Windmill seul
L’utilisation de Windmill seul implique d’utiliser les fonctions suivantes :

Windmill windmill;
windmill.Windmill(&tex_black, &tex_white);
windmill.load_map(map);
windmill.set_camera(&camera);
windmill.draw();

Windmill Page 26 sur 26

Vous aimerez peut-être aussi