Author Topic: Sprite Library Revisited  (Read 2309 times)

Offline TerryRitchie

  • Semper Fidelis
Sprite Library Revisited
« on: September 06, 2018, 01:44:41 AM »
[UPDATE:] This now contains the new sprite library work in progress.

Original post below

I'm currently in the process of updating my sprite library to take advantage of new features available in QB64 that were not present in 2012 when I wrote the library. I also want to enhance the collision detection routines (and finally get a fully working pixel perfect detection routine as well). One problem when working with sprite sheets is that every sprite needs to be the same size. As an example look below at the sprite sheet I created of a TR3B UFO a few days ago. Each sprite is 266x266 in size, however there is a lot of wasted space on many of them, especially the sprites in the middle. This not only takes up RAM but does not play well with collision detection as two dead spaces can trigger a collision when the images contained within did not actually touch. I purposely designed this sprite sheet to see if I could overcome these issues.

Below is some proof of concept code I wrote that detects the image within each sprite, cuts each individual sprite down to its minimum size, then saves an x,y offset value so the sprites can be successfully lined up later even though they are wildly different in size. This should allow rectangular collision detection to be much more accurate and the memory used by the sprites much less.

Keep in mind, the code is sloppy and will need to be cleaned up but I wanted to get other's opinion on this. Do you think I am on the right track or is there a better way of achieving this that I need to know about? Could my image detection routine be done simpler or in a better manner?

Code: QB64 [Select]
  1. '*
  2. '* constants used with SL_FLIP_SPRITE subroutine
  3. '*
  4.  
  5. CONST SL_NOFLIP = 0
  6. CONST SL_HORIZONTAL = 1
  7. CONST SL_VERTICAL = 2
  8. CONST SL_FLIPBOTH = 3
  9.  
  10. '*
  11. '* constants used with SL_NEW_SPRITE_SHEET function
  12. '*
  13.  
  14. CONST SL_SHEETTRANSPARENCY = -1 '       use sheet's transparency info (.PNG)
  15. CONST SL_SETTRANSPARENCY = 0 '          manually set transparency
  16. CONST SL_NOTRANSPARENCY = 1 '           don't use transparency with sheet
  17.  
  18. '*
  19. '* constants used with SL_NEW_SPRITE function
  20. '*
  21.  
  22. CONST SL_NOSAVE = 0 '                   sprite will not save background
  23. CONST SL_SAVE = -1 '                    sprite will save background
  24.  
  25.  
  26. '*
  27. '* type declarations
  28. '*
  29.  
  30. TYPE SL_SHEET ' *********************** sprite sheet database ***************************************
  31.     image AS LONG '                     software sprite image
  32.     mask AS LONG '                      software mask image
  33.     spritewidth AS INTEGER '            width of sprite
  34.     spriteheight AS INTEGER '           height of sprite
  35.     collx1 AS INTEGER '                 collision box top left x
  36.     colly1 AS INTEGER '                 collision box top left y
  37.     collx2 AS INTEGER '                 collision box bottom right x
  38.     colly2 AS INTEGER '                 collision box bottom right y
  39.     transparency AS INTEGER '           -1 (TRUE) if sheet uses transparency
  40.  
  41. TYPE SL_SPRITE ' ********************** sprite database *********************************************
  42.     inuse AS INTEGER '                  this array index in use
  43.     sheet AS INTEGER '                  sheet sprite belongs to
  44.     column AS INTEGER '                 the column on the sheet the sprite resides
  45.     row AS INTEGER '                    the row on the sheet the sprite resides
  46.     sprite AS LONG '                    hardware image
  47.     image AS LONG '                     software image
  48.     mask AS LONG '                      software mask image
  49.     spritewidth AS INTEGER '            width of sprite
  50.     spriteheight AS INTEGER '           height of sprite
  51.     rsprite AS LONG '                   rotated sprite hardware image
  52.     rimage AS LONG '                    rotated sprite software image
  53.     rmask AS LONG '                     rotated sprite mask software image
  54.     rspritewidth AS INTEGER '           rotated sprite image width
  55.     rspriteheight AS INTEGER '          rotated sprite image height
  56.     background AS LONG '                background image behind sprite
  57.     xreal AS SINGLE '                   x location of sprite (center point)
  58.     yreal AS SINGLE '                   y location of sprite (center point)
  59.     xint AS INTEGER '                   x location of sprite on screen INT(xreal) (center point)
  60.     yint AS INTEGER '                   y location of sprite on screen INT(yreal) (center point)
  61.     xactual AS INTEGER '                x location of sprite on screen (upper left x)
  62.     yactual AS INTEGER '                y location of sprite on screen (upper left y)
  63.     RESTORE AS INTEGER '                -1 (true) if sprite restores background
  64.     collx1 AS INTEGER '                 collision box top left x
  65.     colly1 AS INTEGER '                 collision box top left y
  66.     collx2 AS INTEGER '                 collision box bottom right x
  67.     colly2 AS INTEGER '                 collision box bottom right y
  68.     flip AS INTEGER '                   flip horizontally, vertically, or both
  69.     rotation AS SINGLE '                rotation angle of sprite (0 - 359.999)
  70.     transparency AS INTEGER '           -1 (TRUE) if sprite uses transparency
  71.  
  72. TYPE SL_ROTATE '*********************** precalculated rotation table ********************************
  73.     rwidth AS INTEGER '                 width of rotated sprite
  74.     rheight AS INTEGER '                height of rotated sprite
  75.     px0 AS INTEGER '                    rectangular rotation coordinates
  76.     px1 AS INTEGER
  77.     px2 AS INTEGER
  78.     px3 AS INTEGER
  79.     py0 AS INTEGER
  80.     py1 AS INTEGER
  81.     py2 AS INTEGER
  82.     py3 AS INTEGER
  83.  
  84. '*
  85. '* defined arrays
  86. '*
  87.  
  88. REDIM SL_sheet(1, 1, 1) AS SL_SHEET '   master sprite sheet array
  89. REDIM SL_sprite(1) AS SL_SPRITE '       master working sprite array
  90. REDIM SL_rotate(1, 359) AS SL_ROTATE '  precalculated rotation values
  91.  
  92. '*
  93. '* main code (for testing)
  94. '*
  95.  
  96. kongsheet = SL_NEW_SPRITE_SHEET("dkong.png", 64, 64, SL_SETTRANSPARENCY, _RGB32(255, 0, 255))
  97. mysprite% = SL_NEW_SPRITE(kongsheet, 1, 1, SL_NOSAVE)
  98. mysprite2% = SL_NEW_SPRITE(kongsheet, 1, 1, SL_NOSAVE)
  99.  
  100. 'SL_FLIP_SPRITE mysprite%, SL_NOFLIP
  101.  
  102. SCREEN _NEWIMAGE(640, 480, 32)
  103.  
  104.     _LIMIT 120
  105.     SL_PUT_SPRITE 128, 128, mysprite2%
  106.     angle = angle + 1: IF angle = 360 THEN angle = 0
  107.     SL_ROTATE_SPRITE mysprite%, angle
  108.     CIRCLE (128, 128), 64, _RGB32(255, 255, 255)
  109.     SL_PUT_SPRITE 128, 128, mysprite%
  110.     _DISPLAY
  111.  
  112.  
  113.  
  114.  
  115. '    ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
  116. SUB SL_ROTATE_SPRITE (handle AS INTEGER, degrees AS INTEGER) '                                                                                                                         SL_ROTATE_SPRITE
  117.     'ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
  118.     '³                    °°°±±±²²²ÛÛÛ COMMAND DESCRIPTION AND USAGE ÛÛÛ²²²±±±°°°                     ³                                °°°±±±²²²ÛÛÛ NOTES ÛÛÛ²²²±±±°°°                                ³
  119.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  120.     '³                                                                                                ³                                                                                               ³
  121.     '³                                                                                                ³                                                                                               ³
  122.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  123.     '³                            °°°±±±²²²ÛÛÛ KNOWN ISSUES ÛÛÛ²²²±±±°°°                              ³                               °°°±±±²²²ÛÛÛ CREDITS ÛÛÛ²²²±±±°°°                               ³
  124.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  125.     '³                                                                                                ³ Portions of this subroutine have code based off of Galleon's RotoZoom subroutine in the QB64  ³
  126.     '³                                                                                                ³ documentation at http://qb64.net/wiki/index.php?title=MAPTRIANGLE (link no longer works)      ³
  127.     '³                                                                                                ³                                                                                               ³
  128.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  129.     '³                                                                          °°°±±±²²²ÛÛÛ THEORY OF OPERATION ÛÛÛ²²²±±±°°°                                                                         ³
  130.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  131.     '³                                                                                                                                                                                                ³
  132.     '³                                                                                                                                                                                                ³
  133.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  134.     '³                                                                                °°°±±±²²²ÛÛÛ HISTORY ÛÛÛ²²²±±±°°°                                                                               ³
  135.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  136.     '³ Date: 09/11/18 by Terry Ritchie                                                                                                                                                                ³
  137.     '³     : Initial writing of code.                                                                                                                                                                 ³
  138.     '³                                                                                                                                                                                                ³
  139.     'ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
  140.  
  141.     ' declare global variables
  142.  
  143.     SHARED SL_sprite() AS SL_SPRITE '   master working sprite array
  144.     SHARED SL_rotate() AS SL_ROTATE '   precalculated rotation table
  145.  
  146.     'declare local variables
  147.  
  148.     DIM px0 AS INTEGER '                precalculated polar coordinates
  149.     DIM px1 AS INTEGER
  150.     DIM px2 AS INTEGER
  151.     DIM px3 AS INTEGER
  152.     DIM py0 AS INTEGER
  153.     DIM py1 AS INTEGER
  154.     DIM py2 AS INTEGER
  155.     DIM py3 AS INTEGER
  156.     DIM sw AS INTEGER '                 sprite width
  157.     DIM sh AS INTEGER '                 sprite height
  158.     DIM rw AS INTEGER '                 precalculated rotated sprite width
  159.     DIM rh AS INTEGER '                 precalculated rotated sprite height
  160.  
  161.     ' perform error checks
  162.  
  163.     IF NOT SL_VALID_SPRITE(handle) THEN '                                                               is this a valid sprite?
  164.         SL_ERROR "SL_ROTATE_SPRITE", 500, "" '                                                          no, report error to programmer
  165.     END IF
  166.  
  167.     ' correct degree angle if needed (needs to be 0 - 359)
  168.  
  169.     IF degrees = 360 THEN '                                                                             is it 360?
  170.         degrees = 0 '                                                                                   yes, that's the same as 0
  171.     ELSEIF degrees < 0 THEN '                                                                           is it less than 360?
  172.         DO '                                                                                            yes
  173.             degrees = dgrees + 360 '                                                                    increase by 360
  174.         LOOP UNTIL degrees > 0 '                                                                        until it's in a valid range
  175.     ELSEIF degrees > 360 THEN '                                                                         is it greater than 360?
  176.         DO '                                                                                            yes
  177.             degrees = degrees - 360 '                                                                   decrease by 360
  178.         LOOP UNTIL degrees < 360 '                                                                      until it's in a valid range
  179.     END IF
  180.     SL_sprite(handle).rotation = degrees '                                                              remember degree of rotation
  181.     IF degrees = 0 THEN EXIT SUB '                                                                      no rotation needed, leave
  182.     SL_sprite(handle).rspritewidth = SL_rotate(SL_sprite(handle).sheet, degrees).rwidth '               get precalculated rotated sprite width
  183.     SL_sprite(handle).rspriteheight = SL_rotate(SL_sprite(handle).sheet, degrees).rheight '             get precalculated rotated sprite height
  184.     px0 = SL_rotate(SL_sprite(handle).sheet, degrees).px0 '                                             get precalculated polar coordinates
  185.     px1 = SL_rotate(SL_sprite(handle).sheet, degrees).px1
  186.     px2 = SL_rotate(SL_sprite(handle).sheet, degrees).px2
  187.     px3 = SL_rotate(SL_sprite(handle).sheet, degrees).px3
  188.     py0 = SL_rotate(SL_sprite(handle).sheet, degrees).py0
  189.     py1 = SL_rotate(SL_sprite(handle).sheet, degrees).py1
  190.     py2 = SL_rotate(SL_sprite(handle).sheet, degrees).py2
  191.     py3 = SL_rotate(SL_sprite(handle).sheet, degrees).py3
  192.     rw = SL_rotate(SL_sprite(handle).sheet, degrees).rwidth '                                           get precalculated rotated sprite width
  193.     rh = SL_rotate(SL_sprite(handle).sheet, degrees).rheight '                                          get precalculated rotated sprite height
  194.     sw = SL_sprite(handle).spritewidth - 1 '                                                            get sprite width
  195.     sh = SL_sprite(handle).spriteheight - 1 '                                                           get sprite height
  196.     IF SL_sprite(handle).rimage THEN _FREEIMAGE SL_sprite(handle).rimage '                              free rotated image if it already exists
  197.     SL_sprite(handle).rimage = _NEWIMAGE(rw, rh, 32) '                                                  create rotated image
  198.     _MAPTRIANGLE (0, 0)-(0, sh)-(sw, sh), SL_sprite(handle).image TO _
  199.                  (px0, py0)-(px1, py1)-(px2, py2), SL_sprite(handle).rimage '                           map rotated sprite onto image
  200.     _MAPTRIANGLE (0, 0)-(sw, 0)-(sw, sh), SL_sprite(handle).image TO _
  201.                  (px0, py0)-(px3, py3)-(px2, py2), SL_sprite(handle).rimage
  202.     IF SL_sprite(handle).rsprite THEN _FREEIMAGE SL_sprite(handle).rsprite '                            free rotated hardware sprite if it alreadt exists
  203.     SL_sprite(handle).rsprite = _COPYIMAGE(SL_sprite(handle).rimage, 33) '                              create hardware sprite of rotated image
  204.     IF SL_sprite(handle).transparency THEN '                                                            does this sprite have a mask?
  205.         IF SL_sprite(handle).rmask THEN _FREEIMAGE SL_sprite(handle).rmask '                            yes, free mask image if it already exists
  206.         SL_sprite(handle).rmask = _NEWIMAGE(rw, rh, 32) '                                               created rotated mask image
  207.         _MAPTRIANGLE (0, 0)-(0, sh)-(sw, sh), SL_sprite(handle).mask TO _
  208.                      (px0, py0)-(px1, py1)-(px2, py2), SL_sprite(handle).rmask '                        map rotated mask onto image
  209.         _MAPTRIANGLE (0, 0)-(sw, 0)-(sw, sh), SL_sprite(handle).mask TO _
  210.                      (px0, py0)-(px3, py3)-(px2, py2), SL_sprite(handle).rmask
  211.     END IF
  212.  
  213.  
  214. '    ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
  215. SUB SL_FLIP_SPRITE (handle AS INTEGER, flip AS INTEGER) '                                                                                                                                SL_FLIP_SPRITE
  216.     'ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
  217.     '³                    °°°±±±²²²ÛÛÛ COMMAND DESCRIPTION AND USAGE ÛÛÛ²²²±±±°°°                     ³                                °°°±±±²²²ÛÛÛ NOTES ÛÛÛ²²²±±±°°°                                ³
  218.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  219.     '³ Sets a sprite's flipping behavior when drawn to the screen.                                    ³ - Four constants have been created for this subroutine:                                       ³
  220.     '³                                                                                                ³   : SL_NOFLIP     (0) no flipping desired (or reset flip behavior)                            ³
  221.     '³ SL_FLIP_SPRITE mysprite, SL_NOFLIP                                                             ³   : SL_HORIZONTAL (1) flip sprite horizontally                                                ³
  222.     '³                                                                                                ³   : SL_VERTICAL   (2) flip sprite vertically                                                  ³
  223.     '³ input : handle - the sprite to flip.                                                           ³   : SL_FLIPBOTH   (3) flip sprite both horizontally and vertically                            ³
  224.     '³         flip   - the type of flip desired:                                                     ³ - Once a flip behavior has been set it will remain in effect until the behavior is changed.   ³
  225.     '³                  : 0 - no flipping desired (or reset flip behavior)                            ³ - This subroutine will report an error on the following conditions:                           ³
  226.     '³                  : 1 - flip sprite horizontally                                                ³   : An invalid sprite has been requested.                                                     ³
  227.     '³                  : 2 - flip sprite vertically                                                  ³   : An invalid flip behavior.                                                                 ³
  228.     '³                  : 3 - flip sprite both horizontally and vertically                            ³                                                                                               ³
  229.     '³                                                                                                ³                                                                                               ³
  230.     '³ Sets  : SL_sprite(handle).flip = flip  (sets the flip behavior for later use)                  ³                                                                                               ³
  231.     '³                                                                                                ³                                                                                               ³
  232.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  233.     '³                            °°°±±±²²²ÛÛÛ KNOWN ISSUES ÛÛÛ²²²±±±°°°                              ³                               °°°±±±²²²ÛÛÛ CREDITS ÛÛÛ²²²±±±°°°                               ³
  234.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  235.     '³ None                                                                                           ³ None                                                                                          ³
  236.     '³                                                                                                ³                                                                                               ³
  237.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  238.     '³                                                                          °°°±±±²²²ÛÛÛ THEORY OF OPERATION ÛÛÛ²²²±±±°°°                                                                         ³
  239.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  240.     '³ A sprite array setting will be made for use by other library routines.                                                                                                                         ³
  241.     '³                                                                                                                                                                                                ³
  242.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  243.     '³                                                                                °°°±±±²²²ÛÛÛ HISTORY ÛÛÛ²²²±±±°°°                                                                               ³
  244.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  245.     '³ Date: 09/11/18 by Terry Ritchie                                                                                                                                                                ³
  246.     '³     : Initial writing of code.                                                                                                                                                                 ³
  247.     '³                                                                                                                                                                                                ³
  248.     'ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
  249.  
  250.     ' declare global variables
  251.  
  252.     SHARED SL_sprite() AS SL_SPRITE '   master working sprite array
  253.  
  254.     ' perform error checks
  255.  
  256.     IF NOT SL_VALID_SPRITE(handle) THEN '                                                               is this a valid sprite?
  257.         SL_ERROR "SL_FLIP_SPRITE", 400, "" '                                                            no, report error to programmer
  258.     END IF
  259.     IF flip < 0 OR flip > 3 THEN '                                                                      valid flip behavior requested?
  260.         SL_ERROR "SL_FLIP_SPRITE", 401, "" '                                                            no, report error to programmer
  261.     END IF
  262.     SL_sprite(handle).flip = flip '                                                                     set flipping behavior
  263.  
  264.  
  265. '    ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
  266. SUB SL_PUT_SPRITE (x AS SINGLE, y AS SINGLE, handle AS INTEGER) '                                                                                                                         SL_PUT_SPRITE
  267.     'ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
  268.     '³                    °°°±±±²²²ÛÛÛ COMMAND DESCRIPTION AND USAGE ÛÛÛ²²²±±±°°°                     ³                                °°°±±±²²²ÛÛÛ NOTES ÛÛÛ²²²±±±°°°                                ³
  269.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  270.     '³ Places a sprite on the current _DEST (normally screen) at the coordinates provided.            ³ - The x and y values supplied by the programmer can be sent in as single precision to allow   ³
  271.     '³                                                                                                ³   for fine x and y increments. Internally the final x and y values needed for image placement ³
  272.     '³ SL_PUT_SPRITE 100, 100, mysprite%                                                              ³   are converted to integer values.                                                            ³
  273.     '³                                                                                                ³                                                                                               ³
  274.     '³ Input : x      - x location (column) to place sprite.                                          ³                                                                                               ³
  275.     '³         y      - y location (row) to place sprite.                                             ³                                                                                               ³
  276.     '³         handle - the sprite to place on the screen.                                            ³                                                                                               ³
  277.     '³                                                                                                ³                                                                                               ³
  278.     '³ Sets  :                                                                                        ³                                                                                               ³
  279.     '³                                                                                                ³                                                                                               ³
  280.     '³                                                                                                ³                                                                                               ³
  281.     '³                                                                                                ³                                                                                               ³
  282.     '³                                                                                                ³                                                                                               ³
  283.     '³                                                                                                ³                                                                                               ³
  284.     '³ Errors: All reported errors will be in the 300 - 399 range for this function.                  ³                                                                                               ³
  285.     '³                                                                                                ³                                                                                               ³
  286.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  287.     '³                            °°°±±±²²²ÛÛÛ KNOWN ISSUES ÛÛÛ²²²±±±°°°                              ³                               °°°±±±²²²ÛÛÛ CREDITS ÛÛÛ²²²±±±°°°                               ³
  288.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  289.     '³                                                                                                ³                                                                                               ³
  290.     '³                                                                                                ³                                                                                               ³
  291.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  292.     '³                                                                          °°°±±±²²²ÛÛÛ THEORY OF OPERATION ÛÛÛ²²²±±±°°°                                                                         ³
  293.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  294.     '³                                                                                                                                                                                                ³
  295.     '³                                                                                                                                                                                                ³
  296.     '³                                                                                                                                                                                                ³
  297.     '³                                                                                                                                                                                                ³
  298.     '³                                                                                                                                                                                                ³
  299.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  300.     '³                                                                                °°°±±±²²²ÛÛÛ HISTORY ÛÛÛ²²²±±±°°°                                                                               ³
  301.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  302.     '³ Date: 09/10/18 by Terry Ritchie                                                                                                                                                                ³
  303.     '³     : Initial writing of code.                                                                                                                                                                 ³
  304.     '³                                                                                                                                                                                                ³
  305.     'ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
  306.  
  307.     ' declare global variables
  308.  
  309.     SHARED SL_sprite() AS SL_SPRITE '   master working sprite array
  310.  
  311.     ' declare local variables
  312.  
  313.     DIM xa AS INTEGER '                 actual x location of sprite on screen
  314.     DIM ya AS INTEGER '                 actual y location of sprite on screen
  315.     DIM sw AS INTEGER '                 width of sprite to be drawn
  316.     DIM sh AS INTEGER '                 height of sprite to be drawn
  317.     DIM sprite AS LONG '                the sprite to be drawn
  318.  
  319.     ' perform error checks
  320.  
  321.     IF NOT SL_VALID_SPRITE(handle) THEN '                                                               is this a valid sprite?
  322.         SL_ERROR "SL_PUT_SPRITE", 300, "" '                                                             no, report error to programmer
  323.     END IF
  324.  
  325.     'local variable setup
  326.  
  327.     SL_sprite(handle).xreal = x '                                                             (SINGLE)  save requested x center location
  328.     SL_sprite(handle).yreal = y '                                                             (SINGLE)  save requested y center location
  329.     SL_sprite(handle).xint = INT(x) '                                                        (INTEGER)  save screen x center location
  330.     SL_sprite(handle).yint = INT(y) '                                                        (INTEGER)  save screen y center location
  331.     IF SL_sprite(handle).rotation THEN '                                                                is sprite rotated?
  332.         sprite = SL_sprite(handle).rsprite '                                                            yes, get rotated sprite image
  333.         sw = SL_sprite(handle).rspritewidth '                                                           get rotated sprite width
  334.         sh = SL_sprite(handle).rspriteheight '                                                          get rotated sprite height
  335.     ELSE '                                                                                              sprite is not rotated
  336.         sprite = SL_sprite(handle).sprite '                                                             get standard sprite image
  337.         sw = SL_sprite(handle).spritewidth '                                                            get standard sprite width
  338.         sh = SL_sprite(handle).spriteheight '                                                           get standard sprite height
  339.     END IF
  340.     xa = SL_sprite(handle).xint - sw \ 2 '                                                              calculate actual screen x location from center
  341.     ya = SL_sprite(handle).yint - sh \ 2 '                                                              calculate actual screen y location from center
  342.     SL_sprite(handle).xactual = xa '                                                         (INTEGER)  save actual screen x location
  343.     SL_sprite(handle).yactual = ya '                                                         (INTEGER)  save actual screen y location
  344.  
  345.     ' place sprite on the current destination
  346.  
  347.     SELECT CASE SL_sprite(handle).flip '                                                                which flipping style is selected?
  348.         CASE 0 '                                                                  (constant SL_NOFLIP)  normal, no flipping
  349.             _PUTIMAGE (xa, ya), sprite '                                                                draw normal sprite
  350.         CASE 1 '                                                              (constant SL_HORIZONTAL)  flip horizontally
  351.             _PUTIMAGE (xa + sw - 1, ya)-(xa, ya + sh - 1), sprite '                                     draw horizontally flipped sprite
  352.         CASE 2 '                                                                (constant SL_VERTICAL)  flip vertically
  353.             _PUTIMAGE (xa, ya + sh - 1)-(xa + sw - 1, ya), sprite '                                     draw vertically flipped sprite
  354.         CASE 3 '                                                                (constant SL_FLIPBOTH)  flip vertically and horizontally
  355.             _PUTIMAGE (xa + sw - 1, ya + sh - 1)-(xa, ya), sprite '                                     draw horizontally and vertically flipped sprite
  356.     END SELECT
  357.  
  358.  
  359. '    ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
  360. FUNCTION SL_NEW_SPRITE (sheet AS INTEGER, column AS INTEGER, row AS INTEGER, restores AS INTEGER) '                                                                                       SL_NEW_SPRITE
  361.     'ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
  362.     '³                    °°°±±±²²²ÛÛÛ COMMAND DESCRIPTION AND USAGE ÛÛÛ²²²±±±°°°                     ³                                °°°±±±²²²ÛÛÛ NOTES ÛÛÛ²²²±±±°°°                                ³
  363.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  364.     '³ Creates a pointer to a sprite contained in the SL_sprite database array.                       ³ - Two constants have been created for use with this function:                                 ³
  365.     '³                                                                                                ³   : SL_NOSAVE ( 0) do not save the background image behind sprite between calls.              ³
  366.     '³ mysprite% = SL_NEW_SPRITE(mysheet%, 2, 3, SL_NOSAVE)                                           ³   : SL_SAVE   (-1) save the background image behind sprite between calls.                     ³
  367.     '³                                                                                                ³ - The function will report an error on the following conditions:                              ³
  368.     '³ Input : sheet    - the sprite sheet the sprite resides on.                                     ³   : An invalid sprite sheet has been selected.                                                ³
  369.     '³         column   - the column in the sprite sheet the sprite resides in.                       ³   : An invalid row or column value within a sprite sheet has been requested.                  ³
  370.     '³         row      - the row in the sprite sheet the sprite resides in.                          ³   : An invalid background image restoration method has been requested.                        ³
  371.     '³         restores - background saving behavior                                                  ³                                                                                               ³
  372.     '³                    :  0 - don't restore background between calls.                              ³                                                                                               ³
  373.     '³                    : -1 - restore the background between calls.                                ³                                                                                               ³
  374.     '³                                                                                                ³                                                                                               ³
  375.     '³ Output: an integer value greater than zero (0) that acts as a handle pointing to the sheet and ³                                                                                               ³
  376.     '³         location on the sheet where a sprite resides.                                          ³                                                                                               ³
  377.     '³                                                                                                ³                                                                                               ³
  378.     '³ Sets  : SL_sprite(x).inuse        = -1       (TRUE, this sprite index is in use)               ³                                                                                               ³
  379.     '³         SL_sprite(x).sheet        = sheet    (the sprite sheet where this sprite resides)      ³                                                                                               ³
  380.     '³         SL_sprite(x).column       = column   (column within sprite sheet where sprite resides) ³                                                                                               ³
  381.     '³         SL_sprite(x).row          = row      (row within sprite sheet where sprite resides)    ³                                                                                               ³
  382.     '³         SL_sprite(x).restore      = restores (background save behavior of sprite)              ³                                                                                               ³
  383.     '³         SL_sprite(x).spritewidth             (sprite width copied from sprite sheet)           ³                                                                                               ³
  384.     '³         SL_sprite(x).spriteheight            (sprite height copied from sprite sheet)          ³                                                                                               ³
  385.     '³         SL_sprite(x).collx1                  (upper left collision box x copied from sheet)    ³                                                                                               ³
  386.     '³         SL_sprite(x).colly1                  (upper left collision box y copied from sheet)    ³                                                                                               ³
  387.     '³         SL_sprite(x).collx2                  (lower right collision box x copied from sheet)   ³                                                                                               ³
  388.     '³         SL_sprite(x).colly2                  (lower right collision box y copied from sheet)   ³                                                                                               ³
  389.     '³         SL_sprite(x).sprite                  (hardware sprite image created from sheet image)  ³                                                                                               ³
  390.     '³         SL_sprite(x).image                   (software sprite image copied from sheet image)   ³                                                                                               ³
  391.     '³         SL_sprite(x).mask                    (software mask image copied from sheet image)     ³                                                                                               ³
  392.     '³                                                                                                ³                                                                                               ³
  393.     '³         all other SL_sprite(x).* subvariables reset to their initial value                     ³                                                                                               ³
  394.     '³                                                                                                ³                                                                                               ³
  395.     '³ Errors: All reported errors will be in the 200 - 299 range for this function.                  ³                                                                                               ³
  396.     '³                                                                                                ³                                                                                               ³
  397.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  398.     '³                            °°°±±±²²²ÛÛÛ KNOWN ISSUES ÛÛÛ²²²±±±°°°                              ³                               °°°±±±²²²ÛÛÛ CREDITS ÛÛÛ²²²±±±°°°                               ³
  399.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  400.     '³ None                                                                                           ³ None                                                                                          ³
  401.     '³                                                                                                ³                                                                                               ³
  402.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  403.     '³                                                                          °°°±±±²²²ÛÛÛ THEORY OF OPERATION ÛÛÛ²²²±±±°°°                                                                         ³
  404.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  405.     '³ The sprite array database is scanned for a free index and once found that index number becomes the handle (pointer) the the sprite being created. The new index contains further pointers to   ³
  406.     '³ where the requested sprite is located in the sprite sheet array database; the sheet number, the row, and the column the sprite resides in within the sheet. Information from the sprite sheet  ³
  407.     '³ is then copied over (see Sets: above) from the sheet array to the sprite array. A hardware image of the sprite is then created from the software image contained in the sprite sheet.          ³
  408.     '³                                                                                                                                                                                                ³
  409.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  410.     '³                                                                                °°°±±±²²²ÛÛÛ HISTORY ÛÛÛ²²²±±±°°°                                                                               ³
  411.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  412.     '³ Date: 09/10/18 by Terry Ritchie                                                                                                                                                                ³
  413.     '³     : Initial writing of code.                                                                                                                                                                 ³
  414.     '³                                                                                                                                                                                                ³
  415.     'ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
  416.  
  417.     ' declare global variables
  418.  
  419.     SHARED SL_sheet() AS SL_SHEET '     master sprite sheet array
  420.     SHARED SL_sprite() AS SL_SPRITE '   master working sprite array
  421.  
  422.     ' declare local variables
  423.  
  424.     DIM handle AS INTEGER '             handle (pointer) number of new sprite
  425.  
  426.     ' perform error checks
  427.  
  428.     IF sheet > UBOUND(SL_sheet) OR SL_sheet(sheet, 0, 0).image <> -1 THEN '                             valid sprite sheet requested?
  429.         SL_ERROR "SL_NEW_SPRITE", 200, "" '                                                             no, report error to programmer
  430.     END IF
  431.     IF column > UBOUND(SL_sheet, 2) OR row > UBOUND(SL_sheet, 3) OR row < 1 OR column < 1 THEN '        valid row and column requested?
  432.         SL_ERROR "SL_NEW_SPRITE", 201, "" '                                                             no, report error to programmer
  433.     END IF
  434.     IF ABS(restores) > 1 THEN '                                                                         valid background restoration behavior requested?
  435.         SL_ERROR "SL_NEW_SPRITE", 202, "" '                                                             no, report error to programmer
  436.     END IF
  437.  
  438.     ' local variable setup
  439.  
  440.     handle = 0 '                                                                                        initialize handle value
  441.  
  442.     ' increase sprite array's size if needed
  443.  
  444.     DO '                                                                                                look for next available handle
  445.         handle = handle + 1 '                                                                           increment to next handle value
  446.     LOOP UNTIL (NOT SL_sprite(handle).inuse) OR handle = UBOUND(SL_sprite) '                            stop looking when valid handle found
  447.     IF SL_sprite(handle).inuse THEN '                                                                   is the last array element in use?
  448.         handle = handle + 1 '                                                                           yes, increment to next handle value
  449.         REDIM _PRESERVE SL_sprite(handle) AS SL_SPRITE '                                                increase the size of the sprite array
  450.     END IF
  451.  
  452.     ' populate sprite array
  453.  
  454.     SL_sprite(handle).inuse = -1 '                                                              (TRUE)  mark array index as in use
  455.     SL_sprite(handle).sheet = sheet '                                                                   point to sheet where sprite resides              *
  456.     SL_sprite(handle).column = column '                                                                 point to column on sheet where sprite located    * these still needed?
  457.     SL_sprite(handle).row = row '                                                                       point to row on sheet where sprite located       *
  458.     SL_sprite(handle).RESTORE = restores '                             (constants SL_SAVE & SL_NOSAVE)  background restore behavior of sprite
  459.     SL_sprite(handle).rsprite = 0 '                                                                     no rotated hardware image yet
  460.     SL_sprite(handle).rimage = 0 '                                                                      no rotated software image yet
  461.     SL_sprite(handle).rmask = 0 '                                                                       no rotated software mask image yet
  462.     SL_sprite(handle).background = 0 '                                                                  no background image saved yet
  463.     SL_sprite(handle).xreal = 0 '                                                                       reset x location of sprite (center x)
  464.     SL_sprite(handle).yreal = 0 '                                                                       reset y location of sprite (center y)
  465.     SL_sprite(handle).xint = 0 '                                                                        reset x location of sprite on screen INT(xreal) (center x)
  466.     SL_sprite(handle).yint = 0 '                                                                        reset y location of sprite on screen INT(yreal) (center y)
  467.     SL_sprite(handle).xactual = 0 '                                                                     reset x location of sprite on screen (upper left x)
  468.     SL_sprite(handle).yactual = 0 '                                                                     reset y location of sprite on screen (upper left y)
  469.     SL_sprite(handle).collx1 = SL_sheet(sheet, column, row).collx1 '                                    get sprite's collision box boundaries
  470.     SL_sprite(handle).colly1 = SL_sheet(sheet, column, row).colly1
  471.     SL_sprite(handle).collx2 = SL_sheet(sheet, column, row).collx2
  472.     SL_sprite(handle).colly2 = SL_sheet(sheet, column, row).colly2
  473.     SL_sprite(handle).spritewidth = SL_sheet(sheet, column, row).spritewidth '                          get width of sprite
  474.     SL_sprite(handle).spriteheight = SL_sheet(sheet, column, row).spriteheight '                        get height of sprite
  475.     SL_sprite(handle).sprite = _COPYIMAGE(SL_sheet(sheet, column, row).image, 33) '                     create hardware sprite image
  476.     SL_sprite(handle).image = _COPYIMAGE(SL_sheet(sheet, column, row).image, 32) '                      copy software sprite image from sheet
  477.     IF SL_sheet(sheet, column, row).transparency THEN '                                                 does this sprite use transparency?
  478.         SL_sprite(handle).mask = _COPYIMAGE(SL_sheet(sheet, column, row).mask, 32) '                    yes, copy software sprite mask image from sheet
  479.         SL_sprite(handle).transparency = -1 '                                                   (TRUE)  remember this sprite has a transparency layer
  480.     ELSE '                                                                                              no transparency
  481.         SL_sprite(handle).mask = 0 '                                                                    no mask will be brought in
  482.         SL_sprite(handle).transparency = 0 '                                                   (FALSE)  remember this sprite has no transparency layer
  483.     END IF
  484.     SL_sprite(handle).flip = 0 '                                                                        no sprite flipping
  485.     SL_sprite(handle).rotation = 0 '                                                                    no sprite rotation angle
  486.  
  487.     SL_NEW_SPRITE = handle
  488.  
  489.  
  490. '    ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
  491. FUNCTION SL_NEW_SPRITE_SHEET (filename AS STRING, spritewidth AS INTEGER, spriteheight AS INTEGER, transparency AS INTEGER, transcolor AS _UNSIGNED LONG) '                         SL_NEW_SPRITE_SHEET
  492.     'ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
  493.     '³                    °°°±±±²²²ÛÛÛ COMMAND DESCRIPTION AND USAGE ÛÛÛ²²²±±±°°°                     ³                                °°°±±±²²²ÛÛÛ NOTES ÛÛÛ²²²±±±°°°                                ³
  494.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  495.     '³ Loads a sprite sheet's sprites into memory and stores them in the sprite sheet array. Three    ³ - The software image mask will only be created if the sprite sheet contains a transparency    ³
  496.     '³ sprite images are created for each sprite; a hardware image for displaying, a software image   ³   layer (alpha channel) either built-in or user defined.                                      ³
  497.     '³ for manipulating, and a software mask image for pixel collision detection.                     ³ - Three constants have been created for use with this function:                               ³
  498.     '³                                                                                                ³   : SL_SHEETTRANSPARENCY (-1) to have the function use built-in sprite sheet's alpha layer.   ³
  499.     '³ mysheet% = SL_NEW_SPRITE_SHEET("sprites.png", 64, 96, SL_SETTRANSPARENCY, _RGB32(255, 0, 255)) ³   : SL_SETTRANSPARENCY   ( 0) to have the function use the programmer supplied alpha value.   ³
  500.     '³                                                                                                ³   : SL_NOTRANSPARENCY    ( 1) to have the function ignore alpha channel completely.           ³
  501.     '³ Input : filename     - the name of the sprite sheet image file to load in.                     ³ - The function will report an error on the following conditions:                              ³
  502.     '³         spritewidth  - the width of every sprite contained on the sprite sheet.                ³   : A filename is supplied that does not exist.                                               ³
  503.     '³         spriteheight - the height of every sprite contained on the sprite sheet.               ³   : A sprite width or height that is less than one (1).                                       ³
  504.     '³         transparency - the type of transparency to apply to the sprite sheet and sprites:      ³   : An invalid transparency type value. Valid types are from negative one (-1) to one (1).    ³
  505.     '³                         : -1 - use the sprite sheet's built-in alpha channel (PNG files).      ³   : The sprite sheet does not contain at least one row and column of sprites.                 ³
  506.     '³                         :  0 - use the programmer assigned alpha channel value.                ³ - The programmer supplied alpha channel value will be ignored if transparency is set to a     ³
  507.     '³                         :  1 - this sheet does not have any transparency included.             ³   value of negative one (-1).                                                                 ³
  508.     '³         transcolor   - programmer assigned alpha channel value for the sprite sheet.           ³ - When transparency is set to one (1) the programmer supplied transcolor is used to identify  ³
  509.     '³                                                                                                ³   the background color used in the sprite sheet. This is still needed to find the collision   ³
  510.     '³ Output: An integer value greater than zero (0) that acts as a handle pointing to the sheet     ³   box boundaries for collision detection.                                                     ³
  511.     '³         that contains the sprites.                                                             ³                                                                                               ³
  512.     '³                                                                                                ³                                                                                               ³
  513.     '³ Sets  : SL_sheet(x, 0, 0).image        = -1      (TRUE, this sheet index is in use)            ³                                                                                               ³
  514.     '³         SL_sheet(x, 0, 0).spritewidth  = columns (the number indexes in the 2nd dimension of   ³                                                                                               ³
  515.     '³                                                   sheet array)                                 ³                                                                                               ³
  516.     '³         SL_sheet(x, 0, 0).spriteheight = rows    (the number of indexes in the 3rd dimension   ³                                                                                               ³
  517.     '³                                                   of sheet array)                              ³                                                                                               ³
  518.     '³         SL_sheet(x, c, r).image                  software image copied from sprite sheet       ³                                                                                               ³
  519.     '³         SL_sheet(x, c, r).spritewidth            width of sprite in pixels                     ³                                                                                               ³
  520.     '³         SL_sheet(x, c, r).spriteheight           height of sprite in pixels                    ³                                                                                               ³
  521.     '³         SL_sheet(x, c, r).mask                   sprite mask (image black, background white)   ³                                                                                               ³
  522.     '³         SL_sheet(x, c, r).collx1                 collision box upper left x                    ³                                                                                               ³
  523.     '³         SL_sheet(x, c, r).colly1                 collision box upper left y                    ³                                                                                               ³
  524.     '³         SL_sheet(x, c, r).collx2                 collision box lower right x                   ³                                                                                               ³
  525.     '³         SL_sheet(x, c, r).colly2                 collision box lower right y                   ³                                                                                               ³
  526.     '³           * c = column  r = row                                                                ³                                                                                               ³
  527.     '³                                                                                                ³                                                                                               ³
  528.     '³ Errors: All reported errors will be in the 100 - 199 range for this function.                  ³                                                                                               ³
  529.     '³                                                                                                ³                                                                                               ³
  530.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  531.     '³                            °°°±±±²²²ÛÛÛ KNOWN ISSUES ÛÛÛ²²²±±±°°°                              ³                               °°°±±±²²²ÛÛÛ CREDITS ÛÛÛ²²²±±±°°°                               ³
  532.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  533.     '³ Need to incorporate Steve's PNG transparency layer identifier instead of mine.                 ³ Portions of this subroutine have code based off of Galleon's RotoZoom subroutine in the QB64  ³
  534.     '³                                                                                                ³ documentation at http://qb64.net/wiki/index.php?title=MAPTRIANGLE (link no longer works)      ³
  535.     '³                                                                                                ³                                                                                               ³
  536.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  537.     '³                                                                          °°°±±±²²²ÛÛÛ THEORY OF OPERATION ÛÛÛ²²²±±±°°°                                                                         ³
  538.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  539.     '³ Once the sprite sheet is loaded it is scanned for an alpha channel if the programmer requests to use the sheet's transparency layer. The width and height of the sheet are retrieved and then  ³
  540.     '³ divided by the sprite dimensions provided by the programmer to determine how many columns and rows of sprites exist. A three dimensional sheet array is created where the first dimension is   ³
  541.     '³ the sheet number (handle/pointer), the second and thirs dimensions are then related to the sprite column and row locations on the sheet. Each sprite is copied from the sprite sheet into the  ³
  542.     '³ sprite sheet array. Each sprite is scanned to determine the absolute image size within the sprite (background/transparency areas are ignored) to determine the smallest possible collision box ³
  543.     '³ needed for collision detection. Finally, the sprite is scanned again to create an image mask for pixel perfect detection.                                                                      ³
  544.     '³                                                                                                                                                                                                ³
  545.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  546.     '³                                                                                °°°±±±²²²ÛÛÛ HISTORY ÛÛÛ²²²±±±°°°                                                                               ³
  547.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  548.     '³ Date: 09/09/18 by Terry Ritchie                                                                                                                                                                ³
  549.     '³     : Initial writing of code.                                                                                                                                                                 ³
  550.     '³                                                                                                                                                                                                ³
  551.     'ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
  552.  
  553.     ' declare global variables
  554.  
  555.     SHARED SL_sheet() AS SL_SHEET '    master sprite sheet array
  556.     SHARED SL_rotate() AS SL_ROTATE '  precalculated rotation table
  557.  
  558.     ' declare local variables
  559.  
  560.     DIM handle AS INTEGER '             handle (pointer) number of new sprite sheet
  561.     DIM x AS INTEGER '                  generic counter to cycle through sheet sprite columns
  562.     DIM y AS INTEGER '                  generic counter to cycle through sheet sprite rows
  563.     DIM x1 AS INTEGER '                 generic counter to cycle though sprite for collision boundaries and mask creation
  564.     DIM y1 AS INTEGER '                 generic ocunter to cycle though sprite for collision boundaries and mask creation
  565.     DIM osource AS LONG '               original source image before this function was called
  566.     DIM odest AS LONG '                 original destination image before this function was called
  567.     DIM pixel AS _UNSIGNED LONG '       pixel color at each coordinate in sprite sheet
  568.     DIM alpha AS _UNSIGNED LONG '       alpha level of current pixel
  569.     DIM top AS INTEGER '                upper boundary of sprite image
  570.     DIM bottom AS INTEGER '             lower boundary of sprite image
  571.     DIM left AS INTEGER '               left boundary of sprite image
  572.     DIM right AS INTEGER '              right boundary of sprite image
  573.     DIM sheetimage AS LONG '            sprite sheet image
  574.     DIM sheetwidth AS INTEGER '         width of sprite sheet in pixels
  575.     DIM sheetheight AS INTEGER '        height of sprite sheet in pixels
  576.     DIM rows AS INTEGER '               number of sprite rows contained on sheet
  577.     DIM columns AS INTEGER '            number of sprite columns contained on sheet
  578.     DIM clearcolor AS _UNSIGNED LONG '  transcolor passed in will be modified
  579.     DIM tempsprite AS LONG '            temporary sprite for _CLEARCOLOR detection
  580.  
  581.     DIM px(3) AS SINGLE '               polar x coordinates of maptriangle
  582.     DIM py(3) AS SINGLE '               polar y coordinates of maptriangle
  583.     DIM sinr AS SINGLE
  584.     DIM cosr AS SINGLE
  585.     DIM bx1 AS INTEGER
  586.     DIM bx2 AS INTEGER
  587.     DIM by1 AS INTEGER
  588.     DIM by2 AS INTEGER
  589.  
  590.     ' perform error checks
  591.  
  592.     IF NOT _FILEEXISTS(filename) THEN '                                                                 does the sprite sheet exist?
  593.         SL_ERROR "SL_NEW_SPRITE_SHEET", 100, filename '                                                 no, report error to programmer
  594.     END IF
  595.     IF ABS(transparency) > 1 THEN '                                                                     valid transparency setting?
  596.         SL_ERROR "SL_NEW_SPRITE_SHEET", 101, "" '                                                       no, report error to programmer
  597.     END IF
  598.     IF spritewidth < 1 OR spriteheight < 1 THEN '                                                       valid sprite width/height supplied?
  599.         SL_ERROR "SL_NEW_SPRITE_SHEET", 102, "" '                                                       no, report error to programmer
  600.     END IF
  601.     IF transparency = -1 AND UCASE$(RIGHT$(filename, 4)) <> ".PNG" THEN '                               wrong file type for transparency?
  602.         SL_ERROR "SL_NEW_SPRITE_SHEET", 103, UCASE$(RIGHT$(filename, 4)) '                              yes, report error to programmer
  603.     END IF
  604.  
  605.     ' local variable setup
  606.  
  607.     sheetimage = _LOADIMAGE(filename, 32) '                                                             load sprite sheet file
  608.     sheetwidth = _WIDTH(sheetimage) '                                                                   get width of sheet
  609.     sheetheight = _HEIGHT(sheetimage) '                                                                 get height of sheet
  610.     columns = sheetwidth \ spritewidth '                                                                get number of whole columns of sprites
  611.     rows = sheetheight \ spriteheight '                                                                 get number of whole rows of sprites
  612.     IF columns < 1 OR rows < 1 THEN '                                                                   at least one sprite column and row on sheet?
  613.         SL_ERROR "SL_NEW_SPRITE_SHEET", 104, "" '                                                       no, report error to programmer
  614.     END IF
  615.     osource = _SOURCE '                                                                                 remember current source image
  616.     odest = _DEST '                                                                                     remember current destination image
  617.     handle = 0 '                                                                                        initialize handle value
  618.     clearcolor = transcolor '                                                                           get background/transparent color passed in
  619.  
  620.     ' increase sheet array's 1st dimension if needed to create a new sprite sheet
  621.  
  622.     DO '                                                                                                look for the next available handle
  623.         handle = handle + 1 '                                                                           increment the handle value
  624.     LOOP UNTIL (NOT SL_sheet(handle, 0, 0).image) OR handle = UBOUND(SL_sheet) '                       stop looking when valid handle value found
  625.     IF SL_sheet(handle, 0, 0).image = -1 THEN '                                                        is the last array element in use?
  626.         handle = handle + 1 '                                                                           yes, increment the handle value
  627.         REDIM _PRESERVE SL_sheet(handle, UBOUND(SL_sheet, 2), UBOUND(SL_sheet, 3)) AS SL_SHEET '        create new sheet in sprite array
  628.         REDIM _PRESERVE SL_rotate(handle, UBOUND(SL_rotate, 2)) AS SL_ROTATE
  629.     END IF
  630.  
  631.     ' increase sheet array's 2nd and 3rd dimensions if needed to match number of rows and columns
  632.  
  633.     IF columns > UBOUND(SL_sheet, 2) THEN '                                                             more columns in this sheet than others?
  634.         REDIM _PRESERVE SL_sheet(handle, columns, UBOUND(SL_sheet, 3)) AS SL_SHEET '                    yes, increase the array's 2nd dimension to match
  635.     END IF
  636.     IF rows > UBOUND(SL_sheet, 3) THEN '                                                                more rows in this sheet than others?
  637.         REDIM _PRESERVE SL_sheet(handle, UBOUND(SL_sheet, 2), rows) AS SL_SHEET '                       yes, increase the array's 3rd dimension to match
  638.     END IF
  639.  
  640.     ' the variables in SL_sheet(x, 0, 0) will serve a dual purpose
  641.     ' SL_sheet(x, 0, 0).image will contain either -1 (true) or 0 (false) to indicate the first dimension of the array is in use.
  642.     ' SL_sheet(x, 0, 0).spritewidth will contain the number of columns contained in the sheet (the array's 2nd dimension)
  643.     ' SL_sheet(x, 0, 0).spriteheight will contain the number of rows contained in the sheet (the array's 3rd dimension)
  644.  
  645.     SL_sheet(handle, 0, 0).image = -1 '                                                         (TRUE)  mark as in use
  646.     SL_sheet(handle, 0, 0).spritewidth = columns '                                                      remember number of columns in sheet
  647.     SL_sheet(handle, 0, 0).spriteheight = rows '                                                        remember number of rows in sheet
  648.  
  649.     ' identify transparency of sprite sheet if requested
  650.  
  651.     IF transparency = -1 THEN '                                        (constant SL_SHEETTRANSPARENCY)  sheet have alpha channel?
  652.         x = 0 '                                                                                         yes, start at upper left x of sheet
  653.         y = 0 '                                                                                         start at upper left y of sheet
  654.         alpha = 255 '                                                                                   assume no alpha channel
  655.         _SOURCE sheetimage '                                                                            set sprite sheet image as source image
  656.         DO '                                                                                            start looping through the sheet's pixels
  657.             pixel = POINT(x, y) '                                                                       get the pixel's color attributes
  658.             alpha = _ALPHA32(pixel) '                                                                   get the alpha level (0 - 255)
  659.             IF alpha = 0 THEN EXIT DO '                                                                 if it is transparent then leave the loop
  660.             x = x + 1 '                                                                                 move right one pixel
  661.             IF x > sheetwidth THEN '                                                                    have we gone off the sheet?
  662.                 x = 0 '                                                                                 yes, reset back to the left beginning
  663.                 y = y + 1 '                                                                             move down one pixel
  664.             END IF
  665.         LOOP UNTIL y > sheetheight '                                                                    don't stop until the entire sheet has been checked
  666.         IF alpha = 0 THEN '                                                                             did we find a transparent pixel?
  667.             tempsprite = _NEWIMAGE(1, 1, 32) '                                                          yes, create a temporary image         * why did I have to do
  668.             _CLEARCOLOR pixel, tempsprite '                                                             set pixel found as transparent        * this hack to get
  669.             clearcolor = _CLEARCOLOR(tempsprite) '                                                      get the transparent color from image  * clearcolor to come out
  670.             _FREEIMAGE tempsprite '                                                                     temporary image no longer needed      * to the right value?
  671.         ELSE '                                                                                          no transparency found within sheet
  672.             transparency = 1 '                                                                          set sheet to having no alpha channel
  673.         END IF
  674.     ELSEIF transparency = 0 THEN '                                       (constant SL_SETTRANSPARENCY)  manually set alpha channel?
  675.         _CLEARCOLOR clearcolor, sheetimage '                                                            yes, set color as transparent
  676.         clearcolor = _CLEARCOLOR(sheetimage) '                                                          get the transparent color ************* again, why this hack?
  677.     END IF
  678.  
  679.     ' load sprites from sheet and place into sprite array
  680.  
  681.     FOR x = 1 TO columns '                                                                              cycle through the sheet's columns
  682.         FOR y = 1 TO rows '                                                                             cycle through the sheet's rows
  683.             SL_sheet(handle, x, y).image = _NEWIMAGE(spritewidth, spriteheight, 32) '                   create software sprite image
  684.             IF transparency < 1 THEN '                                                                  should a mask be created?
  685.                 SL_sheet(handle, x, y).mask = _NEWIMAGE(spritewidth, spriteheight, 32) '                yes, create software sprite mask image
  686.                 _DEST SL_sheet(handle, x, y).mask '                                                     write to the mask image
  687.             ELSE
  688.                 SL_sheet(handle, x, y).transparency = 0 '                                      (FALSE)  set sprite as having no transparency
  689.             END IF
  690.             _PUTIMAGE , sheetimage, SL_sheet(handle, x, y).image,_
  691.                  ((x - 1) * spritewidth, (y - 1) * spriteheight)-_
  692.                  ((x - 1) * spritewidth + spritewidth - 1, (y - 1) * spriteheight + spriteheight - 1) ' copy sprite from sheet and place in sprite image
  693.  
  694.             ' precalculate collision boundaries and update sprite mask if needed
  695.  
  696.             _SOURCE SL_sheet(handle, x, y).image '                                                      work from the software sprite image
  697.             top = spriteheight '                                                                        set initial collision boundary markers
  698.             left = spritewidth
  699.             bottom = 0
  700.             right = 0
  701.             FOR x1 = 0 TO spritewidth - 1 '                                                             cycle through the width of sprite
  702.                 FOR y1 = 0 TO spriteheight - 1 '                                                        cycle through the height of sprite
  703.                     IF POINT(x1, y1) <> clearcolor THEN '                                               is this pixel a transparent/background color?
  704.                         IF x1 < left THEN left = x1 '                                                   no, save position if left-most pixel
  705.                         IF y1 < top THEN top = y1 '                                                     save position if top-most pixel
  706.                         IF x1 > right THEN right = x1 '                                                 save position if right-most pixel
  707.                         IF y1 > bottom THEN bottom = y1 '                                               save position if bbottom-most pixel
  708.                     END IF
  709.                     IF transparency < 1 THEN '                                                          update software sprite mask?
  710.                         IF POINT(x1, y1) = clearcolor THEN '                                            yes, is this pixel a transparent/background color?
  711.                             PSET (x1, y1), _RGB32(255, 255, 255) '                                      yes, set as white on the mask image
  712.                         END IF
  713.                     END IF
  714.                 NEXT y1
  715.             NEXT x1
  716.             SL_sheet(handle, x, y).collx1 = left '                                                      collision box top left x
  717.             SL_sheet(handle, x, y).colly1 = top '                                                       collision box top left y
  718.             SL_sheet(handle, x, y).collx2 = right '                                                     collision box bottom right x
  719.             SL_sheet(handle, x, y).colly2 = bottom '                                                    collision box bottom right y
  720.             SL_sheet(handle, x, y).spritewidth = spritewidth '                                          remember sprite width
  721.             SL_sheet(handle, x, y).spriteheight = spriteheight '                                        remember sprite height
  722.         NEXT y
  723.     NEXT x
  724.     _FREEIMAGE sheetimage '                                                                             sprite sheet image no longer needed
  725.  
  726.     ' create precalculated rotation table for the sprite sheet (0 to 359 degrees)
  727.  
  728.     FOR x = 1 TO 359
  729.         px(0) = -spritewidth / 2 '                                                                      upper left  x polar coordinate of sprite
  730.         py(0) = -spriteheight / 2 '                                                                     upper left  y polar coordinate of sprite
  731.         px(1) = px(0) '                                                                                 lower left  x polar coordinate of sprite
  732.         py(1) = spriteheight / 2 '                                                                      lower left  y polar coordinate of sprite
  733.         px(2) = spritewidth / 2 '                                                                       lower right x polar coordinate of sprite
  734.         py(2) = py(1) '                                                                                 lower right y polar coordinate of sprite
  735.         px(3) = px(2) '                                                                                 upper right x polar coordinate of sprite
  736.         py(3) = py(0) '                                                                                 upper right y polar coordinate of sprite
  737.         sinr = SIN(-x / 57.2957795131) '                                                                calculate the sin of rotation
  738.         cosr = COS(-x / 57.2957795131) '                                                                calculate the cosine of rotation
  739.         bx1 = 0 '                                                                                       upper left x boundary of sprite
  740.         by1 = 0 '                                                                                       upper left y boundary of sprite
  741.         bx2 = 0 '                                                                                       lower right x boundary of sprite
  742.         by2 = 0 '                                                                                       lower right y boundary of sprite
  743.         FOR y = 0 TO 3 '                                                                                cycle through all four polar coordinates
  744.             x2 = (px(y) * cosr + sinr * py(y)) '                                                        compute new polar coordinate location
  745.             y2 = (py(y) * cosr - px(y) * sinr) '                                                        compute new polar coordinate location
  746.             px(y) = x2 '                                                                                save the new polar coordinate
  747.             py(y) = y2 '                                                                                save the new polar coordinate
  748.             IF px(y) < bx1 THEN bx1 = px(y) '                                                           save lowest  x value seen \  NOTE: use for
  749.             IF px(y) > bx2 THEN bx2 = px(y) '                                                           save highest x value seen  \ background image         <--------------------- LOOK
  750.             IF py(y) < by1 THEN by1 = py(y) '                                                           save lowest  y value seen  / rectangle coordinates
  751.             IF py(y) > by2 THEN by2 = py(y) '                                                           save highest y value seen /
  752.         NEXT y
  753.         SL_rotate(handle, x).rwidth = bx2 - bx1 + 1 '                                                   calculate width of rotated sprite
  754.         SL_rotate(handle, x).rheight = by2 - by1 + 1 '                                                  calculate height of rotated sprite
  755.         SL_rotate(handle, x).px0 = px(0) + ((bx2 - bx1 + 1) / 2) '                                      calculate triangular coordinates
  756.         SL_rotate(handle, x).px1 = px(1) + ((bx2 - bx1 + 1) / 2)
  757.         SL_rotate(handle, x).px2 = px(2) + ((bx2 - bx1 + 1) / 2)
  758.         SL_rotate(handle, x).px3 = px(3) + ((bx2 - bx1 + 1) / 2)
  759.         SL_rotate(handle, x).py0 = py(0) + ((by2 - by1 + 1) / 2)
  760.         SL_rotate(handle, x).py1 = py(1) + ((by2 - by1 + 1) / 2)
  761.         SL_rotate(handle, x).py2 = py(2) + ((by2 - by1 + 1) / 2)
  762.         SL_rotate(handle, x).py3 = py(3) + ((by2 - by1 + 1) / 2)
  763.     NEXT x
  764.     _SOURCE osource '                                                                                   return source to current
  765.     _DEST odest '                                                                                       return destination to current
  766.     SL_NEW_SPRITE_SHEET = handle '                                                                      return the handle number pointing to this sheet
  767.  
  768.  
  769. '    ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
  770. SUB SL_ERROR (routine AS STRING, errno AS INTEGER, info AS STRING) '                                                                                                                           SL_ERROR
  771.     'ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
  772.     '³                    °°°±±±²²²ÛÛÛ COMMAND DESCRIPTION AND USAGE ÛÛÛ²²²±±±°°°                     ³                                °°°±±±²²²ÛÛÛ NOTES ÛÛÛ²²²±±±°°°                                ³
  773.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  774.     '³ Reports a Sprite Library error to the programmer. Used internally only.                        ³ - A copy of this library has been provided that has all of the error checks removed. Once     ³
  775.     '³                                                                                                ³   you are sure no errors exist you would then include that library for your final             ³
  776.     '³ Input : routine - the function/subroutine the error occurred in                                ³   compilation. The error checking routines do take some processing away from your code so     ³
  777.     '³                                                                                                ³   performance will improve by removing them.                                                  ³
  778.     '³         errno   - the error number associated with the error                                   ³                                                                                               ³
  779.     '³                   100 - sprite does not exist                                                  ³                                                                                               ³
  780.     '³                   101 - sprite is not in use                                                   ³                                                                                               ³
  781.     '³                   102 - sprite can't be hidden                                                 ³                                                                                               ³
  782.     '³                   103 - invalid zoom value                                                     ³                                                                                               ³
  783.     '³                   104 - invalid rotation angle                                                 ³                                                                                               ³
  784.     '³                   105 - invalid flipping behavior                                              ³                                                                                               ³
  785.     '³                   106 - sheet does not exist                                                   ³                                                                                               ³
  786.     '³                   107 - sheet is not in use                                                    ³                                                                                               ³
  787.     '³                   108 - invalid transparency setting                                           ³                                                                                               ³
  788.     '³                   109 - invalid sprite width/height                                            ³                                                                                               ³
  789.     '³                                                                                                ³                                                                                               ³
  790.     '³         info    - any information that need to be conveyed with the error                      ³                                                                                               ³
  791.     '³                   such as a file name                                                          ³                                                                                               ³
  792.     '³                                                                                                ³                                                                                               ³
  793.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  794.     '³                            °°°±±±²²²ÛÛÛ KNOWN ISSUES ÛÛÛ²²²±±±°°°                              ³                               °°°±±±²²²ÛÛÛ CREDITS ÛÛÛ²²²±±±°°°                               ³
  795.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  796.     '³ none                                                                                           ³ This routine was created in response to a request from QB64 member pitt                       ³
  797.     '³                                                                                                ³ http://www.qb64.net/forum/index.php?topic=7281.0 (link no longer works)                       ³
  798.     '³                                                                                                ³                                                                                               ³
  799.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  800.     '³                                                                          °°°±±±²²²ÛÛÛ THEORY OF OPERATION ÛÛÛ²²²±±±°°°                                                                         ³
  801.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  802.     '³ A pure text screen is shown, the font reset to default, and _AUTODISPLAY enabled. This forces the code out of any graphics screen it may currently be in. The error is then displayed to the   ³
  803.     '³ programmer based on the values passed in. The program is then forced to terminate.                                                                                                             ³
  804.     '³                                                                                                                                                                                                ³
  805.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  806.     '³                                                                                °°°±±±²²²ÛÛÛ HISTORY ÛÛÛ²²²±±±°°°                                                                               ³
  807.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  808.     '³ Date: 09/09/18 by Terry Ritchie                                                                                                                                                                ³
  809.     '³     : Initial writing of code.                                                                                                                                                                 ³
  810.     '³                                                                                                                                                                                                ³
  811.     'ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
  812.  
  813.     SCREEN 0, 0, 0, 0 '                                                             go to a pure text screen
  814.     _FONT 16 '                                                                      set the standard screen 0 font
  815.     IF _FULLSCREEN THEN _FULLSCREEN _OFF '                                          turn off full screen if on
  816.     _AUTODISPLAY '                                                                  auto update the display
  817.     CLS '                                                                           clear the screen
  818.     COLOR 10, 0
  819.     PRINT "                   **************************************" '             print error header
  820.     PRINT "                   ** Sprite Library Error Encountered **"
  821.     PRINT "                   **************************************"
  822.     PRINT
  823.     COLOR 15, 0
  824.     PRINT " "; routine;
  825.     COLOR 7, 0
  826.     PRINT " has reported error";
  827.     COLOR 30, 0
  828.     PRINT STR$(errno)
  829.     COLOR 7, 0
  830.     PRINT
  831.     SELECT CASE errno '                                                             which error number is being reported?
  832.         CASE 100
  833.             PRINT "- "; CHR$(34); info; CHR$(34); " sprite sheet does not exist"
  834.             PRINT "- check path or spelling"
  835.         CASE 101
  836.             PRINT "- invalid transparency setting supplied - valid settings are"
  837.             PRINT "- : -1 (constant SL_SHEETTRANSPARENCY)"
  838.             PRINT "- :  0 (constant SL_SETTRANSPARENCY)"
  839.             PRINT "- :  1 (constant SL_NOTRANSPARENCY)"
  840.         CASE 102
  841.             PRINT "- sprite width and height must be greater than zero"
  842.         CASE 103
  843.             PRINT "- selecting to use a sheet's transparency only works with .PNG files"
  844.             PRINT "- the function was passed a "; info; " file."
  845.         CASE 104
  846.             PRINT "- there must be at least one column and one row of sprites on sheet"
  847.         CASE 200
  848.             PRINT "- the specified sprite sheet is not in use or does not exist"
  849.         CASE 201
  850.             PRINT "- invalid row or column selected for specified sprite sheet"
  851.         CASE 202
  852.             PRINT "- background restore behavior for a sprite can only be 0 (FALSE) or -1 (TRUE)"
  853.         CASE 300, 400, 500
  854.             PRINT "- the requested sprite does not exist"
  855.     END SELECT
  856.     COLOR 12, 0
  857.     PRINT
  858.     PRINT " See sprite library doumentation for further explanation."
  859.     COLOR 7, 0
  860.     DO: LOOP UNTIL INKEY$ = "" '                                                    clear the keyboard buffer
  861.     END '                                                                           end the program
  862.  
  863.  
  864.  
  865. '    ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
  866. FUNCTION SL_VALID_SPRITE (handle AS INTEGER) '                                                                                                                                         SL_VALID_SPRITE
  867.     'ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
  868.     '³                    °°°±±±²²²ÛÛÛ COMMAND DESCRIPTION AND USAGE ÛÛÛ²²²±±±°°°                     ³                                °°°±±±²²²ÛÛÛ NOTES ÛÛÛ²²²±±±°°°                                ³
  869.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  870.     '³ Reports on the validity of a sprite handle (pointer).                                          ³                                                                                               ³
  871.     '³                                                                                                ³                                                                                               ³
  872.     '³ valid% = SL_VALID_SPRITE(mysprite%)                                                            ³                                                                                               ³
  873.     '³                                                                                                ³                                                                                               ³
  874.     '³ Input : handle - the handle (pointer) of the sprite being examined.                            ³                                                                                               ³
  875.     '³                                                                                                ³                                                                                               ³
  876.     '³ Output: an integer value of zero (0) (FALSE) or negative 1 (-1) (TRUE)                         ³                                                                                               ³
  877.     '³                                                                                                ³                                                                                               ³
  878.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  879.     '³                            °°°±±±²²²ÛÛÛ KNOWN ISSUES ÛÛÛ²²²±±±°°°                              ³                               °°°±±±²²²ÛÛÛ CREDITS ÛÛÛ²²²±±±°°°                               ³
  880.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  881.     '³ None                                                                                           ³ None                                                                                          ³
  882.     '³                                                                                                ³                                                                                               ³
  883.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  884.     '³                                                                          °°°±±±²²²ÛÛÛ THEORY OF OPERATION ÛÛÛ²²²±±±°°°                                                                         ³
  885.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  886.     '³ The sprite database is examined at the index the handle points to. If .inuse is -1 (TRUE) then the sprite handle is valid.                                                                     ³
  887.     '³                                                                                                                                                                                                ³
  888.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  889.     '³                                                                                °°°±±±²²²ÛÛÛ HISTORY ÛÛÛ²²²±±±°°°                                                                               ³
  890.     'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  891.     '³ Date: 09/11/18 by Terry Ritchie                                                                                                                                                                ³
  892.     '³     : Initial writing of code.                                                                                                                                                                 ³
  893.     '³                                                                                                                                                                                                ³
  894.     'ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
  895.  
  896.     ' declare global variables
  897.  
  898.     SHARED SL_sprite() AS SL_SPRITE '   master working sprite array
  899.  
  900.     IF handle > UBOUND(SL_SPRITE) OR (NOT SL_sprite(handle).inuse) THEN '                                is this a valid sprite handle?
  901.         SL_VALID_SPRITE = 0 '                                                                   (FALSE)  no, return 0
  902.     ELSE '                                                                                               yes, it is valid
  903.         SL_VALID_SPRITE = -1 '                                                                   (TRUE)  return -1
  904.     END IF
  905.  
  906.  
  907.  
  908.  
  909. '    ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
  910.  
  911. 'ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
  912. '³                    °°°±±±²²²ÛÛÛ COMMAND DESCRIPTION AND USAGE ÛÛÛ²²²±±±°°°                     ³                                °°°±±±²²²ÛÛÛ NOTES ÛÛÛ²²²±±±°°°                                ³
  913. 'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  914. '³                                                                                                ³                                                                                               ³
  915. '³                                                                                                ³                                                                                               ³
  916. 'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  917. '³                            °°°±±±²²²ÛÛÛ KNOWN ISSUES ÛÛÛ²²²±±±°°°                              ³                               °°°±±±²²²ÛÛÛ CREDITS ÛÛÛ²²²±±±°°°                               ³
  918. 'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  919. '³                                                                                                ³                                                                                               ³
  920. '³                                                                                                ³                                                                                               ³
  921. 'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  922. '³                                                                          °°°±±±²²²ÛÛÛ THEORY OF OPERATION ÛÛÛ²²²±±±°°°                                                                         ³
  923. 'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  924. '³                                                                                                                                                                                                ³
  925. '³                                                                                                                                                                                                ³
  926. 'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  927. '³                                                                                °°°±±±²²²ÛÛÛ HISTORY ÛÛÛ²²²±±±°°°                                                                               ³
  928. 'ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
  929. '³                                                                                                                                                                                                ³
  930. '³                                                                                                                                                                                                ³
  931. 'ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
  932.  
« Last Edit: September 12, 2018, 01:03:22 AM by TerryRitchie »
g=c800:5 fixes everything

Offline SMcNeill

  • QB64 Developer
Re: Sprite Library Revisited
« Reply #1 on: September 06, 2018, 02:01:03 AM »
Why not use a data file to go along with each Sprite sheet? 

MySprite.jpg would be the name of the sheet, MySprite.NFO could be the name of a simple file containing pixel coordinates for each Sprite in the sheet.  Seems the easiest way to me for variable size sprites.

Offline TerryRitchie

  • Semper Fidelis
Re: Sprite Library Revisited
« Reply #2 on: September 06, 2018, 02:06:51 AM »
Yeah, in the game industry that's called a sprite atlas and in an earlier version of my code I actually wrote the coordinates out to a file as you suggested. However, I want the library to contain as much of the inner workings as possible with the programmer shielded from all the details.

Standard practice is to have all sprites the same size and ordered on the sheet. Having the programmer supply an atlas would be a pain in the ascii for him/her, especially since they are using a sprite library to avoid learning how to actually manipulate sprites.

Make sense? I get what your saying though.

One other thing too, manually trying to center up different sized sprites is way harder than it sounds.
« Last Edit: September 06, 2018, 02:09:05 AM by TerryRitchie »
g=c800:5 fixes everything

Offline SMcNeill

  • QB64 Developer
Re: Sprite Library Revisited
« Reply #3 on: September 06, 2018, 08:11:18 AM »
Trick would be to have a program which calculates the Sprite dimensions for you, and then places the individual sprites onto a sheet and preserve the coordinates. 

Steps I'd imagine would be:

Sprite editor to make a Sprite (or MS Paint/whatever tool the user wants).  A lot of these editors set us a default size for sheet creation (a lot of the RPGmaker sprites are 64x64 or 128x128).

A QB64 program to clear color background (black or white, as I've seen both used as a standard background), and then a simple detection routine to minimize size as much as possible.  (A little 32x32 fireball would have the blank edges stripped from it.)  Resave via SaveImage to the new size in BMP or PNG format.

An INFORM program where the user can load sprites and drag them into place on a Sprite sheet, to manually minimize overall size, or to set a specific order/layout....  OR...   A program which automatically assembles the sheet for us, from the edited files.

Either way, preserving the Atlas would be an automated task and wouldn't be anything the end-user would ever have to worry about, with the added feature of saving load/runtime inside the game, as all the calculations have already been done previously, and not need to happen on demand, in game.

*********************
*********************

One personal thing I'd like to see added to your library is the ability to SetSpritePath. 

"TN,P1,N1,P1,TE,P1,E1......RA"

A simple string script which tells the Sprite to try and Turn North (load north facing spite, if you have a directional set), Pause 1 turn, North 1, Pause 1 Turn, Turn East, Pause 1 Turn, East 1.... RepeatAll.

PRESTO!  Simple patrol path instantly added!

Add simple options for NP (no path; just wander), CH (chase hero, using pathfinding as discussed previously), and PB (play brick; don't move).

It'd be the start of a simple scripting system which the user could add/expand on later with future options (such as "LC123" so if the user Left Clicks on the Sprite, the program performs event 123 which might be a Popup saying, "Hi Hero!  How's your Mama today?").

It'd take the Sprite Library from just being a library to draw/display sprites, to becoming a much more active Game Engine.   ;)

Re: Sprite Library Revisited
« Reply #4 on: September 06, 2018, 10:14:31 AM »
I was wondering how you might handle rotation (with collision) but I see you are doing a sprite for every occasion! Wow, that's allot of sprites.

Petr had some discussion with pixel perfect collision here: https://www.qb64.org/forum/index.php?topic=261.0
As I recall he was entangling images pretty well (without collision), but again wow! that's allot of calculation.


« Last Edit: September 06, 2018, 10:15:43 AM by bplus »
B = B + ...

Offline Petr

  • The best code is the DNA of the hops.
Re: Sprite Library Revisited
« Reply #5 on: September 06, 2018, 10:16:11 AM »
Hi,

What you are looking for is the collision detection between N-angles. No matter how big the picture is, the subtlety of its borders is essential. This means that a finer entry that contains more points will also be very demanding on the processor. Making the mask out of the picture is not a problem, then the outer points (image border)  (each N point according to the detector sensitivity setting). The distance between these points will be given by the character's step. For example: If the characters move in the game with a 20 pixel pitch, it is enough to evaluate the collision detection every twentieth point of the circuit.


That's what I did somehow in writing collision detection. Then I realized another thing. To speed up the operation, it is possible to clarify where there is a collision. If the body is to be detected only to the left and right, it is not necessary for the field to contain the coordinates of the bottom and the ceiling. It is possible that MLINE could well serve to detect a collision between 2 points. In essence, it only sends the points through which the line passes. Just rewrite it - not use PSET, but this output send as array outputs...

Next option is ELLIPSE collision detection.

This source create image borders for collision detection:

rewrite on line 25 image name to your image name first
Code: QB64 [Select]
  1.  
  2. TYPE Borders '                                          this is "struct" for array Borders. This array conatains borders between image and background. It is my first vesion for collision detection.
  3.     X AS INTEGER '     X coordinate for point on border between two different colors (that is why you need one colored background for writing borders)
  4.     Y AS INTEGER '     Y coordinate for point on border between two different color
  5.     Clr AS LONG '      color on border, it is read, but then is not used, you need it not, only for drawing colored circuit in original colors
  6.     maxX AS INTEGER '  use index 0 only and return maximal picture X size (real width there are calculated valid pixels only)
  7.     minX AS INTEGER '  use index 0 only and return real image start on oxis X  (for use as quadratic collision detect with MinY and MaxY)
  8.     MaxY AS INTEGER '  use index 0 only and return real height
  9.     MinY AS INTEGER '  use index 0 only and return real start on axis Y
  10.  
  11. TYPE Brd '            this is next level - "compressed" array type Borders - contains not all color borders, but just StartX, EndX (for every Y) and StartY and EndY (for every X) (just circuit)
  12.     Xmin AS INTEGER ' if picture height is 100, there is 100 records for Xmin. Its X on left, its image start X
  13.     Xmax AS INTEGER ' if picture height is 100, there is 100 records for Xmax. Its X from right, last image point
  14.     Y AS INTEGER '    Y it is "help" value, need for draw content but not need for detect function
  15.     Ymin AS INTEGER ' if picture WIDTH is 100, there is 100 records for Ymin. Its Y from above, its image start Y
  16.     Ymax AS INTEGER ' if picture WIDTH is 100, there is 100 records for Ymax. Its Y from bottom, its image end Y
  17.     X AS INTEGER '    the same as Y
  18. REDIM S(0) AS Brd
  19.  
  20. my& = _NEWIMAGE(800, 600, 32)
  21. SCREEN my&
  22. PRINT "1] program load picture to memory"
  23. imag& = _LOADIMAGE("z.jpg", 32) '                       load example picture (downloaded from google)
  24. PRINT "2] function Filter& set image background (R input, G input, B input, R output, G output, B output)"
  25. image& = filter&(imag&, 150, 150, 150, 255, 255, 255) ' this is exemplary function. Downgrade background colors in set range to set RGB32 value: First 3* 255 are RGB inputs, next 3*230 are RGB outputs
  26. '                                                       This muss be set correctly for fine work! For use write program arrays outputs to text file, bacause its then always valid for this one picture
  27. '                                                       Array T contains all colors borders information, array S contains just external borders information
  28. SCREEN image&: SLEEP '                                  'It depends a lot on the correct setting of this function if the source image does not contain clear boundaries for proper border detection.
  29. SCREEN my&
  30. REDIM T(0) AS Borders
  31. _SOURCE image&
  32. PRINT "3] SUB Border create array named 'T' that contains X, Y about all colors borders and show it:"
  33. Border T(), image&, _RGB32(255, 255, 255) '            function based on ONE color in background. Write image borders to array, writed for 256 colors and or truecolor, but tested for truecolor only
  34. '                                                      parameter in function is background color in source image
  35. FOR u = LBOUND(T) TO UBOUND(T)
  36.     PSET (T(u).X, 50 + T(u).Y + 80)
  37. PRINT "4] SUB Compress reduce the input array T by writing only outer points to array S"
  38. compress T(), S(), 25 'if in game - character - step  size is bigger than 25, muss this step be enought for collis detect...
  39.  
  40.  
  41. PRINT "5] This is compressed (array S) output (PSET) on left, LINE for < > method is right" '    program show you detected and to array writed borders
  42. FOR T = LBOUND(s) TO UBOUND(s)
  43.  
  44.     IF S(T).Xmin AND S(T).Xmax THEN LINE (300 + S(T).Xmin, 370 + S(T).Y)-(300 + S(T).Xmax, 370 + S(T).Y)
  45.     IF S(T).Ymin AND S(T).Ymax THEN LINE (300 + S(T).X, 370 + S(T).Ymax)-(300 + S(T).X, 370 + S(T).Ymin)
  46.  
  47.  
  48.     IF S(T).Xmin THEN PSET (S(T).Xmin, S(T).Y + 370)
  49.     IF S(T).Xmax THEN PSET (S(T).Xmax, S(T).Y + 370)
  50.     IF S(T).Ymin THEN PSET (S(T).X, S(T).Ymin + 370)
  51.     IF S(T).Ymax THEN PSET (S(T).X, S(T).Ymax + 370)
  52.  
  53.  
  54. PRINT "Array size in records (S):"; UBOUND(s); " and size array T contains all color borders information:"; UBOUND(T)
  55.  
  56.  
  57.  
  58.  
  59. SUB Border (array() AS Borders, Source AS LONG, Background_Color AS _UNSIGNED LONG) 'own border detection sub
  60.     _DEST Source&
  61.     minX = _WIDTH(Source&)
  62.     minY = _HEIGHT(Source&)
  63.     DIM M AS _MEM '32 bytova promenna                                                                         '  MEM values are 32 BYTES long,
  64.     M = _MEMIMAGE(Source&) '                                                                                     M is pointer to memory with image content
  65.     SELECT CASE _PIXELSIZE(Source&) '                                                                           select if image is 256 colored, 8 bit (1 byte for pixel) or 32 bit colored (4 byte for pixel)
  66.         CASE 0: END 'not writed for text mode yet                                                                0 is for text mode, then this screen contains cells 8 * 16 pixels, one cell has value one BYTE
  67.         CASE 1: '    for 256 colors image
  68.             REDIM Value AS _UNSIGNED _BYTE, OldValue AS _UNSIGNED _BYTE '                                       because i need read value directly from memory, muss set correct type first - basicaly are
  69.             FOR y = 1 TO _HEIGHT(Source&) - 1 '                                                                 all varibles set to SINGLE (4 byte long)
  70.                 FOR x = 1 TO _WIDTH(Source&) - 1
  71.                     OldValue = Value
  72.                     _MEMGET M, M.OFFSET + IN&(x, y), Value '                                                    is the same as POINT but very  more faster!  _MEMGET is as POINT for read color value,
  73.                     '                                                                                           _MEMPUT is the same as POINT for writing color value. In use with mem muss be correct type and offset set.
  74.                     IF Value = Background_Color AND OldValue <> Background_Color OR Value <> Background_Color AND OldValue = Background_Color THEN
  75.                         GOSUB rozsah '                                                                          subprogram continuously compares values for MinX, MaxX, MinY and MaxY
  76.                         i = i + 1
  77.                         REDIM _PRESERVE array(i) AS Borders '                                                   this command increases the field value without losing the field contents // to i size
  78.                         array(i).X = x
  79.                         array(i).Y = y
  80.                         array(i).Clr = Value
  81.                     END IF
  82.                     IF y > 0 THEN _MEMGET M, M.OFFSET + IN&(x, y - 1), Value '                                  condition for preveting MEMORY REGION OUT OF RANGE and read current color value on X, Y
  83.                     IF Value = Background_Color AND OldValue <> Background_Color OR Value <> Background_Color AND OldValue = Background_Color THEN
  84.                         i = i + 1 'This condition: If current color is the same as background and previous color is different than background or above, write this coordinates to array. Easy trick.
  85.                         REDIM _PRESERVE array(i) AS Borders '                                                   this command increases the field value without losing the field contents // to i size
  86.                         array(i).X = x
  87.                         array(i).Y = y '                                                            program line 117 control colors in row, program line 126 control colors in column
  88.                         array(i).Clr = Value
  89.                     END IF
  90.             NEXT x, y
  91.  
  92.         CASE 4: 'for 32 bit screen                                                                ' this block is the same for truecolor (4 byte blocks)
  93.             REDIM Value4 AS LONG, OldValue4 AS LONG '                                               program lines 142 and 153 control and writing borders to array
  94.             FOR y = 0 TO _HEIGHT(Source&) - 4
  95.                 FOR x = 0 TO _WIDTH(Source&) - 4
  96.                     OldValue4& = Value4&
  97.                     _MEMGET M, M.OFFSET + IN&(x, y), Value4&
  98.                     IF Value4& = Background_Color AND OldValue4& <> Background_Color OR Value4& <> Background_Color AND OldValue4& = Background_Color THEN
  99.                         GOSUB rozsah
  100.                         i = i + 1
  101.                         REDIM _PRESERVE array(i) AS Borders
  102.                         array(i).X = x
  103.                         array(i).Y = y
  104.                         array(i).Clr = Value4&
  105.  
  106.                     END IF
  107.  
  108.                     IF y > 0 THEN _MEMGET M, M.OFFSET + IN&(x, y - 1), Value4&
  109.  
  110.                     IF Value4& = Background_Color AND OldValue4& <> Background_Color OR Value4& <> Background_Color AND OldValue4& = Background_Color THEN
  111.                         i = i + 1
  112.                         REDIM _PRESERVE array(i) AS Borders
  113.                         array(i).X = x
  114.                         array(i).Y = y
  115.                         array(i).Clr = Value4&
  116.  
  117.                     END IF
  118.                     nic:
  119.             NEXT x, y
  120.     END SELECT
  121.     _DEST 0
  122.     array(0).minX = minX '                                                                           to zero position in array are writed image width and height for
  123.     array(0).maxX = maxX '                                                                           possibillity quadric collision detection
  124.     array(0).MinY = minY
  125.     array(0).MaxY = maxY
  126.  
  127.     EXIT SUB
  128.     rozsah:
  129.     IF minX > x AND x > 0 THEN minX = x
  130.     IF minY > y AND y > 0 THEN minY = y
  131.     IF maxX < x THEN maxX = x
  132.     IF maxY < y THEN maxY = y
  133.     RETURN
  134.  
  135.     IN& = _PIXELSIZE(_SOURCE) * ((_WIDTH * y) + x) '                                                  function return offset for MEM functions. Copyed from Steve McNeill
  136.  
  137. FUNCTION filter& (image AS LONG, Ri, Gi, Bi, Ro, Go, Bo) '                                            Function has the task of making the background of the specified color and reducing the
  138.     DIM f AS _MEM '                                                                                   background color unevenness to make the best possible image border detection
  139.     f = _MEMIMAGE(image&)
  140.     '   filter& = _MEMNEW(_WIDTH(image&) * _HEIGHT(image&) * _PIXELSIZE(image&)) '                    Here is one bug for developers. Uncomment and give C++ compilation error. I know why, so just for info. :-D With love :-D
  141.     filter& = _NEWIMAGE(_WIDTH(image&), _HEIGHT(image&), 32)
  142.     DIM GG AS _MEM
  143.     GG = _MEMIMAGE(filter&)
  144.     _SOURCE image&
  145.     _DEST image& '                                                                                    next ask for developers. Comment DEST on this line and start it. You give HALF picture. Why?
  146.     SELECT CASE _PIXELSIZE(image&)
  147.         CASE 4
  148.             DIM clr AS LONG
  149.             choice& = _RGBA32(Ro, Go, Bo, 255)
  150.             FOR y = 0 TO _HEIGHT(image&) - 4
  151.                 FOR x = 0 TO _WIDTH(image&) - 4
  152.                     _MEMGET f, f.OFFSET + IN&(x, y), clr&
  153.  
  154.                     R = _RED32(clr&)
  155.                     G = _GREEN32(clr&)
  156.                     B = _BLUE32(clr&)
  157.                     A = _ALPHA32(clr&)
  158.                     IF R > Ri AND G > Gi AND B > Bi THEN _MEMPUT GG, GG.OFFSET + IN&(x, y), choice& ELSE _MEMPUT GG, GG.OFFSET + IN&(x, y), clr&
  159.     NEXT x, y: END SELECT
  160.     _MEMFREE f
  161.     _MEMFREE GG
  162.     _FREEIMAGE image&
  163.  
  164. SUB compress (array() AS Borders, outArray() AS Brd, stp) 'z pole vybere jen nejvetsi a nejmensi X pro JEDNO Y, bude to mit vystup X1, X2, Y, pres line to udela obrys
  165.  
  166.     FOR C = LBOUND(array) TO UBOUND(array)
  167.         FOR D = LBOUND(array) TO UBOUND(array)
  168.             IF array(D).Y = ly THEN
  169.                 IF array(D).X > 0 AND array(D).Y > 0 THEN
  170.                     IF max < array(D).X THEN max = array(D).X
  171.                     IF min > array(D).X THEN min = array(D).X
  172.                 END IF
  173.             END IF
  174.         NEXT D
  175.         IF min < 65535 AND min > 0 THEN
  176.             REDIM _PRESERVE outArray(i) AS Brd
  177.  
  178.             outArray(i).Y = ly
  179.             outArray(i).Xmin = min
  180.             outArray(i).Xmax = max
  181.             i = i + 1
  182.         END IF
  183.         min = 65535: max = 0: ly = ly + 1
  184.     NEXT C
  185.  
  186.     min = 65535: max = 0: ly = 0
  187.     FOR C = LBOUND(array) TO UBOUND(array)
  188.         FOR D = LBOUND(array) TO UBOUND(array)
  189.             IF array(D).X = ly THEN
  190.                 IF array(D).X > 0 AND array(D).Y > 0 THEN
  191.                     IF max < array(D).Y THEN max = array(D).Y
  192.                     IF min > array(D).Y THEN min = array(D).Y
  193.                 END IF
  194.             END IF
  195.         NEXT D
  196.         IF min < 65535 AND min > 0 THEN
  197.             REDIM _PRESERVE outArray(i) AS Brd
  198.             '    LINE (ly, min)-(ly, max)
  199.             outArray(i).X = ly
  200.             outArray(i).Ymin = min
  201.             outArray(i).Ymax = max
  202.             i = i + 1
  203.         END IF
  204.         min = 65535: max = 0: ly = ly + 1
  205.     NEXT C
  206.     IF stp > 1 THEN 'performs a reduction of records according to a specified number of STP steps. This is useful for speeding up the program if the basic
  207.         '            move of the pictures is not 1 but more, so  then it is necessary for all the pictures to move in the same step and it is not necessary to write all
  208.         '            the collision coordinates.
  209.  
  210.         'create copy array outArray AS BRD
  211.         REDIM Arrcopy(0) AS Brd
  212.         ii = 0
  213.         FOR copy = LBOUND(outarray) TO UBOUND(outarray) STEP stp
  214.             ii = ii + 1
  215.             REDIM _PRESERVE Arrcopy(ii) AS Brd
  216.             Arrcopy(ii) = outArray(copy)
  217.         NEXT copy
  218.         REDIM outArray(0) AS Brd
  219.  
  220.         FOR CopyBack = LBOUND(arrcopy) TO UBOUND(arrcopy)
  221.             REDIM _PRESERVE outArray(CopyBack) AS Brd
  222.             outArray(CopyBack) = Arrcopy(CopyBack)
  223.         NEXT
  224.         ERASE Arrcopy
  225.     END IF
  226.  
  227.  

this code NOT DETECT collision, but do borders for collision detection. (i have it not writed yet). I you have this points in memory, then is possible using (after upgrading sub outputs to array) this MLINE sub:

Code: QB64 [Select]
  1.  
  2.  
  3. MLine 0, 320, 200, 0
  4. LINE (0, 320)-(200, 0), 14
  5.  
  6.  
  7.  
  8.  
  9.  
  10.  
  11.  
  12. SUB MLine (x1 AS INTEGER, y1 AS INTEGER, x2 AS INTEGER, y2 AS INTEGER)
  13.     '------------------------------------------------------
  14.     'in line solution for X:
  15.     IF x1 < x2 AND y1 = y2 THEN
  16.         FOR K = x1 TO x2
  17.             PSET (x1 + (K - x1), y1)
  18.         NEXT K
  19.         EXIT SUB
  20.     END IF
  21.  
  22.     IF x1 > x2 AND y1 = y2 THEN
  23.         FOR K = x1 TO x2 STEP -1
  24.             PSET (x1 + (K - x1), y1)
  25.         NEXT K
  26.         EXIT SUB
  27.     END IF
  28.     '-------------------------------------------------------
  29.     'in line solution for Y:
  30.     IF x1 = x2 AND y1 < y2 THEN
  31.         FOR K = y1 TO y2
  32.             PSET (x1, y1 + (K - y1))
  33.         NEXT K
  34.         EXIT SUB
  35.     END IF
  36.  
  37.     IF x1 = x2 AND y1 > y2 THEN
  38.         FOR K = y1 TO y2 STEP -1
  39.             PSET (x1, y1 + (K - y1))
  40.         NEXT K
  41.         EXIT SUB
  42.     END IF
  43.  
  44.  
  45.     '--------------------------------------------------- radkova reseni otestovana a v poradku
  46.     D = SQR((x1 - x2) ^ 2 + (y1 - y2) ^ 2)
  47.  
  48.     ky = ABS(y1 - y2) / D
  49.     kx = ABS(x1 - x2) / D
  50.  
  51.     IF x1 > x2 THEN kx = kx * -1
  52.     IF y1 > y2 THEN ky = ky * -1
  53.  
  54.     'solution for X1 <> X2, Y1 <> Y2
  55.     outX = x1: outY = y1
  56.  
  57.     FOR K = 0 TO D
  58.         PSET (outX, outY)
  59.         outX = outX + kx
  60.         outY = outY + ky
  61.     NEXT K
  62.  

or much easyer. If is picture simetric, use this collision detection function:

Code: QB64 [Select]
  1. 'elipse collision
  2. LET CenterX = 160: LET CenterY = 100: LET A = 40: LET B = 20
  3.  
  4. FOR F = 0 TO _PI(2) STEP .01
  5.     PSET (CenterX + SIN(F) * A, CenterY + COS(F) * B)
  6.  
  7.     IF Ellipse(_MOUSEX, _MOUSEY, CenterX, CenterY, A, B) THEN LOCATE 1, 1: PRINT "collision" ELSE LOCATE 1, 1: PRINT SPACE$(9)
  8.  
  9.  
  10. FUNCTION Ellipse (X&, Y&, CX&, CY&, A&, B&)
  11.     XY## = (((X& - CX&) ^ 2) / A& ^ 2) + (((Y& - CY&) ^ 2) / B& ^ 2)
  12.     IF XY## <= 1.1 THEN Ellipse = 1 ELSE Ellipse = 0
  13.  
  14.  


Offline TerryRitchie

  • Semper Fidelis
Re: Sprite Library Revisited
« Reply #6 on: September 06, 2018, 11:46:34 AM »
I was wondering how you might handle rotation (with collision) but I see you are doing a sprite for every occasion! Wow, that's allot of sprites.

Yes, that's called "cheater" 3D. I designed the ship using a 3D designer program then output an image for each rotation of 10 degrees. This was how Donkey Kong Country was done in 1994 to get the illusion of having 3D characters while using a 2D engine. It's painstaking work to create sheets like this but simple and effective when wanting the illusion of 3D. Most overhead games of years ago (Starcraft) were done using this method as well.

Doom used a similar method to achieve 3D in a 2D environment. I've attached the Archvile sprite sheet to show how much work was put into just one character. The two John's used clay models and a 3D scanner to create their sprites.
g=c800:5 fixes everything

Offline TerryRitchie

  • Semper Fidelis
Re: Sprite Library Revisited
« Reply #7 on: September 06, 2018, 11:51:26 AM »
It'd take the Sprite Library from just being a library to draw/display sprites, to becoming a much more active Game Engine.   ;)

All good points! This is why I wanted to bounce this off the forum before I got too heavy into this. So many good ideas. I can already envision the code in my head for many of the ideas you presented here.
g=c800:5 fixes everything

Offline TerryRitchie

  • Semper Fidelis
Re: Sprite Library Revisited
« Reply #8 on: September 06, 2018, 12:21:00 PM »
Next option is ELLIPSE collision detection.

I like your ellipse detection. My library currently uses circle detection. It never occurred to me to use a ratio between two radii with Pythagoras to achieve elliptical detection. Nice!
g=c800:5 fixes everything

Offline Petr

  • The best code is the DNA of the hops.
Re: Sprite Library Revisited
« Reply #9 on: September 06, 2018, 12:24:04 PM »
Hi again, for  your ask - how do image detection better - for some images is need polygon image scan. It is for cases, if is square image not possible to use as on this:

Offline TerryRitchie

  • Semper Fidelis
Re: Sprite Library Revisited
« Reply #10 on: September 06, 2018, 12:28:58 PM »
I played around with the possibility of using a polygon technique years ago. However, the processing needed to do this slowed everything to a crawl when put into a loop. If memory serves I wasn't able to get over 10-15 FPS because of all the time needed to check each part of the polygon.

I tried making the routine a bit smarter by detecting where the actual collision was taking place in order not to have to check the entire polygon structure of both sprites. But I could never get it to work quite right.

That elliptical collision has me thinking. A few well placed ellipses of different sizes throughout a sprite could be a close representation of a polygon detection method. I could easily write a program that allows the programmer to place the different sized ellipses onto a sprite, covering most if not all of the image. Writing code to automagically do that would take some work though.
« Last Edit: September 06, 2018, 12:32:46 PM by TerryRitchie »
g=c800:5 fixes everything

Offline Petr

  • The best code is the DNA of the hops.
Re: Sprite Library Revisited
« Reply #11 on: September 06, 2018, 12:46:36 PM »
I would deal with this particular case by manually defining the points for each frame. This is then loaded as a _NEWIMAGE set for each. OR, if it's about saving memory, well, it can be done by dragging the picture the way it is and no longer splitting into single frames, but using pre-defined polygons. But I think, that more practical is if  picture will be cut into single frames because then the disk image can be released from memory and the all chopped parts  are together  maximal  the same size as the source image. And then the putimage will be used and speed will not be a problem.

i try do something  in this way.

Offline TerryRitchie

  • Semper Fidelis
Re: Sprite Library Revisited
« Reply #12 on: September 07, 2018, 11:54:49 AM »
I optimized the code in the original post above. Image detection is much simpler and the code now generates a sprite mask for use in pixel-perfect detection.

It also generates a hardware image for viewing now.
« Last Edit: September 07, 2018, 12:15:57 PM by TerryRitchie »
g=c800:5 fixes everything

Offline TerryRitchie

  • Semper Fidelis
Re: Sprite Library Revisited
« Reply #13 on: September 11, 2018, 02:18:35 AM »
Petr - your N-Angles code is intriguing. Sorry I didn't comment on it earlier. I have it saved and will be looking it over to see how I may utilize it.

I'm happy to report that I'm chugging along on the new version of the sprite library (I updated the code in the original post above if anyone is interested in seeing it). I want to make sure it's as compatible as possible with Linux and MacOS as well. I can handle the Linux end of things, but when it comes time I'll need you MacOS users to help me out. My last Powerbook died on me a few years back.

I'm taking a whole new approach to the library that will make it easier to incorporate the ideas that Steve and others have put forth. What I have now is already magnitudes faster than the old library. QB64 coding is all coming back to me like boomerang! The new QB64 version, with its new features, and new IDE make this so much more enjoyable. Really great job to all the contributors to it over the years.
g=c800:5 fixes everything

Offline TerryRitchie

  • Semper Fidelis
Re: Sprite Library Revisited
« Reply #14 on: September 12, 2018, 01:12:50 AM »
Super exciting and productive day today! My goal was to incorporate sprite rotation by the end of the day. I finished sprite rotation and flipping!

The old sprite library was very slow to perform sprite rotation due to the fact that sprites were not preloaded. This meant that every time a sprite needed to be rotated, the image was grabbed from the sheet, calculations were done to get the triangular coordinates for _MAPTRIANGLE and then the mapped image would be placed to the screen. This happened each and every time you rotated a sprite. Keeping a sprite rotating 360 degrees took a LOT of horsepower.

What I did today was create code that precalculates all of the variables needed for sprite rotation when the sheet is initially loaded and places the values in a rotational lookup table. Now keeping a sprite rotating 360 degrees is just a simple matter of plugging the known values into _MAPTRIANGLE. Boom! Instant rotation. And wow is it fast, because of the precalculated figures and the use of hardware images.

I updated the code in the original post above along with adding the sprite sheet (dkong.png)  for the test code contained in it.

Oh, one more thing ... _MAPTRIANGLE is a beast! LOL, sorry, that command was not my friend today.
« Last Edit: September 12, 2018, 01:15:32 AM by TerryRitchie »
g=c800:5 fixes everything