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 >
Text File  |  1994-02-26  |  17KB  |  423 lines

  1. Writing your own modules for the DarkLord screen saver
  2.  
  3. 1. Basic rules for modules written in C
  4.  
  5. Writing external add-on modules for DarkLord is straightforward.
  6. Modules can be written in assembly language or `C'. If you are writing
  7. in C, then the Lattice C 5 compiler is recommended (if not essential)
  8. because fine control is needed over the code which is generated.
  9.  
  10. All the modules included in this package have been written in C, and
  11. the source code is included for two of them, as examples. Writing
  12. modules in C is easy, but you need to follow certain rules. These are:
  13.  
  14. 1.1
  15. You must not use the AES in your module. In fact there is no need to
  16. do so; the AES is used for interaction with the user, which more or
  17. less by definition is not something you do with a screen saver once it
  18. starts up. You can (and probably will) use the VDI, subject to certain
  19. restrictions listed below.
  20.  
  21. 1.2
  22. There is no need to call appl_init(), as you would normally do in a
  23. GEM program. It won't do any harm, but having called appl_init() you
  24. would normally call appl_exit() at the end of a program. If you do
  25. this with a DarkLord module, the machine will hang, so don't do it.
  26.  
  27. 1.3
  28. You must not try to reserve any memory with malloc(), the internal
  29. memory manager function, nor call any function that will do so. This
  30. includes v_opnvwk(), the call to open a virtual workstation. There is
  31. no need to call this as DarkLord passes your module a valid
  32. workstation handle, which you should use.
  33.  
  34. Any memory requirements your module has should be contained within the
  35. memory space available to it (currently there is a total of 32K
  36. available, which should be ample). Use arrays if you need to reserve a
  37. block of memory.
  38.  
  39. I have tried to investigate the use of the GEMDOS function Malloc() to
  40. gain extra, temporary memory for when very large amounts are needed.
  41. This seems to work provided that the module calls Mfree() for any
  42. requested memory before returning control to DarkLord.
  43.  
  44. 1.4
  45. You should include in your C modules the header file "mod_head.h"
  46. supplied with this package. This contains the structure definitions
  47. for the structure which is passed as a parameter to your module.
  48.  
  49. 1.5
  50. Your module must have a main() function as usual, for which the
  51. function prototype is:
  52.  
  53.     int main(DKL_INFO *);
  54.  
  55. This prototype is provided in the header file "mod_head.h" so you
  56. don't need to type in this definition if you have included the header
  57. file.
  58.  
  59. On entry to the main() function, the parameter is a pointer to a data
  60. structure containing certain information used by the module. The
  61. nature and contents of this structure is given in the header file
  62. "mod_head.h" and is explained in detail below.
  63.  
  64. The DKL_INFO structure contains most of the usual information you will
  65. need concerning the screen resolution, number of bitplanes, etc. If
  66. you need more you can always call vq_extnd().
  67.  
  68. The structure also contains the values of the variables and flags (if
  69. any) used by the module and which can be changed by the user via the
  70. DarkLord Control Panel. Your module should extract whichever of those
  71. values it needs from the structure.
  72.  
  73. 1.6
  74. The module should terminate with a return statement (returning an
  75. integer) and a simple closing brace at the end of the main() function
  76. (the compiler will generate an RTS instruction when it finds this). DO
  77. NOT use exit(), Pterm(), appl_exit() or any other program termination
  78. function on exiting - just let the module terminate gracefully.
  79.  
  80. 1.7
  81. All source code sections of your module should be compiled in the
  82. following way:
  83.  
  84.     - disable stack checking for all C modules;
  85.  
  86.     - compile all modules to use default far code and default far data
  87.     (i.e. non-base relative, full 32-bit addressing, compiler option
  88.     -b0). This is because the global data register a4 cannot be set up
  89.     to point to your program's data and BSS areas. If you are using
  90.     Lattice C, the linker will automatically use the correct libraries
  91.     (lcnb.lib, lcgnb.lib, etc).
  92.  
  93.     - link with no startup code (in Lattice, do this by selecting the
  94.     `Executable...' menu entry from Options menu in the compiler's
  95.     integrated editor, and select `None' from the program type).
  96.  
  97.     - your module must use 32-bit integers, don't use the `default
  98.     short integer' option in Lattice.
  99.  
  100.     - the module must be given an extender `.DMO' rather than .PRG
  101.     (the Construction Kit looks for .DMO files when you include a
  102.     module filename in a .DKL file. In any case, the last thing you
  103.     want is someone double-clicking on a module file thinking it's an
  104.     executable!).
  105.  
  106. 1.8
  107. Your module should be so written that it will work in any screen
  108. resolution. This has always been good practice, but is critical
  109. nowadays with the plethora of screen resolutions available on the
  110. Falcon. If your module genuinely cannot be made to work effectively in
  111. certain video modes, you can set the screen resolution flag
  112. appropriately in the controlling .DKL file using the DarkLord
  113. Construction Kit. DarkLord will not call a module which will not
  114. function in a particular resolution. (See the Kit's manual for more
  115. details).
  116.  
  117. 1.9
  118. Finally, and very importantly, how does your module know when it's
  119. time to stop? One of the structure elements passed to the module in
  120. the DKL_INFO structure is a pointer to a flag which the main DarkLord
  121. program maintains under interrupt control. Your program should poll
  122. this flag at frequent and regular intervals. As long as it is non-
  123. zero, the module should continue to operate; as soon as it is zeroed,
  124. it should terminate.
  125.  
  126. The simplest possible shell in C for a DarkLord module would therefore
  127. look like this:
  128.  
  129. /* ------------------------------------------------------------ */
  130. #include "mod_head.h"
  131.  
  132. int *exit_flag;
  133.  
  134. int main(DKL_INFO *info)
  135. {
  136.     exit_flag=info->dklord_flag;
  137.     while(*exit_flag) {
  138.          /* as long as the flag is non_zero */
  139.          /* do your thing here */
  140.     }
  141.     return(0);
  142.     /* return an int */
  143. }
  144. /* ------------------------------------------------------------ */
  145. This module would function, but all it would do is loop until
  146. something happened (e.g. a keypress) which sets the flag to zero. This
  147. is handled by interrupts and is independent of the module.
  148.  
  149. 2. Module termination
  150.  
  151. 2.1 Your module can terminate of its own accord, without the exit flag
  152. having been cleared, if you wish. If this happens, DarkLord will
  153. restore the screen and then re-execute your module from scratch. An
  154. example of this is the module `SPOTS.DMO' included in the package. If
  155. you look at the source code, you will see that, if flag 2 in the
  156. DarkLord Control Panel is set appropriately, this module will draw a
  157. circle 2,000 times and then terminate. As far as DarkLord itself is
  158. concerned however, nothing has happened to make it return control to
  159. the AES, so it will simply re-execute the module. This can be quite
  160. useful if you have a module which alters the screen to such an extent
  161. that it can go no further without restoring it and starting again.
  162.  
  163. If your module does this, note that any variables used in your module
  164. are not guaranteed to keep their value between one call to the module
  165. and the next. Any initialised data which was included in your module
  166. WILL be left unchanged (for example, if you include bit image data for
  167. a picture).
  168.  
  169. DarkLord itself handles the saving and restoring of the screen, the
  170. module can forget about this.
  171.  
  172. 2.2 The module MUST return an int to DarkLord. Normally it would
  173. return a zero, which DarkLord interprets to mean that the module was
  174. executed without problems. In some cases your module may not be able
  175. to execute - perhaps it needed GDOS, or some other feature was
  176. missing. In this case the module should put a null-terminated error
  177. string into the element dk_errmes of the information structure, and
  178. return a non-zero number to DarkLord. DarkLord will then display an
  179. alert box to tell the user what has happened; the error message
  180. generated by the module will appear in this alert box.
  181.  
  182. In a mixture of pseudocode and C this might go something like this:
  183.  
  184.     enter main() function
  185.     check values in information structure
  186.     if(some condition) {
  187.          strpcy(info->dk_errmes, "An error occurred");
  188.          return 1;
  189.     }
  190.     else {
  191.          execute rest of module
  192.     }
  193.     return 0;
  194.  
  195. Important - the message MUST NOT be more than 30 characters long or
  196. you may overwrite something essential!
  197.  
  198. 3. Using assembly language
  199.  
  200. Writing modules in assembly language is even simpler if anything,
  201. because you don't have to worry about what the compiler does to your
  202. code. You should note the following points in addition to the general
  203. points made in sections 1 and 2 above:
  204.  
  205.     - you can use any registers, DarkLord will save and restore them
  206.     for you.
  207.  
  208.     - it is probably best to allocate your own stack and restore the
  209.     stack pointer just before termination. Otherwise you will be using
  210.     DarkLord's stack, and if you corrupt it or mishandle the stack
  211.     pointer a crash is inevitable.
  212.  
  213.     - you will need to allocate your own VDI parameter block if using
  214.     the VDI, but you can use the workstation handle passed to the
  215.     module.
  216.  
  217.     - your module should terminate by moving a 32-bit value into d0
  218.     and end with an RTS.
  219.  
  220. 4. The information structure
  221.  
  222. The information structure, the address of which is passed as a
  223. parameter to the module, contains the following information. In this
  224. list, an int is 4 bytes long, a short 2 bytes, and pointers of course
  225. are always 4 bytes. After the C definition the offset in bytes from
  226. the start of the data structure is given for the benefit of assembly
  227. language programmers.
  228.  
  229. short dk_xres (offset 0)
  230. The screen width in pixels; e.g. 640 in ST high or medium resolution;
  231. the screen VDI coordinates would run from 0 to dk_xres-1.
  232.  
  233. short dk_yres (offset 2)
  234. The screen height in pixels; e.g. 200 in ST medium resolution; the
  235. screen VDI coordinates would run from 0 to dk_yres-1.
  236.  
  237. short dk_handle (offset 4)
  238. The VDI workstation handle to use for VDI screen output.
  239.  
  240. short dk_pens (offset 6)
  241. The number of different colour pens available to the VDI (2 in ST
  242. high, 4 in ST medium, and 16 in ST low resolutions); note that Falcon
  243. True Colour returns 256.
  244.  
  245. short dk_colsloaded (offset 8)
  246. The number of colours contained in the palette loaded as part of the
  247. .DKL file; possible values are: 0, 2, 4, 16, 256.
  248.  
  249. short dk_planes (offset 10)
  250. The number of bitplanes in the current screen mode; possible values
  251. include 1 (ST high or Falcon 2-colour modes), 2 (ST medium or Falcon
  252. 4-colour modes), 4 (ST low or Falcon 16-colour modes), 8 (Falcon 256-
  253. colour modes); note that Falcon True Colour mode returns 16, even
  254. though it does not use a bitplane screen structure.
  255.  
  256. int tc_flag (offset 12)
  257. If set to 1, the machine is in a True Colour mode (in fact any mode
  258. which does not support a colour palette lookup table, of which True
  259. Colour is probably the commonest); if zero, a colour palette lookup
  260. table is supported; this is important because in the absence of a
  261. lookup table animation by colour cycling is not possible.
  262.  
  263. int *dklord_flag (offset 16)
  264. A pointer to the flag maintained by DarkLord itself under interrupt
  265. control; set to 1 on entry to the module, modules should poll this
  266. flag regularly and terminate if it becomes zero.
  267.  
  268. int *counter (offset 20)
  269. A pointer to a countdown timer maintained by DarkLord's VBI routine;
  270. store any positive value in this counter and it will be decremented by
  271. 1 each vertical blank interval until it reaches zero; useful in
  272. slowing down very fast graphic effects.
  273.  
  274. short *loaded_palette (offset 24)
  275. A pointer to the colour palette data loaded as part of the .DKL file
  276. so that it can be accessed (for colour cycling, for example); check
  277. dk_colsloaded to see how many colours were in fact loaded; each colour
  278. is stored as a VDI colour, using 3 shorts for the red, green, and blue
  279. components of the colour; a palette consisting of 16 loaded colours
  280. would contain 96 bytes of data (16 * 3 * 2 bytes).
  281.  
  282. void *screen_ram (offset 28)
  283. A pointer to the screen memory as returned by Logbase().
  284.  
  285. unsigned long gdos (offset 32)
  286. A flag indicating whether GDOS is loaded, and if so what type;
  287. possible values are: 0xfffffffe = no GDOS; 0x5f46534d = FSM or
  288. SpeedoGDOS; 0x5f464e54 = FontGDOS; any other value = `ordinary' GDOS
  289. or clones such as G+Plus (these values are given in the file vdi.h
  290. supplied with Lattice C 5.6).
  291.  
  292. int dk_flag1 (offset 36)
  293. The user-selected state for flag 1 (if there is a flag 1); ranges from
  294. 1 to 6.
  295.  
  296. int dk_flag2 (offset 40)
  297. As for dk_flag1.
  298.  
  299. int dk_flag3 (offset 44)
  300. As for dk_flag1.
  301.  
  302. int dk_min1 (offset 48)
  303. The minimum possible value for variable 1, if there is a variable 1;
  304. this value is set by the programmer in the .DKL file and is not user-
  305. alterable.
  306.  
  307. int dk_max1 (offset 52)
  308. The maximum possible value for variable 1, if there is a variable 1;
  309. this value is set by the programmer in the .DKL file and is not user-
  310. alterable.
  311.  
  312. int dk_start1 (offset 56)
  313. The actual value of variable 1, as set by the user (if the variable
  314. exists); ranges from dk_min1 to dk_max1.
  315.  
  316. int dk_min2 (offset 60)
  317. As for dk_min1.
  318.  
  319. int dk_max2 (offset 64)
  320. As for dk_max1.
  321.  
  322. int dk_start2 (offset 68)
  323. As for dk_start1.
  324.  
  325. int dk_min3 (offset 72)
  326. As for dk_min1.
  327.  
  328. int dk_max3 (offset 76)
  329. As for dk_max1.
  330.  
  331. int dk_start3 (offset 80)
  332. As for dk_start1.
  333.  
  334. char *dk_line1 (offset 84)
  335. Pointer to the first line of a user-entered message (if any); by
  336. default this is a blank string with ASCII NULL as its first character.
  337.  
  338. char *dk_line2 (offset 88)
  339. Pointer to the second line of a user-entered message (if any).
  340.  
  341. char *dk_line3 (offset 92)
  342. Pointer to the third line of a user-entered message (if any).
  343.  
  344. char dk_errmes[35] (offset 96)
  345. Storage area for an error message to be returned by the module to
  346. DarkLord if required; the module must return a non-zero value for this
  347. error message to be displayed; the length of the message MUST NOT
  348. exceed 30 bytes and MUST be null-terminated.
  349.  
  350. char *dk_fontname (offset 132)
  351. A pointer to the name of a GDOS font entered by the user. This font
  352. will be used by some modules to display on-screen text.
  353.  
  354. 5. Using maths libraries in C modules
  355.  
  356. The standard Lattice maths libraries expect certain internal variables
  357. to be provided as placeholders for the library routines. These are
  358. normally provided as part of the C startup routine, and if the linker
  359. can't find them (because, of course, you will have deliberately chosen
  360.  
  361. not to link in a startup stub) then it will abort with a `Symbol not
  362. found' error.
  363.  
  364. If this happens and you have to use the maths routines, try assembling
  365. and linking the file mathlink.s (provided with this package) in your
  366. project. This just supplies placeholders for the missing variables.
  367. Note that you cannot expect math error functions to work properly, so
  368. make sure that you don't generate underflow or overflow errors.
  369. Likewise, forget about using a maths co-processor.
  370.  
  371. If using mathlink.s doesn't solve the problem, try looking for the
  372. missing symbol in the C startup code supplied with Lattice. It may be
  373. possible to simply add this to the mathlink.s file, but in some cases
  374. this may not work.
  375.  
  376. 6. Debugging modules
  377.  
  378. This is something of a problem because DarkLord modules cannot be run
  379. from the Desktop or a debugger in the usual way - they can only be run
  380. from DarkLord itself.
  381.  
  382. In order to debug a module you need to do the following things:
  383.  
  384.     - enable the module debug facility by altering the .DKL file which
  385.     loads the module (see the manual for the DarkLord Construction
  386.     Kit);
  387.  
  388.     - run your favourite debugger;
  389.  
  390.     - load DARKLOR3.PRG and run it;
  391.  
  392.     - load the .DKL file, which in turn will load the module you wish
  393.     to debug;
  394.  
  395.     - select the `Debug' button in DarkLord's Toolbox dialog so that
  396.     it is highlighted;
  397.  
  398.     - turn keyboard monitoring OFF (or you won't be able to use the
  399.     debugger without causing the module to terminate!); from now on,
  400.     don't move the mouse or click the mouse buttons while stepping
  401.     through the module code as this will cause the module to
  402.     terminate;
  403.  
  404.     - execute the module by clicking on the `Activate' button in the
  405.     DarkLord control panel.
  406.  
  407. When you activate the module, if the Debug button is selected DarkLord
  408. will stop with an `illegal' exception. At this point you will see that
  409. the next instruction is `jsr (a0)' which is the instruction which
  410. actually transfers control to the module. The next instruction to
  411. execute after the jsr is the first one in your module.
  412.  
  413. Note that symbolic debugging is not possible because the debugger has
  414. no way of geting access to your module's symbol table.
  415.  
  416. 7. Loading and executing your module
  417.  
  418. One final point - don't forget that in order to use your new module,
  419. you must generate a matching .DKL file from the Construction Kit. The
  420. minimum requirement in the .DKL file is the name of the DMO file to
  421. load, but you can of course include whatever other parameters are
  422. required.
  423.