Modifying a Door

Modifying a Door

The GRM Editor is a map editor built with Gtk2-Perl. It currenly exports images and xml and has most of the features you'd need to make and edit maps for a d20 (or other square tile) campaign.

In the future it will have remote viewing capability, drawing capabilities, and a line of sight calculator. It is still a work in progress. This is only the first release. The hard part was packaging it. Expect new releases soon.

These files are for the 5/17/8 build.

5/17/8: GRM Editor — First Build 

Generator Options

Generator Options

I was recently motivated by an article on Pen Paper and Pixel to build a map editor and Internet viewer. In the article, the author (Jans Carton) states,

... the map is projected ... via monitor spanning. ... I use the eraser tool [Photoshop] ... to reveal line of sight map info. For small areas, I do this freehand.

I've been irritated for years that I can't seem to find any tile-based map editors and viewers designed for use locally or for games over the Internet. They may very well exist for the Windows platform (probably as closed source products), but I have little interest in products like that. It would appear none exist that can do that job as well as photoshop — which is more of a pixel editor than a tile editor.

In a letter to Dragon Magazine Carton further writes:

My hope is that you could help me and any others that wish to use this technique by publishing this letter or similar instructions and by making high-resolution maps, which do not contain DM-only information, available for download.

Rather than scanning maps, this letter encouraged me to try to create software that would work for me over the Internet and for him with his overhead setup. I had already made a map generator, that was loosely based on the generator Jamis Buck provides on the net and it seemed natural to build my editor on top of that.

I have not yet finished the remote viewer and game master server software. Before I got that far, I was distracted by the dismal state of things concerning binary distributions of Gtk2-Perl software. Specifically, I found building bin-dists in Linux based operating systems isn't very difficult at all. However building them for Windows, which represents 80% of my audience, is a rather sad state of affairs.


Building Gtk2-Perl 

Part of a GRM Map

Part of a GRM Map

Simply building Gtk2 under Windows is challenging (to say the least). These days I think most people are using Camelbox to get recent builds. The advantage is that you don't really have to do anything. The disadvantage is that you don't have the PPMs available under ActivePerl. There are actually Gtk2-Perl PPMs available, but they are too old (1.141) to use with the GRM Editor, which uses features from 1.162.

I hate building things under Windows. You can't delete files that are “in use” and you can't execute commands that are “too long.”

These two things alone are great reasons to abandon the platform entirely but it persists for some reason. I feel like Windows is probably the most developer hostile platform that there is but I was recently told that AIX users have to deal with 6bit character sets. So perhaps there are worse places to try to live.

Because Windows is so difficult, I didn't really want to have to build things like libexpat and libgd under it just so I could use the simpler Gtk2 installer from Camelbox. I did try Camelbox, but since it didn't have XML::Parser it seemed too difficult to deal with. I didn't check, but I suspect it didn't have GD either. I made one attempt to get XML::Parser working, but quickly lost interest and set about building Gtk2 for ActivePerl.

I used the Microsoft Visual Studio 6 compiler. I suspect their free compiler would also work and I know people have done this with MinGW, but I already had VS6 installed so it seemed to be the logical choice. I used a Cygwin bash shell and the Cygwin vim for my various edits and things, but I suspect it would build just as well under the MinGW Msys shell.

In fact, I'm quite sure it would build successfully under cmd.exe. The fact of the matter is that you cannot avoid the most irritating part of the build under any shell. The max command line length is endemic to the entire platform and there's no way around it with any shell.

In any event, I expected the build to be very difficult. In actual fact, it was only a challenging. The main secret is to not give up when you encounter this mess while building Glib:

(That's one command by the way.) The way to handle it is to “look Glib” from the CPAN shell, cut and paste that evil command into a “” and execute it. Then make, make test, and make install. It's actually a piece of cake.

Of course, if you didn't get that far, it's probably because you didn't snag the gtk libraries and put them into a directory with no spaces. I'm sure people can get this to work from C:\Program Files, but I couldn't figure it out. It was much simpler to install the “all-in-one bundle” (from in C:\gtk\. Next, add c:\gtk\bin to your PATH (possibly via a right-click on my computer → properties → advanced → environment variables). pkg-config will take care of the rest — e.g.,

C:\> pkg-config --cflags glib-2.0
-Ic:/gtk/include/glib-2.0 -Ic:/gtk/lib/glib-2.0/include

Again, ExtUtils::MakeMaker will find all your libs and includes for you if you have your pkg-config in your path already and it comes with that gtk bundle, so you should be all set.

The next thing you'll encounter is, that blib/ expects itself to be in unix text file encoding... Storable can't load the _DATA_ block unless you unconvert the “\r\n”s back to “\n”s.

Lastly, while building Gtk2, you'll encounter a linker line that's as long as your screen. It may take a bit of playing around, but the following batch file works with Gtk2 1.182. If you play with it, you'll get it to work with later (or earlier) versions I'm sure.

That's really all there is to it. Seriously. You can do it if you stick with it for a couple hours.

By the way, I built a PPM repo so that people could just use my work...


Packing Gtk2-Perl using PAR 

Converting Selected Wall Tiles

Converting Selected Wall Tiles

The task of packing Gtk2-Perl into a PAR archive is considered by some to be impossible. It isn't. It's not even that hard, but it did require a little source diving and research to figure out. In fact, everything you need to know was posted in the middle of a justified rant by Marc Lehmann.

In the post, he informs us that PAR definitely finds and packs all the dependancies of Gtk2-Perl, but for whatever reason PAR renames everything it packs. I really don't know why it does this, but I suspect it's to avoid name collisions between PAR archives (assuming you have more than one). You can see this if you locate your temp folder (on Windows it's probably C:\Documents and Settings\userName\Local Settings\TEMP\par-userName). Click around to see the intentionally obsfucated hash names for everything.

If my guess is right, and this obsfucation is done to avoid collitions, then I can't help but think these types of collisions are fairly rare. Is it really worth guaranteeing that no Gtk2-Perl application can ever function under PAR+win32? Probably not.

Fortunately, it's relatively easy to correct. PAR even provides us with easy access to various tools, environment variables, and the actual archives in the form of Archive::Zip objects.

The first thing I'm going to show you is the code that I pack into PAR to load the GRM Editor. I take the fairly unusual step of packing the entire Games::RolePlay::MapGen blib/ dir into the archive. I suspect most people would not need to do this. You might argue that I don't need to either, but it was convenient.

use strict; 
our $grmfname; 
    # NOTE: grm.par is my pack of the complete GRM CPAN 
    # distribution packed within the PAR .exe.  It's a kind of 
    # double par packjob.  It is mainly to ensure I get the non 
    # perl files in the libdir. 

    $grmfname = "grm.par"; 
    if( $ENV{PAR_TEMP} and -d $ENV{PAR_TEMP} ) { 
        # If this .pl is running from a PAR environment, then 
        # this is the filename we need for the use import() 
        $grmfname = "$ENV{PAR_TEMP}/inc/grm.par"; 

use PAR $grmfname; 

# NOTE: This probably isn't necessary unless we're in Windows. 
# It saves me a headache loading the MapGen.dtd though.  In any 
# case, this builds a non-hash-renaming libdir and unshifts it 
# onto the @INC.  After compile time, PAR will re-insert itself 
# near the top of the @INC. 
use par_gtk_fix; 

use Games::RolePlay::MapGen::Editor; 

# This puts our non-renamed libdirs back at the top of the @INC 
# again at runtime. 

# Once PAR is defanged, I just run my program as usual: 
my $editor = new Games::RolePlay::MapGen::Editor; 

I'm assuming you don't really need to pack your blib/ dirs into your archive, in which case your app would look more like this:

use strict; 
use par_gtk_fix; 
use MyApp; 


my $app = new MyApp; 

The actual functioning of the par_gtk_fix is quite simple also. Behold its wonderous splendor:

package par_gtk_fix; 

use strict; 
our @INCg = (); 


    die "PAR_TEMP must be set" 
      unless $ENV{PAR_TEMP} and -d $ENV{PAR_TEMP}; 

    # At compile time, we simply unpack each par into a numbered 
    # dir and add it at the top of the @INC 

    my @dirs = (); 
    for my $i (0 .. $#PAR::LibCache) { 
        my $archive = $PAR::LibCache[$i]; 
        my $dir     = "$ENV{PAR_TEMP}/$i"; 

        push @INCg, "$dir/lib"; 

        unless( -d $dir ) { 
            mkdir $dir, 0777 or die "couldn't make dir $dir: $!"; 
            $archive->extractTree($_, "$dir/$_") for qw(arch lib); 


    unshift @INC, @INCg; 

sub re_fix_gtk { 
    # At run time, we restore our numbered libdirs 

    @INC = grep { 
        my $e = $_; 
        { return 0 if $e eq $_ } 
    1} @INC; 

    unshift @INC, @INCg; 

I have no intention of publishing this mess on CPAN.

It's a vile hack that works around many of PAR's intended internals. It even unpacks many things twice. In a “do-what-you-have-to-do situation,” this is an acceptable solution. However, this really is a bug or a design flaw in PAR and it needs to be addressed there. On the other hand there are, no doubt, very good reasons for the hash renaming they do.


[show links]

Hey! Lemme know you saw this!!