Lightwave
Plugin Tutorials - Lesson Two
| Saving, loading
and adding an options box Introduction Hopefully you've had time to look at lesson one where we introduced our gravity plugin. But, we missed out on one key feature of any proper plugin, an options box. In this tutorial we will look at how to give your user the flexibility to interact with your plugin and also how to save and load the amends they make to the data. Creating the new project Download the tutorial files if you haven't done so already. To follow the current tutorial, rename "gravity2.c" as "gravity.c" before opening the project file. Now we will look at the changes we've made from the first tutorial. The only change to instance structure is the inclusion of a parameter for version and gravity. To allow us to create different loaders for different versions, having a parameter for the version number makes this convenient. The strength of gravity can also now be changed for each instance of the plugin.
loading and saving A Lightwave scene file is simply a text file. If you,ve never looked at one then now would be a good time to look, this is the scene file for bounce1.lws As you can see a Plugin is indicated using the following syntax: Plugin ItemMotionHandler 1 Gravity 2 5.000000 70.000000 0.800000 9.810000 EndPlugin Lightwave is in charge up to the line with Plugin indicated. It then tries to find the plugin indicated, by looking in the lw.cfg file for the location of the plugin indicated. If it finds it then it creates a new instance of that plugin. It then runs your load routine. Be warned if your load routine passes the EndPlugin tag then all hell will break loose. It is your responsibility. So what does a load look like? Lightwave passes an instance and a LWLoadState pointer. A LWLoadState and its companion a LWSaveState is defined in the include files like this:
The ioMode is used to indicate a binary(Object file) or a text(Scene file) load/save. I'm sure we should test for this, but I've never had a problem so if no-one tells me otherwise we'll ignore this and get straight into the data. To use the LWLoadState to load your data declare a character buffer and read the data line by line. If you've never come across the ascii to float translator atof() or the integer variant atoi() then you are probably new to C. Have a look at a good book on C, its a bit of a learning curve but its worth it.
Obviously the saver needs to match your loader. If you save the data in the wrong order then the loader will geteverything mixed up. A saver uses the standard C function sprintf, again rub down your C book and have a look at the syntax. If you want to print an integer then you use %i, floats are %f.
Showing status information in the plugin description Now that we are allowing the user to alter the way the plugin behaves, why not add a little status information to your description line. Again using the old favourite, sprintf. If you are using a float in sprintf you can format it by using the syntax %x.yf, here x gives the total character width of the text, y the number of characters after the decimal point.
The option box Now the meat of this tutorial, the options box. In the next tutorial we will show you how to get more control over the layout. For now we let Lightwave decide on the layout.
Lightwave passes an instance and access to all global functions to your plugin. We use the global functions pointer to get a pointer to the message functions in case we need to display a quick alert box. We create a short list of strings to display a little text information. Remember lists like this must end with a NULL pointer otherwise bye-bye Lightwave. If everything went OK then we are ready to create our panel.
Before we get our panel up and running we need a pointer to the functions that control it. Have a look at the declaration of a LWPanelFuncs in the include file LWPanels.h. Hopefully now you are getting used to looking into these files, they will help you realise what is going on.
Phew! Fear not lets take it one step at a time. The best news is that we can use lots of macros which give use access to panel functions more conveniently. Firstly, we create a panel. This does not display the panel, it starts to create memory for the panel. At first just a blank box with a simple title. What's the NULL all about? If you wondered that then you are flying, its a void pointer that we can user to pass user data to the plugin. Check out lesson 3 to find out how to use this facility.
The number we get back from the create function is used to add controls to the panel. We add controls using the macros
There are many more macros to use to add, Object lists, file requesters, even an OpenGL window like Morph Gizmo. The TEXT_CTL is initialised on creation. Then we find the control using the nextControl function with NULL passed. This finds the first control. FVECRO_CTL is not initialised on creation, so we find the control by passing the previous control to the nextControl function. Get the idea, NULL finds control 1, after that we can iterate through the controls by passing the previous control. We can then initialise the control using SETV_FVEC this sets the three boxes in the control with the data in the array of three doubles that you pass. Remember a float in Lightwave is a double. This method is used for creating and intialising the read only integer control and the floats.
So all this work and still nothing to see. To actually display the panel we use open. Normally, a panel takes control until it is finished with. The values passed in the second parameter to open provide this information to Lightwave. If you've done any Windows programming then its the same as DoModal in a dialog box. Because we also display a cancel button we can check whether the user intends to save the changes. If they do then the result of the open not be zero. Hence the if block commands will run. Again we can use the nextControl to walk through the list of controls. Just as we can set the data in a control using SET_FLOAT, SET_INT etc. We can retrieve the data that the user has altered using GET_FLOAT, GET_INT etc. We create a new path using this new data. Finally, we tidy up any memory allocations using the destroy function.
Updating the Configuration Information When you add an options box you also need to add this information to the ServerRecord. Its just the same as adding the original plugin only this time its an Interface rather than a Handler. If you are working through the tutorials one by one, then before loading the test scene, "bounce2.lws", add the plugin again, this time it will tell you that 2 plugins were added. One is the plugin, the other is the options box.
Summary So now we have a plugin that the user can interact with. Not a very exciting plugin, but hopefully some of the methods involved in creating your own are starting to become clearer. In the next lesson we will add a picture to the options box, and introduce the marvellous world of callback functions. Lesson
1 - Introduction, compiling your
first plugin. |