- Status: Complete
- Github link
tlmmProgram* prog = tlmmInitProgram(); tlmmParseProgram(prog, "x^2+x+12"); float y = tlmmGetValue(prog, 2); tlmmTerminateProgram(prog);
tlmm::Program prog; prog.Parse("x+2"); float y = prog.GetValue(2);
I have used a couple of different game engines. There is usually some sort of graph input system. If you check out the Animation view in Unity3D you see a graph system, for Transformers 3 – Dark of the moon, I used a graph system to model the vehicle handling in a way that designers could tweak. These systems are usually a simple mapping of value->result, with either linear interpolation, or creating splines between the points.
This sort of system is very very useful for a whole load of applications and is very simple to get working, at least with linear interpolation. I was thinking, however, that it might be useful, rather than setting up a large amount of value pairs for this, to also be able to run arbitrary equations. In theory, Maratis has a scripting system (via lua) so I could tie things in with this, but to expose them to the editor, parse them etc, would be a bit too dirty for how I wanted to do it. Also, if it’s something that would be polled once per frame, potentially more, it should be something that’s as fast as possible and the overhead of lua seemed potentially too much.
So, the design for tlmm was that it would be lightweight, it would be able to evaluate simple mathematical equations and would support standard mathematical operators (,),^,sqrt,*,/,+,-,sin,cos,tan,asin,acos,atan. The plan would be to make something that would be as quick as possible, ideally close to hard coding the equation if possible.
Obviously, there shouldn’t be any complicated API for this, it should parse a string containing an equation, on top of that, I also wanted to add a binary format for faster loading (development systems could still use strings) so it would need an input for that. To get output, the original idea was simple getValue, which would assume the function was in the form y=f(x). But I later added a “register” system that meant the user had access to 26 lettered registers to put inputs into, not just x. To use that, there’s no longer a reason for getValue to take x, so get was introduced to just use the current state.
The internal design was that it would be running an RPN based system, due to it being stack based and simple to run, but it meant that it would have to be parsed and converted. The binary format is simply the “opcodes” for the machine, so can be directly loaded. Some changes were made in release mode where, rather than loading the opcodes into the maths program, it did the opcode->functor lookup at load, so running the equation was marginally faster.
As this was the first ‘Tiny Little’ library, some of the design hadn’t quite been worked out so it differs slightly from later libraries. It also uses C++ internally for string manipulation and token management, as well as providing a C++ API.