3.1.2 Les directives du langage

Le langage de POV contient de nombreuses déclarations appelées directives de langage, qui guident l'analyseur. Ces directives peuvent apparaître dans tous les endroits du fichier de scène, même au milieu d'autres déclarations. Elles sont utilisées pour inclure d'autres fichiers texte dans le canal de commande, déclarer des identificateurs, définir des macros, des analyses conditionnelles ou bouclées, et pour contrôler d'autres aspects importants de l'élaboration de la scène.

Chaque directive commence avec un dièse #. Elle est suivie par un mot clé et d'autres paramètres optionnels.

Dans les versions antérieures à la 3.0, l'utilisation de ces caractères # était optionnelle. Les directives de langage ne pouvaient être utilisées qu'entre les déclarations d'objets, de caméras ou de sources de lumière, et ne pouvaient pas apparaître dans ces déclarations. L'exception était #include qui pouvait apparaître partout. Maintenant qu'elles peuvent être placées partout, le caractère # est obligatoire. Les mots clés suivants introduisent les directives de langage.

#break
#case
#debug
#declare
#default
#else
#end
#error
#fclose
#fopen
#if
#ifdef
#ifndef
#include
#local
#macro
#range
#read
#render
#statistics
#switch
#undef
#version
#warning
#while
#write

Les versions précédentes de POV-Ray considéraient que les mots clés #max_intersections et #max_trace_level étaient des directives de langage, mais ils ont été déplacés vers les déclarations global_settings, sans le signe #. Leur utilisation comme directive fonctionne encore, mais elle génère un message d'alerte, et ne sera plus tolérée dans le futur.

3.1.2.1 Les fichiers inclus et la directive #include

Le langage autorise la spécification de fichiers inclus, en mettant la ligne

#include "filename.inc"

en tout point du fichier en entrée. Le nom de fichier peut être donné par toute chaîne valide, mais c'est usuellement une chaîne littérale cernée d'apostrophes doubles. Il peut avoir jusqu'à 40 caractères de long (ou selon les limites de votre ordinateur), en incluant les apostrophes doubles.

Le fichier inclus est lu comme s'il était inséré en ce point. Cela équivaut au copiage du contenu de ce fichier dans votre scène.

Les fichiers inclus peuvent être emboîtés, et vous pouvez avoir jusqu'à 10 fichiers emboîtés. Il n'y a pas de limites pour les non emboîtés.

Généralement, ces fichiers ont des données pour les scènes, mais n'ont pas de scènes en eux-mêmes. Par convention, les scènes se terminent par .pov et les fichiers inclus par .inc.

Il est légal de spécifier le lecteur et les informations de dossier dans la spécification de fichier, toutefois, c'est déconseillé, car cela réduit la portabilité du fichier vers d'autres plates-formes. L'utilisation de minuscules est aussi recommandée mais pas obligatoire.

Note : si vous avez l'intention de distribuer des fichiers source faits pour POV-Ray, n'oubliez pas que certains systèmes d'exploitation ont des noms de fichier sensibles à la casse.

Il est typique de placer les fichiers inclus standards dans un sous-dossier spécial. POV-Ray peut seulement lire les fichiers dans le dossier courant, ou dans ceux référencés par l'option Library_Path ou le commutateur +L (voir la section "Les chemins de bibliothèques".

Vous pouvez utiliser la directive #local pour les identificateurs temporaires en durée, et limités à la portée du fichier inclus. Pour les détails, voir "#declare vs. #local".

3.1.2.2 Les directives #declare et #local

Les identificateurs peuvent être déclarés, et référencés ultérieurement, pour rendre les scènes plus lisibles et paramétrables. Il y a plusieurs identificateurs intégrés que POV-Ray déclare pour vous. Voir les sections "Les identificateurs numériques intégrés" et "Les identificateurs vectoriels intégrés" pour plus de détails.

3.1.2.2.1 Déclaration des identificateurs

Un identificateur est déclaré ainsi.

DECLARATION:
	#declare IDENTIFIER = RVALUE |
	#local IDENTIFIER = RVALUE
RVALUE:
	FLOAT; | VECTOR; | COLOR; | STRING | OBJECT | TEXTURE |
	PIGMENT | NORMAL | FINISH | INTERIOR | MEDIA | DENSITY |
	COLOR_MAP | PIGMENT_MAP | SLOPE_MAP | NORMAL_MAP |
	DENSITY_MAP | CAMERA | LIGHT_SOURCE | FOG | RAINBOW |
	SKY_SPHERE | TRANSFORM

IDENTIFIER est le nom de l'identificateur, jusqu'à 40 caractères de long, et RVALUE est l'un des éléments listés. Ils sont appelés ainsi car leurs valeurs peuvent apparaître à droite des égalités. La syntaxe de chacun est dans la section correspondante de ce référentiel. Voici quelques exemples.

#declare Rows = 5;
#declare Count = Count+1;
#local Here = <1, 2, 3>;
#declare White = rgb <1, 1, 1>;
#declare Cyan = color blue 1.0 green 1.0;
#declare Font_Name = "ariel.ttf"
#declare Rod = cylinder {-5*x, 5*x, 1}
#declare Ring = torus {5, 1}
#local Checks = pigment {checker White, Cyan}
object {Rod scale y*5}	// pas "cylinder {Rod}"
object {
	Ring
	pigment {Checks scale 0.5}
	transform Skew
}

Note : il doit y avoir un point-virgule à la fin des déclarations numériques, vectorielles ou de couleur. C'est introduit par POV-Ray version 3.1. S'il est omis, une erreur est générée, et certaines macros ne fonctionneront pas. Le point-virgule après les autres déclarations est optionnel.

Les déclarations, comme la plupart des directives de langage, peuvent apparaître n'importe où dans le fichier, même dans d'autres déclarations. Par exemple :

#declare Here = <1, 2, 3>;
#declare Count = 0;	// initialise Count
union {
	object {Rod translate Here*Count}
	#declare Count = Count+1;	// redéclaré dans union
	object {Rod translate Here*Count}
	#declare Count = Count+1;	// redéclaré dans union
	object {Rod translate Here*Count}
}

Comme le montre cet exemple, vous pouvez redéclarer un identificateur, et pouvez réutiliser les valeurs précédentes.

Note : l'identificateur objet utilise une déclaration générique object {...}. Vous n'avez pas besoin de connaître le type d'objet.

Les déclarations peuvent être emboîtées, dans certaines limites. Dans l'exemple de la section précédente, vous pouviez déclarer une union entière comme un objet. Toutefois, pour des raisons techniques, vous ne pouvez pas utiliser de directives de langage dans une déclaration d'expressions numériques, vectorielles ou de couleur. Bien que ces limites aient été repoussées avec POV-Ray 3.1, elles existent toujours.

Les identificateurs déclarés dans le bloc #macro ... #end ne sont pas créés pendant la définition de la macro. Ils ne sont créés qu'à l'appel de la macro. Comme la plupart des choses dans #macro, ils sont ignorés pendant la définition.

3.1.2.2.2 #declare vs. #local

Les identificateurs peuvent être déclarés soit globaux, avec #declare, soit locaux avec #local.

Ceux créés avec la directive #declare sont permanent dans la durée, et globaux dans la portée. Une fois créés, ils sont disponibles pour toute la scène et ne sont détruits qu'après l'analyse, ou si on utilise #undef. Voir "Détruire les identificateurs".

Ceux créés avec la directive #local sont temporaires dans la durée, et locaux dans la portée. Ils surchargent temporairement tout identificateur du même nom. Voir "Les conflits de noms d'identificateurs".

Si #local est utilisé dans une macro, alors l'identificateur est local à la macro. Quand la macro est appelée et analysée, l'identificateur est créé. Il persiste jusqu'au #end de la macro. Au #end, l'identificateur est détruit. Les appels suivants de la macro créent de nouveaux identificateurs.

L'utilisation de #local au sein d'un fichier inclus, mais en dehors d'une macro, crée aussi un identificateur temporaire, qui est local au fichier. Quand le fichier est inclus, et que la directive #local est analysée, l'identificateur est créé. Il persiste jusqu'à la fin du fichier inclus. Les inclusions suivantes de ce fichier créent de nouveaux identificateurs.

L'utilisation de #local dans le fichier maître (ni dans un fichier inclus, ni dans une macro) est identique à #declare. Pour clarifier les choses, vous ne devez pas utiliser #local dans un fichier maître, en dehors des macros.

Il n'y a actuellement aucun moyen de créer des identificateurs permanents mais locaux dans POV-Ray.

Les identificateurs locaux peuvent être détruits précocement avec #undef, mais ce n'est généralement pas nécessaire. Voir "Détruire les identificateurs".

3.1.2.2.3 Les conflits de noms d'identificateurs

Les identificateurs locaux peuvent avoir les mêmes noms que d'autres précédemment déclarés. Dans ce cas, l'identificateur le plus récent et le plus local prend la priorité. Lors de l'apparition d'un fichier inclus, ou de l'appel d'une macro, une nouvelle table de symboles est créée. Quand il est référencé, la table de symboles la plus récente est d'abord parcourue, puis son ainée la plus proche et ainsi de suite jusqu'à la table globale du fichier maître. Chaque fois qu'une macro, ou qu'un fichier inclus est terminé, sa table et ses identificateurs sont détruits. Les paramètres passés résident dans la même table que celle des identificateurs locaux de la macro.

Les règles pour dupliquer les identificateurs peuvent paraître compliquées lorsque plusieurs inclusions et macros sont emboîtées, mais en pratique vous obtenez ce que vous voulez.

Considérons cet exemple : vous avez un fichier maître appelé myscene.pov, et il contient :

#declare A = 123;
#declare B = rgb <1, 2, 3>;
#declare C = 0;
#include "myinc.inc"

Dans le fichier inclus, vous appelez une macro MyMacro(J,K,L). Le lieu de définition de la macro n'est pas important, tant qu'il se situe avant l'appel. Dans cet exemple, il est important que la macro soit appelée depuis myinc.inc.

Les identificateurs A, B et C sont disponibles à tous les niveaux. Si myinc.inc ou MyMacro contient une ligne comme #declare C=C+1; alors la valeur C est changée partout où vous le voulez.

Maintenant, supposons que vous ayez dans myinc.inc...

#local A = 546;

La première version de A est cachée, et un nouveau A est créé. Ce nouvel A est aussi disponible dans MyMacro, car elle est emboîtée dans myinc.inc. Dès que vous quittez myinc.inc, le A local est détruit, et le A original est de nouveau en ligne avec sa valeur de 123. Dès que vous avez créé le A local, il est impossible de référencer le A global sauf en utilisant le #undef A, ou en sortant du fichier inclus. L'utilisation de #undef touche toujours la version la plus locale d'un identificateur.

De la même manière, si MyMacro contient...

#local B = box {0, 1}

alors, un nouvel identificateur B local à la macro est créé. La valeur d'origine de B reste cachée, mais est restaurée dès la fin de la macro. Notez que le B local n'a pas besoin d'être du même type que l'original.

La complication vient lorsqu'on essaie d'assigner une nouvelle valeur à un identificateur local déclaré à un niveau précédent. Supposons dans myinc.inc...

#local D = 789;

Si vous êtes dans myinc.inc et que vous voulez incrémenter D, vous pouvez essayer de faire...

#local D = D + 1;

mais si vous essayer de le faire dans MyMacro, vous créerez un nouveau D local à MyMacro, ce qui ne concerne pas le D externe à MyMacro, mais local à myinc.inc. Vous aurez dit "créer un D de MyMacro avec le D de myinc.inc plus 1". Cela n'est probablement pas ce que vous voulez. Au lieu de cela, vous devriez faire...

#declare D = D + 1;

Vous pouvez penser que cela crée un nouveau D global, mais ceci incrémente le D de myinc.inc. Confus ? Voici les règles :

  1. Pendant le référencement d'un identificateur, vous touchez toujours le plus récent, le plus local. Par référencement, nous entendons l'utilisation de sa valeur dans une déclaration POV-Ray, ou son utilisation à droite d'une égalité, que ce soit pour un #declare ou un #local.
  2. Lors de la déclaration par un mot clé #local, l'identificateur créé ou réévalué est TOUJOURS créé à ce niveau d'emboîtement de la macro ou du fichier inclus.
  3. Lors de la déclaration d'un NOUVEAU identificateur, NON EXISTANT, avec #declare, il est créé comme global. Il est placé dans la table des symboles du fichier maître.
  4. Lors de l'ASSIGNATION D'UNE VALEUR A UN IDENTIFICATEUR EXISTANT, avec #declare, elle touche la version la plus récente, la plus locale, à cet instant.

En conclusion, #local signifie toujours "le niveau actuel", et #declare signifie "global" pour les nouveaux identificateurs, et "plus récent" pour les autres.

3.1.2.2.4 Destruction des identificateurs avec #undef

Les identificateurs créés avec #declare persisteront généralement jusqu'à la fin de l'analyse. Les locaux persisteront jusqu'à la fin de la macro ou de l'inclusion génératrice. Vous pouvez, toutefois, les détruire en utilisant la directive #undef. Par exemple :

#undef MyValue

Si de multiples versions locales sont empilées, la version la plus locale et la plus récente est détruite, et tous les identificateurs de même nom, mais de niveau supérieur, persistent.

Voir aussi "Les directives #ifdef et #ifndef".

3.1.2.3 Les directives I/O sur fichier

Vous pouvez ouvrir, lire, écrire, faire des ajouts et fermer des fichiers texte, pendant l'analyse des scènes. Cette caractéristique devait initialement aider la passage d'informations entre les pages d'une animation. Des valeurs comme la position d'objets peuvent être écrites pendant l'analyse d'une page, puis récupérées à la page suivante. Une utilisation clairvoyante de cette caractéristique autorise une scène POV-Ray à générer des fichiers inclus, ou écrire des scripts auto modifiables. Nous croyons que les utilisateurs amèneront d'autres utilisations intéressantes.

Note : certaines versions de plates-formes de POV-Ray (ex. Windows) fournissent des éléments pour restreindre la possibilité des fichiers scènes de lire & écrire des fichiers.

3.1.2.3.1 La directive #fopen

Les utilisateurs peuvent ouvrir un fichier texte en utilisant la directive #fopen. La syntaxe est :

FOPEN_DIRECTIVE:
	#fopen IDENTIFIER "filename" OPEN_TYPE
OPEN_TYPE:
	read | write | append

IDENTIFIER est un identificateur non défini utilisé pour référencer ce fichier comme terme, "nomfichier" est toute suite de caractères ou expression texte qui spécifie le nom du fichier. Les fichiers ouverts avec read ne peuvent qu'être lus. Le type write crée un nouveau fichier avec le nom spécifié, écrasant tout fichier de même nom existant. Ceux ouverts avec append ouvrent un fichier en mode écriture, mais ajoutent le texte à la fin d'un fichier existant.

Le terme fichier créé par #fopen est toujours global et reste effectif (et le fichier reste ouvert) pendant toute l'analyse de la scène, ou jusqu'à ce que vous fassiez #fclose du fichier. Vous pouvez utiliser #ifdef FILE_HANDLE_IDENTIFIER pour voir si le fichier est ouvert.

3.1.2.3.2 La directive #fclose

Les fichiers ouverts avec la directive #fopen sont automatiquement fermés à la fin de l'analyse, sinon vous pouvez les fermer avec la directive #fclose. La syntaxe est :

FCLOSE_DIRECTIVE:
	#fclose FILE_HANDLE_IDENTIFIER

FILE_HANDLE_IDENTIFIER est un fichier précédemment ouvert avec la directive #fopen. Voir "La directive #fopen".

3.1.2.3.3 La directive #read

Vous pouvez lire des chaînes, des valeurs numériques ou vectorielles depuis un fichier texte, directement dans des variables POV-Ray en utilisant la directive #read. Le fichier doit d'abord être ouvert en mode lecture avec la directive #fopen. La syntaxe est :

READ_DIRECTIVE:
	#read (FILE_HANDLE_IDENTIFIER, DATA_IDENTIFIER[,DATA_IDENTIFIER]..)
DATA_IDENTIFIER:
	UNDECLARED_IDENTIFIER | FLOAT_IDENTIFIER | VECTOR_IDENTIFIER | 
	STRING_IDENTIFIER

FILE_HANDLE_IDENTIFIER est un fichier précédemment ouvert. Il est suivi par un ou plusieurs DATA_IDENTIFIER séparés par des virgules. Les parenthèses autour de l'identificateur sont obligatoires. Un DATA_IDENTIFIER est tout identificateur non déclaré, ou tout identificateur chaîne, numérique ou vecteur déclaré. Les identificateurs non déclarés seront des identificateurs globaux du type déterminé par les datas lus. Les identificateurs déjà définis gardent leur statut global/local. La recherche du type est faite pour s'assurer que le type des datas est identique à celui des identificateurs.

Le format des datas à lire doit être une série de termes chaînes, numériques ou vectoriels valides, séparés par des virgules. Les expressions, ou les identificateurs, ne sont pas autorisés dans cette liste, toutefois, le symbole négatif et la notation exponentielle sont permis sur les valeurs numériques.

Si vous essayez de lire au-delà de la fin de fichier, ce dernier est fermé et FILE_HANDLE_IDENTIFIER est détruit de la table des symboles. Cela signifie que la fonction booléenne defined(IDENTIFIER) peut être utilisée pour détecter la fin de fichier. Par exemple :

#fopen MyFile "mydata.txt" read
#while (defined(MyFile))
	#read (MyFile, Var1, Var2, Var3)
	...
#end
3.1.2.3.4 La directive #write

Vous pouvez écrire des valeurs chaînes, numériques ou vectorielles dans un fichier texte, depuis les variables POV-Ray en utilisant la directive #write. Le fichier doit d'abord être ouvert en mode écriture ou ajout, avec la directive #fopen. La syntaxe est :

WRITE_DIRECTIVE:
	#write( FILE_HANDLE_IDENTIFIER, DATA_ITEM[,DATA_ITEM]...)
DATA_ITEM:
	FLOAT | VECTOR | STRING

FILE_HANDLE_IDENTIFIER est un fichier précédemment ouvert. Il est suivi de un ou plusieurs DATA_ITEM séparés par des virgules. Les parenthèses autour de l'identificateur sont obligatoires. Un DATA_ITEM est toute expression chaîne, numérique ou vectorielle valide. Les expressions numériques sont calculées et écrites sous forme de numérique signé. Si vous voulez un contrôle du format, vous devez utiliser la fonction str(VALUE,L,P) pour faire la conversion. Voir "Les fonctions chaînes de caractères" pour les détails sur la fonction str. Les expressions vectorielles sont transformées en trois constantes numériques signées, et sont écrites avec les parenthèses d'angle et les virgules, dans la notation vectorielle standard de POV-Ray. Les expressions chaînes sont écrites sans modification.

Note : les datas lus doivent avoir des virgules entre eux, et des apostrophes autour des chaînes, mais la directive #write ne le fait pas automatiquement.

Par exemple, la directive #read suivante lit une chaîne, un numérique et un vecteur.

#read (MyFile, MyString, MyFloat, MyVect)

Elle s'attend à lire quelque chose comme :

"A quote delimeted string", -123.45, <1, 2,-3>

Le code POV-Ray pour écrire cela doit être :

#declare Val1 = -123.45;
#declare Vect1 = <1, 2,-3>;
#write(MyFile, "\"A quote delimited string\", ", Val1, ", ", Vect1, "\n")

Voir "Les chaînes littérales" et "Le formatage de texte" pour les détails sur l'écriture de caractères spéciaux comme les apostrophes, les sauts de ligne, etc.

3.1.2.4 La directive #default

POV-Ray crée une texture par défaut quand il commence son travail. Vous pouvez changer ces défauts. Chaque fois que vous créez une déclaration texture, POV-Ray crée une copie de la texture par défaut. Tout ce que vous mettez dans la déclaration de texture surcharge le paramétrage par défaut. Si vous attachez un pigment, une normale ou une finition à un objet, sans la déclaration de texture, alors POV-Ray cherche si une texture a déjà été attachée. Si cela est vrai, alors elle subira ces modifications. Sinon, la texture par défaut est copiée, et les modifications lui sont attachées.

Vous pouvez changer la texture, le pigment, la normale ou la finition par défaut en utilisant la directive #default, comme ceci :

DEFAULT_DIRECTIVE:
	#default {DEFAULT_ITEM}
DEFAULT_ITEM:
	TEXTURE | PIGMENT | NORMAL | FINISH

Par exemple:

#default {
	texture {
		pigment {rgb <1, 0, 0>}
		normal {bumps 0.3}
		finish {ambient 0.4}
	}
}

signifie que les bosses rouges et la finition ambiance un peu haute seront le nouveau défaut pour les objets. Vous pouvez aussi n'en changer qu'une partie, comme ceci :

#default {
	pigment {rgb <1, 0, 0>}
}

Ceci change toujours le pigment de la texture par défaut. A tout instant, il n'y a qu'une texture par défaut, faite d'un pigment, d'une normale et d'une finition par défaut. L'exemple précédent ne fait pas un défaut séparé pour le seul pigment.

Note : Notez que les textures spéciales comme tiles et material_map ou une texture avec un texture_map, ne peuvent pas être utilisées comme défaut.

Vous pouvez changer les défauts plusieurs fois au cours de la scène. Les déclarations successives de #default agissent sur le défaut en cours à cet instant. Si vous voulez restaurer le défaut original, vous devez d'abord le sauvegarder comme ceci :

// Au début du fichier
#declare Original_Default = texture {}

ensuite, vous pouvez le restaurer avec...

#default {texture {Original_Default}}

Si vous ne spécifiez pas une texture pour un objet, la texture par défaut lui est attachée quand il apparaît dans la scène. Elle n'est pas attachée lors de la déclaration de l'objet. Par exemple :

#declare My_Object = sphere {<0, 0, 0>, 1}	// Texture par défaut non appliquée
object {My_Object}	// Texture par défaut ajoutée ici

Vous pouvez forcer une texture par défaut en utilisant une déclaration de texture vide, comme ici :

#declare My_Thing = sphere {<0, 0, 0>, 1 texture {}}	// Texture par défaut appliquée

Les défauts d'origine pour chaque élément sont donnés au fil de la documentation, dans les sections appropriées.

3.1.2.5 La directive #version

Bien que de nombreux changements aient été faits dans le langage, depuis la version 1.0, nous essayons, chaque fois que cela est possible, de maintenir la compatibilité. Certaines caractéristiques anciennes ou obsolètes peuvent être gérées directement sans plus de considération de la part de l'utilisateur. Mais certaines vieilles caractéristiques ne peuvent plus être utilisées. Toutefois, certaines peuvent être utilisées si vous avertissez POV-Ray de leur ancienneté. La directive #version est utilisée pour changer la version à l'intérieur des scènes. La syntaxe est :

VERSION_DIRECTIVE:
	#version FLOAT;

Note : il doit y avoir un point-virgule après l'expression numérique de la directive #version. C'est introduit dans POV-Ray version 3.1. S'il est oublié, cela génère une erreur, et quelques macros peuvent ne pas fonctionner.

En plus, vous pouvez utiliser l'option Version=n.n ou le commutateur +MVn.n pour placer le paramétrage initial. Voir "La version du langage" pour les détails. Par exemple, une caractéristique introduite avec la version 2.0, et qui n'était pas compatible avec la 1.0, était l'analyse des expressions numériques. Utiliser #version 1.0 désactive l'analyse des expressions, et beaucoup de messages d'alerte, ainsi, la plupart des scènes en version 1.0 fonctionneront encore. Naturellement, le défaut pour cette option est #version 3.6.

Note : quelques caractéristiques sont totalement indisponibles sous POV-Ray 3.5 QUELQUE SOIT LE PARAMETRAGE DE LA VERSION. Les détails sur ces caractéristiques sont notées le long de cette documentation.

L'identificateur intégré version contient le paramètre courant de l'option de compatibilité de version. Voir "Les identificateurs numériques intégrés". Avec l'identificateur programmé version, la directive #version vous permet de sauvegarder, et de restaurer, la valeur précédente. Le nouvel identificateur #local est très utile ici. Par exemple, supposons que mystuff.inc est en version 1.0. Au début du fichier, vous pouvez ajouter :

#local Temp_Vers = version;	// Sauve la valeur précédente
#version 1.0;	// Change pour le mode 1.0
...	// Matériel de la version 1.0 ici...
#version Temp_Vers;	// Restaure le version précédente

Les futures versions peuvent ne pas maintenir la compatibilité, même avec la directive #version. Nous vous recommandons de passer en mode 3.6 le plus tôt possible.

3.1.2.6 Les directives conditionnelles

POV-Ray a une large variété de directives de langage pour implémenter une analyse conditionnelle de nombreuses parties de vos scènes. Cela est surtout utile lors de la déclaration de mouvements pour les animations, mais cela peut avoir d'autres usages. Une directive de boucle #while est également disponible. Vous pouvez emboîter les conditions jusqu'à 200 niveaux.

3.1.2.6.1 Les directives #if...#else...#end

La directive conditionnelle la plus simple est la directive traditionnelle #if. Elle est de la forme...

IF_DIRECTIVE:
	#if ( Cond ) TOKENS... [#else TOKENS...] #end

Les TOKENS sont toute quantité de mots clés de POV-Ray, d'identificateurs, ou de ponctuations et ( Cond ) est une expression numérique qui est interprétée en valeur booléenne. Les parenthèses autour de la condition sont requises. La directive #end est requise. Une valeur de 0.0 est fausse, et toute valeur non nulle est vraie.

Note : les valeurs extrêmement petites, proches de 1e-10, sont considérées comme zéro, à cause des erreurs d'arrondi.

Si Cond est vrai, le premier groupe de commandes est analysé, et le second est sauté. S'il est faux, le premier est sauté et le second est analysé. Par exemple :

#declare Which = 1;
#if (Which)
	box {0, 1}
#else
	sphere {0, 1}
#end

La boîte est analysée et la sphère est sautée. Changer la valeur de Which à 0 signifie que la boîte est sautée, et la sphère analysée. La directive #else et le second groupe de termes sont optionnels. Par exemple :

#declare Which = 1;
#if (Which)
	box {0, 1}
#end

Mettre Which à 0 signifie que la boîte est ôtée.

Au début du chapitre "Les directives du langage" il était dit que "Ces directives peuvent apparaître à tous les endroits du fichier scène....". Ce qui suit est un exemple qui ne fonctionnera pas, il déroutera l'analyseur :

#if( #if(yes) yes #end ) #end
3.1.2.6.2 Les directives #ifdef et #ifndef

Les directives #ifdef et #ifndef sont similaires à #if, sauf qu'elles sont utilisées pour vérifier si un identificateur a été déclaré.

IFDEF_DIRECTIVE:
	#ifdef ( IDENTIFIER ) TOKENS... [#else TOKENS...] #end
IFNDEF_DIRECTIVE:
	#ifndef ( IDENTIFIER ) TOKENS... [#else TOKENS...] #end

Si IDENTIFIER existe, alors le premier groupe de termes est normalement analysé, et le second est sauté. Si c'est faux, le premier est sauté et le second analysé. Ceci est utile pour remplacer un élément non défini par le défaut. Par exemple :

#ifdef (User_Thing)
	// Cette section est analysée si
	// l'identificateur "User_Thing" a été
	// précédemment déclaré
	object {User_Thing}	// appelle l'identificateur
#else
	// Cette section est analysée si
	// l'identificateur "User_Thing" n'a pas été
	// précédemment déclaré
	box {<0, 0, 0>, <1, 1, 1>}	// utilise le défaut
#end
// Fin de la partie conditionnelle

La directive #ifndef fonctionne à l'opposé. La premier groupe est analysé si l'identifiicateur n'est pas défini. Comme pour la directive #if, la directive #else est optionnelle, au contraire de #end qui est obligatoire.

Les directives #ifdef et #ifndef peuvent être utilisées pour déterminer si un élément spécifique d'un tableau a été assigné.

#declare MyArray = array[10]
// #declare MyArray[0] = 7;
#ifdef(MyArray[0])
	#debug "premier élément assigné\n"
#else 
	#debug "premier élément pas assigné\n"
#end
3.1.2.6.3 Les directives #switch, #case, #range et #break

Une conditionnelle plus puissante est la directive #switch. La syntaxe est...

SWITCH_DIRECTIVE:
	#switch ( Switch_Value ) SWITCH_CLAUSE... [#else TOKENS...] #end
SWITCH_CLAUSE:
	#case( Case_Value ) TOKENS... [#break] |
	#range( Low_Value , High_Value ) TOKENS... [#break]

Les TOKENS sont tout nombre de mots clés de POV-Ray, d'identificateurs, ou de ponctuations et ( Switch_Value ) est une expression numérique. Les parenthèses sont requises. La directive #end est obligatoire. Le SWITCH_CLAUSE est en deux variétés. Pour #case, le numérique Switch_Value est comparé au numérique Case_Value. S'ils sont égaux, la condition est vraie.

Note : les valeurs dont la différence est inférieure à 1e-10 sont considérées comme égales, à cause des erreurs d'arrondis.

Pour #range, Low_Value et High_Value sont deux numériques séparés par une virgule et entourés de parenthèses. Si Low_Value <= Switch_Value et Switch_Value <= High_Value alors la condition est vraie.

Dans tous les cas, si la condition est vraie, les termes de cette condition sont analysés jusqu'à une directive #break, #else ou #end. Si la condition est fausse, POV-Ray saute sauf si une autre #case ou #range est trouvée.

Il peut y avoir autant de #case ou #range que vous voulez, et dans tout ordre. Si un segment donne vrai, mais qu'il n'y a pas de #break, l'analyse se poursuit à travers le #case ou le #range suivant et cette clause conditionnelle est évaluée. Un #break pendant l'analyse d'une section vraie, cause un saut immédiat jusqu'au #end, sans travailler les sections suivantes, même si une condition suivante pouvait se réaliser.

Une clause #else optionnelle peut être la dernière clause. Ce n'est exécuté que si la clause précédente est fausse.

Voici un exemple :

#switch (VALUE)
	#case (TEST_1)
		// Cette section est analysée si VALUE=TEST_1
		#break	//Fin du premier cas
	#case (TEST_2)
		// Cette section est analysée si VALUE=TEST_2
		#break	//Fin du second cas
	#range (LOW_1,HIGH_1)
		// Cette section est analysée si (VALUE >= LOW_1) & (VALUE <= HIGH_1)
		#break	//Fin du troisième cas
	#range (LOW_2,HIGH_2)
		// Cette section est analysée si (VALUE >= LOW_2) & (VALUE <= HIGH_2)
		#break	//Fin du quatrième cas
	#else
		// Cette section est analysée si aucun autre case ou range est vrai.
#end	// Fin de la partie conditionnelle
3.1.2.6.4 La directive #while...#end

La directive #while est une caractéristique bouclante, qui facilite le placement de multiples objets dans un modèle, ou pour d'autres usages.

WHILE_DIRECTIVE:
	#while ( Cond ) TOKENS... #end

Les TOKENS sont tout nombre de mots clés de POV-Ray, d'identificateurs, ou de ponctuations qui sont le corps de la boucle. La directive #while est suivie d'une expression numérique qui est évaluée en valeur booléenne. Une valeur de 0.0 est fausse, et tout autre est vraie.

Note : les valeurs en dessous de 1e-10 sont considérées comme zéro, en cas d'erreur d'arrondi.

Les parenthèses autour de l'expression sont requises. Si la condition est vraie, l'analyse continue jusqu'à la directive #end. A la fin, POV-Ray remonte à la directive #while, et la condition est réévaluée. La boucle se poursuit jusqu'à ce que la condition échoue. Dans ce dernier cas, l'analyse continue après la directive #end.

Note : il est possible qu'une condition échoue dès la première fois, et la boucle est totalement sautée. C'est de la responsabilité de l'utilisateur de s'assurer que quelque chose change dans la boucle pour autoriser sa fin.

Voici une boucle proprement construite comme exemple :

#declare Count = 0;
#while (Count < 5)
	object {MyObject translate x*3*Count}
	#declare Count = Count+1;
#end

Cet exemple place cinq copies de MyObject dans une ligne sur l'axe x, avec un espacement de 3 unités.

3.1.2.7 Les directives de message utilisateur

Avec l'ajout des directives conditionnelles et de boucle, le langage de POV-Ray a la possibilité de ressembler plus à un langage de programmation actuel. Cela signifie qu'il sera nécessaire d'avoir un moyen de voir ce qui se passe, quand on essaie de corriger les boucles ou les conditions. Pour satisfaire ce besoin, nous avons ajouté la possibilité d'écrire des messages à l'écran. Vous avez le choix entre cinq différents canaux de texte, avec la possibilité de générer une erreur fatale, si vous le jugez nécessaire. Un formatage limité est disponible pour ces chaînes.

3.1.2.7.1 Les canaux de messages

La syntaxe des messages est l'une des suivantes :

TEXT_STREAM_DIRECTIVE:
	#debug STRING | #error STRING | #warning STRING

STRING est toute chaîne de texte valide, incluant les identificateurs de chaîne ou fonctions qui retournent des chaînes. Par exemple :

#switch (clock*360)
	#range (0, 180)
		#debug "Clock dans la fourchette de 0 à 180\n"
		#break
	#range (180, 360)
		#debug "Clock dans la fourchette de 180 à 360\n"
		#break
	#else
		#warning "Clock en dehors des fourchettes attendues\n"
	#warning concat("La valeur est :", str(clock*360, 5, 0), "\n")
#end

Il y a sept canaux de texte différents que POV-Ray utilise pour la sortie. Vous pouvez écrire dans trois d'entre eux. Sur certaines versions de POV-Ray, chaque canal a sa couleur. Les textes de ces canaux sont affichés dès que possible, aussi nous avons souvent un mélange de textes. La distinction n'est importante que si vous choisissiez de désactiver certains canaux, ou de les diriger vers des fichiers texte. Sur certains systèmes, vous pouvez revoir les canaux séparément, dans leur propre fenêtre paginée. Voir 'Rediriger les canaux de texte vers des fichiers' pour les détails sur le détournement des canaux vers des fichiers.

Voici la description de l'utilisation de chaque canal par POV-Ray. Vous pouvez les utiliser pour ce que vous voulez, sauf que l'utilisation du canal #error cause une erreur fatale, après l'affichage.

Debug : ce canal affiche les messages de correction. A l'origine pour les développeurs, il peut être utilisé, comme d'autres, pour afficher des messages depuis les scènes.

Error : ce canal affiche les messages d'erreur fatale. Après l'affichage, POV-Ray stoppera. Quand l'erreur est une erreur d'analyse, vous pouvez voir les lignes incriminées.

Warning : ce canal affiche les messages d'alerte pendant l'analyse de la scène, et d'autres alertes. Malgré les alertes, POV-Ray peut continuer le rendu.

Les canaux #render et #statistsics pouvaient être accédés dans les versions précédentes. Leur sortie est maintenant redirigée vers le canal #debug. Les canaux #banner et #status ne sont pas accessibles.

3.1.2.7.2 Le formatage de texte

Quelques séquences d'échappement sont disponibles pour inclure des caractères non imprimables dans vos textes. Ces séquences sont similaires à celles utilisées dans les chaînes littérales du langage C. Elles sont :

"\a" Sonnerie ou alarme, 0x07
"\b" Espace arrière, 0x08
"\f" Saut de page, 0x0C
"\n" Nouvelle ligne (saut de ligne) 0x0A
"\r" Retour chariot 0x0D
"\t" Tabulation horizontale 0x09
"\uNNNN" Caractère Unicode NNNN 0xNNNN
"\v" Tabulation verticale 0x0B
"\0" Null 0x00
"\\" 'Backslash' 0x5C
"\'" Apostrophe simple 0x27
"\"" Double apostrophe 0x22

Par exemple :

#debug "Voici une ligne.\nMais en voici une autre"

Selon la plate-forme utilisée, elles ne sont pas toutes supportées par la sortie console. Toutefois, elles apparaîtront dans tout fichier texte, si vous détournez le canal vers un fichier.

3.1.2.8 Les macros définies par l'utilisateur

POV-Ray 3.1 a introduit la définition de macros avec des paramètres. Cette nouvelle caractéristique, avec la possibilité de déclarer des variables locales, transforme le langage de POV-Ray en un langage de programmation complètement fonctionnel. Il est maintenant possible d'écrire des utilitaires de génération de scène, ce qui nécessitait auparavant des utilitaires externes.

3.1.2.8.1 La directive #macro

La syntaxe pour déclarer une macro est :

MACRO_DEFINITION:
	#macro IDENTIFIER ([PARAM_IDENT] [, PARAM_IDENT]... ) TOKENS... #end

IDENTIFIER est le nom de la macro et les PARAM_IDENT sont une liste d'aucun ou plusieurs paramètres formels séparés par des virgules, et cernés par des parenthèses. Les parenthèses sont obligatoires, même si aucun paramètre n'est spécifié.

Les TOKENS sont tout nombre de mots clés de POV-Ray, d'identificateurs, ou de ponctuations qui forment le corps de la macro. Ce corps peut contenir tout élément de syntaxe désiré. Il se termine avec la directive #end.

Note: les directives conditionnelles comme #if...#end, #while...#end, etc. doivent être complètement englobées dans ou hors de la macro, de manière à ce que la directive #end appropriée puisse s'apparier.

Une macro doit être déclarée avant d'être appelée. Tous les noms de macro sont globaux et permanents. Vous pouvez redéfinir une macro avec une autre directive #macro du même nom. La définition précédente est perdue. Les noms de macro sont accessibles aux directives #ifdef, #ifndef et #undef. Voir "Les directives #ifdef et #ifndef" et "La destruction d'identificateurs avec #undef".

3.1.2.8.2 L'appel de macros

Vous appelez une macro en spécifiant son nom, suivi par une liste d'aucun ou plusieurs paramètres entre parenthèses et séparés par des virgules. Le nombre actuel de paramètres doit être égal à celui des paramètres formels de la définition. Les parenthèses sont obligatoires, même s'il n'y a pas de paramètres. La syntaxe est :

MACRO_INVOCATION:
	MACRO_IDENTIFIER ( [ACTUAL_PARAM] [, ACTUAL_PARAM]... )
ACTUAL_PARAM:
	IDENTIFIER | RVALUE

RVALUE est toute valeur qui peut apparaître à droite d'une égalité dans une déclaration #declare ou #local. Voir "La déclaration des identificateurs" pour des informations sur RVALUE. Quand une macro est appelée, une nouvelle table locale de symboles est créée. Les paramètres actuels sont assignés en paramètres d'identificateurs formels, comme des variables locales et temporaires. POV-Ray passe au corps de la macro et poursuit l'analyse jusqu'à la directive #end. Là, les variables locales créées par les paramètres sont détruites, comme tout identificateur local créé dans le corps de la macro. Puis il reprend l'analyse au point où la macro avait été appelée. C'est comme si le corps de la macro avait été inséré au point d'appel de la macro.

Note : il est possible d'appeller une macro déclarée dans un autre fichier. C'est assez normal et, en fait, c'est ainsi que fonctionnent tous les plugins (comme la macro populaire Lens Flare). Toutefois, sachez que ce genre d'appel amène plus de surcharge qu'un appel dans le même fichier.

Cela parce que POV-Ray ne stocke pas son langage. L'appel d'une macro d'un autre fichier demande son ouverture et sa fermeture à chaque appel. Normalement cette surcharge est sans conséquences; toutefois, si vous appelez cette macro plusieurs centaines de fois, cela peut donner des délais significatifs. Une version future de POV-Ray éliminera ce problème.

Voici une simple macro qui crée un objet fenêtre quand vous spécifiez les dimensions internes et externes.

#macro Make_Frame(OuterWidth, OuterHeight,InnerWidth, InnerHeight,Depth)
	#local Horz = (OuterHeight-InnerHeight)/2;
	#local Vert = (OuterWidth-InnerWidth)/2;
	difference {
		box {
			<0, 0, 0>, <OuterWidth, OuterHeight, Depth>
		}
		box {
			<Vert, Horz,-0.1>, <OuterWidth-Vert, OuterHeight-Horz, Depth+0.1>
		}
	}
#end
Make_Frame(8, 10, 7, 9, 1)	//appel de la macro

Dans cet exemple, la macro a cinq paramètres numériques. Les paramètres actuels (les valeurs 8, 10, 7, 9, et 1) sont assignés aux cinq identificateurs dans la liste de paramètres formels de #macro. C'est comme si vous aviez utilisé ces cinq lignes de code.

#local OuterWidth = 8;
#local OuterHeight = 10;
#local InnerWidth = 7;
#local InnerHeight = 9;
#local Depth = 1;

Ces cinq identificateurs sont stockés dans la même table de symboles que les autres identificateurs locaux comme Horz ou Vert. Tous sont détruits quand #end est atteint. Voir "Les conflits de noms d'identificateurs" pour une présentation détaillée sur la façon dont les identificateurs locaux, les paramètres et les identificateurs globaux fonctionnent quand un identificateur local porte un nom déjà pris.

3.1.2.8.3 Les macros de POV-Ray sont-elles des fonctions ou des macros ?

Les macros de POV-Ray sont un étrange mélange de macros et de fonctions. Dans les langages de programmation traditionnels, une macro fonctionne totalement par substitution de termes. Le corps de la routine est inséré au point d'appel par simple copiage des termes, et sont analysés comme si ils y avaient été copiés. Cette substitution est appelée macro substitution car c'est sa nature. Dans cette optique, les macros de POV-Ray sont exactement comme les macros traditionnelles dans l'utilisation de la substitution. Toutefois, les macros traditionnelles utilisent cette stratégie pour les paramètres, ce que ne fait pas POV-Ray.

Supposez que vous avez une macro en C Typical_Cmac(Param) et que vous l'appelez avec Typical_Cmac(else A=B). Partout où Param apparaît dans le corps de la macro, les quatre termes else, A, = et B sont substitués en utilisant une opération de couper-coller. Aucun test de type n'est fait car tout est légal. La possibilité de passer un groupe arbitraire de termes par l'intermédiaire des paramètres d'une macro, est une caractéristique puissante (et abusivement utilisée) des macros traditionnelles.

Après une soigneuse délibération, nous nous sommes décidés contre ce type de paramètres pour nos macros. La raison est que POV-Ray utilise plus souvent les virgules, dans sa syntaxe, que la plupart des langages de programmation. Supposez que vous créez une macro pour opérer sur un vecteur et deux numériques. Elle peut être définie comme OurMac(V,F1,F2). Si vous autorisez des chaînes de termes arbitraires, et appelez votre macro avec OurMac(<1, 2, 3>, 4, 5), alors, il est impossible de dire si c'est un vecteur et deux numériques, ou si c'est 5 paramètres avec les deux termes < et 1 comme premiers paramètres. Si vous définissez votre macro comme pouvant avoir 5 paramètres, alors vous ne pouvez pas l'appeler avec... OurMac(MyVector, 4, 5).

Les fonctions, dans les langages de programmation traditionnels, ne font pas de substitution pour passer des valeurs. Elles créent des variables locales pour stocker les paramètres, qui sont des valeurs constantes ou des références pointant en réalité sur une variable. Les macros de POV-Ray utilisent ce système de fonction pour passer des paramètres. Dans notre exemple OurMac(<1, 2, 3>, 4, 5), POV-Ray voit le < et sait que c'est le début d'un vecteur. Il analyse la totalité de l'expression vectorielle et l'assigne au premier paramètre, exactement comme si on avait utilisé #local V = <1, 2, 3>;.

Même si on dit que les paramètres de POV-Ray ressemblent plus aux paramètres de fonctions traditionnelles qu'à des paramètres de macros, il reste une différence. La plupart des langages vous demandent de déclarer le type de chaque paramètre de la définition avant de les utiliser, mais pas POV-Ray. Cela signifie que si vous passez un mauvais paramètre, cela ne génèrera pas d'erreur tant que vous ne le référencerez pas dans le corps de la macro. Aucun test de type n'est fait lorsque le paramètre est passé. Donc dans cette limite, les paramètres de POV-Ray ressemblent quelque peu à ceux des macros, et plus à ceux des fonctions.

3.1.2.8.4 Retourner une valeur comme une fonction

Les macros de POV-Ray ont toutes sortes d'utilisations. Comme d'autres macros, elles fournissent un moyen paramétrable d'insérer du code arbitraire dans une scène. Toutefois, la plupart serviront comme des fonctions ou des procédures dans un langage classique. Les macros sont désignées pour remplir tous ces rôles.

Quand le corps d'une macro est une série de déclarations construisant un élément complet comme un objet, une texture, etc. alors la macro agit comme une fonction qui retourne un valeur unique. L'exemple Make_Frame dans la section "Appeler les macros" est une telle macro qui renvoie une valeur, un objet. Voici quelques exemple sur la façon de l'appeler.

union {	//fait une union de deux objets
	object {Make_Frame(8, 10, 7, 9, 1) translate 20*x}
	object {Make_Frame(8, 10, 7, 9, 1) translate -20*x}
}
#declare BigFrame = object {Make_Frame(8, 10, 7, 9, 1)}
#declare SmallFrame = object {Make_Frame(5, 4, 4, 3, 0.5)}

Parce que aucune vérification de type n'est faite sur les paramètres, et parce que la syntaxe des expressions pour les numériques, les vecteurs et les couleurs est identique, vous pouvez créer des macros qui fonctionnent sur les trois. Voyez la scène MACRO3.POV qui inclut cette macro pour échanger les valeurs.

// Définit la macro. Les paramètres sont :
// T:  Valeur moyenne du temps
// T1: Temps initial
// T2: Temps final
// P1: Position initiale (peut être numérique, vecteur ou couleur)
// P2: Position finale (peut être numérique, vecteur ou couleur)
// Le résultat est une valeur entre P1 et P2 dans les mêmes proportions
// que T est entre T1 et T2.
#macro Interpolate(T, T1, T2, P1, P2)
	(P1+(T1+T/(T2-T1))*(P2-P1))
#end

Vous pouvez l'appeler avec P1 et P2 numériques, vectoriels ou en couleurs comme ce qui suit.

sphere {
	Interpolate(I, 0, 15, <2, 3, 4>, <9, 8, 7>),	//la localisation du centre est un vecteur
	Interpolate(I, 0, 15, 3.0, 5.5)	//le rayon est numérique
	pigment {
		color Interpolate(I, 0, 15, rgb <1, 1, 0>, rgb <0, 1, 1>)
	}
}

Comme valeur numérique, I va de 0 à 15, la position, le rayon et la couleur de la sphère s'y accordent.

Il y a un danger à utiliser les macros comme des fonctions. Dans un langage traditionnel, le résultat est assigné à une variable temporaire, et le code appelé la traite comme une variable d'un certain type. Toutefois, les macros substitutions peuvent donner une syntaxe invalide ou non désirée. La définition de la macro Interpolate a un important lot de paramètres entre parenthèses. Si ces parenthèses sont omises, cela n'aura pas d'importance dans l'exemple précédent, mais si vous faites ceci...

#declare Value = Interpolate(I, 0, 15, 3.0, 5.5)*15;

Le résultat sera comme si vous aviez fait...

#declare Value = P1+(T1+T/(T2-T1))*(P2-P1) * 15;

qui est une syntaxe légale, mais pas mathématiquement correcte, car P1 n'est pas multiplié. Les parenthèses dans l'exemple d'origine résolvent ce problème. Le résultat final est comme si vous aviez fait...

#declare Value = (P1+(T1+T/(T2-T1))*(P2-P1)) * 15;

qui est correct.

3.1.2.8.5 Retourner des valeurs via les paramètres

Quelque fois, il est nécessaire qu'une macro renvoie plus d'une valeur, ou vous pouvez simplement préférer retourner une valeur via un paramètre, comme dans les procédures des langages traditionnels. Les macros de POV-Ray sont capable de le faire. La syntaxe pour les paramètres de macros de POV-Ray dit que le paramètre peut être un IDENTIFIER ou une RVALUE. Les valeurs ne peuvent être retournées comme paramètre que si le paramètre est un IDENTIFIER. Les paramètres qui sont des RVALUE sont des valeurs constantes qui ne peuvent pas retourner d'information. Une RVALUE est tout ce qui peut apparaître légalement à droite de l'égalité d'une directive #declare ou #local. Par exemple, considérons la macro suivante qui fait tourner un objet autour de l'axe x.

#macro Turn_Me(Stuff, Degrees)
	#declare Stuff = object {Stuff rotate x*Degrees}
#end

Ceci essaie de redéclarer l'identificateur Stuff comme la version tournée de l'objet. Toutefois, la macro doit être appelée avec Turn_Me(box {0, 1}, 30) qui utilise un objet boîte comme paramètre RVALUE. Cela ne fonctionnera pas car la boîte n'est pas un identificateur. Vous pouvez faire ceci :

#declare MyObject = box {0, 1}
Turn_Me(MyObject, 30)

L'identificateur MyObject contient maintenant la boîte tournée.

Voir "Les conflits de noms d'identificateurs" pour les détails sur le fonctionnement des identificateurs locaux, et globaux, quand un identificateur local prend un nom déjà déclaré.

Bien qu'il soit évident que MyObject est un identificateur, et pas box {0, 1}, il doit être noté que Turn_Me(object {MyObject}, 30) ne fonctionnera pas car object {MyObject} est considéré comme une déclaration d'objet, et non un identificateur pur. Cette erreur peut être plus fréquente entre les identificateurs numériques et les expressions numériques. Considérez ces exemples.

#declare Value = 5.0;
MyMacro(Value)	// MyMacro peut changer la valeur de Value mais...
MyMacro(Value)	// Cette version et la suite ne sont pas des
MyMacro(Value+0.0)	// identificateurs seuls. Ce sont des expressions numériques
MyMacro(Value*1.0)	// qui ne peuvent pas être changées.

Quoique les 5 appels de MyMacro ont passé la valeur 5.0, seul le premier peut changer la valeur de l'identificateur.

Complément sur "#macro" Complément sur la texture
3.1.1 Les bases du langage 3.1.1 Les bases du langage 3.2 Les paramétrages de scène 3.2 Les paramétrages de scène