Menu

Notes_on_Pipmak's_architecture

Anonymous Christian Walther

For the moment, I'm just going to paste in Christian's email. Hopefully more notes and documentation can be added later.--Rivenwanderer 04:51, 2 November 2008 (UTC)

rivenwanderer wrote:
> I'm not that familiar with Pipmak's source code, nor with Lua in general.
> However, I'd like to add the option to specify handle locations in terms of the
> center of the rectangle (with perhaps parameters name [caz, cel] or something
> similar).  Internally, this could hopefully just be mapped back to the regular
> representation (az=caz-w/2, el=cel+h/2) in a seamless way so that the rest of
> the treatment of handles would be unaffected.

Sounds like a good idea - and it's even something you can add without
having to recompile Pipmak.

I agree with your suggestion, caz/cel would just override az/el when
specified. For flat nodes, I'd add cx/cy that override x/y.

> Can anyone point me at the portion of the source where this could be
> accomplished?

Short answer: defaults.lua, function pipmak_internal.handle(handle)
(line 521 in my development version). The defaults.lua file is at
resources/resources/defaults.lua in the source code (if you want to
compile from source), in
Pipmak.app/Contents/Resources/resources/defaults.lua on Mac OS, or at
resources/defaults.lua in the file "Pipmak Resources", which is a ZIP
archive, on Windows and Linux.

Long answer: Pipmak can be divided into a "Lua side" and a "C side".
Reading project Lua files obviously belongs to the Lua side, but the Lua
side extends futher into Pipmak's innards in that things that Lua is
good at, like handling of dynamic lists, strings, and tables, are done
in Lua. The Lua side is entirely implemented in the mentioned
defaults.lua file (that you can modify in a released binary version,
without having to compile the C side or even needing an SVN checkout or
a source release). All the rest, like the whole rendering and event
handling, is done in C. The interface between the Lua side and the C
side consists of functions callable from Lua but implemented in C,
mostly in file pipmakLuaLib.c, and C objects (structs) wrapped as Lua
"userdata" objects (images and sounds are examples of such objects).
Other objects have representations on both the Lua side and the C side,
such as nodes. The Lua representation (that the project author interacts
with) in that case is an ordinary Lua table, with a metatable assigned
that gives the object its methods. Projects are supposed to treat these
tables as opaque objects, only using their methods or pipmak functions
to interact with them, but the contents of the table are plainly
accessible for those who want to take a look. The C representation of
the object is a C struct that is never directly touched by the project's
Lua code. The two representations refer to each other, and each only
contains as much information as the respective side needs (they largely
overlap, but neither is a subset of the other).

Handles, in particular, are handled entirely on the Lua side, they have
no C representation (hit testing is done by event handling branching out
from the C side to the Lua side by calling function
pipmak_internal.getcontrol_flat() or ..._pano()). Their Lua
representation, incidentally, is directly the table a node.lua file uses
to describe the handle, and the "handle" function that interprets it
mostly consists of argument validation (and conversion of the simplified
"target/effect" syntax for navigation controls to the generic syntax).
Recall that a node.lua statement like "handle { target = 15 }", while
conceptually a declarative statement, is technically a Lua function call
- function "handle" is called with a new table (that maps the string
"target" to the number 15) as a single argument. There is no parser for
node.lua syntax built into Pipmak, reading a node.lua file means running
it. That's the powerful concept that makes it effortless (from the point
of view of me, the Pipmak developer) to support things like making the
image of a patch not constant, but dependent on game state (or even much
more complex things like Andrea's Autocubic system).

Loading a node from a node.lua file works roughly as follows: On the C
side, the C representation of the node object is created and a few of
its most important fields are filled in. Then the Lua representation is
created (still on the C side, by Lua C API calls), the two
representations are cross-referenced, and then handed over to the Lua
side by calling function pipmak_internal.loadnode() (defined in
defaults.lua). That function initializes more fields in the Lua table
representation of the node object and then executes node.lua. Node.lua
calls back to functions like "handle". These functions are only assigned
to these short names during execution of node.lua and unassigned
afterwards (to stop people from trying to call them at other times than
node loading, which would make a mess). Their permanent definitions live
under the same names in the pipmak_internal table, i.e.
pipmak_internal.handle() etc. These functions fill more values into the
Lua representation of the node object. When control returns from the Lua
side to the C side after the end of pipmak_internal.loadnode(), the C
representation of the node is fully initialized by reading out some of
the contents of the Lua representation and storing them in the C struct.

(Disclaimer: This is all written mostly from memory and may contain
small inaccuracies.)

> In general, is there any documentation of the overall structure of Pipmak's architecture?

There isn't, as far as I'm aware. I hope what I wrote above helps to
some extent. You're welcome to put it onto the wiki and augment it by
your own observations. If you have more questions, please come back and
ask. I can show you an implementation of your proposed "handle center"
feature if you like, that's a matter of a few minutes, but maybe you
want to have a try yourself first.

When you examine pipmak_internal.handle(), there's one potentially
confusing expression that jumps at me right now: the line "if
math.mod(node.type, 2) == 1" should be read as "if this node is flat".
It has historically happened that the node types for flat nodes (slides,
panels) are odd, while panoramic node types (cubic, equirectangular)
are even (equirectangular is currently only used for hotspot maps, not
for nodes).

-Christian

Related

Wiki: Main_Page