Manganfred6@gmail.com
A 2-D graphics package.
Platform:
Euphoria 4 + Win32Lib.ew
PolyPic of "Howth Tram"
created with the DrawBust vector
drawing program.
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.
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:
S_DrawPolygon(); and
S_DrawPolyline()
for drawing a polyline as a polygon or as a polyline to a pixmap.
The earlier versions of GSL2014 had a procedure:
S_DrawPolyPic()
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
ability to activate/deactivate the drawing of a PolyPic,
capacity to specify a predetermined sprite-like motion for a PolyPic.
capacity to associate with a PolyPic text which will automatically display beside it on screen.
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.
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.
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.
Using drawing primitives S_DrawPolyline() or S_DrawPolygon() - or their Clip variants. This method is described at "Section 3. Polylines and Polygons" below.
Using PolyPics constructed by your program or imported from the drawing program DrawBust.exe. A polypic is a Euphoria sequence structure used in earlier EuWinGUI versions of GSL2014. PolyPic structures are greatly expanded in scope in this version and many functions for manipulating them have been added. PolyPics and their expansion is described at "Section 1. PolyPics" below.
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 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.
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.
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):
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.
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.
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.
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.
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).
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.
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.
All the demos are animations of varying complexity.
Note that Install instructions are in a text file in the Include folder.
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.
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.
GraphPlotter.exw:
An
old EuWinGUI program converted to Win32Lib that draws user's
typed-in maths functions and uses scaled drawing for graphical
output.
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).
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.
These examples have some of the rigidity of OOP, but there is flexibility to let your program contribute to the graphic effects.
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.
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 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.
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.
polypic_dep : Only old style deprecated polypics conform to this type.
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.
S_DrawPolygon(): draws a polygon on current pixmap; caller should setPenWidth() as needed before call:
S_DrawPolygon(atom clr, -- colour for the polygon atom fill, -- to be filled? (True/False) sequence polgon -- polygon, in world coords. )
S_DrawPolygonClip(): a clipping variant of S_DrawPolygon().
S_DrawPolygonClip(integer colour, -- colour for polygon integer fill, -- fill? (True/False) sequence polg) -- euphoria polygon seq
S_DrawPolyline(): draws a polyline on current pixmap; caller should setPenWidth() as needed before call:
S_DrawPolyline(atom clr, -- polyline colour sequence polyline, -- polyline,"world" coords. integer n_dashes -- False if no dashing, -- > 1 for # of dashes )
S_DrawPolylineClip(): a clipping variant of S_DrawPolyline():
S_DrawPolylineClip(integer colour, -- colour for polyline sequence pline) -- polyline sequence
S_DrawSequenceXor(): Draws polyline in pline in colour fg, with XORing; coordinates in pline should be machine coordinates.
S_DrawSequenceXor(atom xor_id, -- bitmap/win drawen on sequence pline, -- n-point polyline to draw atom fg -- colour to draw it )
InitializeScroller(): This function should be called soon after creation of the Window where the scrolling is to appear and drawing is to be done. This generates ALL the references needed for accessibility to TargetPixmap by the S_DrawPolygon(), S_DrawPolyline() and S_DrawPolyPic() routines. InitializeScroller() itself calls InitializePixDraw(), leaving your program ready to accept real world drawing over a scrolling image. Returns: The system set up for scrolling by calls to Scroll(). The caller can do scaled drawing via his/her copy of Targ_pmap handle:
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(): Does one step of scrolling and then returns to caller. Repeated calls to Scroll() from a procedure triggered by a Timer event will scroll the source pixmap image across the target pixmap on which the caller, from the triggered procedure, can draw, if wished, after each scroll step and before forcing display.
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.
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.
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