Viewport.e
Hawke' <mdeland@nwinfo.net> <trumpyt@nwinfo.net>
9/21/98

General Description
=====================
This is a library which you can include with your
   math/graphing/game library/code that allows
   you to specify a coordinate system to your
   specific needs.

Great pains were taken to make this library impose
   very little penalty upon your graphing/drawing
   functions.  The largest 'hit' to performance is
   most likely at the initialization of the library
   via the SetWorld() and SetViewport() procedures.

CalcPosition() is quite fast as a result of
   making the initialization perform most of
   the actual calculations and storing those
   calculations into a 'lookup' table of sorted
   values that are accessed via binary searching.
   {that means -fast- usually :) ]

If I think, or hear of, a suggestion that can
   improve CalcPosition()'s speed, I'll almost
   assuredly incorporate it.

Usage
=======
This library is currently FREEWARE, usable as
   you wish, with one request: give credit where
   credit is due, thanks where thanks are due.
   A copy of the full version of products made
   with this library might be nice as well. :)

Take note of the global constants SCR_MODE, SCR_WIDTH,
   and SCR_HEIGHT as they (currently) need to be set
   by hand.  I'll be listening to feedback, and then
   deciding how I wish/will "fix" this.

Version History
=================
Version 1.00B
   This is the first issuance of this library to
   the public. Future versions will most likely
   be bug fixes from user reports as well as
   incorporation of suggestions from same, with
   the first big fix being those constants
   mentioned above.

Procedures, Functions and further description
===============================================

----procedure SetWorld(sequence coor)
This determines the range of values that represent
   the new coordinate system.

An origin based system might have x values from
   -10 to 10 and y values from -5 to 5.

Or, you can have -3000 to 3000, for example, to
   represent a 'universe' of some sort.

Finally, you can make a 'true' origin system where
   values for x increase from -x to +x as you go
   to the right and values for y decrease from
   +y to -y as you go down.

----procedure SetViewport(sequence coor)
This procedure determines where upon the actual
   CRT that the values held within the new coordinate
   system are to be mapped to.

If coor is {} then the entire screen is used,
   (actually: {{0,0},{SCR_MAXY,SCR_MAXY}} and 
    to clarify why, see below...)

Otherwise, the rectangular region specified is
   where pixels based upon the new coordinate
   system will be drawn.


Now an example of these two in action might be if you
   wanted an origin based system from -pi to pi along
   the x and y axis.  You then wanted all of your drawing
   to be in the center of the screen with space around
   the drawing area to place labels, values, status bars,
   menus, and the like.

So, you call:
      SetWorld({{-pi,-pi},{pi,pi}})
   to define your coordinate system and then you call:
      SetViewport({ {50,50},{SCR_HEIGHT,SCR_HEIGHT}-50 })

What this will do is if you wish to plot the point
   {-pi,-pi} that it will actually be placed upon the
   screen at {50,50}.  The point {0,0} will actually
   fall (given 800x600 res) at {300,300} and {pi,pi}
   will of course land at {550,550}.

Simple, no? ;)

Now at this point, it's worth noting the use of
   SCR_HEIGHT here... twice... done deliberately... 

Why? To ensure that the region is indeed a *rectangle*
   AND because in any given video mode the SCR_HEIGHT
   value is always less than the SCR_WIDTH value.

This is very important. The viewport _must_ be a rectangle,
   and this is simply the easiest way (known to me) to do that.

Also note that this will leave you an additional amount 
   of screen area to the right of the viewport, spanning 
   from top to bottom, that is SCR_WIDTH-SCR_HEIGHT wide 
   (800x600 yields extra area of 200x600 pixels to the 
   right of the already given 50 pixel buffer zone...)

So... now... we've got this razzle dazzle new coordinate
   system, so how do we put stuff there?

----function CalcPosition(sequence coor)
This function accepts x and y coordinates defined by
   SetWorld via the sequence coor {x,y}, spins them
   in a blender a bit, and spits back an "appropriate"
   {x,y} point based upon the new coordinate system
   definitions.

Take a look at viewport.ex for some examples of all of
   this material, paying real close attention to the
   use of Xstep to build a list of adjoining points
   to send to pixel() which can give added speed.

And finally, we get to *sigh* non-integer values...
I've done what I can to ensure decent stepping
   /* simply, the range of values divided by the
      number of pixels along that axis within 
      the viewport...
      the prior example had 500 pixels to span
      -pi to pi... therefore:
         2pi/500 = ~0.01256637 for each pixel
   */
   and ensure decent accuracy and prevent rounding 
   errors from getting in... your mileage may vary...


Enjoy.  --Hawke'
