|  
             Back to plugin tutorials 
             
             Your first AC3D plugin
            Armed with the SDK header and your template code from the previous section, you are 
               ready to create your first plugin. 
            Hello World, AC3D style
            We are going to create a test plugin. The first iteration of this plugin will simply 
               print "Hello world" when the user invokes the plugin's menu item. 
             This code is based off of the code from the previous section. 
             Create a new AC3D plugin project. Enter this code into a file named "first_plugin.cpp". 
               Then, either change the #include "ac_plugin.h" to point 
               to wherever you keep your "ac_plugin.h" file, or create a copy of "ac_plugin.h" 
               to your working directory. 
             You may also pick up this code here. 
             
                
                  
#ifdef _WINDOWS
#ifndef WINDOWS
#define WINDOWS
#endif
#endif
#include "ac_plugin.h"
//////////////////////////////////////////////////////////////
// This is our plugin's main function.
static void first_plugin()
{
   // This command throws up a message box to the user.
   // Note that I added "first_plugin : " to the beginning of the
   // text.  This lets the user know what operation was responsible
   // for sending them the message.
   message_dialog( "first_plugin : Hello world!" );
   // This displays a message on the AC3D status bar.
   display_message( "first_plugin : I just sent you a message" );
}
//////////////////////////////////////////////////////////////
// The plugin init function
AC3D_PLUGIN_FUNC int AC3DPluginInit( AC3DPluginInitData *d )
{
   static bool firstTime = true;
   if( firstTime )
   {
      // Add our command to AC3D.
      ac_add_command( "my_first_plugin", first_plugin );
      // Add a new menu item for our plugin under the "Tools" menu.
      // This will show up as "First plugin" under the Tools menu,
      // and will call the function we defined above.
      ac_add_tools_menu_item( "First plugin",
                              "ac3d my_first_plugin",
                              "My first plugin" );
      firstTime = false;
   }
   return 0;
}
//////////////////////////////////////////////////////////////
AC3D_PLUGIN_FUNC int AC3DPluginExit()
{
   return 0;
}
//////////////////////////////////////////////////////////////
AC3D_PLUGIN_FUNC char *AC3DPluginAbout()
{
   return( "First plugin - version 1.0 - Me" );
}
//////////////////////////////////////////////////////////////
AC3D_PLUGIN_FUNC char *AC3DPluginInfo()
{
   return( "This is my first plugin." );
} | 
                
             
            Compile this file as first_plugin.p and copy the resulting file to your AC3D /plugins 
               folder, then start AC3D. you should find a "First plugin" menu item under 
               the Tools menu. Execute it, and you should see: 
               
            
 Click OK, and you will see this message in the AC3D status bar. 
               
            
 Making it functional
            With the success of our first plugin, it's time to move onto a plugin that actually 
               does something. 
             We'll change this plugin to perform the following tasks: 
            Scale the selected vertices in the current document down by 50% toward the origin 
               { 0,0,0 }.
            If there is no selected geometry in the current AC3D document, warn the user that 
               nothing was done.
             
             
                
                  A word about linked lists 
                     At the time of this tutorial, AC3D stores all of its geometry in linked 
                        lists (warning: link takes you off-site). All of the Objects, Surfaces, 
                        and Vertices in an AC3D document are stored this way. 
                     ac_plugin.h provides a List object that encapsulates the linked list. 
                     If you are not familiar with linked lists, it may do some good to brush up 
                        on them, but this tutorial will get you through their usage for now.  | 
                
             
            To get the selected vertices in the current document, use this function from ac_plugin.h: 
            ac_selection_get_vertices_all() 
            This gets an AC3D List (linked list) containing all vertices in the current document. 
            An AC3D linked list node is described as: 
            typedef void *ListData;
typedef struct listitem
{
    ListData data;
    struct listitem *next;
} List;
            The "data" field is a void pointer to the data we want (a Vertex, in this 
               case), and "next" points to the next element in the list. 
            An AC3D Vertex is described as: 
            typedef struct vertex_t
{
   float x, y, z;
} Vertex;
            These are the actual x/y/z coordinates of a vertex, and changing these will change 
               the vertex location in AC3D. 
            So, let's replace the contents of our first_plugin() function to the following snippet: 
            
                
                  
static void first_plugin() {    // Get a list of all selected vertices in the current document    List *vlist = ac_selection_get_vertices_all();    // If this list is NULL, then nothing was selected.  We can exit the plugin.    if( vlist == NULL )    {       message_dialog( "first_plugin : nothing was selected" );       return;    }    // Let's keep up with the number of vertices we change    int num_verts_scaled = 0;    // Iterate through the vertices    for( List *pv = vlist; pv != NULL; pv = pv->next )    {       // Cast the current list item as a Vertex       Vertex *currentVertex = ( Vertex * )( pv->data );       // Scale the vertex by 50%       currentVertex->x = currentVertex->x * 0.5f;       currentVertex->y = currentVertex->y * 0.5f;       currentVertex->z = currentVertex->z * 0.5f;       // Increment our counter       num_verts_scaled = num_verts_scaled + 1;    }    // We're done with the List --- we need to clean it up.    // Some Lists returned from AC3D need to be cleaned up, some do not.    // This one needs it.    list_free( &vlist );    // Recalculate the selected normals    selected_calc_normals();    // Recalculate the AC3D selection box.    find_bounding_box();    // Redraw all of the AC3D views to reflect any changes.    redraw_all();    // Update the User Interface    display_status();    // Show the user what we did    display_message( "first_plugin : scaled %d vertices toward {0,0,0}", num_verts_scaled ); }  | 
                
             
            You can grab the entire plugin file here. 
               Note that I also changed the version number in the AC3DPluginAbout() function. 
            Note that this plugin does not resize an object by 50% --- it just moves the vertices 
               halfway toward {0,0,0}. Not the most useful plugin, but it definitely does something. 
            Adding Undo
            AC3D's undo feature is a very powerful feature, especially when compared to other 3D 
               modelers/applications. With the exception of very few functions that destroy Undo history, 
               all AC3D actions, including selections, can be Undone/Redone. 
            Now, if we do not include an Undo for a plugin that changes geometry, this will be 
               a terrible thing, since it may mess up the Undo change a bit. 
            Fortunately, our particular plugin only needs two code changes to make it Undo-compliant. 
               Be thankful for this, as some plugins may require you to implement your own Undo, which 
               can be a nasty business in some cases. 
            The changes are highlighted below, or you can pick up the file here. 
            
                
                   static void first_plugin() {    // Get a list of all selected vertices in the current document    List *vlist = ac_selection_get_vertices_all();    // Store the original positions in Undo
   // "move vertices" is the text that will appear in the Undo menu text.
   add_undoable_vertex_positions( "move vertices", vlist );    // If this list is NULL, then nothing was selected.  We can exit the plugin.    if( vlist == NULL )    {       message_dialog( "first_plugin : nothing was selected" );       return;    }    // Let's keep up with the number of vertices we change    int num_verts_scaled = 0;    // Iterate through the vertices    for( List *pv = vlist; pv != NULL; pv = pv->next )    {       // Cast the current list item as a Vertex       Vertex *currentVertex = ( Vertex * )( pv->data );       // Scale the vertex by 50%       currentVertex->x = currentVertex->x * 0.5f;       currentVertex->y = currentVertex->y * 0.5f;       currentVertex->z = currentVertex->z * 0.5f;       // Increment our counter       num_verts_scaled = num_verts_scaled + 1;    }    // Do not free the list; AC3D's Undo mechanism will take care of this.    //list_free( &vlist );    // Recalculate the selected normals    selected_calc_normals();    // Recalculate the AC3D selection box.    find_bounding_box();    // Redraw all of the AC3D views to reflect any changes.    redraw_all();    // Update the User Interface    display_status();    // Show the user what we did    display_message( "first_plugin : scaled %d vertices toward {0,0,0}", num_verts_scaled ); }  | 
                
             
            You can now Undo/Redo the plugin's actions. 
            It is important that you coment out the code where we "cleaned up" the vlist. 
               Otherwise, Undo will probably throw an exception, since it still uses the list. 
              
             
            Back to plugin tutorials 
             |