PDA

Voir la version complète : Développer un plugin en C++



Riwall
20/12/2010, 14h44
Bonjour à tous!

Comme je l'ai expliqué dans ma présentation je suis en train de développer dans le cadre d'un projet scolaire un plugin pour Cinema4D en C++ (j'utilise Visual Studio 2008). Après maintes je recherches j'ai bien réussi à compiler sans problème le sdk, et commencé à créer mon propre tag.

Que doit réaliser ce plugin?

Heureux que vous posiez cette question! l'idée est de modifier un modèle de visage de base de C4D automatiquement à partir de 2 photos (face + profil). Le tag devra donc avoir comme attributs (au minimum) deux chemins d'accès vers des images. J'ai réussi à créer ces chemins d'accès mais je dois bien avouer que je suis quelque peu perplexe quant à la qualité du code...

Afin de ne pas en effrayer certains je ne mets pas immédiatement le code (faut dire aussi qu'il est pas sur ce PC... la bonne excuse...) mais si vous avez des conseils, des recommandations, ou même envie de voir le code pour savoir si ça va ou si ça ne va pas, je suis là :) (j'ai remarque un certain xs_yann sur le forum... on va dire que c'est un des grands noms qui m'ont permis de m'en sortir à peu près jusque là :whistling: )

Merci à tous! à bientôt :)

édit: j'oubliais de préciser que je suis inscrit sur le forum de plugincafe de Maxon (j'ai donc mon ID pour le plugin) et j'ai également téléchargé la doc... mais rien à faire ça reste assez dur pour moi... Et en terme de prog, je suis pas un crack mais je me débrouille en C, C++, C#, java,... donc au pire pour le coup une petite recherche google me suffit en général en cas de soucis. Ici il s'agit surtout de la syntaxe de C4D

valkaari
20/12/2010, 16h23
j'ai une question, qu'est ce qui motive ton choix de faire un tag et pas par exemple un objet ou un déformateur ?

Riwall
20/12/2010, 16h32
Salut!

Tout d'abord merci de t'intéresser à ce projet :)

Je dois bien avouer que je me suis tourné vers le tag sans grosse conviction, mais il me semblait qu'il répondait bien aux besoins du plugin. Il y a également le fait que les rares tutos que j'ai pu trouver sur le sujet traitaient du développement d'un plugin de type tag donc je ne suis pas allé chercher beaucoup plus loin (de peur de me perdre complètement)

Ceci dit, si vous vous y connaissez (ne serait-ce qu'un peu) et que vous me conseillez autre chose, je suis tout ouïe.

xs_yann
21/12/2010, 13h21
Salut Riwall,

Ton projet à l'air très interessant bien que pas facile.
As-tu commencé a coder l'analyse des images ?


même envie de voir le code pour savoir si ça va ou si ça ne va pas
Moi je veux bien voir le code.

Sinon je dirais que le tag n'a pas l'air d'être le plus adapté à ce que tu recherches. Je pense qu'un plugin de type Command serait plus approprié (ton plugin a besoin d'être executé une seule fois et non pas a chaque modifications / frame).


Il y a également le fait que les rares tutos que j'ai pu trouver sur le sujet traitaient du développement d'un plugin de type tag donc je ne suis pas allé chercher beaucoup plus loin

Je veux bien t'aider a faire un "Menu plugin" (CommandData) quand tu auras posté ce que tu as déjà fais. ;)


je suis en train de développer dans le cadre d'un projet scolaire un plugin pour Cinema4D en C++
C'est possible de savoir dans quelle école tu es ? (Un plugin C4D pour l'école :w00t:)

2Mylent
21/12/2010, 14h33
On peut donner une liste de plugin pour l'école ?:innocent:
:D

Riwall
21/12/2010, 22h43
Salut xs_yann! merci pour ces infos, je vais éditer ce post dans la soirée pour y ajouter les codes (grosso modo je suis parti du tag "look at camera" en bidouillant grassement au feeling... je suis simplement arrivé à afficher un menu dans les attributs ... c'est pas énorme)


C'est possible de savoir dans quelle école tu es ? (Un plugin C4D pour l'école :w00t:)

Héhé, en fait, de base, le projet en question est de modifier un modèle de tête à partir de photos de quelqu'un, et les outils étaient libres. Comme je connais un peu C4D (côté modélisation) je me suis dit que les fonctionnalités que le logiciel propose seraient un plus par rapport à des outils plus classiques (Qt et OpenGL) notamment par rapport au maillage qui a constitué l'un des plus gros problème du binôme qui a fait ce projet l'année dernière.

En terme de traitement d'image, on a récupéré les algo de l'année précédente (détermination de certains points "critiques" du visage, mise en relation,...)

edit: voilà, la seule partie que j'ai modifiée en partant de lookatcamera.cpp (celui du sdk) c'est dans la methode GetDescription, gardez bien à l'esprit que j'étais un peu perdu T.T donc j'ai expérimenté (pas moyen de faire apparaître un bouton "appliquer" d'ailleurs, j'ai essayé DTYPE_BUTTON mais... non ^^) donc voilà c'est que de la bidouille, je pense que j'aurais du demander des conseils plus tôt, mais au moins j'ai appris deux ou trois trucs sur le tas!


Bool MyTagPlugin::GetDDescription(GeListNode *node, Description *description,LONG &flags)
{
if (!description->LoadDescription(1001165)) return FALSE;
const DescID *singleid = description->GetSingleDescID();

DescID cid = DescLevel(6001, DTYPE_GROUP, 0);
if (!singleid || cid.IsPartOf(*singleid,NULL)) // important to check for speedup c4d!
{
BaseContainer maingroup = GetCustomDataTypeDefault(DTYPE_GROUP);
maingroup.SetString(DESC_NAME, "Images");
if (!description->SetParameter(cid, maingroup, DescLevel(0))) return TRUE;
}

cid = DescLevel(6002, DTYPE_GROUP, 0);
if (!singleid || cid.IsPartOf(*singleid,NULL)) // important to check for speedup c4d!
{
BaseContainer subgroup = GetCustomDataTypeDefault(DTYPE_GROUP);
subgroup.SetString(DESC_NAME, "Images");
if (!description->SetParameter(cid, subgroup, DescLevel(6001))) return TRUE;
}

cid = DescLevel(6003, DTYPE_FILENAME, 0);
if (!singleid || cid.IsPartOf(*singleid,NULL)) // important to check for speedup c4d!
{
BaseContainer locked = GetCustomDataTypeDefault(DTYPE_FILENAME);
locked.SetString(DESC_NAME, "Image de face");
locked.SetFilename(DESC_DEFAULT, "Image de face");

if (locked.GetFilename() != *.jpg && locked.GetFilename() != *.bmp)
{

}

if (!description->SetParameter(cid, locked, DescLevel(6002))) return TRUE;
}

cid = DescLevel(6004, DTYPE_FILENAME, 0);
if (!singleid || cid.IsPartOf(*singleid,NULL)) // important to check for speedup c4d!
{
BaseContainer locked = GetCustomDataTypeDefault(DTYPE_FILENAME);
locked.SetString(DESC_NAME, "Image de profil");
locked.SetFilename(DESC_DEFAULT, "Image de profil");
if (!description->SetParameter(cid, locked, DescLevel(6002))) return TRUE;
}

cid = DescLevel(6005, DTYPE_BOOL, 0);
if (!singleid || cid.IsPartOf(*singleid,NULL)) // important to check for speedup c4d!
{
BaseContainer locked = GetCustomDataTypeDefault(DTYPE_BOOL);
locked.SetString(DESC_NAME, "Appliquer");
locked.SetBool(DESC_DEFAULT, TRUE);
if (!description->SetParameter(cid, locked, DescLevel(6002))) return TRUE;
}

flags |= DESCFLAGS_DESC_LOADED;

return TRUE;
}


Il y a tout un tas de trucs qui ne servent à rien (j'aurais pu les mettre en commentaire d'ailleurs) mais bon, je me disais "on sait jamais"

valkaari
22/12/2010, 00h51
Laisse tomber le tag, fait ce que Yann te dit, fait un plugin command.
Ce sera beaucoup plus facile puisque tu vas te retrouver sur une programmation beaucoup plus "classique".
Une petite interface qui demande de sélectionner les deux images, un bouton OK et zoup, ton plug crée la tête.

Sinon tu as la possibilité de créer un objet pour permettre éventuellement la modification de certains paramètres (précision ?) sans avoir à relancer à chaque fois l'interface mais juste à cliquer sur l'objet puis à faire les modifications.

Pour ce qui est de la création de l'interface, passe par les ".res"
D'ailleurs sur le site de maxon, comme tu peux télécharger le/les dsk, tu peux télécharger ResEdit qui permet la création d'interface plus rapidement (bien qu'il faille adapter les fichiers générés).

Riwall
22/12/2010, 02h24
Ok, merci beaucoup, je vais me pencher sur la question :)

Des conseils pour bien débuter? genre un exemple dans le sdk?

valkaari
22/12/2010, 03h08
Comme tu es sur pc, je te conseille de télécharger la doc du sdk au format chm. Beaucoup plus "simple" pour les recherche.

Il faut faire attention, depuis la R12 quelques fonctions ont changé. Donc avoir la bonne documentation ça aide.

D'ailleurs, tu vas faire le plugin avec quelle version de c4D la 11/11.5 ou la 12 ?

Tu peux regarder les exemples de prog en multy-thread dans le répertoire du sdk, c'est assez facile à mettre en place, autant le prévoir dès le début.

Prévoir du café, beaucoup de café et autant de patience.

Riwall
22/12/2010, 03h36
Très bien, je dld la doc de la 11.5 en chm. Je vais me restreindre à cette version pour le moment, peut être que si ça marche bien j'en ferai une version pour les autre releases de C4D ! (on y croit héhé)

xs_yann
22/12/2010, 10h35
peut être que si ça marche bien j'en ferai une version pour les autre releases de C4D ! (on y croit héhé)

Ou un portage en Python. :innocent:

Effectivement, ça à l'air un peu crade ce que tu as fais, comme l'as dit valkaari la GUI non dynamique se défini en '.res' (ou dans le CreateLayout pour un dialog).

Je vais te faire un exemple, avec un 'template' de CommandData. ;)

xs_yann
22/12/2010, 12h47
Héhé, en fait, de base, le projet en question est de modifier un modèle de tête à partir de photos de quelqu'un, et les outils étaient libres. Comme je connais un peu C4D (côté modélisation) je me suis dit que les fonctionnalités que le logiciel propose seraient un plus par rapport à des outils plus classiques (Qt et OpenGL) notamment par rapport au maillage qui a constitué l'un des plus gros problème du binôme qui a fait ce projet l'année dernière.

En terme de traitement d'image, on a récupéré les algo de l'année précédente (détermination de certains points "critiques" du visage, mise en relation,...)


Et tu ne veux vraiment pas dire le nom de ton école ? :D


Tu peux regarder les exemples de prog en multy-thread dans le répertoire du sdk, c'est assez facile à mettre en place, autant le prévoir dès le début.

Je n'ai jamais fais de multi-thread avec C4D mais cela peut être une bonne chose, en effet.

Voici le 'main.cpp' que j'utilise :

#include "c4d.h"

// forward declaration
Bool RegisterRiwallFace(void);

C4D_CrashHandler old_handler;

void MyCrashHandler(CHAR *crashinfo)
{
// printf("Crash Info :\n");
// printf(crashinfo);

if (old_handler)
(*old_handler)(crashinfo);
}

Bool PluginStart(void)
{
old_handler = C4DOS.CrashHandler;
C4DOS.CrashHandler = MyCrashHandler;

return RegisterRiwallFace();
}

void PluginEnd(void)
{
}

Bool PluginMessage(LONG id, void *data)
{
switch (id)
{
case C4DPL_INIT_SYS:
if (!resource.Init())
return FALSE; // don't start plugin without resource
return TRUE;
}

return FALSE;
}


Et voici une base pour ton plugin qui donne ça :
http://www.xsyann.com/fc4d/riwall.png


class RiwallFaceDialog : public GeDialog // La classe pour le dialogue asynchrone
{
public:
virtual Bool CreateLayout(void);
virtual Bool Command(LONG id,const BaseContainer &msg);
};

enum // enum pour les id des elements du dialogue
{
FILENAME_FRONT = 1001,
FILENAME_SIDE,
CREATE_FACE,

_DUMMY_ELEMENT_
};

Bool RiwallFaceDialog::CreateLayout(void) // On cree la GUI (assez intuitif je ne commente pas)
{
Bool res = GeDialog::CreateLayout();

SetTitle("RiwallFace");

GroupBegin(0, BFV_SCALEFIT | BFH_SCALEFIT, 0, 2, String(), 0);
{
GroupBorderSpace(4, 4, 4, 4);

GroupBegin(0, BFV_SCALEFIT | BFH_SCALEFIT, 2, 0, "Images", 0);
{
GroupBorder(BORDER_GROUP_IN | BORDER_WITH_TITLE);
GroupBorderSpace(4, 4, 4, 4);

BaseContainer bc;
bc.SetBool(FILENAME_TEXTURE, TRUE);

AddStaticText(0, BFH_FIT, 40, 0, "Front", BORDER_NONE);
AddCustomGui(FILENAME_FRONT, CUSTOMGUI_FILENAME, "Front", BFH_SCALEFIT, 0, 0, bc);

AddStaticText(0, BFH_FIT, 40, 0, "Side", BORDER_NONE);
AddCustomGui(FILENAME_SIDE, CUSTOMGUI_FILENAME, "Side", BFH_SCALEFIT, 0, 0, bc);
}
GroupEnd();
AddButton(CREATE_FACE, BFH_CENTER, 0, 0, "Create face");
}
GroupEnd();

return res;
}

Bool RiwallFaceDialog::Command(LONG id, const BaseContainer &msg) // Methode appellee lors d'une interaction avec la GUI
{
switch (id)
{
case CREATE_FACE: // Bouton 'create face' clique

FilenameCustomGui *front = (FilenameCustomGui*)(FindCustomGui(FILENAME_FRONT, CUSTOMGUI_FILENAME)); // on recupere les composants
FilenameCustomGui *side = (FilenameCustomGui*)(FindCustomGui(FILENAME_SIDE, CUSTOMGUI_FILENAME)); // (on peut les mettre en propiete private a la place)

Filename frontPath = front->GetData().GetValue().GetFilename(); // on recupere les path
Filename sidePath = side->GetData().GetValue().GetFilename();

GePrint(frontPath.GetString()); // affiche les path dans la console (Menu Window > Console)
GePrint(sidePath.GetString());

if (!frontPath.Content() || !sidePath.Content()) // on verifie si les path ne sont pas vides.
{
MessageDialog("You must select a front and a side image.");
return TRUE;
}
break;
}
return TRUE;
}

// be sure to use a unique ID obtained from www.plugincafe.com
#define ID_RIWALLFACE 1000007

class RiwallFace : public CommandData // la classe pour la commande
{
private:
RiwallFaceDialog dlg;
public:
virtual Bool Execute(BaseDocument *doc);
virtual LONG GetState(BaseDocument *doc);
virtual Bool RestoreLayout(void *secret);
};

LONG RiwallFace::GetState(BaseDocument *doc)
{
return CMD_ENABLED;
}

Bool RiwallFace::Execute(BaseDocument *doc) // qui ouvre le dialogue lorsque elle est executee
{
return dlg.Open(TRUE, ID_RIWALLFACE, -1, -1, 300, 175);
}

Bool RiwallFace::RestoreLayout(void *secret)
{
return dlg.RestoreLayout(ID_RIWALLFACE, 0, secret);
}

Bool RegisterRiwallFace(void)
{
return RegisterCommandPlugin(ID_RIWALLFACE, String("RiwallFace"), 0, NULL, String("RiwallFace"), gNew RiwallFace);
}



Si tu as des questions ou des problèmes, n'hésite pas. ;)

Riwall
04/01/2011, 15h23
Oh la vache ça démonte T.T je vais jeter un coup d'oeil et je reviendrai avec d'éventuelles questions !

édit: De retour sur le projet, ça marche super! La nouvelle étape va maintenant consister à afficher les deux images, je me demande si je peux les afficher dans des fenêtres C4D ou si je dois passer par une librairie genre Qt?

Si j'ai bien compris les variables frontPath et sidePath nous donnent les chemins d'accès. On peut créer une GUI pour afficher une image et à l'aide de patience et d'une souris en sortir manuellement des points caractéristiques?

valkaari
04/01/2011, 18h39
il me semble qu'il faut utiliser un "GeUserData"

Normalement ça permet de faire pleins de trucs perso. Tu peux toujours regarder de ce coté en attendant que yan vienne te donner la réponse ^^

Riwall
06/01/2011, 01h43
Ok merci, je vais "feuilleter" la doc :)


édit: je ne trouve pas GeUserData dans la doc, par contre je trouve 2 GetUserData, c'est ça? Lequel choisir?

GetUserData from (AtomArray)
GetUserData from (GvNodeMaster)

Merci :)

base80
06/01/2011, 04h18
Edites tes messages plutôt que de les supprimer, stp.

valkaari
06/01/2011, 12h07
oupssss :blushing:

milles excuses ---> GeUserArea

Riwall
12/01/2011, 00h14
Edites tes messages plutôt que de les supprimer, stp.

Ok ok, désolé, c'est juste pour éviter le double post et la poussière sur le sujet, un simple édit ne refresh pas le sujet, donc après pour avoir des réponses... je peux attendre, mais soit.



oupssss

milles excuses ---> GeUserArea

héhé, merci bien, je me suis donc penché dessus quelques temps (oui, j'ai beaucoup de choses à faire, je ne consacre pas tout mon temps à ce travail), je suis en train d'essayer d'afficher une fenêtre! Cependant je me demandais si le bitmap sont les seuls fichiers supportés? Je veux dire que je peux instancier des bitmap, mais quid des autres formats?

Afin d'être sûr de ne pas partir complètement de travers, j'ai ajouté pour cela une méthode pour afficher une image (à partir de son chemin d'accès) dans une fenêtre. Cette méthode est dans la classe FrontDialog, mais c'est là où je suis pas super sûr de mon coup...

Merci à vous :)

oli_d
12/01/2011, 04h59
Cependant je me demandais si le bitmap sont les seuls fichiers supportés?

Non, Bitmap est utilisé dans le sens image matricielle, pixel ... et ce n'est pas du tout une référence au format (pourri) bmp. Tu dois pouvoir lire tous les formats que c4d gère (jpeg, tif, psd, png, tga ....)


Cette méthode est dans la classe FrontDialog, mais c'est là où je suis pas super sûr de mon coup...

J'ai pas trouvé dans la doc cette classe ? J'ai pas vraiment compris où tu n'es pas sûr, fais péter un bout de code ...

Personnellement je n'ai encore jamais fait ce genre de truc mais comme a dit Val c'est sûrement du côté de la classe GeUserArea avec les méthodes DrawBitmap ou FillBitmapBackground. Ensuite regarde dans GeDialog la méthode AttachUserArea

Riwall
12/01/2011, 10h01
Non, Bitmap est utilisé dans le sens image matricielle, pixel ... et ce n'est pas dut out une référence au format (pourri) bmp. Tu dois pouvoir lire tous les formats que c4d gère (jpeg, tif, psd, png, tga ....)

Ok merci :)



J'ai pas trouvé dans la doc cette classe ? J'ai pas vraiment compris où tu n'est pas sûr, fais péter un bout de code ...

Personnellement je n'ai encore jamais fait ce genre de truc mais comme a dit Val c'est sûrement du côté de la classe GeUserArea avec les méthodes DrawBitmap ou FillBitmapBackground. Ensuite regarde dans GeDialog la méthode AttachUserArea

Oui, l'idée est de créer une UserArea, de faire un AttachUserArea, et dessiner effectivement avec Draw et Fill, content d'avoir vu juste sur ces points ^^.

Je suis parti de ce que m'a dit xs_yann:


class RiwallFaceDialog : public GeDialog // La classe pour le dialogue asynchrone
{
public:
virtual Bool CreateLayout(void);
virtual Bool Command(LONG id,const BaseContainer &msg);
};

enum // enum pour les id des elements du dialogue
{
FILENAME_FRONT = 1001,
FILENAME_SIDE,
CREATE_FACE,

_DUMMY_ELEMENT_
};

Bool RiwallFaceDialog::CreateLayout(void) // On cree la GUI (assez intuitif je ne commente pas)
{
Bool res = GeDialog::CreateLayout();

SetTitle("RiwallFace");

GroupBegin(0, BFV_SCALEFIT | BFH_SCALEFIT, 0, 2, String(), 0);
{
GroupBorderSpace(4, 4, 4, 4);

GroupBegin(0, BFV_SCALEFIT | BFH_SCALEFIT, 2, 0, "Images", 0);
{
GroupBorder(BORDER_GROUP_IN | BORDER_WITH_TITLE);
GroupBorderSpace(4, 4, 4, 4);

BaseContainer bc;
bc.SetBool(FILENAME_TEXTURE, TRUE);

AddStaticText(0, BFH_FIT, 40, 0, "Front", BORDER_NONE);
AddCustomGui(FILENAME_FRONT, CUSTOMGUI_FILENAME, "Front", BFH_SCALEFIT, 0, 0, bc);

AddStaticText(0, BFH_FIT, 40, 0, "Side", BORDER_NONE);
AddCustomGui(FILENAME_SIDE, CUSTOMGUI_FILENAME, "Side", BFH_SCALEFIT, 0, 0, bc);
}
GroupEnd();
AddButton(CREATE_FACE, BFH_CENTER, 0, 0, "Create face");
}
GroupEnd();

return res;
}

Bool RiwallFaceDialog::Command(LONG id, const BaseContainer &msg) // Methode appellee lors d'une interaction avec la GUI
{
switch (id)
{
case CREATE_FACE: // Bouton 'create face' clique

FilenameCustomGui *front = (FilenameCustomGui*)(FindCustomGui(FILENAME_FRONT, CUSTOMGUI_FILENAME)); // on recupere les composants
FilenameCustomGui *side = (FilenameCustomGui*)(FindCustomGui(FILENAME_SIDE, CUSTOMGUI_FILENAME)); // (on peut les mettre en propiete private a la place)

Filename frontPath = front->GetData().GetValue().GetFilename(); // on recupere les path
Filename sidePath = side->GetData().GetValue().GetFilename();

GePrint(frontPath.GetString()); // affiche les path dans la console (Menu Window > Console)
GePrint(sidePath.GetString());

if (!frontPath.Content() || !sidePath.Content()) // on verifie si les path ne sont pas vides.
{
MessageDialog("You must select a front and a side image.");
return TRUE;
}
break;
}
return TRUE;
}

// be sure to use a unique ID obtained from www.plugincafe.com
#define ID_RIWALLFACE 1000007

class RiwallFace : public CommandData // la classe pour la commande
{
private:
RiwallFaceDialog dlg;
public:
virtual Bool Execute(BaseDocument *doc);
virtual LONG GetState(BaseDocument *doc);
virtual Bool RestoreLayout(void *secret);
};

LONG RiwallFace::GetState(BaseDocument *doc)
{
return CMD_ENABLED;
}

Bool RiwallFace::Execute(BaseDocument *doc) // qui ouvre le dialogue lorsque elle est executee
{
return dlg.Open(TRUE, ID_RIWALLFACE, -1, -1, 300, 175);
}

Bool RiwallFace::RestoreLayout(void *secret)
{
return dlg.RestoreLayout(ID_RIWALLFACE, 0, secret);
}

Bool RegisterRiwallFace(void)
{
return RegisterCommandPlugin(ID_RIWALLFACE, String("RiwallFace"), 0, NULL, String("RiwallFace"), gNew RiwallFace);
}

Et c'est dans la classe FrontDialog de ce bout de code que j'ai insérer ma méthode "ShowImage", qui pour l'instant ne fait pas grand chose, d'ailleurs je n'arrive pas à l'utiliser, erreur à la compilation... ça c'est une question d'habitude après, je ne suis vraiment pas familier avec les fonctions C4D, mais ça viendra (j'ai encore un semestre T.T)

oli_d
12/01/2011, 10h13
Quand je demandais du code c'était le tien, pas celui de XsYann !!

valkaari
12/01/2011, 14h38
dans le SDK, tu as dans le répertoire GUI un exemple d'utilisation de ce "truc" asynctest.cpp gradientuserarea.cpp et gradientuserarea.h

L'exemple permet de créer un dégradé. C'est intéressant comme sujet et j'avoue que je vais devoir m'y coller dans pas longtemps.

Mais j'avoue aussi que le palmier au centre de ma main ne me permet pas de m'y coller de suite xD

Riwall
13/01/2011, 00h45
Merci beaucoup valkaari, c'est exactement le genre d'exemple que je cherche, un truc pas trop complexe qui permette de bien comprendre les trucs (ou pas, à vous de me dire si j'ai fait une boulette)


#include "c4d.h"
#include "c4d_symbols.h"
#include "c4d_gui.h"
#include "customgui_filename.h"


class FaceDialog : public GeDialog // La classe pour le dialogue asynchrone
{
public:
virtual Bool CreateLayout(void);
virtual Bool Command(LONG id,const BaseContainer &msg);
};

enum // enum pour les id des elements du dialogue
{
FILENAME_FRONT = 1001,
FILENAME_SIDE,
CREATE_FACE,

_DUMMY_ELEMENT_
};

Bool FaceDialog::CreateLayout(void) // On cree la GUI (assez intuitif je ne commente pas)
{
Bool res = GeDialog::CreateLayout();

SetTitle("3D Face");

GroupBegin(0, BFV_SCALEFIT | BFH_SCALEFIT, 0, 2, String(), 0);
{
GroupBorderSpace(4, 4, 4, 4);

GroupBegin(0, BFV_SCALEFIT | BFH_SCALEFIT, 2, 0, "Images", 0);
{
GroupBorder(BORDER_GROUP_IN | BORDER_WITH_TITLE);
GroupBorderSpace(4, 4, 4, 4);

BaseContainer bc;
bc.SetBool(FILENAME_TEXTURE, TRUE);

AddStaticText(0, BFH_FIT, 40, 0, "Front", BORDER_NONE);
AddCustomGui(FILENAME_FRONT, CUSTOMGUI_FILENAME, "Front", BFH_SCALEFIT, 0, 0, bc);

AddStaticText(0, BFH_FIT, 40, 0, "Side", BORDER_NONE);
AddCustomGui(FILENAME_SIDE, CUSTOMGUI_FILENAME, "Side", BFH_SCALEFIT, 0, 0, bc);
}
GroupEnd();
AddButton(CREATE_FACE, BFH_CENTER, 0, 0, "Create face");
}
GroupEnd();

return res;
}

Bool FaceDialog::Command(LONG id, const BaseContainer &msg) // Methode appellee lors d'une interaction avec la GUI
{
switch (id)
{
case CREATE_FACE: // Bouton 'create face' clique

FilenameCustomGui *front = (FilenameCustomGui*)(FindCustomGui(FILENAME_FRONT, CUSTOMGUI_FILENAME)); // on recupere les composants
FilenameCustomGui *side = (FilenameCustomGui*)(FindCustomGui(FILENAME_SIDE, CUSTOMGUI_FILENAME)); // (on peut les mettre en propiete private a la place)

Filename frontPath = front->GetData().GetValue().GetFilename(); // on recupere les path
Filename sidePath = side->GetData().GetValue().GetFilename();

GePrint(frontPath.GetString()); // affiche les path dans la console (Menu Window > Console)
GePrint(sidePath.GetString());

if (!frontPath.Content() || !sidePath.Content()) // on verifie si les path ne sont pas vides.
{
MessageDialog("You must select a front and a side image.");
return TRUE;
}
else
{
}
break;
}
return TRUE;
}

class BitmapArea : public GeUserArea
{
public:
BitmapArea(void);
};

BitmapArea::BitmapArea(void)
{
}

class ImageDialog : public GeDialog
{
private:
BitmapArea bmpa;

public:
ImageDialog(void);
virtual Bool CreateLayout(void);
};


ImageDialog::ImageDialog(void)
{
}

Bool ImageDialog::CreateLayout(void)
{
// first call the parent instance
Bool res = GeDialog::CreateLayout();

SetTitle("ImageDialog Demo");

GroupBegin(0,BFH_SCALEFIT,2,0,"",0);
{

}
GroupEnd();

MenuFlushAll();
MenuSubBegin("Menu");

//////////////////////////////////////
////// //////
////// MENU //////
////// //////
//////////////////////////////////////

MenuSubEnd();
MenuFinished();

return res;
}

// be sure to use a unique ID obtained from www.plugincafe.com
#define ID_FACE 1026310

class Face : public CommandData // la classe pour la commande
{
private:
FaceDialog dlg;
ImageDialog idlg1;
ImageDialog idlg2;
public:
virtual Bool Execute(BaseDocument *doc);
virtual LONG GetState(BaseDocument *doc);
virtual Bool RestoreLayout(void *secret);
};

LONG Face::GetState(BaseDocument *doc)
{
return CMD_ENABLED;
}

Bool Face::Execute(BaseDocument *doc) // qui ouvre le dialogue lorsque elle est executee
{
return dlg.Open(TRUE, ID_FACE, -1, -1, 300, 175) && idlg1.Open(TRUE, ID_FACE, -10, 10, 800, 600) && idlg2.Open(TRUE, ID_FACE, -10, -10, 800, 600);
}

Bool Face::RestoreLayout(void *secret)
{
return dlg.RestoreLayout(ID_FACE, 0, secret) && idlg1.RestoreLayout(ID_FACE, 0, secret) && idlg2.RestoreLayout(ID_FACE, 0, secret);
}

Bool RegisterFace(void)
{
return RegisterCommandPlugin(ID_FACE, String("3D Face"), 0, NULL, String("3D Face"), gNew Face);
}


Si j'ai bien compris, lorsque que l'utilisateur clique sur "3D Face" dans le menu des plugins, ça lance la méthode Execute de Face, j'y ai donc ajouté la création deux 2 nouvelles boîtes de dialogue de type "ImageDialog". Bon, pour le moment cette classe est très pauvre, mais elle permettra par la suite d'afficher une image dans la partie "centrale" de la boîte de dialogue par le biais de la classe BitmapArea (héritant de la fameuse classe GeUserArea)

Je me demandais, si je veux appeler des méthodes de ImageDialog/BitmapArea (genre FillBitmap ou quoi) dans la classe FrontDialog, je dois les placer avant? Ou au moins placer tous les headers en tête pour pas avoir de soucis?

Uhm, une petite dernière question qui me chiffonne: vais-je devoir créer 2 classes de ImageDialog (genre ImageFrontDialog et ImageSideDialog) afin de les différencier au niveau du plugin? J'ai comme la vague impression que sinon, ça va coincer...

édit: code modifié, il y avait une classe FrontDialog, copie conforme de FaceDialog, je l'ai supprimée, ça marche pareil (FrontDialog jamais utilisée)

valkaari
13/01/2011, 01h10
pour la methode execute de la classe CommandData, ce que dit le sdk :


virtual Bool Execute(BaseDocument* doc)
Called when the plugin is selected by the user.

Donc vi bingo :)


Pour les appels de methode, il faut évidement qu'elle soit déclarée avant. Déclaré mais pas forcement définie. Pour ça tu peux utiliser le foward declaration. ça donne un truc du genre

bon t'occupe pas, fais comme si tu connaissais une fonction toto
bon j'ai une fonction tata qui fait appel à toto
bon alors toto ça fait 1+2+3+4.

Du coup t'as pas d'erreur à la compilation.


Pour ce qui est de la création ou non de plusieurs classe, ben c'est un problème de programmation orienté objet. Réunir des propriétés et des méthodes communes et faire de l'héritage de classes pour ajouter des propriétés spécifiques.

Si tes objets doivent avoir des méthodes ou propriétés vraiment différentes, tu peux les séparer ou faire une class qui gère les deux cas.
C'est là que le style du codeur entre en jeu je trouve ^^


Sinon, 3 commandes à connaitre absolument quand tu fais du c++ dans c4d.
GePrint("string") permet d'afficher un message dans la console (shift + f10)
LongToString(LONG) permet de convertir un numérique de type LONG en string
RealToString(Real) permet ....................................Real en string.

Tu peux comme ça découvrir les joies de la découverte du "quand est ce que je passe par là ?"

on fini par vaguement s'y retrouver. Puis quand tu "découvre" une fonction, je te conseille de rajouter un commentaire. Même si c'est un truc du genre "est ce que ça construit un menu ?". J'ai testé cette méthode avec du copier coller du SDK, j'ai gagné pas mal de temps dans la découverte de certaines fonctions.

xs_yann
13/01/2011, 02h26
J'ai rapidement parcouru le post, si je comprend bien tu as un problème pour afficher des images. Je connais plusieurs méthode, il y en a peu être des mieux. Voici déjà comment faire en COFFEE (je crois qu'en cpp c'est pas trop différent) avec le GeUserArea :
http://www.xsyann.com/274/coffee/addbitmap#more-274

Sinon tu peux tricher (j'avais utiliser ça sur un projet) :

BitmapButtonCustomGui* bb = (BitmapButtonCustomGui*)AddCustomGui(0, CUSTOMGUI_BITMAPBUTTON, "", BFH_LEFT, 12, 12, BaseContainer());
// si je dis pas de bêtise les cast de type C sont deprecated en cpp, a remplacer par un static_cast ?
BaseBitmap* bmp = BaseBitmap::Alloc();
if (bmp->Init(10, 10) == IMAGERESULT_OK)
{
const Vector& color = op->color;
bmp->Clear(color.x * 255, color.y * 255, color.z * 255); // rempli le bitmap avec une couleur
bb->SetImage(bmp, TRUE);
}
BaseBitmap::Free(bmp);


Cf la classe BaseBitmap du SDK.

Je n'ai pas trop le temps de t'aider plus pour le moment, malheureusement, car ton projet à l'air vachement interessant.
Bon courage.;)

Riwall
13/01/2011, 19h51
Merci infiniment, vos conseils sont très précieux! Je crois voir la lumière au bout du tunnel en ce qui concerne l'affichage des images:


#include "c4d.h"
#include "c4d_symbols.h"
#include "c4d_gui.h"
#include "customgui_filename.h"
#include "ge_prepass.h"

// be sure to use a unique ID obtained from www.plugincafe.com
#define ID_FACE 1026310

class ImageDialog;

enum // enum pour les id des elements du dialogue
{
AREA_FRONT = 2001,
AREA_SIDE,

_DUMMY_
};

class ImageArea : public GeUserArea
{
public:
ImageArea(void);

};

ImageArea::ImageArea(void)
{
GeUserArea::GeUserArea();
}

class ImageDialog : public GeDialog
{
private:
Filename path;
String name;
ImageArea ia;
LONG ID;

public:
ImageDialog(void);
virtual Bool CreateLayout(void);
LONG DrawImage(LONG x1, LONG y1, LONG x2, LONG y2);

// accesseurs

void setPath(Filename p)
{
path = p;
}
Filename getPath(void)
{
return path;
}

void setName(String s)
{
name = s;
}
String getName(void)
{
return name;
}

void setID(LONG id)
{
ID = id;
}
};


ImageDialog::ImageDialog(void)
{
}

Bool ImageDialog::CreateLayout(void)
{
// first call the parent instance
Bool res = GeDialog::CreateLayout();
C4DGadget * g;

SetTitle(name + " image");

GroupBegin(0,BFV_SCALEFIT|BFH_SCALEFIT,1,1,"",0);
{
g = AddUserArea(ID,BFV_SCALEFIT|BFH_SCALEFIT);
if (g) AttachUserArea(ia,g);
}
GroupEnd();

MenuFlushAll();
MenuSubBegin("Menu");

//////////////////////////////////////
////// //////
////// MENU //////
////// //////
//////////////////////////////////////

MenuSubEnd();
MenuFinished();

return res;
}

LONG ImageDialog::DrawImage(LONG x1, LONG y1, LONG x2, LONG y2)
{
BaseBitmap* bmp = BaseBitmap::Alloc();
LONG result = bmp->Init(path);

if( result == IMAGE_OK )
{
ia.DrawBitmap(bmp, 0, 0, bmp->GetBw() - 1, bmp->GetBh() - 1, x1, y1, x2, y2, BMP_NORMALSCALED);
ia.FillBitmapBackground(bmp,0,0);
}

BaseBitmap::Free(bmp);
return result;
}

class FaceDialog : public GeDialog // La classe pour le dialogue asynchrone
{
private:
ImageDialog idlgFront;
ImageDialog idlgSide;

public:
virtual Bool CreateLayout(void);
virtual Bool Command(LONG id,const BaseContainer &msg);
};

enum // enum pour les id des elements du dialogue
{
FILENAME_FRONT = 1001,
FILENAME_SIDE,
CREATE_FACE,

_DUMMY_ELEMENT_
};

Bool FaceDialog::CreateLayout(void) // On cree la GUI (assez intuitif je ne commente pas)
{
Bool res = GeDialog::CreateLayout();

idlgFront.setName("Front");
idlgSide.setName("Side");

SetTitle("3D Face");

GroupBegin(0, BFV_SCALEFIT | BFH_SCALEFIT, 0, 2, String(), 0);
{
GroupBorderSpace(4, 4, 4, 4);

GroupBegin(0, BFV_SCALEFIT | BFH_SCALEFIT, 2, 0, "Images", 0);
{
GroupBorder(BORDER_GROUP_IN | BORDER_WITH_TITLE);
GroupBorderSpace(4, 4, 4, 4);

BaseContainer bc;
bc.SetBool(FILENAME_TEXTURE, TRUE);

AddStaticText(0, BFH_FIT, 40, 0, "Front", BORDER_NONE);
AddCustomGui(FILENAME_FRONT, CUSTOMGUI_FILENAME, "Front", BFH_SCALEFIT, 0, 0, bc);

AddStaticText(0, BFH_FIT, 40, 0, "Side", BORDER_NONE);
AddCustomGui(FILENAME_SIDE, CUSTOMGUI_FILENAME, "Side", BFH_SCALEFIT, 0, 0, bc);
}
GroupEnd();
AddButton(CREATE_FACE, BFH_CENTER, 0, 0, "Create face");
}
GroupEnd();

return res;
}

Bool FaceDialog::Command(LONG id, const BaseContainer &msg) // Methode appellee lors d'une interaction avec la GUI
{
switch (id)
{
case CREATE_FACE: // Bouton 'create face' clique

FilenameCustomGui *front = (FilenameCustomGui*)(FindCustomGui(FILENAME_FRONT, CUSTOMGUI_FILENAME)); // on recupere les composants
FilenameCustomGui *side = (FilenameCustomGui*)(FindCustomGui(FILENAME_SIDE, CUSTOMGUI_FILENAME)); // (on peut les mettre en propiete private a la place)

Filename frontPath = front->GetData().GetValue().GetFilename(); // on recupere les path
Filename sidePath = side->GetData().GetValue().GetFilename();

GePrint(frontPath.GetString()); // affiche les path dans la console (Menu Window > Console)
GePrint(sidePath.GetString());

if (!frontPath.Content() || !sidePath.Content()) // on verifie si les path ne sont pas vides.
{
MessageDialog("You must select a front and a side image.");
return TRUE;
}
else
{
idlgFront.setPath(frontPath);
idlgFront.setID(AREA_FRONT);
idlgFront.Open(TRUE, ID_FACE, 0, 0, 800, 600);
idlgFront.DrawImage(0,0,800,600);
idlgSide.setPath(sidePath);
idlgSide.setID(AREA_SIDE);
idlgSide.Open(TRUE, ID_FACE, 0, 0, 800, 600);
idlgSide.DrawImage(0,0,800,600);
}
break;
}
return TRUE;
}


class Face : public CommandData // la classe pour la commande
{
private:
FaceDialog dlg;
public:
virtual Bool Execute(BaseDocument *doc);
virtual LONG GetState(BaseDocument *doc);
virtual Bool RestoreLayout(void *secret);
};

LONG Face::GetState(BaseDocument *doc)
{
return CMD_ENABLED;
}

Bool Face::Execute(BaseDocument *doc) // qui ouvre le dialogue lorsque elle est executee
{
return dlg.Open(TRUE, ID_FACE, -1, -1, 300, 175);
}

Bool Face::RestoreLayout(void *secret)
{
return dlg.RestoreLayout(ID_FACE, 0, secret);
}

Bool RegisterFace(void)
{
return RegisterCommandPlugin(ID_FACE, String("3D Face"), 0, NULL, String("3D Face"), gNew Face);
}

Tout cela est bien joli, et j'ai vraiment cru que ça afficherait mes images mais... non T.T (on remarque aussi un petit changement, les deux fenêtres s'ouvrent et font ce qu'elles ont à faire une fois qu'on a cliqué sur "create face")

Des idées? Je me suis surement planté du côté des LONG à mettre en paramètre des méthodes gens DrawBitmap ou FillBackgroundBitmap, ou même, j'ai peut être oublié un truc essentiel...

édit: petite piste pour mon erreur: je suis pas hyper convaincu par le C4DGadget au début de la méthode CreateLayout de ImageDialog...

Riwall
25/01/2011, 00h24
Yop!

Je me permet de remonter un peu le sujet, j' ai essayé de maintes manières différentes mais toujours aucun affichage (j'ai bien sûr essayé un version "plus simple" en tentant de charger une couleur dans la fenêtre mais rien n'y fait)

Quelqu'un saurait-il quelque chose sur le sujet?

Merci à tous :)

valkaari
25/01/2011, 03h05
edit : tient la prochaine fois, au lieu de dire des conneries, j'y regarderais à deux fois xD



je fais quelques recherches ce soir ça m'agace ce truc aussi d'image perso
edit :
Bon, 4h pour trouver cette merde ...
Bon faut avoir un fichier nommé toto.jpg dans le répertoire plugins (celui de base, pas celui du plug), c'est hyper figé mais ça fonctionne.





#include "c4d.h"
#include "c4d_symbols.h"
#include "c4d_gui.h"
#include "customgui_filename.h"
#include "ge_prepass.h"

// be sure to use a unique ID obtained from www.plugincafe.com
#define ID_FACE 1026310
// don't use that ID



enum // enum pour les id des elements du dialogue
{
AREA_FRONT = 1001,
AREA_SIDE,
FILENAME_FRONT,
FILENAME_SIDE,
CREATE_FACE


};

class ImageArea : public GeUserArea
{

private :
Filename path;
BaseBitmap *bmp;

public:
ImageArea(void)
{
bmp = BaseBitmap::Alloc();
path = GeGetPluginPath();
path.SetFile(String("toto"));
path.SetSuffix(String("jpg"));


}
// destructor
~ImageArea(void) {
if (bmp) { BaseBitmap::Free(bmp);}
}

virtual void DrawMsg(LONG x1, LONG y1, LONG x2, LONG y2,const BaseContainer &msg);



};



void ImageArea::DrawMsg(LONG x1, LONG y1, LONG x2, LONG y2,const BaseContainer &msg)
{



IMAGERESULT result = bmp->Init(path);
if ( result == IMAGERESULT_OK )
{
// give a color to the pen
DrawSetPen(Vector(1,0.5,0.5));
// draw a rectangle
DrawRectangle(1, 1, 50, 50);
//OffScreenOn();
DrawBitmap(bmp, x1, y1, bmp->GetBw(), bmp->GetBh(), 0, 0, bmp->GetBw(), bmp->GetBh(), BMP_NORMAL);

// FillBitmapBackground(bmp,0,0);
}
// do not put any redraw here ---> infinite looooooooooooop or crash

}



class FaceDialog : public GeDialog // La classe pour le dialogue asynchrone
{
private:
C4DGadget *g;
ImageArea ia;

public:
virtual Bool CreateLayout(void);
virtual Bool Command(LONG id,const BaseContainer &msg);
};



Bool FaceDialog::CreateLayout(void) // On cree la GUI (assez intuitif je ne commente pas)
{
Bool res = GeDialog::CreateLayout();

SetTitle( "image");

GroupBegin(0,BFH_CENTER|BFH_CENTER,0,1,"",0);
{
g = AddUserArea(AREA_FRONT,BFH_CENTER|BFH_CENTER,100,1 00);
if (g) {
AttachUserArea(ia,g);

}
}
GroupEnd();

return res;
}

Bool FaceDialog::Command(LONG id, const BaseContainer &msg) // Methode appellee lors d'une interaction avec la GUI
{
switch (id)
{






}
return TRUE;
}


class Face : public CommandData // la classe pour la commande
{
private:
FaceDialog dlg;
public:
virtual Bool Execute(BaseDocument *doc);
virtual LONG GetState(BaseDocument *doc);
virtual Bool RestoreLayout(void *secret);
};

LONG Face::GetState(BaseDocument *doc)
{
return CMD_ENABLED;
}

Bool Face::Execute(BaseDocument *doc) // qui ouvre le dialogue lorsque elle est executee
{
return dlg.Open(DLG_TYPE_ASYNC, ID_FACE, -1, -1);
}

Bool Face::RestoreLayout(void *secret)
{
return dlg.RestoreLayout(ID_FACE, 0, secret);
}

Bool RegisterTesting(void)
{
return RegisterCommandPlugin(ID_FACE, String("3D Face"), 0, NULL, String("testing"), gNew Face);
}


je te laisse voir pour le reste moi j'en ai marre pour le moment



ps :

j'en oubliais de mettre des explications .....

donc faut juste overwriter la fonction drawmsg qui est appelé par c4D quand il se passe un truc à mettre à jour.
C'est cette fonction qui s'occupe du drawbitmap.

Faut pas vous étonner si les plugs sont à xxxxxxxxx euro après.

oli_d
25/01/2011, 10h54
Merci Val pour le partage,

J'ai testé en Python (à coller dans menu Python/Gestionnaire de script de la r12). J'ai pas commenté mais j'ai vraiment mis uniquement l'essentiel pour afficher l'image. Il y a une boîte de dialogue qui s'affiche au début pour choisir le fichier puis ça affiche l'image à 100%



import c4d

class UserArea(c4d.gui.GeUserArea):

def __init__(self,fn):
self.fn = fn
self.bmp = c4d.bitmaps.BaseBitmap()
self.bmp.InitWith(self.fn)

def GetMinSize(self):
return self.bmp.GetSize()

def DrawMsg(self, x1, y1, x2, y2, msg):
wbmp,hbmp = self.bmp.GetSize()
self.DrawBitmap(self.bmp,x1,y1,x2-x1,y2-y1,
x1,y1,x2-x1,y2-y1,c4d.BMP_NORMAL|c4d.BMP_ALLOWALPHA)

class MonDlg(c4d.gui.GeDialog):
def __init__(self,fn):
self.fn = fn

def CreateLayout(self):
self.SetTitle('Test GeUserArea :')
self.ua = UserArea(self.fn)
self.AddUserArea(1001,flags=c4d.BFH_FIT|c4d.BFV_FI T)
self.AttachUserArea(self.ua, 1001)
return True

if __name__=='__main__':
fn = c4d.storage.LoadDialog()
if fn :
dlg = MonDlg(fn)
dlg.Open(c4d.DLG_TYPE_MODAL_RESIZEABLE)


Si un modo passe dans le coin est-ce qu'il serait possible de déplacer le sujet dans la section programmation, il y a plein de trucs intéressant.

valkaari
25/01/2011, 13h03
cool, par contre j'ai oublié de dire que c'était du code pour la r12 (qui n'est pas le même que pour la r11.5, trop facile sinon.)


Et comment tu fais pour que ta fenêtre soit en DLG_TYPE_ASYNC reste oli ?

oli_d
25/01/2011, 14h04
D'après mes expériences, pour une fenêtre en DLG_TYPE_ASYNC il faut obligatoirement passer par un plugin (type command par ex). Cela ne marche pas apparemment en script ... Par contre en DLG_TYPE_MODAL ça passe et c'est pratique pour les essais avant de créer un plugin

Riwall
22/03/2011, 14h29
Bonjour à tous !!

Le projet continue, et après quelques mois à bosser sur un autre aspect, je me penche à présent sur la gestion de la souris dans une GUI, l'idée est d'afficher des petites croix ou des points sur les images quand on clic, et de rentrer les coordonnées dans une tableau, afin de pouvoir modifier le modèle en conséquence.

J'ai cherche dans la doc, mais c'est un peu brouillon, je me perds pas mal entre les différentes classes en rapport avec la souris.

Merci à vous.

oli_d
22/03/2011, 21h12
Bon je suis toujours un bille en interface et le c++ commence à être un lointain souvenir, mais j'irais regarder du côté des exemples du SDK, dans AsyncTest.cpp. Il y a un exemple d'interaction avec la souris dans la méthode Bool SDKGradientArea::InputEvent(const BaseContainer &msg).


Je tente à nouveau de demander à un modo d'avoir la gentillesse de déplacer ce sujet dans la section programmation car il y a vraiment plein de trucs intéressants et ce serait dommage qu'il se perde au fond du bac à sable ...

tabou
23/03/2011, 01h06
Tout à fait d'accord avec toi oli_d, je déplace le sujet.

@Riwall : je t'ai sorti du bac à sable :icon_wink:

valkaari
23/03/2011, 10h15
Merci ça serait dommage de perdre certain bout de code.

Pour la gestion de la souris, je ferais comme oli_D, j'irais voir du coté de la fonction inputevent avec dedans un switch/case pour gérer les évènements qui m'intéresse. (un peu comme la fonction commande ou message que tu as déjà croisé)

Riwall
23/03/2011, 10h28
Ok, j'étais effectivement parti de ce côté mais sans grosses convictions, je vais me pencher plus profondément sur la chose.

Merci Oli et Tabou pour le dessablage :)

édit: ça marche! héhé j'arrive à gérer la souris, par contre dans un soucis d'épuration du code, je me suis lancé dans des petites modifs, mais une erreur revient sans cesse, et je me demande du coup si on peut surcharger le constructeur d'une boite de dialogue...

Et si oui, ça donnerait par exemple, pour une classe FaceDialog


FaceDialog dlgFront("Front");

en attribut de la classe de commande? Je sèche, parce que en compilant, ça me dit: "erreur C2228: la partie de gauche de '.Open' doit avoir un class/struct/union" pour une ligne un peu plus loin...

J'ai aussi une erreur de syntaxe (C2059): 'chaîne'... pas compris.

Merci!

nouvel edit: C'est bon ça fonctionne, j'ai allégé mon code, je passe à l'affichage de petites croix là où on clique, je vous tiens au jus ;)

encore merci à tous.

Riwall
07/04/2011, 18h10
Bonjour à tous!

A présent, j'affiche 2 images (même trois, mais c'est un détail) et je souhaiterai y ajouter des croix noires centrées en (x;y) définis par la souris lors d'un clic gauche.

Voici la fonction que j'ai essayé d'écrire, mais ça ne marche pas du tout:


void ImageArea::AddCross(LONG x, LONG y)
{
DrawSetPen(COLOR_EDGEBL);
DrawLine(x, y - 10, x, y + 10);
DrawLine(x - 10, y, x + 10, y);
}


Aussi, si vous savez comment empêcher l'utilisateur de modifier la taille d'une boîte de dialogue, je suis preneur!

Merci à vous :)

valkaari
07/04/2011, 18h30
tu aurais pas oublié un MSG_UPDATE à un endroit par hasard ? (en dehors de drawmsg sinon c'est le loop infini)

Riwall
09/04/2011, 02h42
J'ai cherché partout, j'ai trouvé des "op->Message(MSG_UPDATE);" mais dans un cas de "op" en BaseObject, j'en ai pas moi, juste un BaseBitmap "bmp" et il ne possède pas de telle fonction.

Je suis perdu T.T (en plus j'ai C4D R11.5, mais l'aide de la R12 parce que celle de la R11.5 ne marchait pas...)

oli_d
09/04/2011, 06h24
C'est un peu dur de te répondre, tu mets juste ta méthode mais pas où ni comment tu l'utilises ensuite...

Regarde dans l'exemple AsyncTest.cpp, mais en résumé le principe doit être le suivant :


tu dessines dans la méthode DrawMsg
tu récupère les évènements souris dans InputEvent ...

... et tu redessines toujours dans InputEvent en balançant la méthode Redraw()

J'ai rien testé, je ne sais pas si tu peux effectivement dessiner par dessus l'image (mais sûrement )
Si ça ne marche pas tu peux toujours essayer de modifier directement ton BaseBitmap avec la classe GeClipMap

Je ne pense pas qu'il y ait besoint d'un Message(MSG_UPDATE)

Encore une fois toutes les conneries que je dis sont à prendre avec des pincettes, je suis vraiment une bille en interface ...

Riwall
09/04/2011, 11h11
Uhm, pour ce qui est de dessiner sur le Bitmap, j'ai cru comprendre qu'il y avait une classe qui permet d'avoir un Bitmap et des calques par dessus, ça pourrait être une solution?


Voilà pour ce qui est de l'inputevent, là où j'appelle la methode "AddCross"

Bool ImageArea::InputEvent(const BaseContainer &msg)
{
LONG dev = msg.GetLong(BFM_INPUT_DEVICE);
LONG chn = msg.GetLong(BFM_INPUT_CHANNEL);
if (dev==BFM_INPUT_MOUSE)
{
BaseContainer action(BFM_ACTION);
action.SetLong(BFM_ACTION_ID,GetId());
action.SetLong(BFM_ACTION_VALUE,0);

if (chn==BFM_INPUT_MOUSELEFT)
{
LONG mx = msg.GetLong(BFM_INPUT_X);
LONG my = msg.GetLong(BFM_INPUT_Y);

Point p(mx,my,0);
points.push_back(p);

AddCross( points[points.size() - 1].GetX() , points[points.size() - 1].GetY() );

Redraw();
}

return TRUE;
}
return FALSE;
}



Encore une fois toutes les conneries que je dis sont à prendre avec des pincettes, je suis vraiment une bille en interface ...

Et moi donc...? :D

Merci beaucoup pour vos réponses.

valkaari
09/04/2011, 12h53
j'ai rajouté dans la fonction DrawMsg le code suivant.


BaseContainer state;
if (GetInputState (BFM_INPUT_MOUSE, BFM_INPUT_MOUSELEFT,state)) {
LONG x = state.GetLong(BFM_INPUT_X);
LONG y = state.GetLong(BFM_INPUT_Y);
Global2Local(&x,&y);
DrawSetPen(Vector(0,0,0));
DrawLine (x-10,y,x+10,y);
DrawLine (x,y-10,x,y+10);
}

SANS mettre l'image et ça marche presque.

Ton dernier bout de code est pas mal j'ai l'impression si dans la fonction DrawMsg tu vas lire ton tableau pour prendre les coordonnées et ajouter les croix.
Ne pas oublier le Global2Local qui transforme les coordonnées fenêtre en coordonnées UserArea.


Bon une fois de plus, quand on aura compris, ça sera super simple mais bonjour la frustration xD

Riwall
09/04/2011, 21h44
En fait, l'idée c'est de mettre une croix quand on clique, et d'ajouter les coordonnées du point dans un tableau vectoriel de points.

Evidemment j'ai oublié de vous le préciser: points est un tableau vectoriel de "points" qui sont issus d'une classe que j'ai créée, avec en attributs x,y,z et les getters/setters qui vont avec, tout simplement.

En gros, je crée un tableau de points, pour pouvoir les réutiliser ensuite dans la phase de transformation du modèle par zones d'effet (genre le nez, les joues, la bouche etc.).

Riwall
03/05/2011, 13h05
Yop!

Me revoilà, les croix marchent impec', enfin j'ai un truc à faire sur la 3ème fenêtre, mais sinon c'est bon.

Je poste donc l'avancement pour vous expliquer ce que j'aimerais faire, mais que je ne sais pas du tout faire... (gros paradoxe xD):

fig 1.
http://img861.imageshack.us/img861/5654/sansre1i.jpg

Voilà ce qui s'affiche quand on lance le plugin. On a les deux photos (ici tirées d'un site de ressources pour la 3D) face et profil, et une 3ème fenêtre, vide pour le moment (au passage, un clic dans la zone blanche fait tout planter... si vous avez une idée je suis preneur :D). On a un petit menu sur cette 3ème fenêtre, celui-ci permet de choisir la vue d'exemple que l'on souhaite : front/side. Cette vue d'exemple va, à chaque clic, dessiner des croix, une à une, dans un ordre prédéfini, à des endroits précis sans tenir compte de la position du curseur lors du clic.

En gros, l'idée c'est juste de dire à l'utilisateur que sur son image face ou profil, il doit mettre la croix à un endroit équivalent. A noter qu'ici, j'utilise pour des raisons pratiques, les mêmes photos de face et profil, mais l'utilisation du plugin permettra de mettre ses propres photos de face et profil, alors que les exemples resteront les mêmes. Pour mieux comprendre voilà ce que ça donne avec 4/5 points sur le nez:

fig 2.
http://img222.imageshack.us/img222/1962/sansre2o.jpg

On voit donc les petites croix qui définiront les dimensions du nez (pour le moment déjà, on va juste jouer sur les dimension, peut être une déformation plus performante par la suite).

fig 3.
http://img109.imageshack.us/img109/385/sansre3.jpg

Sachant que le modèle de base est cette tête en 3D, et que toutes les sélections de points ont été faites au préalable, je souhaiterais "par zone" d'effet, redimensionner, voire déformer, les sélections. Si vous avez des idées de plugins open source ou de plugins du sdk qui pourraient m'aider à faire ça, prévenez moi :). Au passage, s'il existe une fonction d'enveloppe, qui, à partir d'une liste de points contraint un objet à la forme de l'ensemble des points ou un truc du genre (je pense à une expression en COFFEE que j'avais vu dans un tuto il y a loooonngtemps qui permettait de "plaquer" un plan sur une sphère pour faire des paupières réalistes en 2sec.

Voilà voilà, toute idée est la bienvenue, merci à tous :)