[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
All interesting extensions take arguments passed from the main program
so that they can do different things depending on how they were
called. In the case of picture generators, these arguments are passed
from the Create Pictures from CXR (%I
) command.
Here we would like our SHAPE
extension to take several arguments. The
first argument will be an integer which specifies which shape to draw:
say 1 means circle, and 2 means square. Let's say that all squares will
be drawn of the same size, 50x50 pixels. A circle, however, will have
another argument, a radius. If the radius is nonzero, then a
circle with a radius of that many pixels is drawn.
If the radius is zero, then the circle is drawn with the
radius of the picture number. Remember that first argument you pass to
%I
is the number of pictures you want drawn. So, by specifying
%I[50,1,0]
we are asking Cogsys to generate 50 pictures, where the
first picture has a circle of radius 1, the second of radius 2, and so on.
By using the Multiframe Picture Display commands, you can show these
50 pictures in succession and create the animated effect of a growing circle.
So, let's see how we would write our shape.c
file.
We start with the standard extension header for a picture generator:
static void extension(unsigned char *A, unsigned char *arg) |
The header must be written exactly like this for all picture
generators. The function is called extension
, and it takes two
arguments (that are filled in by Cogsys): 1) a playground, called
A
, and 2) an argument buffer, arg
. Both are pointers to
unsigned char
. For maximum flexibility, they are untyped data
blocks that can be interpreted any way that's necessary.
The playground is the block of data that holds the picture data. Essentially,
all our extension will do is modify the array pointed to by A
.
The argument buffer arg
is the important one. By default, the
argument buffer is exactly 1 kilobyte (1,024 bytes). This can be changed
by the Cogsys developer via the Cogsys constant ARGBUF_SIZE
(see section Setting Cogsys Constants). The argument buffer comes with 4 values (totalling 10
bytes) already filled in:
DATASEG
| external function's data segment | |
SIZE
| size of playground | |
NUMPICS
| total number of pictures requested | |
NUM
| this picture's number |
The first value is discussed below under Data Segments. The next three values tell the extension
important information about how it is being called. SIZE
is a
long integer that gives the size of the playground; it tells us how big
A
is. In all of the picture generating extensions included with
Cogsys, Type 2 pictures are being displayed, which are 320x200 pixels, 1
byte per pixel, so SIZE
is usually 64,000. NUMPICS
is a
short
integer that indicates how many pictures were
requested. This correpsonds directly to the first argument the user gave
to %I
. Finally, NUM
tell us which of those NUMPICS
pictures we are currently generating.
Starting at the 10th byte, the contents of arg
are the values
that the user passed in the %I
command. Values are always one
of three types: 1) a four byte long
integer, or 2) a four byte float
(not
double
), or 3) a null-terminated string. Note specifically that
user-passed arguments are never short
integers.
So in the case of our shape extension, the array has at least one more entry:
SHAPETYPE
| circle or square subfunction selector |
Furthermore, if circle is selected, there is another entry for radius:
RADIUS
| raidus |
These values are all embedded in the arg
array, where they
are hard to access. Thus the first variables we declare in the
extension are usually size
, numpics
, and num
.
We then assign theese variables from the arg
buffer by
casting the unsigned char *
to a type *
(where
type is the type of the argument we're extracting) and then
dereferencing:
static void extension(unsigned char *A, unsigned char *arg) { long size; short numpics, num; /* Read in the standard arguments. */ size = *((long *) (arg+2)); numpics = *((short *) (arg+6)); num = *((short *) (arg+8)); } |
(If that looks scary, don't worry about it, just copy those lines
into the start of every extension you write and use size
,
numpics
, and num
as you would any integer.)
We can use similar code to access our shapetype
argument,
and set up the switch
structure. Inside the CIRCLE
case, we get the radius
argument, and if it's zero, adjust it
to be the picture number instead:
#define CIRCLE 1 #define SQUARE 2 static void extension(unsigned char *A, unsigned char *arg) { /* Standard arguments */ long size; short numpics, num; /* Custom arguments */ long shapetype, radius; /* Read in the standard arguments. */ size = *((long *) (arg+2)); numpics = *((short *) (arg+6)); num = *((short *) (arg+8)); shapetype = *((long *) (arg+10)); switch shapetype { case CIRCLE: radius = *((long *) (arg+14)); if (radius == 0) radius = num; break; case SQUARE: break; } } |
Strings can be handled similarly: let's say the first argument wasn't
an integer code that represented what type of shape to draw, but instead
a null-terminated ASCII string. The user would invoke the extension
with something like this: %I[1,CIRCLE,5]
. In the extension, we'd
extract the arguments like this:
char *shapestr; int len; ... shapestr = arg+10; /* no need for cast, arg is already ptr-to-char */ len = strlen(shapestr); radius = *((long *) (arg+10+len)); if (strcmp(shapestr,"CIRCLE"==0)) ... |
Of course, this technique isn't recommended for this case, because it takes more space and more time to process. But it is very important for extensions that display text, for example.
There is only one more important detail about argument passing that merits special attention:
The contents of the playground and the argument buffer are never reset by Cogsys.
This means that unless you want your image to be superimposed on the
last thing in the playground (which could very well be garbage), you
(that is, your extension) must explicitly reset all element of the
A
array to zero. It also means that you can deliberately
not reset the array to create cool superimposition effects.
Similarly, the argument buffer is only updated with values most recently
passed. For example, if a user creates a circle of radius 10 with our shape extension
with the command %I[1,1,10]
, and then creates a square with %I[1,2]
,
the value 10 is still present at location arg+14
. This provides a neat
means of passing values from one call of the extension to the next. A common
technique is to save values near the high end of the buffer, where they won't
ever get overwritten by a call to %I
which has longer arguments.
More importantly, even though error checking for extensions is not implemented in Cogsys 3.0.15, when it is, it will be through this mechanism. If the extension catches an error, it writes error information in the high end of the argument buffer, and exits. Create Pics from CXR will check the argument buffer for error status after every call to the extension. If it finds an error, it will raise a main Cogsys error, and the list will terminate cleanly.
Here, then is the almost-complete shape extension source file (it won't work until the code described in Data Segments, is added).
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |