Writing Hugin PreviewTools
- Draws something, using OpenGL calls, under or above the images in the preview.
- Changes how images are drawn in the preview.
- Responds to the user clicking or dragging in the preview.
This page introduces writing these tools.
The PreviewTool class
To make a new tool, first derive an object from this class. There are a few virtual functions to pay attention to, so read the following:
This is a base class from which all tools must derive from. You must call the constructor in the base class, PreviewTool::PreviewTool(PreviewToolHelper *helper), but you can do anything else you want in your constructor. If you want to create OpenGL Display lists or textures you may do it here.
You must override the Activate function. This is called when your tool is turned on by the GLPreviewFrame. Here you must use the PreviewToolHelper object your tool is linked to to request notifications of any events (your tool cannot do anything unless an event occurs). If you need to initialise any values, do it here. If your tool is turned off by the user your tool will get no notification until Activate is called again. Register events by using something like <source lang="cpp"> helper->NotifyMe(PreviewToolHelper::MOUSE_MOVE, this); </source>
Have a look at PreviewToolHelper.h for more information about events. For an example, look at one of the existing PreviewTools, such as PreviewCropTool.
The Event Functions
Each event has a corresponding virtual function in PreviewTool. When an event occurs, this function is called. So override any of these functions for events that you request notification of. You can request more event notifications in these functions, but be aware that if they thieve something from another tool (e.g. mouse clicks) the other tool will be disabled, but no notification to the GLPreviewFrame will be made, so the button for it on the user interface may remain in the on position. For the drawing functions you can draw what you want, the ViewState object can provide you with access the textures and meshes used to draw the images (see Hugin's OpenGL preview system overview to see how it works). Use helper->GetViewStatePtr() to get a pointer to the VeiwState used for the preview. Read ViewState.h to see how to use it.
If you use OpenGL functions in your tool, here are some simple rules to follow to ensure everything works:
- When you are done, set the colour to (1.0, 1.0, 1.0, 1.0).
- You can leave the blending function set to whatever you want, but leave blending turned off.
- 2D Texturing will be turned on when your functions are called, please leave it on when you are done.
- Use glGenLists and glGenTextures to get a new display list number or texture name, as any of them may already be used.
- Generally the rest of the system expects something near the default OpenGL state.
A few notes on the ViewState object
The view state handles what has changed in the preview's representation of the panorama. It redraws the preview automatically when the panorama has changed. However you probably don't want to change the panorama during interactive things, as each change must have a corresponding undo level. You can therefore change the information used to draw the preview using the ViewState directly. When you have changed everything you need, call the ViewState's Redraw() function. At this point the ViewState will redraw the preview if it notices something has changed. However, if the representation of the panorama doesn't change, no drawing will take place. Therefore if you want to display something different yourself, you must call ForceRequireRedraw() before Redraw().
Integrating with GLPreviewFrame
Firstly you will want to make a pointer to the type of your tool in the declaration of GLPreviewFrame. Leave it with the others for clarity. The class type should be forward declared at the top of the file to save on the #includes.
In GLPreviewFrame.cpp you will want to add a #include to the header file your tool is defined in. Next you will want to create an instance of it in GLPreviewFrame::MakeTools, using your pointer. The creation of the tools is delayed so they can expect an OpenGL context in their constructor (the context is made by the GLViewer, which is inside the GLPreviewFrame). You will then want to free your tool in GLPreviewFrame::~GLPreviewFrame, providing MakeTools was called. It isn't called if the user closes Hugin without opening the OpenGL preview frame, no OpenGL context is made until the window becomes visible.
The next step is getting your tool activated when you want. If your tool provides some useful service continuously, you can activate it when MakeTools is called. However make sure it can never be automatically turned off in this case: it cannot draw under or over individual images or respond to mouse clicks, but it can use every other event including drawing under or over all of the panorama. You can add buttons in a similar style to the buttons already there. Remember to disable the buttons for any tools your tool may switch off on activation, use something like <source lang="cpp"> TurnOffTools(helper->ActivateTool(my_tool)); </source> Also add your tool to TurnOffTools, in case another tool does the same to yours. You may need to redraw the preview when your tool is activated or turned off, if so use m_GLViewer->Refresh(); afterwards.
Finally, add any new source files you made in the corresponding CMakeLists.txt. After that, you can compile it, give it some testing and off you go. If you've made a useful tool, be sure to show it off on the Hugin mailing list.