GSL2014.ew

Manganfred6@gmail.com
A 2-D graphics package.
Platform: Euphoria 4 + Win32Lib.ew


PolyPic of "Howth Tram" created with the DrawBust vector drawing program.

Introduction

This package implements a 2-D scaled drawing scheme for Euphoria 4 + Win32Lib. The point of such a scheme is that, once your program has created a scaled "Drawing World" it can then do all the drawing needed in terms of Cartesian coordinates instead of in terms of machine coordinates. Throughout, the things that are drawn are represented by sequences, either individual polylines, or individual polygons, or by what I have called PolyPics - a structure that contains polylines and/or polygon sequences which represent the components of some larger drawing object, like the tram in the picture above.

All modern computer graphics packages approach vector graphics in this way. Unfortunately not all computer languages have caught up with this, as a consequence many programmers are obliged to do graphics limited by the few drawing primitives provided by their computer language, as if we were still living in the 1960s. Euphoria's sequence type is spectacularly well suited to representation of vector drawing objects.

Besides these notes - and many comments in listings - the package is accompanied by demo programs ranging from the very simple to some fairly complicated ones. I hesitated about including the latter, but kept them in in the end, because they do give some idea of what can be achieved, often without having to write mountains of code. I make no claim that this package is easy to use, but if you work at it, starting with simple things, you will soon get the hang and be able to tackle more difficult graphical projects.

Also included in the package are:

* Some Classes implemented for EuCanOop. These are largely undocumented, so your only guide to them will be the few programs that demonstrate them. These Classes use GSL2014.ew.

* A simple vector graphic drawing package, DrawBust.exe, with which you can create PolyPics of a sort too complicated to create "on the fly" in a computer program.

GSL2014.ew and its associated files have many features not present in my earlier graphics schemes, which it supplants, though as far as possible backward compatibility is preserved.


Summary of Features

The GSL2014.ew file (henceforward GSL2014) is a major extension of my previous efforts in producing 2D graphics that are scaled to a designated VIEWport via a WINdow on a graphical world. As before there are simple procedures:

for drawing a polyline as a polygon or as a polyline to a pixmap.

The earlier versions of GSL2014 had a procedure:

for drawing a complex drawing object made up of component polylines and polygons. This procedure has now been upgraded to a function and extended so that a PolyPic can have features additional to its component parts, such as

  1. ability to activate/deactivate the drawing of a PolyPic,

  2. capacity to specify a predetermined sprite-like motion for a PolyPic.

  3. capacity to associate with a PolyPic text which will automatically display beside it on screen.

  4. capacity to re-order the sequence in which its elements are drawn,

There is a variety of functions available for transforming both individual polylines and whole PolyPics in the drawing plane.

The Scroll() procedure can be used to produce a scrolling background image for objects drawn with GSL2014 functions and procedures.

The InterpolatePolyFrames() procedure can be used to interpolate frames between PolyPic Key Frames that your program supplies, thereby reducing the amount of drawing that you - or your program - have to explicitly do.

A slightly improved version of the vector drawing program Draw Bust is included - along with some sample drawings. The improvements encompass elimination of one bad bug, improvement and extension of some post-editing features, and change to how they program exports drawings as Euphoria sequences (they are now exported as an includable function file).

The GSL2014 package is (mostly) backward compatible with its predecessors, although some things - such as how to initial a pixmap for drawing on - have been altered.

Due to limitations of space - and of my desire not to write endlessly - what follows can only be a guide to how to use the main features of the package in the context of Euphoria and Win32Lib, not a lesson in classical computer graphics or maths.


Setting Up Scaling

Before a program can do scaled drawing it has to define a viewport and a world window. A viewport relates to a device such as a bitmap control or a pixmap control, and can be described by a sequence containing two machine coordinates, thus:

constant VIEW = { {1, 1}, {300, 200} }

A world window describes a rectangular portion of the Cartesian Plane inside which we will do our drawing. It is similarly described using a sequence containing two Cartesian coordinates, thus:

constant W_WIN = { {0, 0}, {100.5, 32.5} }

In each case the defining sequence is a rising diagonal of the 2D space involved. Ideally each defining sequence should have the same aspect ratio as the other to avoid distortion of reproduction of drawings, though in non-critical applications this rule may be broken to some extent.

Actual creation of the scale mapping is carried out with the procedure

InitializePixDraw(atom pixmap,       -- handle of the pixmap to draw on
                  integer bg_color,  -- background colour
                  atom parent,       -- handle of parent of the pixmap
                  sequence pwhere,   -- where on parent it is, as {Xp,Yp}
                  sequence view,     -- rising diagonal of viewport
                  sequence win       -- rising diagonal of world window
                 )
-- For Win32 - Caller should have created the Pixmap on its parent window,
-- e.g., with Judith's IDE.
-- Also sets up scaling to be used, via SetScale(view, win);

Once this is done your program is ready to carry out drawing using world coordinates.

To change scaling at any time during a program run, just execute:

SetScale(view1, win1)

where view1 and win1 are alternative viewport and/or world window definitions.


Scroll Initialling

If you are using the Scroll feature of the GSL2014 file you should execute the function InitializeScroller() instead of procedure InitializePixDraw() : SEE "_Section 4_. Pixmap Scrolling."

If your program creates its own drawing objects, it is a good idea to execute InitializePixDraw() or InitializeScroller() before you create the drawing objects. That way, you can invoke PolyPic or Polyline transformation functions if you need them to assist in creating the drawing objects.


Scaled Drawing.

There are several ways to do scaled drawing:

The scaled drawing routines support ONLY ONE scaling at a time. If caller wants something more complex, (e.g. simultaneous scaling and drawing to multiple windows/viewports), (s)he will have to arrange for it themselves. This restriction is probably less applicable in the Win32Lib version, but has not been pursued or developed. Your program can execute InitializePixDraw() as often as you like, nominating different pixmaps, viewports and world windows according to your needs.


PolyPics

PolyPics form such a large part of this package that they need an introduction of their own. What I have called a polypic originally started as a simple structure with the form:

{ element_1, element_2, .... etc }

where element_i is:

{ integer type_flag,      -- POLY or LINE (i.e., polygon or polyline)
  integer bgcolor,        -- a BGR colour
  integer fill flag,      -- w32True or w32False
  sequence polyline       -- eg, { {x1,y1}, {x2,y2}, .... etc }
}

This is the format of the drawings exported by the rather basic vector drawing program DrawBust. This format is now the deprecated form of polypic, replaced by the PolyPic developed for GSL2014.

The format change gives greater flexibility and range to the things that can be done with PolyPics, which are now rather sprite-like and supported by new transformation functions.

GSL2014 can reproduce drawings in the deprecated format. The deprecated form can easily and automatically be converted to the new format. For the new format PolyPic see "Section 1. PolyPics" below.


Key Frames

There is still one feature of GSL2014 which I have not mentioned and which I almost hesitate to mention since it is still incomplete and rather experimental. This is routines relating to Key Frames described (as far as they are described at all) at "_Section 5_. Key Frames" below. These routines have still not been updated to conformity with the new PolyPic format - and maybe never will be.


Bustout Functions

Here is a list of the various bustout functions. They live in the file bustout.e, automatically included by GSL2014. Each bustout function returns a sequence representing a simple geometric shape. Here is how you call the more important ones (there are few less useful bustouts - SEE bustout.e):

  1. s = bustout_rectangle( diag )
    Given diag(onal), returns the 4 vertices of the rectangle it defines as an unclosed polyline. diag may slope up or down.

  2. s = bustout_arc( n, r, theta, phi )
    Bustouts an arc of radius r, centered on {0,0}. The arc subtends theta, starts at angle phi and consists of n elements. If r is sequence {a, b} the arc will be a part of an ellipse.

  3. s = bustout_circle( num, centre, r )
    Generates a (polygonal) circle or ellipse, radius r, centered on centre = {xc, yc}. The polygon has num sides. If r = {a, b}, a != b, it will be an ellipse.

  4. s = bustout_arc_slice( n, r, centre, theta, phi )
    Bustouts a pie-chart type of slice. Arc has radius r, centered on centre, subtends theta, start angled at phi, and has n elements. If r = {a, b}, it will be elliptical.

  5. s = bustout_star( r_major, centre, num_points )
    Returns a polygon 'star' of radius r_major about centre = { Xc, Yc }. The star has num_points "rays". Returns a sequence of sequences { star, radii }. You would normally use only the first one (star).

  6. s = bustout_rock( num, centre, mean_r )
    Returns a sequence containing an "irregular" (!) circle, of radius mean_r, centered on centre = { xc, yc }. The polygon has num sides. Used this to generate rocks in an asteroids game.

  7. s = bustout_can_xhair( radius )
    Bustsout a canonical XORable drawing cursor of radius 'radius'. Typically radius would be a positive integer in units of machine coordinates.


    Some of the Demo Programs

All the demos are animations of varying complexity.

Note that Install instructions are in a text file in the Include folder.

A. GSL2014 ON ITS OWN

  1. Spider.exw:
    The spider is coming to get the fly! Creation of the spider (actually 2 of them) was complicated; it would have been easier to create them with DrawBust and to have imported them. The fly however is idiotically simple to make. I used this program a lot when last working on GSL2014, and have left traces of things done by way of testing.

  2. ScrollTest1.exw:
    Simple demo of scrolling a background bitmap, with a moving red star being drawn over it. The star is created by ScrollTest1 and is not an import.

  3. GraphPlotter.exw:
    An old EuWinGUI program converted to Win32Lib that draws user's typed-in maths functions and uses scaled drawing for graphical output.

  4. MovingPgons.exw:
    Has most of its custom code in file Teeming.ew. Its CreateAnObject() procedure gives a clearly shows how easy it can be to code directly to create a simple drawing object in the newest PolyPic format and illustrates objects that carry with them a snippet of displayable text and also their own 'physics', though the programmer has to step in when objects run off the boundary of the display area. This program could just about animate 800 of the polygon objects but staggered while their texts were also drawn (a slow process).

  5. HowthTramScroll.exw:
    This program uses drawings imported from the DrawBust drawing program and a scrolled background bitmap to try to bring this tramline back to life in a reasonably convincing way. The imports are in deprecated polypic form and are not upgraded, the simple 'physics' of their movement being managed by the programmer directly.

B. OOP WITH EUCANOOP + PICOOP.EW

These examples have some of the rigidity of OOP, but there is flexibility to let your program contribute to the graphic effects.

  1. TargetTeeze.exw:
    This shooting game is pure Oop and shows how simple creating Oop drawing objects can be (if a bit tedious) and how you can control these Oop objects in the context of a simple game. The many targets all make use of just one imported graphic picture and the (transitory) Sun is an example of an object using a flicker-pic a sequence containing several polypics, each slightly different from the other. As is often the way with Oop, the routine that does the heavy lifting of running the game is surprisingly brief and seemingly simple. The gun-flash effect is not drawn via Oop but directly by the S_DrawPloygon() function when needed.

  2. HowthTramOop.exw:
    This is a modification of the program above. It uses PicOop.ew to create and maintain the drawing world, but direct use of GSL2014 to draw the trams etc. So it's really a mixed up program!


    Section 1. PolyPics

Section deals with scaled vector drawing objects called PolyPics. It is important to read sub-section (a) as well as what comes next. First, a summary of the main functions relating to polypics.

(pp means a polypic structure; [ ] encloses optional things).

1. S_DrawPolyPic( )
This renders a polypic: This is now a function which returns the updated pp polypic. In the case that the polypic submitted was a deprecated polypic, the return will be that polypic converted to the new PolyPic format. The returned polypic can be ignored if that suits you program's operation. All Polypic transformation functions return the polypic in the new format.

[ pp = ] S_DrawPolyPic( pp [, clip_flag] )   -- default is no clipping

2. RotatePolyPic( )
Rotate a PolyPic about a centre {xc, yc} by rad_angle (*):

pp = RotatePolyPic(pp, {xc, yc}, rad_angle )

3. TranslatePolyPic
Translate a PolyPic by {dx, dy} (*):

pp = TranslatePolyPic( pp, { dx, dy } )

4. ShearPolyPic()
Shear a PolyPic with respect to a point {x, y} by shear_fac in the x- or y-direction (*):

pp = ShearPolyPic(pp, { x, y }, shear_fac,  'x' | 'y' )

5. ResizePolyPic( )
Resize a PolyPic by size factors {sx, sy}:

pp = ResizePolyPic( pp, { sx, sy } )

6. FlipPolyPicAcrossAxis( )
Transpose a PolyPic across x- or y-axis (*):

pp = FlipPolyPicAcrossAxis( pp, 'x' | 'y' )

7. GetMaxMinPolyPic( )
Return the diagonal spanning a polypic at its current position:

s = GetMaxMinPolyPic( pp )

8. GetObjPosnDiag( )
Return the position and the diagonal of a polypic:

s = GetObjPosnDiag( pp )

8. ConvertToPolyPic( )
Return a deprecated polypic (pp_d) in the form of a current PolyPic:

pp_d = ConvertToPolyPic( pp_d )

For every function description above marked by an asterisk (*) there is a globally available function which will do the same thing for a polyline. These functions have been named consistently:

s = RotatePolyline()

s = TranslatePolyline()

s = ShearPolyline()

##**s = FlipPolylineAcrossAxis()

For backward compatibility, S_ routines have not been renamed.

THIS NEEDS A HOME:
InterpolatePolylinePoints( )

s = InterpolatePolylinePoints(sequence track, integer minnum_pts)\\

track should be a sequence containing at least 2 points. The function returns sequence s, which is track with at least minnum_pts interpolated in between the original points in track.

(a) Definitions (3/06/2014 9:23 PM)

Important to read this sub-section and its code. Although easy to use, the new form of PolyPic is a complex structure. I have provided indices to help in accessing its components, and other constants to help in using it:

global enum POLY,        -- flags a Polygon
            LINE,        -- flags a Polyline
            CIRCLE,      -- flags paramaterised circle
                         --          {n_points, centre, radius}
            RECTANGLE,   -- flags paramaterised rectangle
                         --          {diagonal[, theta_rot]}
            STAR         -- flags paramaterised star
                         --  {n_points, centre, radius[, theta_rot]}

 -- indices into drawing object
 global enum O_ACTIVE, O_ELEMENTS, O_ORDER, O_MOVER, O_TEXT, O_TEXT_BG
 global enum O_TRACK_CNT, O_TRACK_MODE, O_TRACK

 global enum MODE_REPEAT,    -- Tracking to repeat on end of 1st execution
             MODE_STOP,      -- Tracking to stop on end of 1st execution
             MODE_REVERSE    -- Tracking to reverse on end ...

 -- This is the raw drawing object template, a PolyPic; use it to initial
 -- each new PolyPic your program creates:
 global constant  -- TEMPLATE: -------------------   GLOBAL INX --------
 NEW_DRAWING_OBJECT = 
    { O_ACTIVE, -- object active flag,default.       O_ACTIVE    = 1.
      {},       -- bucket for drawing elements.      O_ELEMENTS  = 2.
      {},       -- bucket for el draw order.         O_ORDER     = 3.
      {         -- auto-moves object along a         O_MOVER     = 4.
                --  pre-defined track (optional).
        0,      -- auto step counter                   O_TRACK_CNT  = 1.
        1,      -- flags MODE of movement              O_TRACK_MODE = 2.
        {}      -- polyline track to follow            O_TRACK      = 3.
                --  in world coords (if used)
      },
      {},       -- for baloon text if used           O_TEXT      = 5.
      0         -- bg for text (0=none, else color)  O_TEXT_BG   = 6.
    }

 -- The drawing object must contain drawing elements. This is the drawing
 -- element template. An object created from NEW_DRAWING_OBJECT should 
 -- have its [O_ELEMENTS] sequence occupied by 1 or more elements of this
 -- form. Use this template to initial a drawing element:
 global enum E_TYPE, E_COLOR, E_FILL, E_STRUCT  -- indices to elements 
                                                -- of a polypic.

 -- Here is the drawing element template:
 global constant  -- TEMPLATE: -------------------    GLOBAL INX --------
 NEW_DRAWING_ELEMENT = 
     {POLY,       -- type of element (default POLY)      E_TYPE   = 1.
      Black,      -- drawing colour                      E_COLOR  = 2.
      w32True,    -- fill flag (True/False)              E_FILL   = 3.
      {}          -- polyline or param list              E_STRUCT = 4.
                  -- (param list for types CIRCLE,RECTANGLE,STAR)
     }

 -- Advise to use the global constants to create and to reference new 
 -- PolyPics; doing so will minimise risk of older programs getting 
 -- caught out with update problems, should these formats be modified or
 -- upgraded at a later date.

(b) Global Types

  1. polypic_dep : Only old style deprecated polypics conform to this type.

  2. PolyPic : New style AND old style polypics conform to this type.

Programatically, you would normally test for this type, to verify that a sequence conforms to the type.

SEE additional Euphoria types in file CommonTypes.e.


Section 3. Polylines and Polygons

S_DrawPolygon(atom clr,        -- colour for the polygon
              atom fill,       -- to be filled? (True/False)
              sequence polgon  -- polygon, in world coords.
             )
Usually clipping should not be required:
S_DrawPolygonClip(integer colour, -- colour for polygon
                  integer fill,   -- fill? (True/False)
                  sequence polg)  -- euphoria polygon seq
S_DrawPolyline(atom clr,             -- polyline colour
               sequence polyline,    -- polyline,"world" coords.
               integer n_dashes      -- False if no dashing,
                                     -- > 1 for # of dashes
              )
S_DrawPolylineClip(integer colour,  -- colour for polyline
                   sequence pline)  -- polyline sequence
S_DrawSequenceXor(atom xor_id,      -- bitmap/win drawen on
                  sequence pline,   -- n-point polyline to draw
                  atom fg           -- colour to draw it
                 )

Section 4. Pixmap Scrolling

function InitializeScroller(
           atom Targ_pmap,         -- handle of target pixmap
           atom ParentWin,         -- parent of target pixmap
           sequence PxPosn,        -- position for target on its parent
           atom Src_pmap,          -- handle of source pixmap (the pic to scroll)
           sequence ScrollFileSpec,-- spec of file containing scroll image.
           sequence ScrollFileSize,-- pixel size of scroll image {x,y}.
           sequence View,          -- rising diagonal of viewport.
           sequence Win            -- rising diagonal of World Window.
       )
Scroll( integer scroll_step -- May not be fractional.
                            -- scroll_step > 0 ==> scroll to left.
                            -- scroll_step < 0 ==> scroll to right.
        integer horizontal  -- w32True  to scroll horizontal;
                            -- w32False to scroll vertical.
       )

Returns: an increment of scrolling done and copied to Targ_pmap.

Note 1: Caller must execute InitializeScroller() once before calling Scroll(), the procedure that does the scrolling.

Note 2: Caller must execute a command like the following in order to SEE scrolling picture after executing a Scroll():

copyBlt( Window_id, id_x, id_y, TgtPixmap )

where TgtPixmap is the originator of Targ_pmap.

Note 3: if you want to use Scroll() and to draw on the resulting scrolled image, do your drawing on the pixmap that originated TargetPixmap. Keep your drawing objects simple, small and few! Objects that are too many or too complex may reproduce with image flicker.


Section 5. Key Frames

The only function relating to Key Frames about which, at this stage, I have any confidence is RenderKeyFrames(). All I have to offer in relation to it is the demo program Stick2.exw. In it a "stick" figure walks back and forth across the displayed picture. The walk has its origin in just 2 key-frame drawings of the stick figure in file stick.ew. The computer generates all the intermediate frames needed to make the stick figure transition smoothly between these 2 major poses of the figure.

Conclusion

There are lots of shortcomings and disorganisation in this documentation due mostly to my inexperience with eudoc and creole. At least it has enabled me to incorporate the documentation into the GSL2014 file, so that everything can be in the one place.

If you have any comments or suggestions about the package, or pick up any bugs which have escaped my attention, please contact me at: http://www.Manganfred6@gmail.com

Document generated with library programs eudoc.exe and creole.exe