home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
No Fragments Archive 10: Diskmags
/
nf_archive_10.iso
/
MAGS
/
AT_WORLD
/
ATRIW1.MSA
/
DARKLORD.S13_MODULES_MODULES.TXT
< prev
next >
Wrap
Text File
|
1994-02-26
|
17KB
|
423 lines
Writing your own modules for the DarkLord screen saver
1. Basic rules for modules written in C
Writing external add-on modules for DarkLord is straightforward.
Modules can be written in assembly language or `C'. If you are writing
in C, then the Lattice C 5 compiler is recommended (if not essential)
because fine control is needed over the code which is generated.
All the modules included in this package have been written in C, and
the source code is included for two of them, as examples. Writing
modules in C is easy, but you need to follow certain rules. These are:
1.1
You must not use the AES in your module. In fact there is no need to
do so; the AES is used for interaction with the user, which more or
less by definition is not something you do with a screen saver once it
starts up. You can (and probably will) use the VDI, subject to certain
restrictions listed below.
1.2
There is no need to call appl_init(), as you would normally do in a
GEM program. It won't do any harm, but having called appl_init() you
would normally call appl_exit() at the end of a program. If you do
this with a DarkLord module, the machine will hang, so don't do it.
1.3
You must not try to reserve any memory with malloc(), the internal
memory manager function, nor call any function that will do so. This
includes v_opnvwk(), the call to open a virtual workstation. There is
no need to call this as DarkLord passes your module a valid
workstation handle, which you should use.
Any memory requirements your module has should be contained within the
memory space available to it (currently there is a total of 32K
available, which should be ample). Use arrays if you need to reserve a
block of memory.
I have tried to investigate the use of the GEMDOS function Malloc() to
gain extra, temporary memory for when very large amounts are needed.
This seems to work provided that the module calls Mfree() for any
requested memory before returning control to DarkLord.
1.4
You should include in your C modules the header file "mod_head.h"
supplied with this package. This contains the structure definitions
for the structure which is passed as a parameter to your module.
1.5
Your module must have a main() function as usual, for which the
function prototype is:
int main(DKL_INFO *);
This prototype is provided in the header file "mod_head.h" so you
don't need to type in this definition if you have included the header
file.
On entry to the main() function, the parameter is a pointer to a data
structure containing certain information used by the module. The
nature and contents of this structure is given in the header file
"mod_head.h" and is explained in detail below.
The DKL_INFO structure contains most of the usual information you will
need concerning the screen resolution, number of bitplanes, etc. If
you need more you can always call vq_extnd().
The structure also contains the values of the variables and flags (if
any) used by the module and which can be changed by the user via the
DarkLord Control Panel. Your module should extract whichever of those
values it needs from the structure.
1.6
The module should terminate with a return statement (returning an
integer) and a simple closing brace at the end of the main() function
(the compiler will generate an RTS instruction when it finds this). DO
NOT use exit(), Pterm(), appl_exit() or any other program termination
function on exiting - just let the module terminate gracefully.
1.7
All source code sections of your module should be compiled in the
following way:
- disable stack checking for all C modules;
- compile all modules to use default far code and default far data
(i.e. non-base relative, full 32-bit addressing, compiler option
-b0). This is because the global data register a4 cannot be set up
to point to your program's data and BSS areas. If you are using
Lattice C, the linker will automatically use the correct libraries
(lcnb.lib, lcgnb.lib, etc).
- link with no startup code (in Lattice, do this by selecting the
`Executable...' menu entry from Options menu in the compiler's
integrated editor, and select `None' from the program type).
- your module must use 32-bit integers, don't use the `default
short integer' option in Lattice.
- the module must be given an extender `.DMO' rather than .PRG
(the Construction Kit looks for .DMO files when you include a
module filename in a .DKL file. In any case, the last thing you
want is someone double-clicking on a module file thinking it's an
executable!).
1.8
Your module should be so written that it will work in any screen
resolution. This has always been good practice, but is critical
nowadays with the plethora of screen resolutions available on the
Falcon. If your module genuinely cannot be made to work effectively in
certain video modes, you can set the screen resolution flag
appropriately in the controlling .DKL file using the DarkLord
Construction Kit. DarkLord will not call a module which will not
function in a particular resolution. (See the Kit's manual for more
details).
1.9
Finally, and very importantly, how does your module know when it's
time to stop? One of the structure elements passed to the module in
the DKL_INFO structure is a pointer to a flag which the main DarkLord
program maintains under interrupt control. Your program should poll
this flag at frequent and regular intervals. As long as it is non-
zero, the module should continue to operate; as soon as it is zeroed,
it should terminate.
The simplest possible shell in C for a DarkLord module would therefore
look like this:
/* ------------------------------------------------------------ */
#include "mod_head.h"
int *exit_flag;
int main(DKL_INFO *info)
{
exit_flag=info->dklord_flag;
while(*exit_flag) {
/* as long as the flag is non_zero */
/* do your thing here */
}
return(0);
/* return an int */
}
/* ------------------------------------------------------------ */
This module would function, but all it would do is loop until
something happened (e.g. a keypress) which sets the flag to zero. This
is handled by interrupts and is independent of the module.
2. Module termination
2.1 Your module can terminate of its own accord, without the exit flag
having been cleared, if you wish. If this happens, DarkLord will
restore the screen and then re-execute your module from scratch. An
example of this is the module `SPOTS.DMO' included in the package. If
you look at the source code, you will see that, if flag 2 in the
DarkLord Control Panel is set appropriately, this module will draw a
circle 2,000 times and then terminate. As far as DarkLord itself is
concerned however, nothing has happened to make it return control to
the AES, so it will simply re-execute the module. This can be quite
useful if you have a module which alters the screen to such an extent
that it can go no further without restoring it and starting again.
If your module does this, note that any variables used in your module
are not guaranteed to keep their value between one call to the module
and the next. Any initialised data which was included in your module
WILL be left unchanged (for example, if you include bit image data for
a picture).
DarkLord itself handles the saving and restoring of the screen, the
module can forget about this.
2.2 The module MUST return an int to DarkLord. Normally it would
return a zero, which DarkLord interprets to mean that the module was
executed without problems. In some cases your module may not be able
to execute - perhaps it needed GDOS, or some other feature was
missing. In this case the module should put a null-terminated error
string into the element dk_errmes of the information structure, and
return a non-zero number to DarkLord. DarkLord will then display an
alert box to tell the user what has happened; the error message
generated by the module will appear in this alert box.
In a mixture of pseudocode and C this might go something like this:
enter main() function
check values in information structure
if(some condition) {
strpcy(info->dk_errmes, "An error occurred");
return 1;
}
else {
execute rest of module
}
return 0;
Important - the message MUST NOT be more than 30 characters long or
you may overwrite something essential!
3. Using assembly language
Writing modules in assembly language is even simpler if anything,
because you don't have to worry about what the compiler does to your
code. You should note the following points in addition to the general
points made in sections 1 and 2 above:
- you can use any registers, DarkLord will save and restore them
for you.
- it is probably best to allocate your own stack and restore the
stack pointer just before termination. Otherwise you will be using
DarkLord's stack, and if you corrupt it or mishandle the stack
pointer a crash is inevitable.
- you will need to allocate your own VDI parameter block if using
the VDI, but you can use the workstation handle passed to the
module.
- your module should terminate by moving a 32-bit value into d0
and end with an RTS.
4. The information structure
The information structure, the address of which is passed as a
parameter to the module, contains the following information. In this
list, an int is 4 bytes long, a short 2 bytes, and pointers of course
are always 4 bytes. After the C definition the offset in bytes from
the start of the data structure is given for the benefit of assembly
language programmers.
short dk_xres (offset 0)
The screen width in pixels; e.g. 640 in ST high or medium resolution;
the screen VDI coordinates would run from 0 to dk_xres-1.
short dk_yres (offset 2)
The screen height in pixels; e.g. 200 in ST medium resolution; the
screen VDI coordinates would run from 0 to dk_yres-1.
short dk_handle (offset 4)
The VDI workstation handle to use for VDI screen output.
short dk_pens (offset 6)
The number of different colour pens available to the VDI (2 in ST
high, 4 in ST medium, and 16 in ST low resolutions); note that Falcon
True Colour returns 256.
short dk_colsloaded (offset 8)
The number of colours contained in the palette loaded as part of the
.DKL file; possible values are: 0, 2, 4, 16, 256.
short dk_planes (offset 10)
The number of bitplanes in the current screen mode; possible values
include 1 (ST high or Falcon 2-colour modes), 2 (ST medium or Falcon
4-colour modes), 4 (ST low or Falcon 16-colour modes), 8 (Falcon 256-
colour modes); note that Falcon True Colour mode returns 16, even
though it does not use a bitplane screen structure.
int tc_flag (offset 12)
If set to 1, the machine is in a True Colour mode (in fact any mode
which does not support a colour palette lookup table, of which True
Colour is probably the commonest); if zero, a colour palette lookup
table is supported; this is important because in the absence of a
lookup table animation by colour cycling is not possible.
int *dklord_flag (offset 16)
A pointer to the flag maintained by DarkLord itself under interrupt
control; set to 1 on entry to the module, modules should poll this
flag regularly and terminate if it becomes zero.
int *counter (offset 20)
A pointer to a countdown timer maintained by DarkLord's VBI routine;
store any positive value in this counter and it will be decremented by
1 each vertical blank interval until it reaches zero; useful in
slowing down very fast graphic effects.
short *loaded_palette (offset 24)
A pointer to the colour palette data loaded as part of the .DKL file
so that it can be accessed (for colour cycling, for example); check
dk_colsloaded to see how many colours were in fact loaded; each colour
is stored as a VDI colour, using 3 shorts for the red, green, and blue
components of the colour; a palette consisting of 16 loaded colours
would contain 96 bytes of data (16 * 3 * 2 bytes).
void *screen_ram (offset 28)
A pointer to the screen memory as returned by Logbase().
unsigned long gdos (offset 32)
A flag indicating whether GDOS is loaded, and if so what type;
possible values are: 0xfffffffe = no GDOS; 0x5f46534d = FSM or
SpeedoGDOS; 0x5f464e54 = FontGDOS; any other value = `ordinary' GDOS
or clones such as G+Plus (these values are given in the file vdi.h
supplied with Lattice C 5.6).
int dk_flag1 (offset 36)
The user-selected state for flag 1 (if there is a flag 1); ranges from
1 to 6.
int dk_flag2 (offset 40)
As for dk_flag1.
int dk_flag3 (offset 44)
As for dk_flag1.
int dk_min1 (offset 48)
The minimum possible value for variable 1, if there is a variable 1;
this value is set by the programmer in the .DKL file and is not user-
alterable.
int dk_max1 (offset 52)
The maximum possible value for variable 1, if there is a variable 1;
this value is set by the programmer in the .DKL file and is not user-
alterable.
int dk_start1 (offset 56)
The actual value of variable 1, as set by the user (if the variable
exists); ranges from dk_min1 to dk_max1.
int dk_min2 (offset 60)
As for dk_min1.
int dk_max2 (offset 64)
As for dk_max1.
int dk_start2 (offset 68)
As for dk_start1.
int dk_min3 (offset 72)
As for dk_min1.
int dk_max3 (offset 76)
As for dk_max1.
int dk_start3 (offset 80)
As for dk_start1.
char *dk_line1 (offset 84)
Pointer to the first line of a user-entered message (if any); by
default this is a blank string with ASCII NULL as its first character.
char *dk_line2 (offset 88)
Pointer to the second line of a user-entered message (if any).
char *dk_line3 (offset 92)
Pointer to the third line of a user-entered message (if any).
char dk_errmes[35] (offset 96)
Storage area for an error message to be returned by the module to
DarkLord if required; the module must return a non-zero value for this
error message to be displayed; the length of the message MUST NOT
exceed 30 bytes and MUST be null-terminated.
char *dk_fontname (offset 132)
A pointer to the name of a GDOS font entered by the user. This font
will be used by some modules to display on-screen text.
5. Using maths libraries in C modules
The standard Lattice maths libraries expect certain internal variables
to be provided as placeholders for the library routines. These are
normally provided as part of the C startup routine, and if the linker
can't find them (because, of course, you will have deliberately chosen
not to link in a startup stub) then it will abort with a `Symbol not
found' error.
If this happens and you have to use the maths routines, try assembling
and linking the file mathlink.s (provided with this package) in your
project. This just supplies placeholders for the missing variables.
Note that you cannot expect math error functions to work properly, so
make sure that you don't generate underflow or overflow errors.
Likewise, forget about using a maths co-processor.
If using mathlink.s doesn't solve the problem, try looking for the
missing symbol in the C startup code supplied with Lattice. It may be
possible to simply add this to the mathlink.s file, but in some cases
this may not work.
6. Debugging modules
This is something of a problem because DarkLord modules cannot be run
from the Desktop or a debugger in the usual way - they can only be run
from DarkLord itself.
In order to debug a module you need to do the following things:
- enable the module debug facility by altering the .DKL file which
loads the module (see the manual for the DarkLord Construction
Kit);
- run your favourite debugger;
- load DARKLOR3.PRG and run it;
- load the .DKL file, which in turn will load the module you wish
to debug;
- select the `Debug' button in DarkLord's Toolbox dialog so that
it is highlighted;
- turn keyboard monitoring OFF (or you won't be able to use the
debugger without causing the module to terminate!); from now on,
don't move the mouse or click the mouse buttons while stepping
through the module code as this will cause the module to
terminate;
- execute the module by clicking on the `Activate' button in the
DarkLord control panel.
When you activate the module, if the Debug button is selected DarkLord
will stop with an `illegal' exception. At this point you will see that
the next instruction is `jsr (a0)' which is the instruction which
actually transfers control to the module. The next instruction to
execute after the jsr is the first one in your module.
Note that symbolic debugging is not possible because the debugger has
no way of geting access to your module's symbol table.
7. Loading and executing your module
One final point - don't forget that in order to use your new module,
you must generate a matching .DKL file from the Construction Kit. The
minimum requirement in the .DKL file is the name of the DMO file to
load, but you can of course include whatever other parameters are
required.