libtweak lets you define parameters that can be adjusted while your
C++ program is running. It is particularly suited to realtime
applications like games, where you want instant feedback when making
changes.
- Supported languages: C++11
- Supported platforms
- Full Support: Linux, Mac
- Production mode only: All other platfoms
- Extra Requirements: Python 3
Run make. Find libtweak.a in build/ and link your program with
it. Add libtweak’s include directory to your header file search path.
The examples below will also assume that libtweak’s bin directory is
on your PATH.
Declare tweakable parameters in your program:
#include <tweak.h>
TWEAK(float, sausage_length)
TWEAK(float, temperature)Use them like ordinary variables:
int main()
{
tweak::init();
// ...
}
void do_frame()
{
tweak::process();
printf("The sausages are %fcm long and %f°C!", sausage_length, temperature);
}While your program is running, adjust parameters using the GUI:
tweakWhen distributing your program, you can build a version where libtweak
is not linked in, and your parameters compile to ordinary constants.
To do this:
- Generate a header file with the constants baked in:
tweakc > myconstants.h - Include this file before
<tweak.h>. - Define
TWEAK_BAKEbefore including<tweak.h>. This tellstweak.hto use the constants from your generated header file. - No need to link to
libtweak.a
For example:
#ifdef MY_PRODUCTION_FLAG
# include "myconstants.h"
# define TWEAK_BAKE
#endif
#include <tweak.h>As well as compiling libtweak itself, make will also compile a test
program called test. This program will define some parameters and
continuously output them to the terminal.
To try out libtweak, run this program and, while it’s running, use
tweak to adjust its parameters and see them update live.
When your program calls tweak::init, a file named Tweakfile is
written to the working directory, detailing the available parameters
and their values. A Unix FIFO called Tweakfifo is also created.
The next time your program starts, values are read from the existing
Tweakfile.
Additionally, when you call tweak::process, commands are read from
the Tweakfifo and used to update parameter values.
Tools that update values do two things:
- Update the
Tweakfileso the program will see the value when it is next started. - Write a value change command to the
Tweakfifoso the program can instantly update that value on its next call totweak::process.
The tweakc tool simply reads parameter values from the Tweakfile and
writes them out in the form of a C++ header.
Define a tweakable parameter. If TWEAK_BAKE is defined this simply defines
a constant. Otherwise, it defines a const reference to a value, which
may change when you call tweak::process.
Use this to refer to a tweakable parameter defined in another translation unit.
Sets all parameters to their initial values. Reads the Tweakfile or
creates one if not present. Sets up the mechanism for live updating
(Tweakfifo).
You’ll usually want to call this early in your program’s startup, or
at least before you call tweak::process for the first time.
If TWEAK_BAKE is defined, tweak::init is a no-op and your compiler
will optimize out any calls to it.
Check for new live-update messages and update any parameters. You’ll want to call this frequently during execution of your program.
In games, you can afford to call this every frame; if there’s nothing to update it is very cheap.
If TWEAK_BAKE is defined, tweak::process is a no-op and your compiler
will optimize out any calls to it.
All of these tools operate on the Tweakfile and Tweakfifo in the
working directory.
Starts a GUI for tweaking the program’s parameters.
Writes the current values of all parameters, formatted as a C++ header
file, to standard output. Use this file in conjunction with the
TWEAK_BAKE option to optimize out all of libtweak for production
builds.
Both Tweakfile and Tweakfifo have the same format: a list of lines
where each line is a command name followed by a space-separated list
of arguments. Possible commands are:
Specifies the type of a parameter. Every parameter must have a type. By
default, the available types are int, float, string and bool. You
can also add your own types; see Extending.
Specifies a value for a paramater. See Value Format.
Specifies the range for a parameter. Only applies to int and float
parameters. This is only used by the GUI tool to display an
appropriate GUI; libtweak itself ignores range commands.
Values are converted to and from strings for storage in Tweakfile and
transmission through Tweakfifo. How a value is converted to and from a
string depends on its type:
These are read by the C++ formatted extraction operators and so are dependent on your locale.
0 or 1.
Strings begin with a literal $ character, and end at the end of the
line. They may contain any characters except newlines.
(This is a strange format, but it’s very easy to parse and leaves the door open to implement proper delimited strings later.)
You can add support for your own custom types to libtweak. To do
so, you need to:
- Specialize the
type_namestruct solibtweakknows what your type is called:namespace tweak { template<> struct type_name<MyType> { static std::string get() { return "mytype"; } } }
This is the name that will be used in
typecommands in theTweakfile. - If necessary, specialize the
iostruct solibtweakknows how to load and save your type. If you don’t do this, the standardiostream‘<<’ and ‘>>’ operators will be used. You can overload these instead of specializingio.namespace tweak { template<> struct io<MyType> { static void load(MyType &value, std::istream &is) { /* ... */ } static void save(const MyType &value, std::ostream &os) { /* ... */ } } }
That’s enough for libtweak to handle your type. You can now use it in
TWEAK declarations.
However, the tools tweak and tweakc will not yet be able to
intelligently handle your type.
By default, tweak will show a text entry field for any type it doesn’t
know about, allowing you to modify the raw textual representation of the
parameter’s value (as used by load and save).
tweakc will take a shot at emitting C++ code for your type, but don’t hold
your breath.
You can override these default behaviours by putting some code in a
tweak_ext.py file alongside your Tweakfile:
import tweak
class MyWidget(tweak.Widget):
"..."
class MyType(tweak.Param):
widget = MyWidget
def cname(self):
return "c++ type name here"
def cvalue(self):
return "c++ value of self.value here"
tweak.types['mytypename'] = MyTypeFor guidance on implementing your own type and widget classes, see the existing
classes in bin/tweak.
This library uses FIFOs which don’t exist on Windows. The code is organized for easy porting, and full Windows support shouldn’t be too much work.
In production mode (with TWEAK_BAKE defined), Windows is supported,
as libtweak becomes a trivial header-only library in that case. So,
it’s still possible to develop your program on Unix and support
Windows as a release target.