We will implement a simple but useful mechanism for saving and loading the parameters' states. The code used in the examples will be based on the previous recipes.
Let's say we have a variable that we are changing frequently. In this case, it will be the color of some element we are drawing and the main class will have the following member variable:
ColorA mColor;
We will use a built-in XML parser and the fileDrop
event handler.
#include "cinder/params/Params.h" #include "cinder/ImageIo.h" #include "cinder/Utilities.h" #include "cinder/Xml.h"
void MainApp::loadParameters(std::string filename) { try { XmlTree doc( loadFile( fs::path(filename) ) ); XmlTree &generalNode = doc.getChild( "general" ); mColor.r = generalNode.getChild("ColorR").getValue<float>(); mColor.g = generalNode.getChild("ColorG").getValue<float>(); mColor.b = generalNode.getChild("ColorB").getValue<float>(); } catch(XmlTree::Exception e) { console() << "ERROR: loading/reading configuration file." << e.what() << std::endl; } } void MainApp::saveParameters(std::string filename) { std::string beginXmlStr( "<?xml version="1.0" encoding="UTF-8" ?>" ); XmlTree doc( beginXmlStr ); XmlTree generalNode; generalNode.setTag("general"); generalNode.push_back(XmlTree("ColorR", toString(mColor.r))); generalNode.push_back(XmlTree("ColorG", toString(mColor.g))); generalNode.push_back(XmlTree("ColorB", toString(mColor.b))); doc.push_back(generalNode); doc.write( writeFile( getAppPath() / fs::path("..") / fs::path(filename) ) ); }
bool mMakeSnapshot;
setup
method:mMakeSnapshot = false;
draw
method we put the following code, just before the params::InterfaceGl::draw();
line:if(mMakeSnapshot) { mMakeSnapshot = false; double timestamp = getElapsedSeconds(); std::string timestampStr = toString(timestamp); writeImage(getAppPath() / fs::path("..") / fs::path("snapshot_" + timestampStr + ".png"), copyWindowSurface()); saveParameters("snapshot_" + timestampStr + ".xml"); }
InterfaceGl
window:mParams.addButton( "Make snapshot", std::bind( &MainApp::makeSnapshotClick, this ) );
As you can see we don't have the makeSnapshotClick
method yet. It is simple to implement:
void MainApp::makeSnapshotClick() { mMakeSnapshot = true; }
void MainApp::fileDrop( FileDropEvent event ) { std::string filepath = event.getFile( event.getNumFiles() - 1 ).generic_string(); loadParameters(filepath); }
We have two methods for loading and storing the mColor
values in an XML file. These methods are loadParameters
and saveParameters
.
The code we put inside the draw
method needs some explanation. We are waiting for the mMakeSnapshot
method to be set to true
and then we are creating a timestamp to avoid overwriting previous snapshots.The next two lines store the chosen values by invoking the
saveParameters
method and save a current window view as a PNG file using the writeImage
function. Please notice that we have put that code before invoking InterfaceGl::draw
, so we save the window view without the GUI.
A nice thing we have here is the drag-and-drop feature for loading snapshot files. It's implemented in the fileDrop
method; Cinder invokes this method every time files are dropped to your application window. First, we get a path to the dropped file; in the case of multiple files, we are taking only one. Then we invoke the loadParameters
method with the dropped file path as an argument.
18.220.174.191