Discussion:
[Pipmak-Devel] Would like to make a small addition to Pipmak
rivenwanderer
2008-10-31 16:41:42 UTC
Permalink
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.

Can anyone point me at the portion of the source where this could be
accomplished? In general, is there any documentation of the overall structure
of Pipmak's architecture?

Thanks!
-rivenwanderer
Christian Walther
2008-10-31 21:02:45 UTC
Permalink
Hi rivenwanderer

I was just writing my reply to your e-mail (sorry for the delay, busy
days at work) and was about to suggest moving such discussion to the
mailing lists. I see you found them on your own - welcome.
Post by rivenwanderer
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.
Post by rivenwanderer
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.)
Post by rivenwanderer
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
rivenwanderer
2008-11-02 07:18:35 UTC
Permalink
http://www.nabble.com/file/p20287577/defaults.lua defaults.lua
OK, that was easier than I'd expected! I've uploaded my implementation
(assuming the Nabble interface does what I want). The tabs may be wrong,
and the nesting of if blocks is a bit messy, but it works :)

I discovered that if you specify a handle with a negative azimuth, it draws
properly when you show handles with "C", but the negative portion does not
recognize your clicks to transfer you to the target node. So I added a
check to make sure that my center-referenced coordinates are always
converted to positive azimuths (maybe this should be done for all azimuths?
or should other work be done so that the click is recognized?)

I'd obviously like to see center-referenced handles make it into the
official release at some point--but I saw that the
pipmak_internal.handle(handle) function can be overridden by defining it in
my own project's main.lua, which makes me happy :)

Thanks for the help so far!
--
View this message in context: http://www.nabble.com/Would-like-to-make-a-small-addition-to-Pipmak-tp20269828p20287577.html
Sent from the pipmak-devel mailing list archive at Nabble.com.
Christian Walther
2008-11-02 14:47:08 UTC
Permalink
Post by rivenwanderer
http://www.nabble.com/file/p20287577/defaults.lua defaults.lua
OK, that was easier than I'd expected! I've uploaded my implementation
(assuming the Nabble interface does what I want). The tabs may be wrong,
and the nesting of if blocks is a bit messy, but it works :)
Cool, thanks for the contribution!
Post by rivenwanderer
I discovered that if you specify a handle with a negative azimuth, it draws
properly when you show handles with "C", but the negative portion does not
recognize your clicks to transfer you to the target node. So I added a
check to make sure that my center-referenced coordinates are always
converted to positive azimuths (maybe this should be done for all azimuths?
or should other work be done so that the click is recognized?)
Good point, I fixed this in revision 212
<http://pipmak.svn.sourceforge.net/viewvc/pipmak?view=rev&revision=212>.
Your suggestion is good - wrapping the left edge of the handle into the
range [0, 360) at creation time is more efficient than checking it
modulo 360 in the hit test function.
Post by rivenwanderer
I'd obviously like to see center-referenced handles make it into the
official release at some point
Certainly - your change is in as revision 213 and will be included in
the next release. I made one small change (besides fixing the
indentation and adding documentation): assigning to handle.az is not
necessary in the panoramic case, Pipmak only ever uses handle.x (and
dito for el/y).
Post by rivenwanderer
but I saw that the
pipmak_internal.handle(handle) function can be overridden by defining it in
my own project's main.lua, which makes me happy :)
Well, yeah, but that's a bit hacky. Projects are not supposed to use
pipmak_internal (that's why it's called internal) and its contents may
change in arbitrary ways between releases, breaking your project.

-Christian

Loading...