From BlenderWiki

Jump to: navigation, search
Blender3D FreeTip.gif
IMPORTANT! Do not update this page!
We have moved the Blender User Manual to a new location. Please do not update this page, as it will be locked soon.

Traduction effectuée d’après cette révision de la version anglaise.

Le système de plugins de Blender

Cette page résume une référence sur l’écriture des plugins Blender de types Texture et Sequence.

NdT
J’ai choisi de ne pas traduire les exemples de code, même pas les commentaires ! En effet, j’ai remarqué (dans mes manuels de programmation, par ex.) que cela mène presque toujours à des incohérences : noms de variables traduits dans le commentaire mais pas dans le code lui-même… De plus, je crois qu’il vaut mieux maîtriser un minimum la langue de Shakespeare (ou de Turing, par exemple !) pour se lancer sérieusement dans la programmation… ne serait-ce que parce que (presque) tous les langages (ainsi que les APIs, comme celle de Blender) utilisent l’anglais comme “base”, et que leur documentation est rarement traduite !
Essayez donc d’écrire votre code (noms des fichiers, variables, constantes, fonctions…) et vos commentaires en anglais : c’est la meilleure façon de les rendre accessibles au plus grand nombre… même pour l’interface utilisateur : si vous employez un système d’i18n comme gettext, vous aurez plus de chance de trouver des traducteurs anglais → japonais, que français → japonais, par exemple !


Écrire un plugin de texture

Dans cette partie, nous écrirons un plugin texture basique, puis verrons les étapes nécessaires à son utilisation.

Les principes de base d’un plugin texture est que vous lui fournissez des données d’entrée : entre autre, position, normales…, et il produira des données en sortie, intensité, couleur et/ou normale, suivant le type de plugin texture.

Tous les fichiers nécessaires au développement de plugins, de même que quelques plugins d’exemple, sont situés dans le dossier blender/plugins. Vous pouvez également récupérer un ensemble de plugins depuis ce dépôt de plugins. Les plugins sont gérés (chargés/déchargés) par Blender via la famille de fonctions dlopen(). Pour ceux qui ne sont pas familiers avec ce système, celui-ci permet à un programme (Blender) d’utiliser un objet compilé à part comme s’il faisait partie du programme lui-même, sur le même principe que les bibliothèques (ou “librairies” – sic) liées dynamiquement (dynamically linked libraries), sauf que cet objet n’est pas connu à la compilation du programme principal : il est “découvert” par le programme lui-même, souvent au démarrage.

L’avantage d’utiliser le système dlopen pour les plugins est que l’accès aux fonctions de ceux-ci est très rapide, et qu’on ne perd ni temps ni mémoire à établir une interface avec le plugin, ce qui est un point critique quand (pour un plugin texture) il peut être appelé plusieurs millions de fois dans un seul rendu. Le désavantage de ce système est que le code du plugin est “intégré” à celui de Blender lorsqu’il est chargé : si le plugin plante, Blender plante.

Les fichiers include du sous-dossier plugin/include/ de celui où est installé Blender documentent les fonctionnalités fournies par Blender aux plugins. Cela inclut les fonctions de bibliothèque Imbuf pour charger et travailler avec des images et tampons (buffers) d’image, et les fonctions de bruit et turbulence.

Spécifications

#include "plugin.h"
Tous les plugins Blender doivent inclure ce fichier d’en-tête, qui contient toutes les structures et définitions nécessaires pour bien travailler avec Blender.
char name[]="Tiles";
Une chaîne de caractères contenant le nom du plugin, cette valeur sera affichée comme titre de la texture dans la fenêtre Button en sous-contexte Texture.
#define NR_TYPES 2; char stnames[NR_TYPES][16]= {"Square", "Deformed"};
Les plugins peuvent avoir des “sous-types” séparés pour des variations mineures de leur(s) algorithme(s) – par exemple, la texture Clouds de Blender a les sous-types Default et Color. NR_TYPES devrait être défini au nombre de sous-types présents dans votre plugin, et un nom pour chacun d’entre-eux devrait être donné (tableau stnames[NR_TYPES]). Tous les plugins doivent avoir au moins un sous-type et un nom de sous-type.
VarStruct varstr[]= {...};
varstr contient toute l’information dont Blender a besoin pour afficher les contrôles d’un plugin. Ceux-ci peuvent être des boutons numériques – pour entrer des valeurs, du texte statique – pour des commentaires… Les plugins sont limités à au maximum 32 variables de ce type. Chaque entrée VarStruct est constituée d’un “type”, “name” (nom), “range information” (information de limites), et d’un “tool tip” (message d’aide).
Le type définit le type de donnée pour chaque contrôle, et le type de celui-ci. Pour les boutons numériques, cette valeur devrait être une combinaison (OU binaire, “|”) de “INT” ou “FLO” pour le format numérique (entier ou flottant), et de “NUM”, “NUMSLI” ou “TOG”, pour le type de contrôle (numérique, numérique avec curseur, ou bouton toggle “interrupteur”). Les contrôles texte devraient avoir un type “LABEL”.
Le name est ce qui sera écrit sur le (ou à côté du) contrôle. Limité à 15 caractères.
La range information est constituée de trois nombres flottants qui définissent les valeurs par défaut, minimale et maximale du contrôle. Pour les boutons “interrupteur”, le minimum correspond à l’état actif (pressé), et le maximum à l’état désactivé (relâché).
La tool tip est une chaîne de caractères qui sera affichée quand le pointeur de la souris survolera le contrôle (si l’utilisateur a activé les Tool Tips (info-bulles)). Sa longueur maximale est de 80 caractères, et elle devrait avoir la valeur chaîne nulle ("") si elle n’est pas utilisée.
typedef struct Cast {...};
La structure Cast est utilisée à l’appel de la fonction doit, et sert à avoir un accès aisé aux valeurs de tous les contrôles du plugin. Elle devrait contenir, dans l’ordre, un entier ou un flottant pour chacun des contrôles définis dans varstr, même les textes. Normalement, ils devraient avoir le même nom que le contrôle, pour simplifier la lecture/maintenance du code.
float result[8];
le tableau result est utilisé pour passer des données au plugin et en recevoir. Les valeurs du tableau sont organisées comme suit :
 Index de result  Signification  Min/Max 
 result[0]  Valeur d’intensité  0.01.0 
 result[1]  Valeur de couleur rouge  0.01.0 
 result[2]  Valeur de couleur vert  0.01.0 
 result[3]  Valeur de couleur bleu  0.01.0 
 result[4]  Valeur de couleur alpha  0.01.0 
 result[5]  Composante X de la normale  -1.01.0 
 result[6]  Composante Y de la normale  -1.01.0 
 result[7]  Composante Z de la normale  -1.01.0 
Le plugin devrait toujours retourner une valeur d’intensité. Retourner une valeur RGBA ou une normale est optionnel, et devrait être indiqué par la valeur de retour de doit() : “1” (RGBA) ou “2” (Normale).
Avant d’appeler le plugin, Blender remplit result[5], result[6] et result[7] avec les valeurs de la normale courante.
float cfra
La valeur cfra est mise par Blender à l’image courante, avant chaque passe de rendu. Il s’agit d’un numéro d’image (± 0.5 si les trames sont activées).
Prototype plugin_tex_doit
La fonction plugin_tex_doit devrait être prototypée pour être utilisée par la fonction getinfo. Vous n’avez pas besoin de modifier cette ligne.
plugin_tex_getversion
Cette fonction doit être dans chaque plugin pour qu’il soit chargé correctement. Vous ne devriez pas la modifier.
plugin_but_changed
Cette fonction est utilisée pour passer des informations sur quels contrôles de l’interface ont été modifiés par l’utilisateur. La plupart des plugins ne devraient pas avoir besoin de cette fonction, utile seulement quand l’interface permet à l’utilisateur de modifier des variables qui obligent le plugin à refaire des calculs (comme pour une table de hachage aléatoire, par exemple).
plugin_init
Si besoin, les plugins peuvent utiliser cette fonction pour initialiser leurs variables internes.
Note : Cette fonction d’initialisation peut être appelée plusieurs fois si la même texture plugin est copiée. N’initialisez pas les variables globales spécifiques à une instance particulière d’un plugin dans cette fonction.
plugin_getinfo
Cette fonction est utilisée pour communiquer des informations à Blender. Vous ne devriez jamais avoir besoin de la modifier.
plugin_tex_doit
La fonction doit est celle qui effectue vraiment les calculs : elle est chargée de retourner à Blender les données modifiées pour le pixel spécifié.
Les arguments
int stype
Il s’agit du numéro du sous-type choisi, voyez NR_TYPES et char stnames[NR_TYPES][16] ci-dessus.
Cast *cast
La structure Cast qui contient les variables du plugin, voyez typedef struct Cast ci-dessus.
float *texvec
Il s’agit d’un pointeur sur un tableau de trois nombres flottants, qui sont les coordonnées texture du pixel à calculer.
float *dxt, float *dyt
Si ces pointeurs sont non-NULL, ils pointent sur deux vecteurs (deux tableaux de trois nombres flottants) qui définissent la taille de la zone de texture à calculer (dans l’espace de celle-ci). Ils ne sont valides que lorsque l’OSA (anti-aliasing) est activé, et sont utilisés pour un calcul correct de celui-ci.
La fonction doit devrait remplir le tableau de résultat (elle devrait au minimum toujours produire une valeur d’intensité), et retourner 0, 1, 2 ou 3 en fonction des données produites :
  • 0 pour l’intensité seule,
  • 1 pour l’intensité + la couleur RGBA,
  • 2 pour l’intensité + la normale, et
  • 3 pour l’intensité + la couleur RGBA + la normale.


Interaction Texture/Matériau

Blender est quelque peu différent de la plupart des autres logiciels 3D dans la séparation entre textures et matériaux. Dans Blender, les textures sont des objets qui retournent certaines valeurs, des générateurs de signaux, en fait (comme les générateurs d’onde des synthétiseurs, par exemple). Les matériaux contrôlent le “placage” (“mapping”) des textures sur les objets, ce qui est affecté, à quel point, de quelle manière, etc.

Les plugins bien conçus ne devraient fournir des contrôles que pour modifier le comportement du “générateur de signaux”, pas la manière dont ces signaux sont plaqués. Les contrôles modifiant l’échelle, les proportions, etc. ne devraient être inclus que s’ils rendent la texture générée plus facile à utiliser (comme dans le cas du bouton Size du plugin Tiles – “mur de briques”), ou s’ils accélèrent les calculs (les sous-types Intensity/Color/Bump du plugins Clouds2 – “nuages”). Autrement, ces contrôles seraient redondants avec ceux des matériaux (sous-contexte Material), et rendraient l’interface du plugin inutilement complexe.

Plugin Texture générique

#include "plugin.h"

/* Texture name */
char name[24]= "";

#define NR_TYPES 3
char stnames[NR_TYPES][16]= {"Intens", "Color", "Bump"};

/* Structure for buttons,
 * {butcode, name, default, min, max, tooltip}
 */
VarStruct varstr[]= {
	{ NUM|FLO, "Const 1", 1.7, -1.0, 1.0, ""},
};

typedef struct Cast {
	float a;
} Cast;

float result[8];
float cfra;

int plugin_tex_doit(int, Cast*, float*, float*, float*);

/* Fixed Functions */
int plugin_tex_getversion(void) {
	return B_PLUGIN_VERSION;
}

void plugin_but_changed(int but) {
}

void plugin_init(void) {
}

void plugin_getinfo(PluginInfo *info) {
	info->name= name;
	info->stypes= NR_TYPES;
	info->nvars= sizeof(varstr)/sizeof(VarStruct);
	info->snames= stnames[0];
	info->result= result;
	info->cfra= &cfra;
	info->varstr= varstr;
	info->init= plugin_init;
	info->tex_doit= (TexDoit) plugin_tex_doit;
	info->callback= plugin_but_changed;
}

int plugin_tex_doit(int stype, Cast *cast, float *texvec, float *dxt, float *dyt) {
	if (stype == 1) {
		return 1;
	} if (stype == 2) {
		return 2;
	}
	return 0;
}


Nos modifications

La première chose est de s’éclaircir les idées et de faire un plan : que va faire ce plugin, et comment l’utilisateur va interagir avec lui. Pour cet exemple, nous allons créer une simple texture procédurale qui créera un motif “briques”, “bloc”.

Nous allons d’abord copier le code du plugin générique ci-dessus dans un fichier nommé cube.c, puis nous allons en remplir les vides. C’est toujours une (très) bonne idée d’ajouter des commentaires. D’abord pour dire aux utilisateurs ce que fait ce plugin, où ils peuvent en obtenir une copie, qui ils devraient contacter pour les bugs/améliorations, et la licence du code.

Quand vous écrivez des commentaires, n’utilisez que la syntaxe /* */ (style C). Les plugins sont écrits en C, et certains compilateurs C n’acceptent pas la syntaxe // (style C++).

/*
Description: This plugin is a sample texture plugin that creates a simple
brick/block pattern with it.
It takes two values a brick size, and a mortar size.
The brick size is the size of each brick.
The mortar size is the mortar size in between bricks.
Author: Kent Mein (mein@cs.umn.edu)
Website: http://www.cs.umn.edu/~mein/blender/plugins
Licensing: Public Domain
Last Modified: Tue Oct 21 05:57:13 CDT 2003
*/
NdT
Pour les anglophobes, voici la traduction de ce commentaire :

Description : Ce plugin est une texture d’exemple qui produit un simple motif de brique/bloc. Il prend deux paramètres, brick size et mortar size.
brick size est la taille de chaque “brique”.
mortar size est l’épaisseur du “mortier” entre les “briques”.
Auteur : Kent Mein (mein@cs.umn.edu).
Site Web : http://www.cs.umn.edu/~mein/blender/plugins.
License : Domaine Publique.

Dernière modification : Mardi 21 Octobre 2003, à 05:57:13 CDT.


Nous devons ensuite remplir name, le nom du plugin, vous devriez vraiment garder le même nom que celui de votre fichier *.c, de préférence un nom descriptif, de 23 caractères maximum, sans espace et en minuscules.

char name[24]= "cube.c";

Nous resterons simples et ne donnerons à notre plugin qu’un seul sous-type ne travaillant que sur l’intensité. Nous avons besoin de ce qui suit :

#define NR_TYPES 1
char stnames[NR_TYPES][16]= {"Default"};

Nous allons autoriser l’utilisateur à modifier, via l’interface graphique, les tailles des briques et du mortier, ainsi que les intensités (niveaux de gris) retournées pour les briques et le mortier. Pour cela nous devons éditer varstr et Cast. Cast doit avoir une variable pour chaque entrée dans varstr.

/* Structure for buttons,
 *	{butcode, name,     default, min, max, tooltip}
 */
VarStruct varstr[]= {
	{NUM|FLO, "Brick",      0.8, 0.1, 1.0, "Size of Cell"},
	{NUM|FLO, "Mortar",     0.1, 0.0, 0.4, "Size of boarder in cell"},
	{NUM|FLO, "Brick Int",  1.0, 0.0, 1.0, "Color of Brick"},
	{NUM|FLO, "Mortar Int", 0.0, 0.0, 1.0, "Color of Mortar"},
};

typedef struct Cast {
	float brick, mortar, bricki, mortari;
} Cast;

Maintenant, le “plat de résistance” : nous devons remplir la fonction plugin_tex_doit, nous voulons en fait “briser” notre texture en “cellules” constituées d’une brique et du mortier sur son bord inférieur. Il nous suffira alors de déterminer si nous sommes dans la brique ou le mortier. Le code suivant devrait remplir cette tâche :

int plugin_tex_doit(int stype, Cast *cast, float *texvec, float *dxt, float *dyt) {
	int c[3];
	float pos[3], cube;

	/* setup the size of our cell */
	cube = cast->brick + cast->mortar;

	/* what we need to do is determine where we are inside of the current brick. */
	c[0] = (int)(texvec[0] / cube);
	c[1] = (int)(texvec[1] / cube);
	c[2] = (int)(texvec[2] / cube);
	pos[0] = ABS(texvec[0] - (c[0] * cube));
	pos[1] = ABS(texvec[1] - (c[1] * cube));
	pos[2] = ABS(texvec[2] - (c[2] * cube));

	/* Figure out if we are in a mortar position within the brick or not. */
	if((pos[0] <= cast->mortar) ||
	   (pos[1] <= cast->mortar) ||
	   (pos[2] <= cast->mortar)) {
		result[0] = cast->mortari;
	} else {
		result[0] = cast->bricki;
	}
	return 0;
}

Une chose à noter, la fonction ABS (“valeur absolue”) est définie dans un en-tête dans plugins/include. Il y a d’autres fonctions utiles à cet endroit, allez donc y jeter un coup d’œil.

Compilation

“bmake” est un petit utilitaire (script shell) d’aide au développement et à la compilation de plugins Blender. Il se trouve dans le sous-dossier plugins/ du répertoire d’installation de Blender. Il est invoqué par : bmake (nom_du_plugin.c), et essaye alors de compiler et de lier aux bibliothèques appropriées le fichier C spécifié, pour votre système.

Si vous essayez de développer des plugins sous Windows, bmake peut ne pas fonctionner, dans ce cas, essayez “lcc”. Vous pouvez utiliser lcc pour compiler un plugin comme suit :

Supposons que votre plugin est dans C:\blender\plugins. Pour compiler un plugin texture sinus.c, ouvrez une fenêtre DOS et tapez ce qui suit (assurez-vous que le répertoire lcc\bin est dans votre “path”):

cd c:\blender\plugins\texture\sinus
lcc -Ic:\blender\plugins\include sinus.c
lcclnk -DLL sinus.obj c:\blender\plugins\include\tex.def
implib sinus.dll

Les dernières versions de lcc n’ont plus “implib”. Faites donc plutôt ce qui suit :

cd c:\blender\plugins\texture\sinus
lcc -Ic:\blender\plugins\include sinus.c
lcclnk -dll -nounderscores sinus.obj c:\blender\plugins\include\tex.def

Notez que tex.def n’est pas distribué avec Blender, mais il est accessible depuis le dépôt de plugins Blender. Vous pouvez également créer un fichier tex.def et y copier-coller ce qui suit :

EXPORTS
LibMain@12
plugin_but_changed
plugin_getinfo
plugin_init
plugin_tex_doit
plugin_tex_getversion


Écrire un plugin de séquence

Dans cette partie, nous allons écrire un plugin séquence basique, puis verrons les étapes nécessaires à son utilisation.

Les bases d’un plugin séquence sont que l’on vous fournit en entrée de 1 à 3 tampons d’images, ainsi que quelques autres données, et vous devez produire un tampon d’image en sortie.

Tous les fichiers nécessaires au développement de plugins, ainsi que quelques exemples, se trouvent dans le sous-dossier blender/plugins. Vous pouvez aussi vous procurer un ensemble de plugins depuis ce dépôt.

Spécifications

#include "plugin.h"
Tous les plugins Blender doivent inclure ce fichier d’en-tête, qui contient toutes les structures et définitions nécessaires pour bien travailler avec Blender.
char name[]="Blur";
Une chaîne de caractères contenant le nom du plugin.
VarStruct varstr[]= {...};
varstr contient toute l’information dont Blender a besoin pour afficher les contrôles d’un plugin. Ceux-ci peuvent être des boutons numériques – pour entrer des valeurs, du texte statique – pour des commentaires… Les plugins sont limités à au maximum 32 variables de ce type. Chaque entrée VarStruct est constituée d’un “type”, “name” (nom), “range information” (information de limites), et d’un “tool tip” (message d’aide).
Le type définit le type de donnée pour chaque contrôle, et le type de celui-ci. Pour les boutons numériques, cette valeur devrait être une combinaison (OU binaire, “|”) de “INT” ou “FLO” pour le format numérique (entier ou flottant), et de “NUM”, “NUMSLI” ou “TOG”, pour le type de contrôle (numérique, numérique avec curseur, ou bouton toggle “interrupteur”). Les contrôles texte devraient avoir un type “LABEL”.
Le name est ce qui sera écrit sur le (ou à côté du) contrôle. Limité à 15 caractères.
La range information est constituée de trois nombres flottants qui définissent les valeurs par défaut, minimale et maximale du contrôle. Pour les boutons “interrupteur”, le minimum correspond à l’état actif (pressé), et le maximum à l’état désactivé (relâché).
Le tooltip est une chaîne de caractères qui sera affichée quand le pointeur de la souris survolera le contrôle (si l’utilisateur a activé les Tool Tips (info-bulles)). Sa longueur maximale est de 80 caractères, et elle devrait avoir la valeur chaîne nulle ("") si elle n’est pas utilisée.
typedef struct Cast {...};
La structure Cast est utilisée à l’appel de la fonction doit, et sert à avoir un accès aisé aux valeurs de tous les contrôles du plugin. Elle devrait contenir, dans l’ordre, un entier ou un flottant pour chacun des contrôles définis dans varstr, même les textes. Normalement, ils devraient avoir le même nom que le contrôle, pour simplifier la lecture/maintenance du code.
float cfra
La valeur cfra est mise par Blender à l’image courante, avant chaque passe de rendu. Il s’agit d’un numéro d’image (± 0.5 si les trames sont activées).
Prototype plugin_seq_doit
La fonction plugin_seq_doit devrait être prototypée pour être utilisée par la fonction getinfo. Vous n’avez pas besoin de modifier cette ligne.
plugin_seq_getversion
Cette fonction doit être dans chaque plugin pour qu’il soit chargé correctement. Vous ne devriez pas la modifier.
plugin_but_changed
Cette fonction est utilisée pour passer des informations sur quels contrôles de l’interface ont été modifiés par l’utilisateur. La plupart des plugins ne devraient pas avoir besoin de cette fonction, utile seulement quand l’interface permet à l’utilisateur de modifier des variables qui obligent le plugin à refaire des calculs (comme pour une table de hachage aléatoire, par exemple).
plugin_init
Si besoin, les plugins peuvent utiliser cette fonction pour initialiser leurs variables internes.
Note : Cette fonction d’initialisation peut être appelée plusieurs fois si le même plugin de séquence est copié. N’initialisez pas les variables globales spécifiques à une instance particulière d’un plugin dans cette fonction.
plugin_getinfo
Cette fonction est utilisée pour communiquer des informations à Blender. Vous ne devriez jamais avoir besoin de la modifier.
plugin_seq_doit
La fonction doit est celle qui effectue vraiment les calculs : elle est chargée de retourner à Blender, via le tampon de sortie, l’image finale.
Les arguments
Cast *cast
La structure Cast qui contient les variables du plugin, voyez typedef struct Cast ci-dessus.
float facf0
La valeur courante de la première courbe Ipo du plugin. Si l’utilisateur n’a pas créé cette Ipo, cette valeur ira de 0.0 à 1.0 sur la durée du plugin.
float facf1
La valeur courante de la deuxième courbe Ipo du plugin. Si l’utilisateur n’a pas créé cette Ipo, cette valeur ira de 0.0 à 1.0 sur la durée du plugin.
int x, int y
La largeur et la hauteur des tampons image, respectivement.
Imbuf *ibuf1
Un pointeur vers le premier tampon image auquel le plugin est lié. Ce sera toujours un pointeur valide.
Imbuf *ibuf2
Un pointeur vers le second tampon image auquel le plugin est lié. Les plugins utilisant ce tampon devraient vérifier que le pointeur n’est pas NULL, puisque l’utilisateur peut ne pas avoir lié le plugin à deux tampons.
Imbuf *out
Un pointeur vers le tampon image de sortie.
Imbuf *use
Un pointeur vers le troisième tampon image auquel le plugin est lié. Les plugins utilisant ce tampon devraient vérifier que le pointeur n’est pas NULL, puisque l’utilisateur peut ne pas avoir lié le plugin à trois tampons.
Structure d’image ImBuf
Les structures ImBuf contiennent toujours des valeurs de pixels sur 32 bits RGBA. Elles ont toutes la même taille, indiquée par les paramètres x et y.
Interaction avec l’utilisateur
Blender n’a aucun moyen de savoir combien de tampons image attend un plugin, il est donc possible à un utilisateur de ne lier au plugin qu’un tampon en entrée, alors qu’il en attend deux. Il est de ce fait très important que les plugins testent toujours les tampons d’entrée qu’ils utilisent, pour s’assurer qu’ils sont valides. Les plugins séquence devraient également inclure une ligne de texte dans leur interface graphique, décrivant le nombre de tampons d’entrée attendus.


Plugin Séquence générique

#include "plugin.h"

char name[24]= "";

/* structure for buttons,
 *	{butcode, name,       default, min, max, tooltip}
 */
VarStruct varstr[]= {
	{LABEL,   "In: X strips", 0.0, 0.0, 0.0, ""},
};

/* The cast struct is for input in the main doit function
 * Varstr and Cast must have the same variables in the same order
 */
typedef struct Cast {
	int dummy; /* because of the 'label' button */
} Cast;

/* cfra: the current frame */
float cfra;

void plugin_seq_doit(Cast *, float, float, int, int, ImBuf *, ImBuf *, ImBuf *, ImBuf *);

int plugin_seq_getversion(void) {
	return B_PLUGIN_VERSION;
}

void plugin_but_changed(int but) {
}

void plugin_init() {
}

void plugin_getinfo(PluginInfo *info) {
	info->name= name;
	info->nvars= sizeof(varstr)/sizeof(VarStruct);
	info->cfra= &cfra;
	info->varstr= varstr;
	info->init= plugin_init;
	info->seq_doit= (SeqDoit) plugin_seq_doit;
	info->callback= plugin_but_changed;
}

void plugin_seq_doit(Cast *cast, float facf0, float facf1, int xo, int yo,
                     ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *outbuf, ImBuf *use) {
	char *in1= (char *)ibuf1->rect;
	char *out=(char *)outbuf->rect;
}


Nos modifications

La première chose est de s’éclaircir les idées et de faire un plan : que va faire ce plugin, et comment l’utilisateur va interagir avec lui. Pour cet exemple, nous allons créer un simple filtre qui aura un curseur d’intensité de 0 à 255. Si l’une des composantes RGB (rouge, vert ou bleu) d’un pixel de notre image d’entrée est inférieure à l’intensité choisie, ce pixel sera remplacé dans l’image de sortie par un pixel noir transparent, sinon il restera “intact”.

Nous allons d’abord copier le code du plugin générique ci-dessus dans un fichier nommé simpfilt.c, puis nous allons en remplir les vides. C’est toujours une (très) bonne idée d’ajouter des commentaires. D’abord pour dire aux utilisateurs ce que fait ce plugin, où ils peuvent en obtenir une copie, qui ils devraient contacter pour les bugs/améliorations, et la licence du code.

Quand vous écrivez des commentaires, n’utilisez que la syntaxe /* */ (style C). Les plugins sont écrits en C, et certains compilateurs C n’acceptent pas la syntaxe // (style C++).

/*
Description: This plugin is a sample sequence plugin that filters out lower
intensity pixels. It works on one strip as input.
Author: Kent Mein (mein@cs.umn.edu)
Website: http://www.cs.umn.edu/~mein/blender/plugins
Licensing: Public Domain
Last Modified: Sun Sep 7 23:41:35 CDT 2003
*/
NdT
Pour les anglophobes, voici la traduction de ce commentaire:

Description: Ce plugin est un exemple de plugin séquence qui filtre et efface les pixels de faible intensité. Il travaille avec une piste en entrée.
Auteur: Kent Mein (mein@cs.umn.edu).
Site Web: http://www.cs.umn.edu/~mein/blender/plugins.
License: Domaine Publique.

Dernière modifications: Dimanche 7 Septembre 2003, à 23:41:35 CDT.


Nous devons ensuite remplir name, le nom du plugin, vous devriez vraiment garder le même nom que celui de votre fichier *.c, de préférence un nom descriptif, de 23 caractères maximum, sans espace et en minuscules.

char name[24]= "simpfilt.c";

Cast et varstr doivent correspondre ; nous voulons un curseur, donc nous devons avoir ce qui suit :

varStruct varstr[]= {
	{LABEL,   "In: 1 strips",  0.0, 0.0,   0.0, ""},
	{NUM|INT, "Intensity",    10.0, 0.0, 255.0, "Our threshold value"},
};

typedef struct Cast {
	int dummy; /* because of the 'label' button */
	int intensity;
} Cast;

Maintenant, le “plat de résistance” : pour remplir la fonction plugin_seq_doit, nous devons simplement boucler sur chaque pixel et, si les trois valeurs RGB sont inférieures à l’intensité choisie, mettre le pixel sortant à (0, 0, 0, 255). Sinon, se contenter de copier les valeurs d’entrée de ce pixel.

void plugin_seq_doit(Cast *cast, float facf0, float facf1, int xo, int yo,
                     ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *outbuf, ImBuf *use) {
	int nbrComp = xo * yo * 4; /*There are xo times yo pixels, with 4 components for each;*/
	int i;
	char *in1 = (char *)ibuf1->rect; /*ImBuf::rect is an int pointer (containing 4 chars!)
	char *out = (char *)outbuf->rect;

	for(i=0; i < nbrComp; i+=4)
	{
		/* if R and G and B of the pixel are all greater than
		   the intensity, keep it unchanged. */
		if((in1[i+0] > cast->intensity) &&
		   (in1[i+1] > cast->intensity) &&
		   (in1[i+2] > cast->intensity))
		{
			out[i+0] = in1[i+0];
			out[i+1] = in1[i+1];
			out[i+2] = in1[i+2];
			out[i+3] = in1[i+3];
		}
		/* else, make the pixel black and transparent! */
		else
		{
			out[i+0] = out[i+1] = out[i+2] = 0;
			out[i+3] = 255;
		}
	}
}

Et nous en avons fini avec simpfilt.c.

Compilation

“bmake” est un petit utilitaire (script shell) d’aide au développement et à la compilation de plugins Blender. Il se trouve dans le sous-dossier plugins/ du répertoire d’installation de Blender. Il est invoqué par : bmake (nom_du_plugin.c), et essaye alors de compiler et de lier aux bibliothèques appropriées le fichier C spécifié, pour votre système.

Si vous essayez de développer des plugins sous Windows, bmake peut ne pas fonctionner, dans ce cas, essayez “lcc”. Vous pouvez utiliser lcc pour compiler un plugin comme suit :

Supposons que votre plugin est dans C:\blender\plugins. Pour compiler un plugin texture sweep.c, ouvrez une fenêtre DOS et tapez ce qui suit (assurez-vous que le répertoire lcc\bin est dans votre “path”) :

cd c:\blender\plugins\sequence\sweep
lcc -Ic:\blender\plugins\include sweep.c
lcclnk -DLL sweep.obj c:\blender\plugins\include\seq.def
implib sweep.dll

Les dernières versions de lcc n’ont plus “implib”. Faites donc plutôt ce qui suit :

cd c:\blender\plugins\sequence\sweep
lcc -Ic:\blender\plugins\include sweep.c
lcclnk -dll -nounderscores sweep.obj c:\blender\plugins\include\seq.def

Notez que seq.def n’est pas distribué avec Blender, mais il est accessible depuis le dépôt de plugins Blender. Vous pouvez également créer un fichier seq.def et y copier-coller ce qui suit :

EXPORTS
LibMain@12
plugin_but_changed
plugin_getinfo
plugin_init
plugin_seq_doit
plugin_seq_getversion