PDA

Voir la version complète : Créez vos propres plug-ins*!



Steph3D ::.
20/03/2005, 19h45
Hello monde, alors je suis en train de voir dans la doc comment crée un vrai plug-in Coffee, et ici plus exactement un Tag.

Mais bon, c'est pas évident vu que la doc n'est pas franchement des plus easy, surtout quand on ne comprend pas très bien l'english :roll:

Donc, ben j'étais en train de me traduire un peu grossièrement le truc pour y voir plus clair, alors je me dis finalement, tan que j'y suis, autant poster quelques infos sur le sujet même si je ne sais pas si je vais etre compréhensif, n'ayant moi-même, pas encor développer la chose en question :roll:

Je vais prendre pour exemple un petit code facile à comprendre que j'ai entièrement commenté pour l'occasion.
Mon expression suivante permet dans un classique Coffee de fixé automatiquement la profondeur de champ de la camera sur un objet. L'idéal et de l'associer à un Tag Expression Cible, car j'écris pas le codage du target pour ne pas alourdir le code d'exemple, pour rester Easy.


main(doc,op)
{
if(!instanceof(op,CameraObject)) return; // Si l'objet n'est pas une caméra, on quitte

var Obj_Cible = doc->FindObject("Ma_Cible"); if(!Obj_Cible) return;
// Définir l'objet cible (s'il n'existe pas, on quitte l'expression)

var Pos1 = op->GetPosition(); // Position de la caméra
var Pos2 = Obj_Cible->GetPosition(); // Position de la cible

var Distance = vlen(Pos1-Pos2); // Calcul de la distance entre les deux
var Container = op->GetContainer(); // Ouvrir le container de la caméra
Container->SetData(CAMERAOBJECT_DEPTHMIDDLE,Distance); // Inscrire la distance de séparation dans la distance de mire
op->SetContainer(Container); // Renvoyer l'info au container de la camera
}

Maintenant le but, c'est de pouvoir transformer ça en plug-in, d'en faire un vrai Tag avec un menu pour choisir la cible.
Préparez le tube d'aspirine, car ça va être tres chaud !!! :coup:

Tengaal
20/03/2005, 20h31
Dans la doc du Coffee (version C4D 6) il y avait un petit pack nommé "Basic Frameworks" dans la partie "exemples", qui contenait 7 structute vide pour chaque type de plugin, où il n'y avait plus qu'à ajouter son code et personnaliser le plugin.
Je n'ai pas retrouvé ce Basic Frameworks dans la doc actuelle (pour C4D 9.1)...

EDIT:
Finallement les 7 fichiers "types" sont dispatchés dans la rubrique "Plugin Types" de la dernière doc du SDK Coffee (ex: menuplugin.cof, filterplugin.cof, animationplugin.cof...)

Steph3D ::.
20/03/2005, 20h49
Oui j'avais trouvé, mais c'est que la structure vide sans exemple des codes, du moins pour les versions Tags. Et les commentaires des fonctions sont un peu légers, surtout quand on ne comprend pas super bien l'anglais :oops:

Je vais tenté de décodé chaque fonction en bon français, et je vous poste tout ça. Comme ça on y verra plus clair, car c'est pas forcement évident de débuter sur l'Expression plugin tags avec tout ça, surtout pour faire ensuite les menus :coup:

Guedinouff
20/03/2005, 22h32
Cà c'est une super idée, j'aimerais moi aussi créer un tag (pour mettre en forme mon expression de calcul du temps), et en lisant le SDK, je me suis rendu compte que çà avait l'air assez compliqué. Donc merci de te lancer là-dedans et en plus d'en faire profiter tout le monde :poucehaut:

Kaldera Lake
20/03/2005, 23h13
:bounce: Je me suis pencher sur Coffee et ne reussissant pas a faire les dites fenetre de communication je me suis retrancher sur les DU et l'integration du Coffee dans Xpresso... C'est un peu beaucoup frustrant mais ca marche plus ou moins... :|

Je te suis avec attention :)

Steph3D ::.
20/03/2005, 23h15
La difficulté vient surtout du faite qu'on manque d'exemples concrets avec C4D, contrairement à Max ou tu trouves de milliers de scripts sur le web avec les codes ouverts.

La simple doc du SDK est parfois dure à interpréter, ce que j'ai appris, je le dois surtout aux quelques exemples COFFEE qu'on trouve sur le WEB.
Perso, j'étudie un code d'exemple en lisant le doc du SDK pour le décrypter, là ça roule. Mais par contre, commencer un nouveau truc juste avec la doc brute, là c'est vraiment galère !

C'est dommage, car un mellieur développement du coffee peut être un sacré tremplin pour C4D, comme ce fut le cas pour Max avec la multiplication à grande échelle de MaxScript qui bouste à fond le logiciel et fait naître de nouvelles idées.

Bon, la suite demain ! :)

Steph3D ::.
21/03/2005, 15h00
Bon voilà ma 1er description basée sur la structure de base de l'expression Tag.
C'est une structure de base à copier/coller, ensuite il faut remplir les fonctions avec nos codes, notez que toutes fonctions ne sont pas indispensables pour faire notre plug-in selon les cas de figure

Bon si je fais des erreurs ou que vous avez de meilleures précisions à ajouter, n'hésitez pas ! :-)


// Expression Plugin Tag

class MyExpressionPluginTag : ExpressionPluginTag
{
// ici on déclare public toutes les fonctions qui suivent, héritées à la class ExpressionPluginTag
// rien besoin de toucher ici, copier/coller et go !!!
public:

MyExpressionPluginTag();

GetID();

MultipleAllowed();
DisplayAllowed();

GetIcon();
GetHelpText();

UseMenu();
GetName();

Edit();

Copy(dest);
Save(hf);
Load(hf);

Message(type, data);

Execute(doc, op);
Speedup(doc, op);
}

MyExpressionPluginTag::MyExpressionPluginTag()
{
super(); // Appele le constructeur parent

// ici on déclare si-dessous toutes nos variables locales, etc...
}

MyExpressionPluginTag::GetID()
{
// Renvoie l'identification unique de notre plug-in qu'il faut obtenir sur http://www.plugincafe.com
// Faut un ID par plug-in, sinon il peut avoir des conflits !
return 1000001; // Exemple temporaire pour nos tests
}

MyExpressionPluginTag::MultipleAllowed()
{
// Faut renvoyé TRUE si on permet de mettre plusieurs Tag de ce type sur un meme objet
// Mettre FALSE on n'autorise qu'un seul Tag par objet
return FALSE; // exemple
}

MyExpressionPluginTag::DisplayAllowed()
{
// Renvoyez TRUE si le Tag montre une icône sur l'objet dans la liste de la scene.. // Mettre FALSE si on veux faire un Tag invisible
return TRUE; // exemple
}

MyExpressionPluginTag::GetIcon()
{
// Ici on va faire un script pour chercher le fichier image qui va nous servir d'icône pour le Tag
}

MyExpressionPluginTag::GetHelpText()
{
// Permets de renvoyer une bulle d'aide avec un texte quand on passe avec la souris sur le Tag
}

MyExpressionPluginTag::UseMenu()
{
// Renvoyez TRUE si le Tag doit être énumérée dans le nouveau Tag menu.
// heu... pas sur, je suppose qu'on puisse ici faire un code pour le placer dans une nouvelle
// liste de Tag quand on clique sur le bouton droit de la souris sur l'objet dans la liste)
// Autrement renvoyez FALSE
return TRUE; // exemple}

MyExpressionPluginTag::GetName()
{
// Pour renvoyer le nom du menu
return "Mon 1er Tag en C.O.F.F.E.E"; // exemple
}

MyExpressionPluginTag::Edit()
{
// Le code à renvoyer quand l'utilisateur double clique sur le Tag (pour créer la boîte de dialogue)
}

MyExpressionPluginTag::Copy(dest)
{
// Si le Tag a des variables locales, les copier au DEST (pas encor capté la ... )
}

MyExpressionPluginTag::Save(hf)
{
// Si le Tag a des variables locales, les sauvé dans l'hyperfile (heu... ? )
}

MyExpressionPluginTag::Load(hf)
{
// Si le Tag a des variables locales, chargez-les dans l'hyperfile ( Ou j'ai mis mon tube d'aspirine ? )
}

MyExpressionPluginTag::Message(type, data)
{
// Accéder aux données de C4D. À voir à quoi cela peut nous servir...}

MyExpressionPluginTag::Execute(doc, op)
{
// Script appelé à chaque redraw, donc exécuté en permanence. Fonctionne un peu comme "main(doc,op) { }", le classique Tag COFFEE qu'on connaît bien
// En fait, c'est là qu'il faut mettre notre code principal
}

MyExpressionPluginTag::Speedup(doc, op)
{
//Faut employer la fonction Touch() pour chaque objet que notre fonction Execute() d'haut dessus modifie, enfin si quelqu'un a une traduction plus claire ? SVP.
//D'après les infos trouver, faut faire un petit script du style
//if(op) Touch(op); return TRUE;
}

main()
{
// Enregistrement de l'expression plug-in tag
Register(MyExpressionPluginTag);
}

Steph3D ::.
21/03/2005, 15h24
Bon, voila deja le code qu'on doit écrire dans la fonction MyExpressionPluginTag::GetIcon() pour afficher l'icône de notre Tag dans la liste des objets.


MyExpressionPluginTag::GetIcon()
{
// Ici on va faire un script pour chercher le fichier image qui va nous servir d'icône pour le Tag

// Création des variables fichier et bitmap
var Bitmap = new(BaseBitmap,1,1);
var File = new(Filename);

// Lecture/Chargement du fichier ico.tif
// dans le répertoire où se trouve notre plug-in
File = GeGetRootFilename();
File->RemoveLast();
File->AddLast("ico.tif");
Bitmap->Load(File);

// Renvoie l'icône à afficher
return Bitmap;
}

Steph3D ::.
21/03/2005, 16h05
Voilà comment il faut mettre notre code principal
En rouge, c'est l'instruction à modifier pour communiquer avec le futur menu à créer


MyExpressionPluginTag::Execute(doc, op)
{

if(!instanceof(op,CameraObject)) return; // Si l'objet n'est pas une caméra, on quitte

var Obj_Cible = doc->FindObject("Ma_Cible"); if(!Obj_Cible) return;
// Définir l'objet cible (s'il n'existe pas, on quitte l'expression)

var Pos1 = op->GetPosition(); // Position de la caméra
var Pos2 = Obj_Cible->GetPosition(); // Position de la cible

var Distance = vlen(Pos1-Pos2); // Calcul de la distance entre les deux
var Container = op->GetContainer(); // Ouvrir le container de la caméra
Container->SetData(CAMERAOBJECT_DEPTHMIDDLE,Distance); // Inscrire la distance de séparation dans la distance de mire
op->SetContainer(Container); // Renvoyer l'info au container de la camera
}

Steph3D ::.
21/03/2005, 16h32
Bon, à ce stade de notre code, si on le met dans un fichier cof du répertoire plug-in de C4D avec une icône, nous pouvons constater qu'il marche déjà très bien.
Cependant comme il n'y a aucune interface utilisateur de fait, on doit renommer manuellement notre cible pour que le script fonctionne, en gros il marche comme le script de base pour le moment

Voilà le fichier d'exemple tout cuit ;-) > http://stephlx.free.fr/c4df/TagTest01.zip

http://stephlx.free.fr/c4df/PTag01.jpg

padawa
21/03/2005, 17h04
Merci de nous faire partager ca :poucehaut:

J'ai pas encore tout compris mais ca va venir :mrgreen:

Allez la création d'interface maintenant :wink:

Steph3D ::.
21/03/2005, 18h05
Oui le menu, ça, c'est le plus dur à capter :coup:
Faut définir une Classe dialogue un peu comme la Classe Expression Tag, puis la créer dans notre code
Ensuite faut comprendre comment créé les boutons et tout ça, et pour finir, comme lié les variables du dialogue à notre code

De plus, je me demande si on peu pas non plus créé notre interface aussi sous forme de container, plutot que de type ModalDialog ?? mais bon je vais déjà commencé par la.

Bon, p'tit problème, c'est pas vraiment important pour le moment, mais GetHelpText() ne semble pas renvoyé de message :?

Steph3D ::.
21/03/2005, 18h23
Voila le code pour ouvrir la boite de dialogue par double click sur le Tag, bien sur, pour que ça marche, il faudrait déjà définir la class Dialog dérivé de la classe de base GeModalDialog de C4D qui possède la fonction Open()
Open permet d'ouvrir le menu au coordonnées x, y. Si on met -1 ça créé le menu la ou est la souris


MyExpressionPluginTag::Edit()
{
// Le code ą renvoyer quand l'utilisateur double clique sur le Tag (pour créer la boīte de dialogue)
var Interface = new(Dialog);
Interface->Open(-1,-1);
}

Steph3D ::.
21/03/2005, 18h50
Voilà la création de base de la classe Dialoge, hérité de GeModalDialog
C'est à mettre tout en haut du code ou dans un fichier séparer qu'on appel avec include"Mon_Fichier";


class Dialog : GeModalDialog
{
public: // ici on déclare public toutes les fonctions qui suivent, hériter a là class GeModalDialog
Dialog();
CreateLayout();
}

Dialog::Dialog()
{
super(); // Appele le constructeur parent
// ici on déclare si dessous toutes nos variables locales de notre interface
}

Dialog::CreateLayout()
{
// La on va créé notre code d'interface, création des boutons, textes, etc...
}

zegolem
21/03/2005, 19h18
Je poste juste pour te suivre, c'est plus que passionnant... :efface:

Steph3D ::.
21/03/2005, 19h44
Voilà un petit code de base pour faire une boîte de dialogue.
Faites une recherche dans le SDK sur GeUserDialog, voir aussi GeUserArea pour voir toutes les fonctions de dialogue et leur forts nombreuses posibilités.


Dialog::CreateLayout()
{
SetTitle("Ma 1er Interface"); // Titre de la boîte de dialogue
AddStaticText(4000,BFH_FIT,0,0,"Hello World",BORDER_THIN_IN); // Création d'un texte statique avec un encadrement
AddDlgGroup(DR_DLGGROUP_OK|DR_DLGGROUP_CANCEL); // Bouton Ok/Cancel

return TRUE;
}

Maintenant quant on double click sur le Tag, ben on ouvre la boîte de dialogue du Tag :-)

C'est la méthode de base par codage pur et dur, mais il y a une méthode plus recommander avec le plug-in Resedit qu'on trouve dans le SDK et qui crée notamment les fameux string_us, strings_fr, etc... pour les langues.

A voir comment ça marche...

Steph3D ::.
21/03/2005, 20h05
Voilà, ça, c'est Resedit

http://stephlx.free.fr/c4df/Resedit.jpg

Il permet de construire un peu à la manière de visual basic, visuellement une interface, bon c'est bien moins évolué, mais c'est mieux que rien ;-)

Comme on peut le voir, il y a nettement plus de possibilité que les simples DU d'Xpresso.

Quand on a finit, on sauvegarde dans le dossier de notre plug-in et il nous crée auto une série de fichiers est répertoires, ainsi que les variables des différentes langues fr,jp,us,de, etc...

On ne touche pas aux fichiers, il suffit juste de faire include "c4d_symbols.h"; tout au début du script pour pouvoir exploiter l'ensemble dans nos plug-ins.

Maintenant, toute la question est de savoir comment exploiter ça au coeur de notre programme :coup:

Majoul
21/03/2005, 20h31
On exploite tout cela avec les ID que tu cree dans le Resedit


deja pour charger ton interface




var resource ;

// tu accéde au fichier resource dans le main() par exemple avec une variable global resource

var file = GeGetRootFilename(); if (!file) return;
file->RemoveLast();
resource = new(GeResource,file);

// et ici dans CreateLayout()

Dialog::CreateLayout()
{
LoadDialogResource(IDD_TEST, resource, 0) ;
return TRUE;
}


IDD_TEST est cité comme exemple ce qui veut dire que ton fichier resouce est ( IDD_TEST.res )

Guedinouff
21/03/2005, 20h40
Excusez-moi, mais vous avez trouvé où la doc sur resEdit, parce que moi je l'avais téléchargé et je n'avais pas trouvé de doc, et en testant vite fait, je n'étais pas arrivé à faire une interface. En fait je ne savais même pas que l'on pouvait faire çà avec.
C'est caché quelque part dans le SDK ou bien c'est sur internet et j'ai mal cherché. Ou encore on doit se fier à son instinct pour l'utiliser... :)

Steph3D ::.
21/03/2005, 20h50
Ok merci, tout est expliqué dans "Dialog layout" mais faut prendre le temps de décodé, car il n'y a pas d'exemple direct pour la méthode avec Resedit

Pour tél Resedit > http://www.plugincafe.com/sdk/resedit17.zip
Pour comprendre Resedit, faut décodé le SDK, et notamment lire la partie "Dialog layout"

Steph3D ::.
21/03/2005, 21h28
Bon, maintenant faut créer une interface pour notre Tag avec ResEdit

On à juste besoin d'un champ texte pour entrer le nom de la cible et un bouton Ok comme ceci

http://stephlx.free.fr/c4df/EditDTag.jpg

J'ai nommé l'ID déléments IDC_Target pour le text et ID_Ok pour le bouton.
On sauvegarde sous le nom IDD_TagTest

Ensuite faut bien mettre les fichiers générés par ResEdit dans le dossier de notre plug-in et les disposer exactement comme sur cette capture.

http://stephlx.free.fr/c4df/TagRes.jpg

Steph3D ::.
23/03/2005, 08h05
Bon la suite...

On commence par tout en haut


// Interface
include "c4d_symbols.h"; // Pour exploiter les symboles de définition de l'interface, les ID des éléments
var plugin_resource; // on déclare globale la variable "plugin_resource"

Ensuite tout en bas dans main()


main()
{
// Enregistrement de l'expression plug-in tag
Register(MyExpressionPluginTag);

// pour pouvoir accéder au fichier de ressource de l'interface
var plugin_path = GeGetRootFilename(); if (!plugin_path) return;
plugin_path->RemoveLast();
plugin_resource = new(GeResource,plugin_path);

}

Pour finir dans CreateLayout()

LoadDialogResource( [ Le nom de notre fichier *.res ] , [ Le fichier ressource] ,0);

donc


Dialog::CreateLayout(){
return LoadDialogResource(IDD_TagTest,plugin_resource,0); // Chargement des ressources externes
}

Esayez, cela marche tres bien, et avec ResEdit c'est pas trop chiant à faire, pour les interface :-)

Maintenant, il nous reste à encor résoudre une dernière petite chose.
Comment faire communiquer notre boîte de dialogue avec notre code ? :coup:
Donc transmettre les variables de la boîte de dialogue à notre script, et éventuellement le contraie (ça peut aussi nous servir à l'occasion)

Majoul
08/02/2006, 22h46
Steph cette fois ci, Je remonte le bon sujet :oops:. je le complète et je reviens.

A+

Majoul
09/02/2006, 00h11
var PLUGIN_ID* *= 1000001 ;
var PLUGIN_NAME = "Mon 1er Tag en C.O.F.F.E.E" ;
var PLUGIN_HELP = "Tag de test" ;
var PLUGIN_ICON = "ico.tif"* * *;

include "c4d_symbols.h"

var resource , Icon ;

//************************************************** **********************
//* * * * * * * * on enum les ids du container du tag
//************************************************** **********************

enum
{
* ID_CIBLE = 100 ,

_dummy
}

//************************************************** **********************
//* * * * * * * * * * *Basic Routines
//************************************************** **********************

LoadIcon(nom)
{
var fichier = GeGetRootFilename() ;
* * fichier->RemoveLast()* *;
* * fichier->AddLast("res") ;
* * fichier->AddLast(nom) ;

* var ic = new(BaseBitmap, 1, 1) ;
* * ic->Load(fichier) ;

* return ic ;
}

//************************************

LoadResource()
{
* var fichier = GeGetRootFilename(); if (!fichier) return NULL ;
* * fichier->RemoveLast() ;

var res = new(GeResource, fichier) ;
* if (!res) return NULL ;

* return res ;
}

//************************************************** **********************
//* * * * *definition de la class du dialogue
//************************************************** **********************

class Dialog : GeModalDialog
{
* private:

* * *var Bc ; // Variable pour le container

* public:

* * *Dialog();
* * *CreateLayout();
* * *GetContainer() ;
* * *SetContainer(bc);
* * *Init() ;
* * *Command(id, msg);
}

Dialog::Dialog()
{
super() ;
}

Dialog::CreateLayout()
{
LoadDialogResource (IDD_DIALOG1, resource, 0) ;
}

Dialog::GetContainer()
{
return Bc ; // avec cette fontion on renvoit le container au tag
}

Dialog::SetContainer(bc)
{
Bc = bc ; // avec cette fonction on reçoit le container du tag
}

Dialog::Init()* *
{
* // ici on transmet les valeurs du container Bc au dialogue
SetString(IDC_NAME_TARGET, Bc->GetData(ID_CIBLE)) ;
}

Dialog::Command(id, msg)
{
switch(id)
* *{
* * *// ici on reçoit les valeurs du dialogue et on les Stockes dans le container Bc
* * *case IDC_NAME_TARGET : Bc->SetData(ID_CIBLE, GetString(id)) ; break ;
* *}

Init() ; // avec la fonction Init() on retransmet les valeurs du container Bc au dialogue
}

//************************************************** **********************
//* * * * *definition de la class de l'ExpressionPluginTag
//************************************************** **********************

class MyExpressionPluginTag : ExpressionPluginTag
{
* private:

* * *GetNewContainer() ;

* public:

* * *MyExpressionPluginTag();

* * *GetID();
* * *MultipleAllowed();
* * *DisplayAllowed();
* * *GetIcon();
* * *GetHelpText();
* * *UseMenu();
* * *GetName();

* * *Edit();
* * *Execute(doc, op);
}

MyExpressionPluginTag::MyExpressionPluginTag()
{
* super();
}

MyExpressionPluginTag::GetID()* * * * * * * *
{
return PLUGIN_ID ;
}

MyExpressionPluginTag::MultipleAllowed()* * *
{
* return FALSE ;
}

MyExpressionPluginTag::DisplayAllowed()* * *
{
* return TRUE;
}

MyExpressionPluginTag::GetIcon()* * * * * * *
{
* return Icon ;
}

MyExpressionPluginTag::GetHelpText()* * * * *
{
* return PLUGIN_HELP ;
}

MyExpressionPluginTag::UseMenu()
{
* return TRUE ;
}

MyExpressionPluginTag::GetName()
{
return PLUGIN_NAME ;
}

MyExpressionPluginTag::GetNewContainer()
{
* var bc = new(BaseContainer) ;
* * * bc->SetData(ID_CIBLE, "") ;

* return bc ;
}

MyExpressionPluginTag::Edit()
{
* * * * * *// on prend le container du tag
var bc = GetContainer() ;

* * * * * *// on verifi si le container existe, sinon on lu affecte un nouveau container
* * * * * *// avec la fontion privée que j'ai défini par GetNewContainer()
if(!bc->FindIndex(ID_CIBLE)) bc = GetNewContainer() ;

var d = new(Dialog) ;* * *// on creer un dialogue de la class Dialog defini un peut plus haut
* * *d->SetContainer(bc) ; // on transmet le container au dialogue par le fonction SetContainer() de cette class
* * *d->Open(-1,-1) ;* * * // on ouvre le dialogue


* * // si le resultat est validé alors on transmet le container du dialogue au Tag
if (d->GetResult()) SetContainer(d->GetContainer()) ;
}

MyExpressionPluginTag::Execute(doc, op)
{
if(!instanceof(op,CameraObject)) return ;

var bc = GetContainer() ;
var CibleName = bc->GetData(ID_CIBLE) ; if(!CibleName) return ;

var Obj_Cible = doc->FindObject(CibleName); if(!Obj_Cible) return ;

var Pos1 = op->GetPosition() ;
var Pos2 = Obj_Cible->GetPosition() ;

var Distance* = vlen(Pos1-Pos2) ;
var Container = op->GetContainer() ;
Container->SetData(CAMERAOBJECT_DEPTHMIDDLE, Distance) ;
op->SetContainer(Container) ;

}

main()
{
* resource = LoadResource() ; if(!resource) { println(PLUGIN_NAME + " : erreur de resource") ; return ; }

* Icon* * *= LoadIcon(PLUGIN_ICON) ;

* Register(MyExpressionPluginTag);
}


Le fichier http://perso.wanadoo.fr/archizone/fc4d/ExempleTag.zip

kiteman
09/02/2006, 00h23
ouch ! :o c'est fort ça Majoul :poucehaut: .. ( j'ai rien compris ..mais ça claque :mrgreen: )

Sir Gong
09/02/2006, 08h54
j'ai rien compris ..mais ça claque :mrgreen: )c'est facile, je vais t'expliquer.


:nono:

Lt.Col.Powell
09/02/2006, 18h13
Regardez ICI (http://www.deltazone.org/~fc4d/autres/lt.col.powell_COFFEE.txt), moi aussi je fais de la programmation !
De pres on n'y comprand rien mais avec de l'expérience et surtout du recule, tout devient plus clair !!
Ok bon* :mrgreen: j'ai compris je* :arrow:
:odile:

oli_d
10/02/2006, 18h17
Super, merci Majoul, j'étais justement entrain de plancher sur cette problématique pour avancer ma maison paramétrique :coup:

Allez au boulot il faut que je m'y remette :wip:

Daubermman
17/02/2006, 18h56
Pardon de déranger mais pour apprendre je fais un COFFEE de type plugin, j'ai me suis un peu appuyé sur l'exemple de Majoul en changant ce qui ne correspond pas au meme type de plug, mais mais mais j'ai un problème sur le GetId, c'est la même chose, j'ai une variable PLUGIN_ID et à chaque fois sur le Return, il me met Variable Or Function expected. Je pense savoir pourquoi y a ça mais impossible de régler ce problème :cry2:

Majoul
18/02/2006, 00h23
C'est normal qu'il te sort ce message, le D du GetID() doit être en majuscule, fait gaffe au majuscule et minuscule.

Daubermman
18/02/2006, 15h10
Ah oui oui il l'est sans problème, j'ai repris de ton code et des exemples de la doc, donc j'ai bien fait gaffe à ca mais rien à faire. Enfin merci quand même pour l'aide :wink:.

Steph3D ::.
15/04/2007, 22h13
Le champ pour la cible est nommé IDC_NAME_TARGET dans le Res, j'pige pas ou tu sors le ID_CIBLE = 100 que je ne retrouve nulle part pendant la création de l'interface. J'arrive à exploiter des interfaces par la méthode classique, mais bien lourde et pénible à mettre en place, par contre pour exploiter ceux générés par Resedit je nage comme un poisson dans le sable :arg: heu... c'est du gros sable même :mrgreen: vite ! vite ! mon tube d'aspirine :cry2:

Majoul
15/04/2007, 23h44
IDC_NAME_TARGET c’est l’id cadget (le champ texte que tu a défini dans le resedit) cet id est attribuer (enum) dans le fichier « c4d_symbols.h »

ID_CIBLE c’est l’id de la variable string du container du tag , je l’ai attribué au début du code


enum
{
ID_CIBLE = 100 ,
ID_DISTANCE = 101 ,
etc ….
_Dummy
}


donc



var bc = tag->GetContainer() ;
var name = bc->GetData(ID_CIBLE) ;


Ce sont deux id distincts.

Steph3D ::.
16/04/2007, 13h58
Ah ok, on accède donc bien aux variables par les IDC_* , ton code m'avait mis dans l'erreur, car je connais pas le principe des enum :oops:
C'est bon :bounce: j'ai réussi à programmer une interface qui fonctionne avec mon code au bout de 2 jours sous aspirine :mrgreen: La 1er fois, j'ai l'impression de me péter du C++ quand je monte l'interface :arg:

Steph3D ::.
18/04/2007, 05h07
Bon j'ai retenté la méthode de resedit, j'ai passé des heures à tout décoder :oops: J'ai enfin pigé les enum et cette histoire d'ID, de container, etc...
J'ai donc refait un code de plugintag, tout fonctionne, l'interface se lance... mais malheureusement les variables ne semblent pas se mémoriser une fois qu'on quitte l'interface :o :(
J'ai pourtant suivi la même méthode que toi, sauf avec plus de boutons :? ça fait 4 heures que je tourne en rond :coup: :coup: :coup: :cry2: :cry2: :cry2:

Faut vraiment s'accrocher pour ne pas devenir chèvre avec la prog :mrgreen: Bon une aspirine et un petit somme....


var PLUGIN_ID =1000021;
var PLUGIN_NAME = "Test d'interface";
var PLUGIN_HELP = "MonTag";
var PLUGIN_ICON = "IcoTag.tif";

enum // on enum les ids du container du tag
{
ID_XML = 100 ,
ID_RENDER = 101 ,
ID_TEXTURE = 102 ,
ID_LIGHT = 103 ,
ID_SHADOW = 104 ,
_Dummy
}

//////////////////////////////////////////
var resource,obj;
var RENDU,TEXTURE,LIGHT,SHADOW,XML;



// debug -------------------------------------------------------------------------------------------------------------------------
DeBug(c,msg,on) {
println("------------------------------------------------------ "+msg );
RENDU = c->GetData(ID_RENDER) ;
println("RENDU = "+ tostring(RENDU) );
TEXTURE = c->GetData(ID_LIGHT) ;
println("TEXTURE = "+ tostring(TEXTURE) );
LIGHT = c->GetData(ID_TEXTURE) ;
println("LIGHT = "+ tostring(LIGHT) );
SHADOW = c->GetData(ID_SHADOW) ;
println("SHADOW = "+ tostring(RENDU) );
XML = c->GetData(ID_XML) ;
if (on==1) println("XML = "+XML);
println("------------------------------------------------------" );

}

//************************************************** **********************
// definition de la class du dialogue
//************************************************** **********************

include "c4d_symbols.h";

class Dialog : GeModalDialog
{
private:
var Bc ; // Variable pour le container

public: // ici on déclare public toutes les fonctions qui suivent, hériter a là class GeModalDialog
Dialog();
CreateLayout();
GetContainer() ;
SetContainer(bc);
Init(); // fonction qui détermine ce qui se passe à l'ouverture du dialogue (donc de l'interface)
Command(id, msg); // "enregistre" les changements de l'interface (comme le déplacement d'un slider ou un bouton cliqué etc...).

}

Dialog::Dialog() // ici on déclare toutes nos variables locales de notre interface
{
super(); // Appele le constructeur parent
}

Dialog::CreateLayout()// La on va créé notre code d'interface, création des boutons, textes, etc...
{
LoadDialogResource(IDD_DIALOG1, resource, 0) ;
}

Dialog::GetContainer()
{
return Bc ; // avec cette fontion on renvoit le container au tag
}

Dialog::SetContainer(bc)
{
Bc = bc ; // avec cette fonction on reçoit le container du tag
}

Dialog::Init() // On détermine ce qui se passe à l'ouverture de l'interface)
{

SetString(IDC_XML, Bc->GetData(ID_XML));
SetCheckbox(IDC_RENDER, Bc->GetData(ID_RENDER));
SetCheckbox(IDC_LIGHT, Bc->GetData(ID_LIGHT));
SetCheckbox(IDC_TXT, Bc->GetData(ID_TEXTURE));
SetCheckbox(IDC_SHADOW, Bc->GetData(ID_SHADOW));

// code debug
DeBug(Bc,"Init",1);
}

Dialog::Command(id, msg){ // on change les valeurs des variables quand on touche commande de l'interface


switch (id) // switch selon le numéro ID de l'objet qu'on touche dans l'interface
{
// ici on reçoit les valeurs du dialogue et on les Stockes dans le container Bc
case IDC_RENDER : Bc->SetData(ID_RENDER, GetCheckbox(id)) ; break ;
case IDC_LIGHT : Bc->SetData(ID_LIGHT, GetCheckbox(id)) ; break ;
case IDC_TXT : Bc->SetData(ID_TEXTURE, GetCheckbox(id)) ; break ;
case IDC_SHADOW : Bc->SetData(ID_SHADOW, GetCheckbox(id)) ; break ;
case IDC_XML : Bc->SetData(ID_XML, GetString(id)) ; break ;
}

Init() ; // avec la fonction Init() on retransmet les valeurs du container Bc au dialogue

// code debug
DeBug(Bc,"Command",1);

}

//************************************************** **********************
// definition de la class de l'ExpressionPluginTag
//************************************************** **********************

class MonTag : ExpressionPluginTag
{
private:
GetNewContainer() ;

public: // ici on déclare public toutes les fonctions qui suivent, héritées de la class ExpressionPluginTag
MonTag();
GetID();
MultipleAllowed();
DisplayAllowed();
GetIcon();
GetHelpText();
UseMenu();
GetName();

Edit(); // ouverture du menu
Execute(doc, op); // code principal
}

MonTag::MonTag() { super(); } // Appelle le constructeur parent . ici on déclare aussi toutes nos variables locales, etc...
MonTag::GetID() { return PLUGIN_ID; } // Renvoie l'identification unique de notre plug-in qu'il faut obtenir sur http://www.plugincafe.com Faut un ID unique par plug-in, sinon il peut avoir des conflits !
MonTag::MultipleAllowed() { return FALSE; } // Faut renvoyé TRUE si on permet de mettre plusieurs Tag de ce type sur un meme objet. Mettre FALSE on n'autorise qu'un seul Tag par objet
MonTag::DisplayAllowed() { return TRUE; } // Renvoyez TRUE si le Tag montre une icône sur l'objet dans la liste de la scene. Mettre FALSE si on veux faire un Tag invisible
MonTag::GetHelpText() { return PLUGIN_HELP; } // Permets de renvoyer une bulle d'aide avec un texte quand on passe avec la souris sur le Tag
MonTag::UseMenu() { return TRUE; } // Renvoyez TRUE si le Tag doit etre énumérée dans le nouveau Tag menu.
MonTag::GetName() { return PLUGIN_NAME; } // Pour renvoyer le nom du menu

MonTag::GetIcon()
{ // Ici on va faire un script pour chercher le fichier image en tif qui va nous servir d'icône pour le Tag
// Création des variables fichier et bitmap
var Bitmap = new(BaseBitmap,1,1);
var File = new(Filename);
// Lecture/Chargement du fichier ico.tif ...
File = GeGetRootFilename(); // ...dans le répertoire ou se trouve notre plug-in
File->RemoveLast();
File->AddLast(PLUGIN_ICON);
Bitmap->Load(File);
// Renvoie l'icône à afficher
return Bitmap;
}

MonTag::GetNewContainer()
{
var bc = new(BaseContainer) ;
bc->SetData(ID_RENDER,true) ;
bc->SetData(ID_LIGHT,true) ;
bc->SetData(ID_TEXTURE,false) ;
bc->SetData(ID_SHADOW,false) ;

bc->SetData(ID_XML, "Hello World !") ;

return bc ;
}

MonTag::Edit() // ----------------------------------------------------------------------------------------------------------------------------------->>> interface
{
var bc = GetContainer() ; // on prend le container du tag
// on verifi si les container existe, sinon on affecte des nouveaux container

DeBug(bc,"edit",0); // code debug

if(!bc->FindIndex(ID_XML)) bc = GetNewContainer() ;

// Le code a renvoyer quand l'utilisateur double clique sur le Tag (pour créer la boite de dialogue)
var Interface = new(Dialog); // on creer un dialogue de la class Dialog defini un peut plus haut
Interface->SetContainer(bc) ; // on transmet le container au dialogue par le fonction SetContainer() de cette class
Interface->Open(-1,-1); // on ouvre le dialogue

// si le resultat est validé alors on transmet le container du dialogue au Tag
if (Interface->GetResult()) SetContainer(Interface>GetContainer()) ;
}



MonTag::Execute(doc, op) { // Script appelé à chaque redraw, donc exécuté en permanence.

// code debug
var bc = GetContainer();
DeBug(bc,"exec",0);

}

main()
{
// Enregistrement de l'expression plug-in tag
Register(MonTag);

// Pour pouvoir accéder au fichier de ressource de l'interface
var file = GeGetRootFilename(); if (!file) return;
file->RemoveLast();
resource = new(GeResource,file);

}

[Fichier joint supprimé par l'administrateur]

Majoul
18/04/2007, 22h35
true et false c'est en majuscule TRUE FALSE


MonTag::GetNewContainer()
{
var bc = new(BaseContainer) ;
bc->SetData(ID_RENDER,TRUE) ;
bc->SetData(ID_LIGHT, TRUE) ;
bc->SetData(ID_TEXTURE, FALSE) ;
bc->SetData(ID_SHADOW, FALSE) ;

bc->SetData(ID_XML, "Hello World !") ;

return bc ;
}

Steph3D ::.
18/04/2007, 23h16
Merci, mais d'après mes tests en coffee, que tu écrives TRUE ou true, ben visiblement ça marche pareil.
Enfin, j'ai quand meme changé pour voir, et cela ne change rien au problème :( j'ai pourtant relu au moins 50 x le code :oops: :oops: mais je ne vois toujours pas se qui cloche :shock:

Majoul
19/04/2007, 00h58
c'est qu'il y a toujours une erreur qui traîne

if (Interface->GetResult()) SetContainer(Interface->GetContainer()) ;

-> et non >





[Fichier joint supprimé par l'administrateur]

Steph3D ::.
19/04/2007, 05h39
Merci ! ça marche enfin !!! je vais pouvoir un peu dormir :bounce:

J'ai aussi ajouté à ton code >


MonTag::Save(hf)
{
var bc = GetContainer();
hf->WriteContainer(bc);
}
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------
MonTag::Load(hf)
{
var bc = hf->ReadContainer();
SetContainer(bc);
}
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------
MonTag::Copy(dest)
{
var bc = GetContainer();
dest->SetContainer(bc->GetClone());
}


Sinon ça ne garde pas la mémoire des contenaires quand on sauvegarde la scène et qu'on quitte C4D, donc la ça permet de l'ecrire en dur dans notre fichier de scene C4D
Quand j'ai le temps, je posterai une version au propre pour boucler le pseudo wip/tutoriel du pluginTag :mrgreen:

Mais sinon il me reste encor des énigmes à résoudre :roll: comment faire pour que C4D tourne derrière, voir exécuter tout le script en permanence avec l'interface ouverte ?
Par ce que là, quand j'entre dans l'interface, C4D se met en pause et attend la fermeture du dialogue.

De plus, je me demande si on peu pas créer des interfaces resizable avec une taille par défaut ? par ce que la elle se ressert comme un élastique sur les gadgets.

Steph3D ::.
19/04/2007, 23h38
Petite astuce, si on veux reprendre ou écrire des infos du tag personalisé avec nos expressions, il suffit d'ecrire un truc du style...


enum // enum les ID du container
{
ID_XML = 100 ,
ID_RENDER ,
ID_TEXTURE ,
ID_LIGHT ,
ID_SHADOW
}

main(doc,op)
{
var mon_tag = op->GetFirstTag(); // je prends le 1er tag de la liste (ou j'ai mis le tag perso)
var container=mon_tag->GetContainer();
var test = container->GetData(ID_XML);
println(test);
}