[clue-talk] Stupid OCaml tricks

T. Joseph Carter tjcarter at bluecherry.net
Tue Aug 15 05:51:51 MDT 2006


On Mon, Aug 14, 2006 at 12:55:22PM -0600, Matt Gushee wrote:
>   PROBLEM:
> 
>     An image viewer has several modes of operation: fullscreen vs. not,
>     slideshow vs. manual, etc. The user is allowed to switch between
>     modes at runtime. Each time an image is displayed, it needs to be
>     displayed in an appropriate manner for the current mode.
> 
>   CONVENTIONAL SOLUTION:
> 
>     Set up some flags to indicate the mode, and test them each time
>     an image is displayed:
> 
>       let mode = {
>         fullscreen = false;
>         slideshow = false;
>         interval = 1000;   (* milliseconds *)
>       }
> 
>       ....
> 
>       let show_image img =
>         if mode.slideshow && mode.fullscreen then
>           [ do something ]
>         else if mode.slideshow then
>           [ do something else ]
>         else if mode.fullscreen then
>           [ something else again ]
>         else
>           [ etc. ]
> 
>   WHAT'S WRONG WITH THAT?

It's not very nice code?

Let's assume you have the record above..

	if mode.fullscreen then
	    [ draw image fullscreen ]
	else
	    [ draw image in a window ]

	if mode.slideshow then
		[ set auto-advance timer ]
	[ wait for user or timer to give us something to do ]

It's actually simpler than that because these days the command for drawing
the image in the window vs. fullscreen is the same--that is, as far as
your code is concerned you are always drawing to a window, it just might
be sized and positioned such that it has no titlebar and takes up the
entire screen.  This usually happens automatically because you told the OS
that your window is fullscreen mode.  The special case of fullscreen (an
optimization state where in anything but 640x480x16 these days) is handled by
your video drivers for you pretty much automatically.  This is so on X11
and MacOS X at least.  Not so much for writing to a framebuffer console or
most embedded applications--but in both cases that's pretty much because
you must write your own video driver for the most part as was done in the
DOS daze.

Let us assume, for the sake of argument, that you are writing to fbcon
here and the difference between putting the image on part of the screen
versus the full screen was large.  You still would not implement it as
above because the assumption is also that your input-processing code is
also not trivial, hence the above refactored implementation.


Oh certainly you _can_ do it the way you did above, but this is why
Windows XP and clones (GNOME and KDE!) each require 128 MB just to play
solitaire.  This is why I lament that they don't teach kids to write code
anymore.  The classical approach is usually the best here:  Identify the
problem , the steps to solve the problem, implement those steps, evaluate
and improve.  In mere seconds, that redefined the solution using this
logic.  Pseudocode not almost valid python, for once:

The problem is to get your pictures on the screen.  Okay.

	Draw Pictures ()

So how do you do that?

	For each picture to draw:
		Draw a picture ()
		Wait for user ()

We decided we have two methods of drawing pictures:

	For each picture to draw:
		If mode is fullscreen:
			Draw a picture fullscreen ()
		Else:
			Draw a picture windowed ()

		Wait for user ()

Now, the user might be replaced by an auto-advancing slideshow.  Does this
require a separate routine?  No, because if the user is pressing right
arrow, a slideshow will simply simulate the user advancing:

	For each picture to draw:
		If mode is fullscreen:
			Draw a picture fullscreen ()
		Else:
			Draw a picture windowed ()

		If mode is slideshow:
			Set the auto-advance timer ()
		Wait for happy user or timer ()

Now we go back and look at our solution.  It's got limitations--namely
that this loop goes one direction and assumes that your pictures just come
from somewhere.  Fine, so your Draw pictures () takes a list or an
array/length and waiting for the user means waiting for forward, back,
mode toggle, exit, picture controls, and whatever else the user is allowed
to do in this program.  No biggie.

Now, I can imagine where your OCaml solution might be useful--loading of
Targa images as OpenGL textures.  The problem is that if your Targa is
stored the classic way, it is written left-to-right and bottom-to-top.
Now the problem is that the file format explicitly allows right-to-left
and top-to-bottom as well.  You literally do have four separate cases to
deal with.  In addition, you have several recognized modes (greymap,
indexed, the usually unsupported indexed > 256 colors, RGB and RGBA of
various bit depths for each component, and this may or may not be RLE
compressed), making the so-called "simple" format anything but.

This is really a pain in C!  An implementation of passingly acceptable
complexity in Java would just define a couple of iterators depending on
the X/Y directions, but still require that the image be a predictable
combination of greymap/indexed or Targa's "true-color" (RGB/RGBA).  RLE
support is typically only supported for the latter, and there are a couple
of bugs you have to support where the RLE is allowed to extend past a line
boundary.  I've seen better loaders in Python and Ruby, but my assumption
is that you could create the infrastructure to use these solutions in any
language, it just might not be worth the trouble if you use them only for
loading a damned picture.  ;)


This ends Professor Joseph's rant/lecture/lesson on graphics code.  =D




More information about the clue-talk mailing list