Updated 2011-01-24 22:53:48 by AK

by Theo Verelst

After a long break, I got a maze application, sort of game, out of the dust. More than a few years ago, I did a robot arm ([insert address of info here]) which was also an openGL window, as seperate program, controlled over a socket connection by a tcl program, which evidently has the major advantage of building scripts (..) to control the graphical scene. Also, the interactive nature of tcl lets you play along or experiment with the graphics and the pieces of program controlling them.

I picked a maze application this time, and found out as I started that it is programmed with typical windows stuff (messages, window handling) in it. It's an older example I picked up on the web somewhere long ago, and it compiled fine under cygwin years ago. Maybe I'll make another glut based or so program later, which compiles on linux and others, too.

The tcl script is very simple, but it works, though it needs adapting parameter ranges, and is just basic. I just finished it, and the principle works, which is fun and interesting. I applied similar principles in the past to another application, a sound generator based on string simulation, about which I'll also add the Tk control part here [1].

The program is made by compiling these two source files:
 [http://www.theover.org/Wiki/maze.c] maze.c
 [http://www.theover.org/Wiki/serv2.c] serv2.c

under a recent (or older, probably) cygwin:
 gcc -O -DWIN32 -D__WIN32__ -D_WINDOW -o maze.exe serv2.c maze.c -lglut32 -lglaux -lglu32 -luser32 -lgdi32 -lopengl32  -lm -lwinmm

The tcl script is:
 # maze socket based control script
 set mas stdout
 frame .ma
 pack .ma -expand y -fill both
 scale .ma.sv -orient hor
 scale .ma.sh
 button .ma.bc -text connect -command {
    if {$mas == "stdout"} {
       set mas [socket localhost 4100]
       fileevent $mas readable {
          if [eof $mas] {
             close $mas;
             set mas stdout
          } {
             puts "[gets $mas]"
          }
       }
    }
 }
 button .ma.bz -text stop -command {.ma.sv set 50; .ma.sh set 50; mazp}
 button .ma.bb -text brake -command {brake init}
 pack .ma.sh -expand y -fill y
 pack .ma.sv -expand n -fill x
 pack .ma.bb -expand n -fill x
 pack .ma.bz -expand n -fill x
 pack .ma.bc -expand n -fill x
 proc brake {{i {}}} {
   global bh bv
   if {$i != {}} {
      set bh [.ma.sh get]
      set bv [.ma.sv get]
   }
   set bv [expr ($bv-50.0 )/1.3 + 50.0]
   if {[expr abs($bv-50.0)] < 1.0} {
      set bv 50
   }
   set bh [expr ($bh-50.0 )/1.3 + 50.0]
   if {[expr abs($bh-50.0)] < 1.0} {
      set bh 50
   }
   .ma.sv set $bv
   .ma.sh set $bh
   if {$bv != 50 || $bh != 50} {after 100 brake}
 }
 .ma.sh set 50
 .ma.sv set 50
 bind .ma.sv <ButtonRelease-1> mazp
 bind .ma.sh <ButtonRelease-1> mazp
 .ma.sv conf -command mazp
 .ma.sh conf -command mazp
 proc mazp {{a {}}} {
    global mas;
    if [eof $mas] {
       close $mas
       set mas stdout
    }
    puts $mas "[expr ([.ma.sv get] - 50.0)/50.0] [expr ([.ma.sh get] - 50.0)/-3000]";
    flush $mas
 }

The upper slider controls the speed, the other the turning.

Start the maze.exe program, make sure the cygwin1.dll and glut32.dll can libraries can be found, when necessary copy them from /cygwin/bin to the current directory.

Then connect the tcl script by pressing the button Connect, and after the initial maze 'flight' you have control by topping the maze window and with the normal arrow keys, or by the tcl program, using the sliders!

You'll have to make a .bmp file (gimp can write them) of exactly 256x256 pixels to enable the texture feature of the opengl program, but the maze also works without texture.

Quality and load, and contraints on the tcl script program depend on the graphics hardware and computer speed, on a recent 2+G pentium with accelerated graphics, high speeds are completely smooth, and load remains low. The tcl program can also receive data (for instance from the keys being pressed) over the do_write() function in C.

I didn't test the channels overload characteristics, the robot arm application had major trouble with that, maybe because of cygwin, maybe because of opengl (which I compiled myself after lots of hacking at the time) in combination with sockets.

TV (Nov 28 03) I've updated the script, it is a bit nicer with respect ro connecting behaviour, it doesn't matter if you connect more than once, and detects if a connection is lost without error.

Also, after some trying (not hard though) to choke the socket connection, it seems that for unknown reason (maybe just more recent cygwin sockets) it is possible to rely on the streaming to deal with buffer filling correctly, so that apart from my not testing for message boundaries (based on newline here) which IS necessary in some cases, the error which I encountered years ago with a similar approach as here at least didn't show up.

So I made the slider control continuous, making the application nicer to use.

Also, I added a 'reset' button, to set the controls back to the middle, and even a gradual 'brake' button, which starts a after sequence to damp the sliders slowly to the middle position, resembling a car brake.

When the script is run without a connection, the slider get their values printed to stdout, which works when you have a console window, to see what get s actually sent.

I just ran the same stuff on another machine, where a 512x512 texture runs, but makes the machine have 100% cpu usage (it also runs a webserver, a tv card, bwise, pcom, webbrowser and cygwin shell, but most is at rest), even when the picture is stable.

Different opengl implementation, I guess, and probably no hardware support for textures on the graphics card.

Yet the above picture is part of a working maze application, the program and the needed dll's (unless you run from recent cygwin or otherwise already have them) are:
 [http://www.theover.org/Wiki/maze.exe]
 [http://www.theiver.org/Wiki/cygwin1.dll]
 [http://www.theover.org/Wiki/glut32.dll]

This is the texture, processed from a picture I made myself:


TV Aug 28, '08 Anyone know how to get a select loop for the socket combined with the OpenGL idle call to work decently on a modern Linux? I suppose I can well hack something together but maybe some core members know the modern system level socket/multiprocessing programming prerequisites by heart?! Considering the recent attention for threads which in windows envs are usually 'good' for usually no more than some UI issues, maybe the above example is interesting.