Plug-iny definující nové příkazy Třída MPxCommand Základní třída pro odvozování nových příkazů, které se volají z příkazové řádky MELu. Příkaz může, ale nemusí implementovat undo. Tyto prikazy neumi zpracovavat udalosti generovane mysi. Následující příklad vytváří nový příkaz "doselection", který ve scéně vybere všechny objekty jejichž jméno obsahuje zadaný řetězec. #include <stdio.h> #include <maya/mstring.h> #include <maya/marglist.h> #include <maya/mfnplugin.h> #include <maya/mpxcommand.h> #include <maya/mselectionlist.h> #include <maya/mglobal.h> #include <maya/msyntax.h> #include <maya/margdatabase.h> #include <maya/mdagpath.h> #include <maya/mfndagnode.h> // Novy prikaz doselectioncmd je potomkem tridy MPxCommand. class doselectioncmd : public MPxCommand { // Konstruktor tridy. doselectioncmd() { // Destruktor tridy. virtual ~doselectioncmd() { // Metoda provadejici pozadovanou akci - prikaz. // Obvykle zpracuje parametry prikazove radky + selection list a nastavi vnitrni promen // Pro vlastni provedeni akce prikazu zavola metodu redoit(). MStatus doit( const MArgList& ); // Jadro tridy - zde se provadi vlastni akce prikazu. Chovani prikazu je ovlivneno // stavem vnitrnich promennych nastavenych v doit(). MStatus redoit(); // Metoda provadi undo - tedy opak operaci provedenych v redoit(). MStatus undoit(); // Metoda vracejici true / false podle toho zda prikaz implementuje undo nebo ne. // Ne vsechny prikazy museji implementovat undo. bool isundoable() const; // Staticka metoda pro vytvareni instanci teto tridy (tuto metodu vola Maya). // Staticka metoda popisujici parametry prikazove radky pomoci objektu MSyntax. // Ukazatel na metodu je predavan prikazu registercommand(). // MSyntax objekt vytvoreny touto metodou je vracen pri volani metody syntax(). static MSyntax newsyntax(); // Uzivatelska metoda, ktera zpracovava parametry prikazove radky. MStatus parseargs(const MArgList &args); MString _name; // vzor hledany ve jmenech objektu ve scene MSelectionList _selectionlist; // zalozni kopie seznamu vybranych objektu v okamziku // Metoda volana pri prvnim provedeni prikazu. MStatus doselectioncmd::doit( const MArgList& args) { // Volani metody zpracovavajici parametry prikazove radky. MStatus status = parseargs(args); status.perror("error: parseargs()"); // Nastaveni vnitrnich promennych tridy. // // Zazalohovani seznamu vybranych objektu. status = MGlobal::getActiveSelectionList(_selectionList); status.perror("error: getactiveselectionlist()"); // Provedeni pozadovane akce prikazu. status = redoit(); // Jadro tridy - zde se provadi vlastni akce prikazu. Metoda je volana z doit() // a pri pozadavku znovu vykonani prikazu. MStatus doselectioncmd::redoit() { MDagPath node; // cesta k objektu v DAG MObject component; // uzel / objekt DAG MFnDagNode nodefn; // Oznaceni vsech objektu odpovidajicich zadanemu vyrazu. // MStatus status = MGlobal::selectByName(_name, MGlobal::kReplaceList); MSelectionList newselectionlist; MStatus status = MGlobal::getSelectionListByName(_name, newselectionlist); printf("\nseznam vybranych objektu (%i objektu):\n", newselectionlist.length()); // postupne prochazeni seznamu - vypsani vsech oznacenych objektu for ( unsigned int index = 0; index < newselectionlist.length(); index++ ) { // ziskani uzlu reprezentovaneho indexem index a cesty k tomuto uzlu v DAG newselectionlist.getdagpath( index, node, component ); // nastaveni objektu nad kterym bude function set pracovat nodefn.setobject( node ); // vypsani jmena uzlu printf("* %s\n", nodefn.name().aschar() ); // Prikaz muze take vracet navratove hodnoty do MELu - pro tento ucel lze // vyuzit pretizene metody "setresult" a "appendtoresult". // Nasledujici sekvence prikazu vraci jako vysledek cislo pocet // prvku v selection listu newselectionlist. int result = newselectionlist.length(); clearresult(); // inicializace mista kam se bude ukladat vysledek setresult( result ); // ulozeni vysledku // Nasledujici priklad ukazuje jak lze vratit pole doublu reprezentujici bod. // Metoda appendtoresult pridava zadanou hodnotu na konec pole, ktere reprezentuje vysl // MPoint result (1.0, 2.0, 3.0); // clearresult(); // inicializace mista kam se bude ukladat vysledek // appendtoresult( result.x ); // pridani x-ove souradnice k vysledku // appendtoresult( result.y ); // pridani y-ove souradnice k vysledku // appendtoresult( result.z ); // pridani z-ove souradnice k vysledku // Muzeme ale take vratit primo pole. // MDoubleArray result; // pole reprezentujici vysledek // MPoint point (1.0, 2.0, 3.0); // vysledny bod // result.append( point.x ); // pridani x-ove souradnice do pole result // result.append( point.y ); // pridani y-ove souradnice do pole result 1 of 10 23.3.2005 17:05 2 of 10 23.3.2005 17:05
// result.append( point.z ); // pridani z-ove souradnice do pole result // clearresult(); // inicializace mista kam se bude ukladat vysledek // setresult( result ); // ulozeni vysledku // Nastaveni noveho seznamu vybranych objektu. status = MGlobal::setActiveSelectionList(newSelectionList, MGlobal::kReplaceList); // Metoda implementujici undo - navrat ke stavu pred volanim prikazu. MStatus doselectioncmd::undoit() { // Obnoveni puvodniho seznamu vybranych objektu. return MGlobal::setActiveSelectionList(_selectionList, MGlobal::kReplaceList); // Implementuje prikaz undo? bool doselectioncmd::isundoable() const { return true; // Metoda volana Mayou pro vytvoreni instance teto tridy. void* doselectioncmd::creator() { return new doselectioncmd(); // Definice kratkych a dlouhych jmen parametru prikazove radky. #define knameflag "-n" #define knameflaglong "-name" // Registrace noveho prikazu - parametrem je jmeno prikazu, ukazatel na // metodu vytvarejici instance teto tridy a ukazatel na metodu vytvarejici // objekt MSyntax popisujici syntaxi parametru prikazove radky. status = plugin.registercommand( "doselection", doselectioncmd::creator, doselectioncmd status.perror("error: registercommand()"); // Metoda volana Mayou pri odstranovani plug-inu. MStatus uninitializeplugin( MObject obj ) { status = plugin.deregistercommand( "doselection" ); status.perror("error: deregistercommand()"); Nasledujici obrazky ukazuji priklad pouziti nove definovaneho prikazu - doselection -name "nurbs*";. // Staticka metoda popisujici parametry prikazove radky pomoci objektu MSyntax. MSyntax doselectioncmd::newsyntax() { MSyntax syntax; // trida obsahujici definici parametru prikazove radky // Pridani definice jednoho parametru jehoz hodnotou bude string. syntax.addflag(knameflag, knameflaglong, MSyntax::kString); // Ukazka pridani definice prepinace (parametru ktery nema hodnotu). // #define kbreadthflag "-b" // #define kbreadthflaglong "-breadth" // syntax.addflag(kbreadthflag, kbreadthflaglong); return syntax; // Uzivatelska metoda, ktera zpracovava parametry prikazove radky. MStatus doselectioncmd::parseargs(const MArgList &args) { // MArgDatabase je parser pro zpracovani parametru prikazove radky. // Parametry jsou MSyntax objekt a MArgList. // Misto MArgDatabase muzete take pouzit tridu MArgParser. MArgDatabase argdata(syntax(), args); // Test zda byl pouzit flag "-name". if (argdata.isflagset(knameflag)) { // Pro ziskani hodnoty parametru lze vyuzit metody getflagargument(). // Ziskani hodnoty parametru knameflag. argdata.getflagargument(knameflag, 0, _name); else _name = "*Cube*"; // Metoda zajistujici inicializaci plug-inu - v tomto pripade registraci // noveho prikazu doselection. MFnPlugin plugin( obj, "Jara", "1.0", "Any" ); Třída MPxContext Třídy odvozené z MPxContext definují jakým způsobem se budou zpracovávat akce provedené myší. Tyto třídy mohou spouštět jiné příkazy, modifikovat seznam vybraných objektů a kreslit. V Maye jsou třídy odvozené z MPxContext nazývány "tool". Pro vytváření instancí této třídy je nutné vytvořit třídu odvozenou z MPxContextCommand. Typicky tool založený na MPxContext obsahuje metody uvedene v nasledujicim prikladu, ktery umoznuje pomoci mysi vybrat obdelnikovou oblast. S obdelnikovou oblasti 3 of 10 23.3.2005 17:05 4 of 10 23.3.2005 17:05
je provedena akce implementovana tridou mytool (potomek tridy MPxContextCommand a jeji definice bude uvedena pozdeji). const char helpstring[] = "Použijte prostřední tlačítko pro označení oblasti "; class mycontext : public MPxContext { mycontext(); // Metoda volaná při aktivaci toolu. virtual void toolonsetup( MEvent & event ); // Metoda volaná při stisknutí tlačítka myši. virtual MStatus dopress( MEvent & event ); // Metoda volaná při pohyby myši se stiskutým tlačítkem. virtual MStatus dodrag( MEvent & event ); // Metoda volaná při uvolnění tlačítka myši. virtual MStatus dorelease( MEvent & event ); short start_x, start_y; // počáteční pozice myši short last_x, last_y; // koncová pozice myši M3dView view; // třída reprezentující aktuální kreslící okno mycontext::mycontext() { // Jméno toolu, které je při jeho aktivaci vypsáno v UI. settitlestring ( "Template of Tool" ); // Metoda volaná při vyvolání toolu - obvykle vypisuje help a provádí potřebnou inicializ void mycontext::toolonsetup ( MEvent & ) { // Vypsání nápovědy na příkazovou řádku. sethelpstring( helpstring ); // Tato metoda je volána při stisku tlačítka myši (pokud je tool aktivní). // Třída MEvent obsahuje informace o provedené akci. MStatus mycontext::dopress( MEvent & event ) { // Zapamatujeme si pozici myši v okamžiku stisku tlačítka (souřadnice okna). event.getposition( start_x, start_y ); // Přepnutí na aktivní okno. view = M3dView::active3dView(); // Začátek kreslení - povolení kreslení pomocí OpenGL. view.begingl(); // Nastavení OpenGL kontextu pro pkreslení do Overlay Plane. view.beginoverlaydrawing(); // Tato metoda je volána pokud pohybujete myší se stisknutým tlačítkem. MStatus mycontext::dodrag( MEvent & event ) { // Uložení aktuální pozice myši. event.getposition( last_x, last_y ); // Vymazání Overlay Plane. view.clearoverlayplane(); // Vykreslení obdélníku, který ohraničuje oblast vybranou myší. glmatrixmode( GL_PROJECTION ); glloadidentity(); gluortho2d( 0.0, (GLdouble) view.portwidth(), 0.0, (GLdouble) view.portheight() ); glmatrixmode( GL_MODELVIEW ); glloadidentity(); gltranslatef(0.375, 0.375, 0.0); glbegin( GL_LINE_LOOP ); glvertex2i( start_x, start_y ); glvertex2i( last_x, start_y ); glvertex2i( last_x, last_y ); glvertex2i( start_x, last_y ); glend(); #ifndef _WIN32 glxswapbuffers(view.display(), view.window() ); #else SwapBuffers(view.deviceContext() ); #endif // Metoda, která je volána při uvolnění tlačítka myši. MStatus mycontext::dorelease( MEvent & event ) { // Ukončení kreslení - vymazání Overlay Plane a deaktivace OpenGL. view.clearoverlayplane(); view.endoverlaydrawing(); view.endgl(); // Uložení pozice myši v okamžiku uvolnění tlačítka. event.getposition( last_x, last_y ); provedení nějaké akce - např. výběr objektů nacházejících se v oblasti definované pomocí (start_x, start_y, last_x, last_y) // Ukazka zavolani prikazu definovaneho tridou mytool (viz dale) mytool *cmd = (mytool*)newtoolcommand(); cmd->setselectionarea( start_x, start_y, last_x, last_y ); cmd->redoit(); cmd->finalize(); Třída MPxContextCommand Speciální třída MPxContextCommand slouží pro odvození příkazů jejichž hlavním ukolem je vytvoření instance toolu (tedy potomka třídy MPxContext). Tyto příkazy nikdy neimplementují operaci undo. Kostra této třídy vypadá takto: class mycontextcmd : public MPxContextCommand { 5 of 10 23.3.2005 17:05 6 of 10 23.3.2005 17:05
mycontextcmd(); // Metoda vytvářející instance třídy odvozené z MPxContext. virtual MPxContext* makeobj(); // Metoda vytvářející instance této třídy. mycontextcmd::mycontextcmd() { // Tuto metodu používá Maya pro vytváření instancí toolu (třídy odvozené z MPxContext). MPxContext* mycontextcmd::makeobj() { return new mycontext(); // Metoda volaná Mayou pro vytváření instancí třídy mycontextcmd. void* mycontextcmd::creator() { return new mycontextcmd; // Inicializace plug-inu. MFnPlugin plugin( obj, "Alias", "1.0", "Any"); // registrace příkazu pro vytváření kontextu. status = plugin.registercontextcommand( "mytoolcontext", mycontextcmd::creator ); // Metoda volaná při odstraňování plug-inu z Mayi. MStatus uninitializeplugin( MObject obj ) { // odregistrování příkazu. status = plugin.deregistercontextcommand( "mytoolcontext" ); Přidání toolu do Mayi Následující MEL script vytvoří tool a tlačítko pro tento tool. mytoolcontext mytoolcontext1; // Vytvoření instance mycontext. setparent Custom; // Budeme přidávat do Shelf1. toolbutton -cl toolcluster // Do jaké kolekce se má tool přidat. -t mytoolcontext1 // Jméno toolu připojovaného k tlačítku. -i1 "mytool.xpm" mujtool1; // Ikona reprezentující tento tool a jméno t Tento kód může být také uložen do souboru a spušťen přímo při inicializaci plug-inu v metodě initializeplugin() zavoláním metody MGlobal::sourceFile(). Třída MPxToolCommand Třída MPxToolCommand představuje základ příkazů, které lze volat z toolů (potomci třídy MPxContext). Takto vytvořené příkazy lze samozřejmě spouštět přímo z příkazové řádky. Příkazy mohou být ale volány z toolů a proto musejí obsahovat navíc metody pomocí nichž tool nastaví parametry příkazu, které jsou za normalních okolností předávány z příkazové řádky. Třída je odvozena z třídy MPxCommand, ale obsahuje navíc další metody. Každý tool může spouštět pouze jeden příkaz a ten musí být zaregistrován při inicualizaci plug-inu. Následující příklad ukazuje typickou kostru příkazu odvozeného z třídy MPxToolCommand. class mytool : public MPxToolCommand { mytool(); virtual ~mytool(); // Následující metody mají stejný význam jako metody ve třídě MPxCommand. MStatus doit( const MArgList& args ); MStatus redoit(); MStatus undoit(); bool isundoable() const; static MSyntax newsyntax(); // Metoda vypisující informace o tomto příkazu do log souboru. MStatus finalize(); // Pomocné metody sloužící pro nastavení parametrů plug-inu pokud není volán z příkazov void setselectionarea( double startx, double starty, double endx, double endy ); void setradius( double newradius ); // Proměnné pro uložení nastavení jednotlivých parametrů. double startx, starty; double endx, endy; double radius; void* mytool::creator() { return new mytool; mytool::~mytool() { mytool::mytool() { // Nastavení jména tohoto příkazu - požito v metodě finalize(). setcommandstring( "helixtoolcmd" ); MSyntax mytool::newsyntax() { MSyntax syntax; syntax.addflag(kpitchflag, kpitchflaglong, MSyntax::kDouble); return syntax; MStatus mytool::doit( const MArgList &args ) { status = parseargs(args); if (MS::kSuccess!= status) return redoit(); 7 of 10 23.3.2005 17:05 8 of 10 23.3.2005 17:05
MStatus mytool::parseargs(const MArgList &args) { MArgDatabase argdata(syntax(), args); if (argdata.isflagset(kradiusflag)) { double tmp; status = argdata.getflagargument(kradiusflag, 0, tmp); status.perror("radius flag parsing failed."); radius = tmp; MStatus mytool::redoit() { MStatus stat; return stat; MStatus mytool::undoit() { MStatus stat; "mytoolcontext", mycontextcmd::creator, "mytoolcmd", mytool::creator, mytool::newsyntax); status.perror("registercontextcommand"); MStatus uninitializeplugin( MObject obj) { // Deregister the tool command and the context creation command. status = plugin.deregistercontextcommand( "mytoolcontext", "mytoolcmd" ); status.perror("deregistercontextcommand"); Příklady plug-inu helix tool (kresleni spiraly do obdelniku zadaneho pomoci mysi) helixtool.cpp helixtool.mel lasso tool (vyber objektu v oblasti oznacene mysi) lassotool.cpp lassotoolcreateui.mel return stat; bool mytool::isundoable() const { return true; // Metoda zapisující příkazový řádek pomocí kterého byl příkaz spuštěn do log souboru. MStatus mytool::finalize() { MArgList command; command.addarg( commandstring() ); command.addarg( MString(kRadiusFlag) ); command.addarg( radius ); return MPxToolCommand::doFinalize( command ); void mytool::setradius( double newradius ) { radius = newradius; void mytool::setselectionarea( double startx, double starty, double endx, double endy ) { _startx = startx; _starty = starty; _endx = endx; _endy = endy; MFnPlugin plugin(obj, "Alias", "3.0", "Any"); // Register the context creation command and the tool command // that the helixcontext will use. status = plugin.registercontextcommand( 9 of 10 23.3.2005 17:05 10 of 10 23.3.2005 17:05