Author Topic: UnseenGDK (Game Development Kit) For QB64  (Read 65325 times)

unseenmachine

  • Hero Member
  • *****
  • Posts: 3648
  • Make the Game not the ENGINE!!!
Re: UnseenGDK (Game Development Kit) For QB64
« Reply #645 on: September 25, 2011, 11:42:12 am »
I don't quite get what you mean by "tearing" but the tile engine portion of GDK works by using the pre calced XY tile posistions.

Quote
Is all the graphics pasted onto a buffer and then this buffer onto screen?
No, they are drawn directly onto whatever is set as the current _DEST, this allows you to draw to the screen or on a seperate image so you only have to draw the map once/when it needs to be updated. I used the draw when update method in Barricade.

John

Lachie Dazdarian

  • Sr. Member
  • ****
  • Posts: 280
    • http://games.freebasic.net
Re: UnseenGDK (Game Development Kit) For QB64
« Reply #646 on: September 25, 2011, 12:13:23 pm »
While the screen is scrolling you can notice the screen like "tearing" on one section, and few tile rows flicker a bit.

What should I do to paste onto a buffer and then onto a screen using GDK? Simple example would be great.

unseenmachine

  • Hero Member
  • *****
  • Posts: 3648
  • Make the Game not the ENGINE!!!
Re: UnseenGDK (Game Development Kit) For QB64
« Reply #647 on: September 25, 2011, 04:58:07 pm »
Here's a demo...

Tileset : http://dl.dropbox.com/u/8822351/Platformer1.PNG

Code :
Code: [Select]
GDK_Screen_SetRes Main&, 800, 600, 32, 0

DIM Sheet AS Tileset '// The tile sheet - Must be equally spaced.
DIM TileXY(1 TO 90) AS XY '// Tile positions on the sheet allways start from 1
DIM Map(19, 9) AS Tile '// The level

GDK_Tileset_New Sheet, "Platformer1.PNG", TileXY(), 18, 5, _RGB(0, 0, 0), 1, 1
GDK_TileMap_Load Map(), 20, 10

'// Create a "Buffer" image
MapImage& = _NEWIMAGE(Sheet.TWidth * 20, Sheet.THeight * 10, 32)

'// Set the current _DEST (draw destination) to the "Buffer" image
_DEST MapImage&
'// Draw the tiles
GDK_Tiles_Draw Sheet, TileXY(), Map(), 0, 0, 0, 0, 20, 10

'// Set the screen as the draw destination
_DEST 0

'// Draw the "Buffer" image
_PUTIMAGE (0, 0), MapImage&



REM $INCLUDE:'UnseenGDK.bm'

DATA 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DATA 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DATA 1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DATA 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DATA 0,0,0,0,0,1,1,1,1,0,0,1,1,1,1,1,0,0,0,0
DATA 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DATA 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DATA 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DATA 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DATA 0,0,0,0,0,0,0,0,0,78,78,0,0,0,0,0,78,78,0,0


Hope it helps.

John

unseenmachine

  • Hero Member
  • *****
  • Posts: 3648
  • Make the Game not the ENGINE!!!
Re: UnseenGDK (Game Development Kit) For QB64
« Reply #648 on: September 17, 2012, 04:25:41 am »
UnseenGDK Update v1.2

New commands for path based movement of sprites.
  • SUB GDK_Path_New (Path AS Path, PathPoint() AS PathPoint, NumPoints%, Reverse%)
  • SUB GDK_Path_Update (Path AS Path, PathPoint() AS PathPoint)

Update/Bug fixes :
  • GDK_Rectangle_Autosize - Now works with sprite sheets.
  • GDK_Rectangle_GetCollisionArea - Fixed bug where if X or Y of both rectangles were equal no collision area would be defined.

New command demo's : (Requires this sprite to be in your QB64 folder https://dl.dropbox.com/u/8822351/Ship1.PNG)

Path movement :
Code: [Select]
'// UnseenGDK Patch - Path Movement v.01

'// Create a screen
GDK_Screen_SetRes Main&, 800, 800, 32, 0

DIM Ship AS Sprite, PathPoints(7) AS PathPoint, ShipPath AS Path

GDK_Sprite_New Ship, "Ship1.PNG", 1, 1, 1, 1
GDK_Sprite_Show Ship
GDK_Sprite_SetAlpha Ship, _RGB(255, 0, 255)
GDK_Sprite_SetRotationPoint Ship, Ship.Width / 2, Ship.Height / 2

'// Load path points
GDK_Path_New ShipPath, PathPoints(), 8, 1

'// Main loop
DO
  _LIMIT 30
  CLS

  '// Update path
  GDK_Path_Update ShipPath, PathPoints()

  '// Draw the sprite
  GDK_Sprite_Draw Ship, ShipPath.Vector, 1

  _DISPLAY
LOOP

'// Path points are stored as X,Y,Speed
DATA 0,50,16,750,50,24,750,750,20,50,750,15,50,50,12,400,400,15,400,50,20,400,150,20

REM $INCLUDE:'UnseenGDK.BM'

Autosized rectangles for collision detection :
Code: [Select]
GDK_Screen_SetRes Main&, 800, 800, 32, 0

DIM Ship AS Sprite, ShipPos AS Vector, ShipRect AS Rectangle

'// Load the sprite, make it visible, set alpha colour and then set to rotate from the center of the image
GDK_Sprite_New Ship, "Ship1.PNG", 1, 1, 1, 1
GDK_Sprite_Show Ship
GDK_Sprite_SetAlpha Ship, _RGB(255, 0, 255)
GDK_Sprite_SetRotationPoint Ship, Ship.Width / 2, Ship.Height / 2

'// Set the sprites initial position,speed and rotation
GDK_Vector_New ShipPos, 400, 400, 0, 0

'// Rotation increment value
RotInc! = (4 * ATN(1)) / 64

'// Main loop
DO
  _LIMIT 30
  CLS

  '// Autosize the collision rectangle based on the sprite and it's vector
  GDK_Rectangle_AutoSize Ship, ShipPos, ShipRect

  '// Draw the sprite
  GDK_Sprite_Draw Ship, ShipPos, 1

  '// Draw a box to show where the rectangle is
  LINE (ShipRect.X, ShipRect.Y)-(ShipRect.X + ShipRect.Width, ShipRect.Y + ShipRect.Height), _RGB(255, 0, 0), B

  '// Rotate the sprite
  ShipPos.Rotation = ShipPos.Rotation + RotInc!

  _DISPLAY
LOOP

REM $INCLUDE:'UnseenGDK.BM'

Download : https://dl.dropbox.com/u/8822351/UnseenGDK.bm

Any questions, bugs or suggestions, please feel free.

Thanks,

Unseen

OlDosLover

  • Moderator
  • Hero Member
  • *****
  • Posts: 5320
  • OlDosLover
Re: UnseenGDK (Game Development Kit) For QB64
« Reply #649 on: September 17, 2012, 03:11:57 pm »
Hi all,
    Great to have you back unseenmachine. Thanks for this addition!
OlDosLover.

unseenmachine

  • Hero Member
  • *****
  • Posts: 3648
  • Make the Game not the ENGINE!!!
Re: UnseenGDK (Game Development Kit) For QB64
« Reply #650 on: March 03, 2015, 09:51:01 am »
UnseenGDK v.1.4 - Update Log

- Fixed an error in GDK_Gameobject_Intersect function.

- Added GDK_Rectangle_Scale function.

- Added SpriteFont library

   - GDK_SpriteFont_New
   - GDK_SpriteFont_SetAlpha
   - GDK_SpriteFont_SetSpacing
   - GDK_SpriteFont_SetScale
   - GDK_SpriteFont_SetSpaceWidth
   - GDK_PrintWidth
   - GDK_PrintHeight
   - GDK_Print

- Added support for drawing isometric tilemaps

   - GDK_Tiles_Draw_ISO

- Added GDK_GL v.01 to package - Rebuilt to work with GDK and QB64GL directly (no more SFML).

- Changed GDK_Screen_SetRes and GDK_screen_MatchRes commands - No longer need colour variable and and SetRes no longer needs Fullscreen command.

   - Old way : GDK_Screen_SetRes MainScreen&, 1024, 768, 32, 0
   - New way : GDK_Screen_SetRes MainScreen&, 1024, 768


- Added support for reverse animations.

- Added support for rotated rectangle collision detection.

   - GDK_RectangleX_New
   - GDK_RectangleX_Autosize
   - GDK_RectangleX_Intersect

- Added PI! function.


Code: [Select]
'\\ UnseenGDK Core v1.4 - Updated March 3rd 2015
'// Created By John Onyon a.k.a Unseen Machine
'// Optimistation by CodeGuy
'// ScanKeys% function by Cypherium
'// Image rotation function by Galleon
'// Rotated rectangle collisions by Richard Notley
'##########################################################################################################################
'// Typdef's
'##########################################################################################################################

SUB GDK_Types

TYPE Sprite
   File AS LONG
   Width AS INTEGER
   Height AS INTEGER
   Alpha AS LONG
   IsVisible AS INTEGER
   XFrameCount AS INTEGER
   YFrameCount AS INTEGER
   TotalFrameCount AS INTEGER
   RotationX AS INTEGER
   RotationY AS INTEGER
   Scale AS SINGLE
END TYPE

TYPE Vector
   X AS SINGLE
   Y AS SINGLE
   Speed AS SINGLE
   Rotation AS DOUBLE
   Accel AS SINGLE
   Decel AS SINGLE
END TYPE

TYPE Rectangle
   X AS INTEGER
   Y AS INTEGER
   Width AS INTEGER
   Height AS INTEGER
   CollisionX AS INTEGER
   CollisionY AS INTEGER
   CollisionXX AS INTEGER
   CollisionYY AS INTEGER
   Scale AS SINGLE
END TYPE

TYPE BoundingCircle
   X AS INTEGER
   Y AS INTEGER
   Radius AS INTEGER
END TYPE

TYPE MouseState
   X AS INTEGER
   Y AS INTEGER
   LB AS INTEGER
   RB AS INTEGER
END TYPE

TYPE KeyBoardState
   Left AS LONG
   Right AS LONG
   Down AS LONG
   Up AS LONG
   CTRL AS LONG
   SHIFT AS LONG
   ALT AS LONG
   SPACE AS LONG
   ENTER AS LONG
   ESC AS LONG
   Num1 AS LONG
   Num2 AS LONG
   Num3 AS LONG
   Num4 AS LONG
   Num5 AS LONG
   Num6 AS LONG
   Num7 AS LONG
   Num8 AS LONG
   Num9 AS LONG
   Num0 AS LONG
   PLUS AS LONG
   MINUS AS LONG
   BACKSPACE AS LONG
   TAB AS LONG
   A AS LONG
   B AS LONG
   C AS LONG
   D AS LONG
   E AS LONG
   F AS LONG
   G AS LONG
   H AS LONG
   I AS LONG
   J AS LONG
   K AS LONG
   L AS LONG
   M AS LONG
   N AS LONG
   O AS LONG
   P AS LONG
   Q AS LONG
   R AS LONG
   S AS LONG
   T AS LONG
   U AS LONG
   V AS LONG
   W AS LONG
   X AS LONG
   Y AS LONG
   Z AS LONG
END TYPE

TYPE GameObject
   Sprite AS Sprite
   Vector AS Vector
   Rect AS Rectangle
END TYPE

TYPE ANIMATION
   Frame AS INTEGER
   StartFrame AS INTEGER
   ResetFrame AS INTEGER
   Timer AS DOUBLE
   Time AS DOUBLE
   Dir AS _BYTE
END TYPE

TYPE SpriteX
   File AS LONG '// Handle to the file
   Width AS INTEGER '// Width of the entire spritesheet
   Height AS INTEGER '// Height of the entire spritesheet
   XFrames AS INTEGER '// Number of frames on x axis - For Equally spaced spritesheets only.
   YFrames AS INTEGER '// Number of frames on y axis - For Equally spaced spritesheets only.
   TotalFrames AS INTEGER
   FrameWidth AS INTEGER '// For Equally spaced spritesheets only.
   FrameHeight AS INTEGER '// For Equally spaced spritesheets only.
   RotX AS INTEGER '// Rotation point on x axis for a single sprite from an equally spaced sprite sheet.
   RotY AS INTEGER '// Rotation point on y axis for a single sprite from an equally spaced sprite sheet.
   ScaleX AS INTEGER '// Scale on x axis
   ScaleY AS INTEGER '// Scale on y axis
   Alpha AS LONG '// Tranparent colour
   IsVisible AS INTEGER '// Detrmines if sprite is drawn or not  = 0 no, <> 0 = yes
   IsEqual AS INTEGER '// 0 = False (non equally spaced sprite sheet),sprite spacing cannot be/is not calculated, <> 0 = true,
END TYPE

TYPE Path
   Vector AS Vector
   LastVector AS Vector
   TargetVector AS Vector
   NumPoints AS INTEGER
   CurrentPoint AS INTEGER
   HitTargetX AS INTEGER
   HitTargetY AS INTEGER
   Repeat AS INTEGER
   Relative AS INTEGER
   Reverse AS INTEGER
   IsReversing AS INTEGER
END TYPE

TYPE PathPoint
   X AS INTEGER
   Y AS INTEGER
   Speed AS INTEGER
END TYPE

TYPE Emitter
   X AS INTEGER
   Y AS INTEGER
   SpawnRate AS INTEGER
   SpawnAngleMin AS SINGLE
   SpawnAngleMax AS SINGLE
   SpawnMaxVelocity AS SINGLE
   SpawnMinVelocity AS SINGLE
   MaxLifeTime AS DOUBLE
   MinLifeTime AS DOUBLE
   AccelMax AS SINGLE
   DecelMax AS SINGLE
   AccelMin AS SINGLE
   DecelMIn AS SINGLE
   Gravity AS SINGLE
END TYPE

TYPE Particle
   InitialCLR AS LONG
   CurrentCLR AS LONG
   ClrChange AS LONG
   ClrChangeMode AS INTEGER
   Vector AS Vector
   BirthTime AS DOUBLE
   LifeTime AS DOUBLE
   Exists AS INTEGER
   Accel AS SINGLE
   Decel AS SINGLE
   Gravity AS SINGLE
END TYPE

TYPE Tileset
   File AS LONG
   Width AS INTEGER
   Height AS INTEGER
   THeight AS INTEGER
   TWidth AS INTEGER
   XTiles AS INTEGER
   YTiles AS INTEGER
   Alpha AS LONG
   XOffset AS INTEGER
   YOffset AS INTEGER
   Scale AS SINGLE
END TYPE

TYPE XY
   X AS INTEGER
   Y AS INTEGER
END TYPE

TYPE Tile
   RECT AS Rectangle
   Tile AS INTEGER
END TYPE

TYPE TilesetX
   File AS LONG
   Width AS INTEGER
   Height AS INTEGER
   THeight AS INTEGER
   TWidth AS INTEGER
   XTiles AS INTEGER
   YTiles AS INTEGER
   Alpha AS LONG
   XOffset AS INTEGER
   YOffset AS INTEGER
   Scale AS SINGLE
   Spacing AS INTEGER
END TYPE

TYPE XY2
   X AS INTEGER
   Y AS INTEGER
   RealRect AS Rectangle
END TYPE

TYPE SPRITEFONT
   Image AS Sprite
   Spacing AS SINGLE
   SpaceWidth AS SINGLE
END TYPE

TYPE RectangleX
    XY AS XY
    WH AS XY
    Rotation AS SINGLE
END TYPE

END SUB

'##########################################################################################################################
'// Collision detection
'##########################################################################################################################

SUB GDK_Rectangle_New (RectRef AS Rectangle, x%, y%, Width%, Height%)
RectRef.X = x%
RectRef.Y = y%
RectRef.Width = Width%
RectRef.Height = Height%
END SUB

'// Returns -1 for true, 0 for false
FUNCTION GDK_Rectangle_Intersect (RectangleRef1 AS Rectangle, RectangleRef2 AS Rectangle)
IF RectangleRef1.X <= RectangleRef2.X + RectangleRef2.Width THEN
   IF RectangleRef1.X + RectangleRef1.Width >= RectangleRef2.X THEN
      IF RectangleRef1.Y <= RectangleRef2.Y + RectangleRef2.Height THEN
         IF RectangleRef1.Y + RectangleRef1.Height >= RectangleRef2.Y THEN
            GDK_Rectangle_Intersect = -1
         END IF
      END IF
   END IF
ELSE
   GDK_Rectangle_Intersect = 0
END IF
END FUNCTION

SUB GDK_Rectangle_GetCollisionArea (RectRef1 AS Rectangle, RectRef2 AS Rectangle)
IF RectRef1.X < RectRef2.X THEN
   RectRef2.CollisionX = 0
   RectRef1.CollisionX = RectRef2.X - RectRef1.X
   IF RectRef2.Width + RectRef1.CollisionX < RectRef1.Width THEN
      RectRef2.CollisionXX = RectRef2.Width
      RectRef1.CollisionXX = RectRef1.CollisionX + RectRef2.Width
   ELSE
      RectRef1.CollisionXX = RectRef1.Width
      RectRef2.CollisionXX = (RectRef1.X + RectRef1.Width) - RectRef2.X
   END IF
ELSEIF RectRef1.X > RectRef2.X THEN
   RectRef1.CollisionX = 0
   RectRef2.CollisionX = RectRef1.X - RectRef2.X
   IF RectRef2.Width - RectRef2.CollisionX < RectRef1.Width THEN
      RectRef1.CollisionXX = (RectRef1.CollisionX + RectRef2.Width) - RectRef2.CollisionX
      RectRef2.CollisionXX = RectRef2.Width
   ELSE
      RectRef1.CollisionXX = RectRef1.Width
      RectRef2.CollisionXX = RectRef2.CollisionX + RectRef1.Width
   END IF
ELSEIF RectRef1.X = RectRef2.X THEN
   RectRef1.CollisionX = 0
   RectRef2.CollisionX = 0
   IF RectRef1.Width < RectRef2.Width THEN
      ColWidth% = RectRef1.Width
   ELSE
      ColWidth% = RectRef2.Width
   END IF
   RectRef1.CollisionXX = ColWidth%
   RectRef2.CollisionXX = ColWidth%
END IF
IF RectRef1.Y < RectRef2.Y THEN
   RectRef2.CollisionY = 0
   RectRef1.CollisionY = RectRef2.Y - RectRef1.Y
   IF RectRef2.Height + RectRef1.CollisionY < RectRef1.Height THEN
      RectRef2.CollisionYY = RectRef2.Height
      RectRef1.CollisionYY = RectRef1.CollisionY + RectRef2.Height
   ELSE
      RectRef1.CollisionYY = RectRef1.Height
      RectRef2.CollisionYY = (RectRef1.Y + RectRef1.Height) - RectRef2.Y
   END IF
ELSEIF RectRef1.Y > RectRef2.Y THEN
   RectRef1.CollisionY = 0
   RectRef2.CollisionY = RectRef1.Y - RectRef2.Y
   IF RectRef2.Height - RectRef2.CollisionY < RectRef1.Height THEN
      RectRef1.CollisionYY = (RectRef1.CollisionY + RectRef2.Height) - RectRef2.CollisionY
      RectRef2.CollisionYY = RectRef2.Height
   ELSE
      RectRef1.CollisionYY = RectRef1.Height
      RectRef2.CollisionYY = RectRef2.CollisionY + RectRef1.Height
   END IF
ELSEIF RectRef1.Y = RectRef2.Y THEN
   RectRef1.CollisionY = 0
   RectRef2.CollisionY = 0
   IF RectRef1.Height < RectRef2.Height THEN
      ColHeight% = RectRef1.Height
   ELSE
      ColHeight% = RectRef2.Height
   END IF
   RectRef1.CollisionYY = ColHeight%
   RectRef2.CollisionYY = ColHeight%
END IF
END SUB

SUB GDK_Rectangle_AutoSize (Sprite AS Sprite, Vector AS Vector, Rect AS Rectangle)
DIM pX(3) AS SINGLE, pY(3) AS SINGLE, W AS LONG, H AS LONG, I AS LONG, X AS LONG, Y AS LONG, X2 AS LONG, Y2 AS LONG, PointX AS LONG, PointY AS LONG
X = Vector.X
Y = Vector.Y
W = (Sprite.Width / Sprite.XFrameCount)
H = (Sprite.Height / Sprite.YFrameCount)
PointX = Sprite.RotationX
PointY = Sprite.RotationY
pX(0) = -PointX
pY(0) = -PointY
pX(1) = -PointX
pY(1) = -PointY + H - 1
pX(2) = -PointX + W - 1
pY(2) = -PointY + H - 1
pX(3) = -PointX + W - 1
pY(3) = -PointY 'Set dest screen points
SINr = SIN(Vector.Rotation)
COSr = COS(Vector.Rotation) 'Precalculate SIN & COS of angle
FOR I = 0 TO 3
   pX(I) = pX(I) * Sprite.Scale
   pY(I) = pY(I) * Sprite.Scale 'Scale
   X2 = pX(I) * COSr + SINr * pY(I)
   pY(I) = pY(I) * COSr - pX(I) * SINr
   pX(I) = X2 'Rotate Dest Points
   pX(I) = pX(I) + X
   pY(I) = pY(I) + Y 'Translate Dest Points
   IF I = 0 THEN
      MinX% = pX(I)
      MinY% = pY(I)
      MaxX% = pX(I)
      MaxY% = pY(I)
   ELSE
      IF pX(I) < MinX% THEN MinX% = pX(I)
      IF pX(I) > MaxX% THEN MaxX% = pX(I)
      IF pY(I) < MinY% THEN MinY% = pY(I)
      IF pY(I) > MaxY% THEN MaxY% = pY(I)
   END IF
NEXT
Rect.X = MinX%
Rect.Y = MinY%
Rect.Width = MaxX% - MinX%
Rect.Height = MaxY% - MinY%
END SUB

SUB GDK_Rectangle_Scale (Sprite AS Sprite, Vector AS Vector, Rect AS Rectangle, Scale!)
DIM pX(3) AS SINGLE, pY(3) AS SINGLE, W AS LONG, H AS LONG, I AS LONG, X AS LONG, Y AS LONG, X2 AS LONG, Y2 AS LONG, PointX AS LONG, PointY AS LONG
X = Vector.X
Y = Vector.Y
W = (Sprite.Width / Sprite.XFrameCount)
H = (Sprite.Height / Sprite.YFrameCount)
PointX = Sprite.RotationX
PointY = Sprite.RotationY
pX(0) = -PointX
pY(0) = -PointY
pX(1) = -PointX
pY(1) = -PointY + H - 1
pX(2) = -PointX + W - 1
pY(2) = -PointY + H - 1
pX(3) = -PointX + W - 1
pY(3) = -PointY 'Set dest screen points
SINr = SIN(Vector.Rotation)
COSr = COS(Vector.Rotation) 'Precalculate SIN & COS of angle
FOR I = 0 TO 3
   pX(I) = pX(I) * Scale!
   pY(I) = pY(I) * Scale!
   X2 = pX(I) * COSr + SINr * pY(I)
   pY(I) = pY(I) * COSr - pX(I) * SINr
   pX(I) = X2 'Rotate Dest Points
   pX(I) = pX(I) + X
   pY(I) = pY(I) + Y 'Translate Dest Points
   IF I = 0 THEN
      MinX% = pX(I)
      MinY% = pY(I)
      MaxX% = pX(I)
      MaxY% = pY(I)
   ELSE
      IF pX(I) < MinX% THEN MinX% = pX(I)
      IF pX(I) > MaxX% THEN MaxX% = pX(I)
      IF pY(I) < MinY% THEN MinY% = pY(I)
      IF pY(I) > MaxY% THEN MaxY% = pY(I)
   END IF
NEXT
Rect.X = MinX%
Rect.Y = MinY%
Rect.Width = MaxX% - MinX%
Rect.Height = MaxY% - MinY%
END SUB

FUNCTION GDK_BoundingCircle_Intersect (Circ1 AS BoundingCircle, Circ2 AS BoundingCircle)
LRAD% = Circ1.Radius + Circ2.Radius
CDist! = GDK_Distance(Circ1.X, Circ1.Y, Circ2.X, Circ2.Y)
IF CDist! > LRAD% THEN
   GDK_BoundingCircle_Intersect = 0
ELSE
   GDK_BoundingCircle_Intersect = -1
END IF
END FUNCTION

SUB GDK_BoundingCircle_New (Circ1 AS BoundingCircle, X%, Y%, Radius%)
Circ1.X = X%
Circ1.Y = Y%
Circ1.Radius = Radius%
END SUB


SUB GDK_RectangleX_New (Rect AS RectangleX, X%, Y%, Width%, Height%, Rotation!)
Rect.XY.X = X%
Rect.XY.Y = Y%
Rect.WH.X = Width%
Rect.WH.Y = Height%
Rect.Rotation = Rotation!
END SUB


SUB GDK_RectangleX_Autosize (Sprite AS Sprite, Vector AS Vector, Rect AS RectangleX)
Rect.XY.X = Vector.X - (Sprite.RotationX * Sprite.Scale)
Rect.XY.Y = Vector.Y - (Sprite.RotationY * Sprite.Scale)
Rect.WH.X = (Sprite.Width / Sprite.XFrameCount) * Sprite.Scale
Rect.WH.Y = (Sprite.Height / Sprite.YFrameCount) * Sprite.Scale
Rect.Rotation = Vector.Rotation
END SUB


FUNCTION GDK_RectangleX_Intersect (Rect1 AS RectangleX, Rect2 AS RectangleX)
IF Rect1.Rotation = 0 AND Rect2.Rotation = 0 THEN '// No rotation do standard GDK collision check
    DIM Rect(1) AS Rectangle
    Rect(0).X = Rect1.XY.X
    Rect(0).Y = Rect1.XY.Y
    Rect(0).Width = Rect1.WH.X
    Rect(0).Height = Rect1.WH.Y
    Rect(1).X = Rect2.XY.X
    Rect(1).Y = Rect2.XY.Y
    Rect(1).Width = Rect2.WH.X
    Rect(1).Height = Rect2.WH.Y
    IF GDK_Rectangle_Intersect(Rect(0), Rect(1)) THEN
        GDK_RectangleX_Intersect = 0
    ELSE
        GDK_RectangleX_Intersect = -1
    END IF

ELSE '// Rotated rectangles

    '// Adapted from code created by Richard Notley
    '// http://www.qb64.net/forum/index.php?topic=12564.0
    DIM Arr1!(4), Arr2!(4), EFGH!(3, 1), Arr2A!(4)

    '// Put rect data into arrays
    Arr1!(0) = Rect1.XY.X
    Arr1!(1) = Rect1.XY.Y
    Arr1!(2) = Rect1.WH.X
    Arr1!(3) = Rect1.WH.Y
    Arr1!(4) = Rect1.Rotation
    Arr2!(0) = Rect2.XY.X
    Arr2!(1) = Rect2.XY.Y
    Arr2!(2) = Rect2.WH.X
    Arr2!(3) = Rect2.WH.Y
    Arr2!(4) = Rect2.Rotation

    XCross! = (Arr2!(1) - (TAN(Arr2!(4)) * Arr2!(0)) - Arr1!(1) + (TAN(Arr1!(4)) * Arr1!(0))) / (TAN(Arr1!(4)) - TAN(Arr2!(4)))
    YCross! = Arr1!(1) + TAN(Arr1!(4)) * (XCross! - Arr1!(0))

    X1Top! = Arr1!(0) + (Arr1!(2) * COS(Arr1!(4)) / 2)
    X1Bottom! = Arr1!(0) - (Arr1!(2) * COS(Arr1!(4)) / 2)
    IF X1Bottom! > X1Top! THEN SWAP X1Bottom!, X1Top!

    X2Top! = Arr2!(0) + (Arr2!(2) * COS(Arr2!(4)) / 2)
    X2Bottom! = Arr2!(0) - (Arr2!(2) * COS(Arr2!(4)) / 2)
    IF X2Bottom! > X2Top! THEN SWAP X2Bottom!, X2Top!

    Y1Top! = Arr1!(1) + (Arr1!(2) * SIN(Arr1!(4)) / 2)
    Y1Bottom! = Arr1!(1) - (Arr1!(2) * SIN(Arr1!(4)) / 2)
    IF Y1Bottom! > Y1Top! THEN SWAP Y1Bottom!, Y1Top!

    Y2Top! = Arr2!(1) + (Arr2!(2) * SIN(Arr2!(4)) / 2)
    Y2Bottom! = Arr2!(1) - (Arr2!(2) * SIN(Arr2!(4)) / 2)
    IF Y2Bottom! > Y2Top! THEN SWAP Y2Bottom!, Y2Top!

    IF XCross! >= X1Bottom! AND XCross! <= X1Top! AND XCross! >= X2Bottom! AND XCross! <= X2Top! AND YCross! >= Y1Bottom! AND YCross! <= Y1Top! AND YCross! >= Y2Bottom! AND YCross! <= Y2Top! THEN
        GDK_RectangleX_Intersect = -1
    ELSE

        'centre on Arr1!
        Arr2A!(0) = Arr2!(0) - Arr1!(0)
        Arr2A!(1) = Arr2!(1) - Arr1!(1)
        Arr2A!(2) = Arr2!(2)
        Arr2A!(3) = Arr2!(3)
        Arr2A!(4) = Arr2!(4)

        'find EFGH
        EX! = Arr2A!(0) + (Arr2A!(2) * COS(Arr2A!(4)) / 2) - (Arr2A!(3) * SIN(Arr2A!(4)) / 2)
        EY! = Arr2A!(1) + (Arr2A!(2) * SIN(Arr2A!(4)) / 2) + (Arr2A!(3) * COS(Arr2A!(4)) / 2)

        FX! = Arr2A!(0) + (Arr2A!(2) * COS(Arr2A!(4)) / 2) + (Arr2A!(3) * SIN(Arr2A!(4)) / 2)
        FY! = Arr2A!(1) + (Arr2A!(2) * SIN(Arr2A!(4)) / 2) - (Arr2A!(3) * COS(Arr2A!(4)) / 2)

        GX! = Arr2A!(0) - (Arr2A!(2) * COS(Arr2A!(4)) / 2) + (Arr2A!(3) * SIN(Arr2A!(4)) / 2)
        GY! = Arr2A!(1) - (Arr2A!(2) * SIN(Arr2A!(4)) / 2) - (Arr2A!(3) * COS(Arr2A!(4)) / 2)

        HX! = Arr2A!(0) - (Arr2A!(2) * COS(Arr2A!(4)) / 2) - (Arr2A!(3) * SIN(Arr2A!(4)) / 2)
        HY! = Arr2A!(1) - (Arr2A!(2) * SIN(Arr2A!(4)) / 2) + (Arr2A!(3) * COS(Arr2A!(4)) / 2)

        'rotate to Arr1!
        R! = SQR(EX! * EX! + EY! * EY!): Phi! = Angle!(EX!, EY!)
        EFGH!(0, 0) = R! * COS(Phi! - Arr1!(4))
        EFGH!(0, 1) = R! * SIN(Phi! - Arr1!(4))

        R! = SQR(FX! * FX! + FY! * FY!): Phi! = Angle!(FX!, FY!)
        EFGH!(1, 0) = R! * COS(Phi! - Arr1!(4))
        EFGH!(1, 1) = R! * SIN(Phi! - Arr1!(4))

        R! = SQR(GX! * GX! + GY! * GY!): Phi! = Angle!(GX!, GY!)
        EFGH!(2, 0) = R! * COS(Phi! - Arr1!(4))
        EFGH!(2, 1) = R! * SIN(Phi! - Arr1!(4))

        R! = SQR(HX! * HX! + HY! * HY!): Phi! = Angle!(HX!, HY!)
        EFGH!(3, 0) = R! * COS(Phi! - Arr1!(4))
        EFGH!(3, 1) = R! * SIN(Phi! - Arr1!(4))

        FOR N%% = 0 TO 3
            IF EFGH!(N%%, 0) < Arr1!(2) / 2 AND EFGH!(N%%, 0) > -Arr1!(2) / 2 AND EFGH!(N%%, 1) < Arr1!(3) / 2 AND EFGH!(N%%, 1) > -Arr1!(3) / 2 THEN
                GDK_RectangleX_Intersect = -1
            END IF
        NEXT

    END IF
END IF
END FUNCTION


FUNCTION Angle! (X!, Y!)
IF X! = 0 THEN
    IF Y! < 0 THEN
        Angle! = -Pi! / 2
    ELSE
        Angle! = Pi! / 2
    END IF
ELSE
    Angle! = ATN(Y! / X!)
END IF
IF X! < 0 THEN
    Angle! = Angle! - Pi!
    IF Angle! < -Pi! THEN Angle! = Angle! + 2 * Pi!
END IF
END FUNCTION


FUNCTION Pi!
'Pi! = 4 * ATN(1)
Pi! = 3.14159265359
END FUNCTION
'##########################################################################################################################
'//Vector stuff
'##########################################################################################################################

SUB GDK_Vector_New (Vector AS Vector, X%, Y%, Speed!, Rotation#)
Vector.X = X%
Vector.Y = Y%
Vector.Speed = Speed!
Vector.Rotation = Rotation#
END SUB

SUB GDK_Vector_SetPosition (Vector AS Vector, X%, Y%)
Vector.X = X%
Vector.Y = Y%
END SUB

SUB GDK_Vector_SetRotation (Vector AS Vector, Rotation#)
Vector.Rotation = Rotation#
END SUB

SUB GDK_Vector_SetSpeed (Vector AS Vector, Speed!)
Vector.Speed = Speed!
END SUB

SUB GDK_Vector_SetAccelDecel (Vector AS Vector, Accel!, Decel!)
Vector.Accel = Accel!
Vector.Decel = Decel!
END SUB

SUB GDK_Vector_Update (Vector AS Vector)
IF Vector.Decel > 0 THEN
   IF Vector.Accel > 0 THEN
      Vector.Accel = Vector.Accel - Vector.Decel
   ELSE
      IF Vector.Speed > (Vector.Decel) THEN Vector.Speed = Vector.Speed - Vector.Decel ELSE Vector.Speed = 0
   END IF
END IF
IF Vector.Accel > 0 THEN Vector.Speed = Vector.Speed + Vector.Accel
GDK_Vector_Move Vector
END SUB

SUB GDK_Vector_Move (Vector AS Vector)
Vector.X = Vector.X - SIN(Vector.Rotation) * Vector.Speed
Vector.Y = Vector.Y - COS(Vector.Rotation) * Vector.Speed
END SUB

'##########################################################################################################################
'// Sprite stuff
'##########################################################################################################################

SUB GDK_Sprite_New (SpriteFile AS Sprite, FileSource$, XFrameCount%, YFrameCount%, TotalFrameCount%, Scale!)
SpriteFile.File = _LOADIMAGE(FileSource$)
SpriteFile.Width = _WIDTH(SpriteFile.File)
SpriteFile.Height = _HEIGHT(SpriteFile.File)
SpriteFile.XFrameCount = XFrameCount%
SpriteFile.YFrameCount = YFrameCount%
SpriteFile.TotalFrameCount = TotalFrameCount%
SpriteFile.Scale = Scale!
SpriteFile.IsVisible = -1
END SUB

SUB GDK_Sprite_SetRotationPoint (SpriteFile AS Sprite, X%, Y%)
SpriteFile.RotationX = X%
SpriteFile.RotationY = Y%
END SUB

SUB GDK_Sprite_SetVisibility (SpriteFile AS Sprite, OnOff%)
SpriteFile.IsVisible = OnOff%
END SUB

SUB GDK_Sprite_SetAlpha (SpriteFile AS Sprite, Alpha&)
SpriteFile.Alpha = Alpha&
END SUB

SUB GDK_Sprite_DrawXY (Sprite AS Sprite, X%, Y%, Rotation!, AnimationFrame%)
DIM tempvect AS Vector
GDK_Vector_New tempvect, X%, Y%, 0, Rotation!
GDK_Sprite_Draw Sprite, tempvect, AnimationFrame%
END SUB

SUB GDK_Sprite_Hide (Handle AS Sprite)
Handle.IsVisible = 0
END SUB

SUB GDK_Sprite_Show (Handle AS Sprite)
Handle.IsVisible = -1
END SUB

SUB GDK_Sprite_Free (SpriteFile AS Sprite)
_FREEIMAGE (SpriteFile.File)
SpriteFile.IsVisible = 0
END SUB

SUB GDK_Sprite_Clone (SourceSprite AS Sprite, DestSprite AS Sprite)
DestSprite = SourceSprite
END SUB

SUB GDK_Sprite_Clone_X (SourceSprite AS Sprite, DestSprite() AS Sprite, FirstClone%, NumberOfClones%)
FOR CloneCount% = FirstClone% TO FirstClone% + NumberOfClones% - 1
   DestSprite(CloneCount%) = SourceSprite
NEXT
END SUB

SUB GDK_Sprite_Draw (SpriteFile AS Sprite, DestVector AS Vector, Frame%)
_CLEARCOLOR SpriteFile.Alpha, SpriteFile.File
IF SpriteFile.IsVisible THEN
   IF Frame% = 0 THEN '// Draw the entire image.
      IF DestVector.Rotation = 0 THEN
         _PUTIMAGE (DestVector.X - (SpriteFile.RotationX * SpriteFile.Scale), DestVector.Y - (SpriteFile.RotationY * SpriteFile.Scale))-((DestVector.X - (SpriteFile.RotationX * SpriteFile.Scale)) + (SpriteFile.Width * SpriteFile.Scale), (DestVector.Y - (SpriteFile.RotationY * SpriteFile.Scale)) + (SpriteFile.Height * SpriteFile.Scale)), SpriteFile.File
      ELSE
         GDK_Sprite_Rotate SpriteFile, SpriteFile.RotationX * SpriteFile.Scale, SpriteFile.RotationY * SpriteFile.Scale, DestVector, SpriteFile.Scale
      END IF
   ELSE '// Draw a specific frame.
      FrameXSize% = SpriteFile.Width / SpriteFile.XFrameCount
      FrameYSize% = SpriteFile.Height / SpriteFile.YFrameCount
      FrameCnt% = 0
      FrameYStart% = 0
      FOR j% = 1 TO SpriteFile.YFrameCount
         FrameXStart% = 0
         FOR i% = 1 TO SpriteFile.XFrameCount
            FrameCnt% = FrameCnt% + 1
            IF FrameCnt% = Frame% THEN
               IF DestVector.Rotation <> 0 THEN
                  DIM TmpImage AS Sprite
                  TmpImage.File = _NEWIMAGE(FrameXSize%, FrameYSize%, 32)
                  _PUTIMAGE (0, 0), SpriteFile.File, TmpImage.File, (FrameXStart%, FrameYStart%)-(FrameXStart% + FrameXSize%, FrameYStart% + FrameYSize%)
                  '//GDK_Sprite_Rotate tmpimage, SpriteFile.RotationX, SpriteFile.RotationY, DestVector, SpriteFile.Scale
                  Rotate_Scale_AroundPoint DestVector.X, DestVector.Y, TmpImage.File, -GDK_RadianToDegree(DestVector.Rotation), SpriteFile.Scale, SpriteFile.Scale, SpriteFile.RotationX, SpriteFile.RotationY
                  _FREEIMAGE TmpImage.File
               ELSE
                  _PUTIMAGE (DestVector.X - (SpriteFile.RotationX * SpriteFile.Scale), DestVector.Y - (SpriteFile.RotationY * SpriteFile.Scale))-((DestVector.X - (SpriteFile.RotationX * SpriteFile.Scale)) + (FrameXSize% * SpriteFile.Scale), (DestVector.Y - (SpriteFile.RotationY * SpriteFile.Scale)) + (FrameYSize% * SpriteFile.Scale)), SpriteFile.File, , (FrameXStart%, FrameYStart%)-(FrameXStart% + FrameXSize% - 1, FrameYStart% + FrameYSize%)
               END IF
               EXIT FOR
            END IF
            FrameXStart% = FrameXStart% + FrameXSize%
         NEXT
         FrameYStart% = FrameYStart% + FrameYSize%
      NEXT
   END IF
END IF
END SUB

SUB GDK_Sprite_Rotate (TypeRef AS Sprite, sx!, sy!, Vector AS Vector, Scale!)
_SOURCE TypeRef.File
w% = _WIDTH(_SOURCE)
h% = _HEIGHT(_SOURCE)
cs! = COS(Vector.Rotation)
sn! = SIN(Vector.Rotation)
calculateMinMax cs!, sn!, sx!, sy!, Scale!, x1, y1, x2, y2
mask# = 2 ^ 32 - 1 '* (used to make sure integer and not < 0 at the same time), cool, eh?
FOR y = y1 TO y2
   FOR x = x1 TO x2
      xx = ((x * cs! - y * sn!) / Scale! + sx!) AND mask#
      yy = ((x * sn! + y * cs!) / Scale! + sy!) AND mask#
      IF xx >= w% OR yy >= h% THEN
         p& = 0 ' Make transparent if outside image
      ELSE
         p& = POINT(xx, yy)
      END IF
      IF p& <> TypeRef.Alpha THEN PSET (x + INT(Vector.X), y + INT(Vector.Y)), p&
   NEXT
NEXT
END SUB

SUB calculateMinMax (cs!, sn!, sx!, sy!, zoom!, x1, y1, x2, y2)
lt! = -sx!
up! = -sy!
rt! = _WIDTH(_SOURCE) - sx!
dn! = _HEIGHT(_SOURCE) - sy!
ulX! = (up! * sn! + lt! * cs!) * zoom!
ulY! = (up! * cs! - lt! * sn!) * zoom!
dlX! = (dn! * sn! + lt! * cs!) * zoom!
dlY! = (dn! * cs! - lt! * sn!) * zoom!
urX! = (up! * sn! + rt! * cs!) * zoom!
urY! = (up! * cs! - rt! * sn!) * zoom!
drX! = (dn! * sn! + rt! * cs!) * zoom!
drY! = (dn! * cs! - rt! * sn!) * zoom!
x1 = INT(min(min(ulX!, dlX!), min(urX!, drX!))) '    INT(x) = floor(x)
y1 = INT(min(min(ulY!, dlY!), min(urY!, drY!)))
x2 = -INT(-max(max(ulX!, dlX!), max(urX!, drX!))) ' -INT(-x)) = ceil(x)
y2 = -INT(-max(max(ulY!, dlY!), max(urY!, drY!)))
END SUB

FUNCTION min! (a!, b!)
min! = a! + (a! - b!) * (b! < a!)
END FUNCTION

FUNCTION max! (a!, b!)
max! = a! + (a! - b!) * (b! > a!)
END FUNCTION


SUB GDK_Sprite_SetRotationAsCenter (Sprite AS Sprite)
GDK_Sprite_SetRotationPoint Sprite, Sprite.Width / (Sprite.XFrameCount * 2), Sprite.Height / (Sprite.YFrameCount * 2)
END SUB

'##########################################################################################################################
'// SCREEN Stuff!
'##########################################################################################################################

SUB GDK_Screen_MatchRes (ScreenHandle&, fs%)
ScreenHandle& = _NEWIMAGE(_WIDTH(_SCREENIMAGE), _HEIGHT(_SCREENIMAGE), 32)
SCREEN ScreenHandle&
IF fs% = 1 THEN _FULLSCREEN
IF fs% = 0 THEN _FULLSCREEN _OFF
END SUB

SUB GDK_Screen_SetRes (ScreenHandle&, width%, height%)
ScreenHandle& = _NEWIMAGE(width%, height%, 32)
SCREEN ScreenHandle&
END SUB

FUNCTION GDK_WindowHeight%
GDK_WindowHeight% = _HEIGHT(0)
END FUNCTION

FUNCTION GDK_WindowWidth%
GDK_WindowWidth% = _WIDTH(0)
END FUNCTION

FUNCTION GDK_ScreenWidth%
GDK_ScreenWidth% = _WIDTH(_SCREENIMAGE)
END FUNCTION

FUNCTION GDK_ScreenHeight%
GDK_ScreenHeight% = _HEIGHT(_SCREENIMAGE)
END FUNCTION

SUB GDK_ToggleFullScreen
IF _FULLSCREEN THEN _FULLSCREEN _OFF ELSE _FULLSCREEN
END SUB

SUB GDK_Screen_Store (ImageHandle&)
ImageHandle& = _COPYIMAGE(0)
END SUB

SUB GDK_Screen_Restore (ImageHandle&)
_PUTIMAGE (0, 0), ImageHandle&
END SUB

SUB GDK_Screen_FadeIn (Time#)
TmpScrnImage& = _COPYIMAGE(0)
FOR i% = 255 TO 0 STEP -5
   _PUTIMAGE , TmpScrnImage&
   LINE (0, 0)-(_WIDTH(0), _HEIGHT(0)), _RGBA(0, 0, 0, i%), BF
   _DELAY (Time# / 51)
   _DISPLAY
NEXT
END SUB

SUB GDK_Screen_FadeOut (Time#)
TmpScrnImage& = _COPYIMAGE(0)
FOR i% = 0 TO 255 STEP 5
   _PUTIMAGE , TmpScrnImage&
   LINE (0, 0)-(_WIDTH(0), _HEIGHT(0)), _RGBA(0, 0, 0, i%), BF
   _DELAY (Time# / 51)
   _DISPLAY
NEXT
END SUB

'##########################################################################################################################
'// User input subs and functions.
'##########################################################################################################################

SUB GDK_Keyboard_GetState (KeyboardRef AS KeyBoardState)
FOR x% = 1 TO 88 'read each key scancode from array
   IF x% = 1 THEN KeyboardRef.ESC = ScanKey%(x%)
   IF x% = 2 THEN KeyboardRef.Num1 = ScanKey%(x%)
   IF x% = 3 THEN KeyboardRef.Num2 = ScanKey%(x%)
   IF x% = 4 THEN KeyboardRef.Num3 = ScanKey%(x%)
   IF x% = 5 THEN KeyboardRef.Num4 = ScanKey%(x%)
   IF x% = 6 THEN KeyboardRef.Num5 = ScanKey%(x%)
   IF x% = 7 THEN KeyboardRef.Num6 = ScanKey%(x%)
   IF x% = 8 THEN KeyboardRef.Num7 = ScanKey%(x%)
   IF x% = 9 THEN KeyboardRef.Num8 = ScanKey%(x%)
   IF x% = 10 THEN KeyboardRef.Num9 = ScanKey%(x%)
   IF x% = 11 THEN KeyboardRef.Num0 = ScanKey%(x%)
   IF x% = 12 THEN KeyboardRef.PLUS = ScanKey%(x%)
   IF x% = 13 THEN KeyboardRef.MINUS = ScanKey%(x%)
   IF x% = 14 THEN KeyboardRef.BACKSPACE = ScanKey%(x%)
   IF x% = 15 THEN KeyboardRef.TAB = ScanKey%(x%)
   IF x% = 30 THEN KeyboardRef.A = ScanKey%(x%)
   IF x% = 48 THEN KeyboardRef.B = ScanKey%(x%)
   IF x% = 46 THEN KeyboardRef.C = ScanKey%(x%)
   IF x% = 32 THEN KeyboardRef.D = ScanKey%(x%)
   IF x% = 18 THEN KeyboardRef.E = ScanKey%(x%)
   IF x% = 33 THEN KeyboardRef.F = ScanKey%(x%)
   IF x% = 34 THEN KeyboardRef.G = ScanKey%(x%)
   IF x% = 35 THEN KeyboardRef.H = ScanKey%(x%)
   IF x% = 23 THEN KeyboardRef.I = ScanKey%(x%)
   IF x% = 36 THEN KeyboardRef.J = ScanKey%(x%)
   IF x% = 37 THEN KeyboardRef.K = ScanKey%(x%)
   IF x% = 38 THEN KeyboardRef.L = ScanKey%(x%)
   IF x% = 50 THEN KeyboardRef.M = ScanKey%(x%)
   IF x% = 49 THEN KeyboardRef.N = ScanKey%(x%)
   IF x% = 24 THEN KeyboardRef.O = ScanKey%(x%)
   IF x% = 25 THEN KeyboardRef.P = ScanKey%(x%)
   IF x% = 16 THEN KeyboardRef.Q = ScanKey%(x%)
   IF x% = 19 THEN KeyboardRef.R = ScanKey%(x%)
   IF x% = 31 THEN KeyboardRef.S = ScanKey%(x%)
   IF x% = 20 THEN KeyboardRef.T = ScanKey%(x%)
   IF x% = 22 THEN KeyboardRef.U = ScanKey%(x%)
   IF x% = 47 THEN KeyboardRef.V = ScanKey%(x%)
   IF x% = 17 THEN KeyboardRef.W = ScanKey%(x%)
   IF x% = 45 THEN KeyboardRef.X = ScanKey%(x%)
   IF x% = 21 THEN KeyboardRef.Y = ScanKey%(x%)
   IF x% = 44 THEN KeyboardRef.Z = ScanKey%(x%)
   IF x% = 72 THEN KeyboardRef.Up = ScanKey%(x%)
   IF x% = 75 THEN KeyboardRef.Left = ScanKey%(x%)
   IF x% = 77 THEN KeyboardRef.Right = ScanKey%(x%)
   IF x% = 80 THEN KeyboardRef.Down = ScanKey%(x%)
   IF x% = 28 THEN KeyboardRef.ENTER = ScanKey%(x%)
   IF x% = 57 THEN KeyboardRef.SPACE = ScanKey%(x%)
   IF x% = 29 THEN KeyboardRef.CTRL = ScanKey%(x%)
   IF x% = 56 THEN KeyboardRef.ALT = ScanKey%(x%)
   IF x% = 42 THEN KeyboardRef.SHIFT = ScanKey%(x%)
NEXT
END SUB

FUNCTION ScanKey% (scancode%)
STATIC Ready%, keyflags%() 'retain values on procedure exit
IF NOT Ready% THEN REDIM keyflags%(0 TO 127): Ready% = -1 'create array on first use
i% = INP(&H60) 'read keyboard states
IF (i% AND 128) THEN keyflags%(i% XOR 128) = 0
IF (i% AND 128) = 0 THEN keyflags%(i%) = -1
K$ = INKEY$ 'clears key buffer to prevent beeps
ScanKey% = keyflags%(scancode%)
IF scancode% = 0 THEN Ready% = 0 'allows program to reset all values to 0 with a REDIM
END FUNCTION

SUB GDK_Mouse_GetState (MouseRef AS MouseState)
DO
   MouseRef.X = _MOUSEX
   MouseRef.Y = _MOUSEY
   MouseRef.LB = _MOUSEBUTTON(1)
   MouseRef.RB = _MOUSEBUTTON(2)
LOOP WHILE _MOUSEINPUT
END SUB

'##########################################################################################################################
'// Graphics Manipulation subs and functions
'##########################################################################################################################

SUB GDK_ApplyMonoFilter (TypeRef AS Sprite)
_SOURCE TypeRef.File
_DONTBLEND TypeRef.File
_DEST TypeRef.File
w% = TypeRef.Width
h% = TypeRef.Height
FOR i% = 0 TO w%
   FOR j% = 0 TO h%
      m& = POINT(i%, j%)
      IF m& <> TypeRef.Alpha THEN
         clrsum% = (INT((_BLUE(m&) / 100) * 11) + INT((_RED(m&) / 100) * 39) + INT((_GREEN(m&) / 100) * 50))
         IF clrsum% > 0 AND clrsum% < 255 THEN
            IF m& <> _RGB(clrsum%, clrsum%, clrsum%) THEN PSET (i%, j%), _RGB(clrsum%, clrsum%, clrsum%)
         END IF
      END IF
   NEXT
NEXT
_BLEND TypeRef.File
_DEST 0
END SUB

SUB GDK_ApplyColorFilter (TypeRef AS Sprite, r%, g%, b%, a%)
_SOURCE TypeRef.File
_DONTBLEND TypeRef.File
_DEST TypeRef.File
w% = TypeRef.Width
h% = TypeRef.Height
FOR i% = 0 TO w%
   FOR j% = 0 TO h%
      m& = POINT(i%, j%)
      IF m& <> TypeRef.Alpha THEN
         PSET (i%, j%), _RGBA(_RED(m&) + r%, _GREEN(m&) + g%, _BLUE(m&) + b%, _ALPHA(m&) + a%)
      END IF
   NEXT
NEXT
_BLEND TypeRef.File
_DEST 0
END SUB

SUB GDK_ReplaceColor (TypeRef AS Sprite, OldColor&, NewColor&)
tmpimg& = _COPYIMAGE(TypeRef.File)
_CLEARCOLOR OldColor&, tmpimg&
_DEST TypeRef.File
PAINT (0, 0), NewColor&
_PUTIMAGE (0, 0), tmpimg&
_FREEIMAGE tmpimg&
_DEST 0
END SUB

SUB GDK_ChangeColorValue (TypeRef AS Sprite, Color$, Value%)
_SOURCE TypeRef.File
_DONTBLEND TypeRef.File
_DEST TypeRef.File
w% = TypeRef.Width
h% = TypeRef.Height
FOR i% = 0 TO w%
   FOR j% = 0 TO h%
      m& = POINT(i%, j%)
      IF m& <> TypeRef.Alpha THEN
         SELECT CASE UCASE$(Color$)
            CASE "R"
               PSET (i%, j%), _RGBA(_RED(m&) + Value%, _GREEN(m&), _BLUE(m&), _ALPHA(m&))
            CASE "G"
               PSET (i%, j%), _RGBA(_RED(m&), _GREEN(m&) + Value%, _BLUE(m&), _ALPHA(m&))
            CASE "B"
               PSET (i%, j%), _RGBA(_RED(m&), _GREEN(m&), _BLUE(m&) + Value%, _ALPHA(m&))
            CASE "A"
               PSET (i%, j%), _RGBA(_RED(m&), _GREEN(m&), _BLUE(m&), _ALPHA(m&) + Value%)
         END SELECT
      END IF
   NEXT
NEXT
_BLEND TypeRef.File
_DEST 0
END SUB

'##########################################################################################################################
'// Non Sprite Specific functions
'##########################################################################################################################

SUB GDK_Sphere (X%, Y%, Radius%, R%, G%, B%)
FOR py% = 0 TO (Radius% - 1)
   FOR px% = 0 TO (Radius% - 1)
      alpha = SQR((px% - (Radius% / 2)) ^ 2 + (py% - (Radius% / 2)) ^ 2) / (Radius% / 2)
      IF alpha < 0 THEN alpha = 0
      alpha = (1 - alpha * alpha) 'parabolic curve
      PSET (X% + px%, Y% + py%), _RGBA32(R%, G%, B%, alpha * 255)
   NEXT
NEXT
END SUB

'##########################################################################################################################
'//Particle engine v.02
'##########################################################################################################################

SUB GDK_Emitter_New (EmitRef AS Emitter, x%, y%, SpawnRate%, AngleMin!, AngleMax!, VelMin!, VelMax!, MinLifeTime#, MaxLifeTime#)
EmitRef.X = x%
EmitRef.Y = y%
EmitRef.SpawnRate = SpawnRate%
EmitRef.SpawnAngleMin = AngleMin!
EmitRef.SpawnAngleMax = AngleMax!
EmitRef.SpawnMaxVelocity = VelMax!
EmitRef.SpawnMinVelocity = VelMin!
EmitRef.MaxLifeTime = MaxLifeTime#
EmitRef.MinLifeTime = MinLifeTime#
END SUB

SUB GDK_Emitter_SetGravity (EmitRef AS Emitter, Gravity!)
EmitRef.Gravity = Gravity!
END SUB

SUB GDK_Emitter_SetAccelDecel (EmitRef AS Emitter, AccelMin!, AccelMax!, DecelMin!, DecelMax!)
EmitRef.AccelMin = AccelMin!
EmitRef.AccelMax = AccelMax!
EmitRef.DecelMIn = DecelMin!
EmitRef.DecelMax! = DecelMax!
END SUB

SUB GDK_Particles_Spawn (EmitRef AS Emitter, PartRef() AS Particle, ParticleMax%, InitialColor&, ColorChange&, ChangeMode%)
SuccessfulSpawns% = 0
FOR i% = 0 TO ParticleMax%
   IF NOT PartRef(i%).Exists THEN
      PartRef(i%).Vector.X = EmitRef.X
      PartRef(i%).Vector.Y = EmitRef.Y
      PartRef(i%).Exists = -1
      PartRef(i%).Vector.Rotation = (RND * EmitRef.SpawnAngleMax) + EmitRef.SpawnAngleMin
      PartRef(i%).Vector.Speed = (RND * EmitRef.SpawnMaxVelocity) + EmitRef.SpawnMinVelocity
      PartRef(i%).LifeTime = (RND * EmitRef.MaxLifeTime) + EmitRef.MinLifeTime
      PartRef(i%).InitialCLR = InitialColor&
      PartRef(i%).CurrentCLR = InitialColor&
      PartRef(i%).ClrChange = ColorChange&
      PartRef(i%).BirthTime = TIMER(.001)
      PartRef(i%).ClrChangeMode = ChangeMode%
      IF EmitRef.AccelMax > 0 THEN
         PartRef(i%).Accel = (RND * EmitRef.AccelMax) + EmitRef.AccelMin
      END IF
      IF EmitRef.DecelMax > 0 THEN
         PartRef(i%).Decel = (RND * EmitRef.DecelMax) + EmitRef.DecelMIn
      END IF
      SuccessfulSpawns% = SuccessfulSpawns% + 1
      IF SuccessfulSpawns% = EmitRef.SpawnRate THEN EXIT FOR
   END IF
NEXT
END SUB

SUB GDK_Particles_Update (PartRef() AS Particle, ParticleMax%)
FOR i% = 0 TO ParticleMax%
   IF PartRef(i%).Exists THEN
      IF TIMER(.001) - PartRef(i%).BirthTime >= PartRef(i%).LifeTime THEN
         PartRef(i%).Exists = 0
      ELSE
         IF PartRef(i%).Vector.Speed > 0 THEN
            IF PartRef(i%).Decel > 0 THEN
               IF PartRef(i%).Accel > 0 THEN
                  PartRef(i%).Accel = PartRef(i%).Accel - PartRef(i%).Decel
               ELSE
                  PartRef(i%).Vector.Speed = PartRef(i%).Vector.Speed - PartRef(i%).Decel
               END IF
            END IF
            IF PartRef(i%).Accel > 0 THEN PartRef(i%).Vector.Speed = PartRef(i%).Vector.Speed + PartRef(i%).Accel
            IF PartRef(i%).ClrChangeMode = 1 THEN
               PartRef(i%).CurrentCLR = PartRef(i%).CurrentCLR - PartRef(i%).ClrChange
            ELSE
               PartRef(i%).CurrentCLR = PartRef(i%).CurrentCLR + PartRef(i%).ClrChange
            END IF
            GDK_Vector_Move PartRef(i%).Vector
         END IF
      END IF
   END IF
NEXT
END SUB

SUB GDK_Particles_Draw (PartRef() AS Particle, ParticleMax%)
FOR i% = 0 TO ParticleMax%
   IF PartRef(i%).Exists THEN
      PSET (PartRef(i%).Vector.X, PartRef(i%).Vector.Y), PartRef(i%).CurrentCLR
   END IF
NEXT
END SUB

'##########################################################################################################################
'// MATH FUNCTIONS
'##########################################################################################################################

FUNCTION GDK_Distance! (X%, Y%, XX%, YY%)
xd% = XX% - X%
yd% = YY% - Y%
GDK_Distance! = SQR((xd% * xd%) + (yd% * yd%))
END FUNCTION

FUNCTION GDK_RadianToDegree! (Radians!)
GDK_RadianToDegree! = Radians! * (180 / (4 * ATN(1)))
END FUNCTION

FUNCTION GDK_DegreeToRadian! (Degrees!)
GDK_DegreeToRadian! = Degrees! * ((4 * ATN(1)) / 180)
END FUNCTION

SUB GDK_MathX
DECLARE LIBRARY
   FUNCTION atan2# (BYVAL y#, BYVAL x#)
   FUNCTION acos# (BYVAL x#)
   FUNCTION asin# (BYVAL x#)
   FUNCTION cosh# (BYVAL x#)
   FUNCTION sinh# (BYVAL x#)
   FUNCTION tanh# (BYVAL x#)
   FUNCTION pow# (BYVAL base#, BYVAL exponent#)
END DECLARE
END SUB

'##########################################################################################################################
'// Tile engine
'##########################################################################################################################

SUB GDK_TileMap_Load (Level() AS Tile, XTiles%, YTiles%)
FOR j% = 0 TO YTiles% - 1
   FOR i% = 0 TO XTiles% - 1
      READ tile%
      Level(i%, j%).Tile = tile%
   NEXT
NEXT
END SUB

SUB GDK_Tiles_Draw (TileRef AS Tileset, XYRef() AS XY, Level() AS Tile, X%, Y%, XCnt%, YCnt%, XMax%, YMax%)
Tx% = X%
Ty% = Y%
sx% = _WIDTH(_DEST)
sy% = _HEIGHT(_DEST)
FOR j% = YCnt% TO YMax% - 1
   FOR i% = XCnt% TO XMax% - 1
      IF Tx% < sx% THEN
         IF Level(i%, j%).Tile > 0 THEN
            GDK_Tile_Draw TileRef, Level(i%, j%).Tile, XYRef(), Tx%, Ty%
            GDK_Rectangle_New Level(i%, j%).RECT, Tx%, Ty%, TileRef.TWidth * TileRef.Scale, TileRef.THeight * TileRef.Scale
         END IF
         Tx% = Tx% + (TileRef.TWidth * TileRef.Scale)
      ELSE
         EXIT FOR
      END IF
   NEXT
   Tx% = X%
   IF Ty% < sy% THEN Ty% = Ty% + (TileRef.THeight * TileRef.Scale) ELSE EXIT FOR
NEXT
END SUB

SUB GDK_Tileset_New (TileRef AS Tileset, File$, XYRef() AS XY, XTiles%, YTiles%, Alpha&, XOffset%, YOffset%)
TileRef.XTiles = XTiles%
TileRef.YTiles = YTiles%
TileRef.Alpha = Alpha&
TileRef.File = _LOADIMAGE(File$, 32)
TileRef.Width = _WIDTH(TileRef.File)
TileRef.Height = _HEIGHT(TileRef.File)
TileRef.TWidth = (TileRef.Width / TileRef.XTiles) - XOffset%
TileRef.THeight = (TileRef.Height / TileRef.YTiles) - YOffset%
FOR j% = 1 TO YTiles%
   FOR i% = 1 TO XTiles%
      Count% = Count% + 1
      XYRef(Count%).X = (i% - 1) * (TileRef.Width / XTiles%) + XOffset%
      XYRef(Count%).Y = (j% - 1) * (TileRef.Height / YTiles%) + YOffset%
   NEXT
NEXT
_CLEARCOLOR Alpha&, TileRef.File
TileRef.Scale = 1
END SUB

SUB GDK_Tile_Draw (TileRef AS Tileset, TileNum%, XYRef() AS XY, x%, y%)
_PUTIMAGE (x%, y%)-(x% + (TileRef.TWidth * TileRef.Scale), y% + (TileRef.THeight * TileRef.Scale)), TileRef.File, , (XYRef(TileNum%).X, XYRef(TileNum%).Y)-(XYRef(TileNum%).X + TileRef.TWidth - 1, XYRef(TileNum%).Y + TileRef.THeight - 1)
END SUB

SUB GDK_TileMap_Load_FromFile (GameFile$, Level() AS Tile, YTiles%)
X& = FREEFILE
OPEN GameFile$ FOR INPUT AS #X&
FOR i% = 0 TO YTiles% - 1
   LINE INPUT #X&, DataLine$
   Cnt% = 0
   FOR j% = 0 TO LEN(DataLine$)
      IF INSTR(j%, DataLine$, ",") > 0 THEN
         Level(Cnt%, i%).Tile = VAL(MID$(DataLine$, j%, INSTR(j%, DataLine$, ",") - j%))
         j% = INSTR(j%, DataLine$, ",")
         Cnt% = Cnt% + 1
      ELSE
         Level(Cnt%, i%).Tile = VAL(MID$(DataLine$, j%))
      END IF
   NEXT
NEXT
CLOSE #X&
END SUB

SUB GDK_Tileset_SetScale (TileRef AS Tileset, Scale!)
TileRef.Scale = Scale!
END SUB

SUB GDK_Tiles_Draw_ISO (TileRef AS Tileset, XYRef() AS XY, Level() AS Tile, X%, Y%, XCnt%, YCnt%, XMax%, YMax%)
Tx% = X%
Ty% = Y%
YCntr% = 0
FOR j% = YCnt% TO YMax%
   FOR i% = XCnt% TO XMax%
      IF Level(i%, j%).Tile > 0 THEN GDK_Tile_Draw TileRef, Level(i%, j%).Tile, XYRef(), Tx%, Ty%
      Tx% = Tx% + (TileRef.TWidth / 2)
      Ty% = Ty% + (TileRef.THeight / 4)
   NEXT
   YCntr% = YCntr% + 1
   Ty% = Y% + YCntr% * (TileRef.THeight / 4)
   Tx% = X% - (YCntr% * (TileRef.TWidth / 2))
NEXT
END SUB

'##########################################################################################################################

SUB GDK_TilesetX_New (TileRef AS TilesetX, File$, XYRef() AS XY2, XTiles%, YTiles%, Alpha&, XOffset%, YOffset%)
TileRef.XTiles = XTiles%
TileRef.YTiles = YTiles%
TileRef.Alpha = Alpha&
TileRef.File = _LOADIMAGE(File$, 32)
TileRef.Width = _WIDTH(TileRef.File)
TileRef.Height = _HEIGHT(TileRef.File)
TileRef.Scale = 1
_CLEARCOLOR Alpha&, TileRef.File

TileRef.TWidth = (TileRef.Width / TileRef.XTiles) - XOffset%
TileRef.THeight = (TileRef.Height / TileRef.YTiles) - YOffset%
OldSource& = _SOURCE
_SOURCE TileRef.File
FOR j% = 1 TO YTiles%
   FOR i% = 1 TO XTiles%
      Count% = Count% + 1
      XYRef(Count%).X = (i% - 1) * (TileRef.Width / XTiles%) + XOffset%
      XYRef(Count%).Y = (j% - 1) * (TileRef.Height / YTiles%) + YOffset%
      '// Get RealRect (actual pixel area) data for the tile
      '// This is relative to the tiles XY position
      FirstY% = TileRef.TWidth
      FirstX% = TileRef.THeight
      LastY% = 0
      LastX% = 0
      H% = TileRef.TWidth - 1
      W% = TileRef.THeight - 1
      FOR k% = 0 TO H%
         FOR l% = 0 TO W%
            RealK% = k% + j% - 1
            RealL% = l% + i% - 1
            C& = POINT(RealL%, RealK%)
            IF C& <> TileRef.Alpha THEN
               IF l% < FirstX% THEN FirstX% = l%
               IF l% > LastX% THEN LastX% = l%
               IF k% < FirstY% THEN FirstY% = k%
               IF k% > LastY% THEN LastY% = k%
            END IF
         NEXT
      NEXT
      XYRef(Count%).RealRect.X = FirstX%
      XYRef(Count%).RealRect.Y = FirstY%
      XYRef(Count%).RealRect.Width = LastX% - FirstX%
      XYRef(Count%).RealRect.Height = LastY% - FirstY%
   NEXT
NEXT
_SOURCE OldSource&
END SUB

'##########################################################################################################################

SUB GDK_TileX_Draw (TileRef AS TilesetX, TileNum%, XYRef() AS XY2, x%, y%)
_PUTIMAGE (x%, y%)-(x% + (TileRef.TWidth * TileRef.Scale), y% + (TileRef.THeight * TileRef.Scale)), TileRef.File, , (XYRef(TileNum%).X, XYRef(TileNum%).Y)-(XYRef(TileNum%).X + TileRef.TWidth - 1, XYRef(TileNum%).Y + TileRef.THeight - 1)
END SUB

'##########################################################################################################################

SUB GDK_TilesX_Draw (TileRef AS TilesetX, XYRef() AS XY2, Level() AS Tile, X%, Y%, XCnt%, YCnt%, XMax%, YMax%)
Tx% = X%
Ty% = Y%
sx% = _WIDTH(_DEST)
sy% = _HEIGHT(_DEST)
FOR j% = YCnt% TO YMax% - 1
   FOR i% = XCnt% TO XMax% - 1
      IF Tx% < sx% THEN
         IF Level(i%, j%).Tile > 0 THEN
            GDK_TileX_Draw TileRef, Level(i%, j%).Tile, XYRef(), Tx%, Ty%
            GDK_Rectangle_New Level(i%, j%).RECT, Tx% + XYRef(Level(i%, j%).Tile).RealRect.X, Ty% + XYRef(Level(i%, j%).Tile).RealRect.Y, XYRef(Level(i%, j%).Tile).RealRect.Width * TileRef.Scale, XYRef(Level(i%, j%).Tile).RealRect.Height * TileRef.Scale
         END IF
         Tx% = Tx% + (TileRef.TWidth * TileRef.Scale)
      ELSE
         EXIT FOR
      END IF
   NEXT
   Tx% = X%
   IF Ty% < sy% THEN Ty% = Ty% + (TileRef.THeight * TileRef.Scale) ELSE EXIT FOR
NEXT
END SUB

'##########################################################################################################################

SUB GDK_TilesetX_SetScale (TileRef AS TilesetX, Scale!)
TileRef.Scale = Scale!
END SUB

'##########################################################################################################################
'// GameObject Subs and Functions - SUper fast prototyping commands for games
'##########################################################################################################################

SUB GDK_GameObject_New (Handle AS GameObject, File$, XframeCount%, YFrameCount%, X%, Y%, Speed!, Rotation!)
GDK_Sprite_New Handle.Sprite, File$, XframeCount%, YFrameCount%, XframeCount% * YFrameCount%, 1
GDK_Vector_New Handle.Vector, X%, Y%, Speed!, Rotation!
GDK_Rectangle_New Handle.Rect, X%, Y%, Handle.Sprite.Width / XframeCount%, Handle.Sprite.Height / YFrameCount%
GDK_Sprite_SetVisibility Handle.Sprite, -1
GDK_Sprite_SetAlpha Handle.Sprite, _RGB(255, 0, 255)
END SUB

SUB GDK_GameObject_Draw (GameObject AS GameObject, AnimationFrame%)
GDK_Sprite_Draw GameObject.Sprite, GameObject.Vector, AnimationFrame%
END SUB

SUB GDK_GameObject_Update (Handle AS GameObject)
GDK_Vector_Update Handle.Vector
GDK_Rectangle_AutoSize Handle.Sprite, Handle.Vector, Handle.Rect
END SUB

SUB GDK_GameObject_Rotate (Handle AS GameObject, Rot!)
Handle.Vector.Rotation = Handle.Vector.Rotation + Rot!
END SUB

SUB GDK_GameObject_Hide (Handle AS GameObject)
Handle.Sprite.IsVisible = 0
END SUB

SUB GDK_GameObject_Show (Handle AS GameObject)
Handle.Sprite.IsVisible = -1
END SUB

FUNCTION GDK_GameObject_Intersect (Handle AS GameObject, Handle2 AS GameObject)
IF GDK_Rectangle_Intersect(Handle.Rect, Handle2.Rect) THEN
   GDK_GameObject_Intersect = -1
ELSE
   GDK_GameObject_Intersect = 0
END IF
END SUB

'##########################################################################################################################
'// Animation routines - Taken from GDK_GL
'##########################################################################################################################

SUB GDK_ANIMATION_NEW (Anim AS ANIMATION, Frame%, StartFrame%, ResetFrame%, AnimTime#, AnimTimer#)
Anim.Frame = Frame%
Anim.StartFrame = StartFrame%
Anim.ResetFrame = ResetFrame%
Anim.Time = AnimTime#
Anim.Timer = AnimTimer#
IF ResetFrame% < StartFrame% THEN Anim.Dir = -1 ELSE Anim.Dir = 0
END SUB

SUB GDK_ANIMATION_UPDATE (Anim AS ANIMATION)
IF Anim.Dir = -1 THEN
    IF Anim.Frame > Anim.StartFrame OR Anim.Frame < Anim.ResetFrame THEN
        Anim.Frame = Anim.StartFrame
        Anim.Timer = TIMER(.001)
    ELSE
        IF TIMER(.001) - Anim.Timer >= Anim.Time THEN
            IF Anim.Frame = Anim.ResetFrame THEN
                Anim.Frame = Anim.StartFrame
            ELSE
                Anim.Frame = Anim.Frame - 1
            END IF
            Anim.Timer = TIMER(.001)
        END IF
    END IF
ELSE
    IF Anim.Frame < Anim.StartFrame OR Anim.Frame > Anim.ResetFrame THEN
        Anim.Frame = Anim.StartFrame
        Anim.Timer = TIMER(.001)
    ELSE
        IF TIMER(.001) - Anim.Timer >= Anim.Time THEN
            IF Anim.Frame = Anim.ResetFrame THEN
                Anim.Frame = Anim.StartFrame
            ELSE
                Anim.Frame = Anim.Frame + 1
            END IF
            Anim.Timer = TIMER(.001)
        END IF
    END IF
END IF
END SUB



'##########################################################################################################################
'// SpriteX Functions
'##########################################################################################################################

SUB GDK_SpriteX_New (Sprite AS SpriteX, File$, Rect() AS Rectangle, XFrames%, YFrames%, MaxFrames%, Spacing%)
Sprite.File = _LOADIMAGE(File$, 32)
Sprite.Width = _WIDTH(Sprite.File)
Sprite.Height = _HEIGHT(Sprite.File)
Sprite.IsEqual = Spacing%
Sprite.ScaleX = 1
Sprite.ScaleY = 1
Sprite.TotalFrames = MaxFrames%
IF Spacing% THEN '// Is an equally spaced sprite sheet, if x or y frames count > 1 calculate posisitons into rect array
   Sprite.FrameWidth = Sprite.Width / XFrames%
   Sprite.FrameHeight = Sprite.Height / YFrames%
   IF XFrames% > 1 OR YFrames% > 1 THEN
      FOR Y% = 1 TO YFrames%
         FOR X% = 1 TO XFrames%
            IF X% > 1 THEN Px% = Px% + Sprite.FrameWidth
            Rect(RectCnt%).X = Px%
            Rect(RectCnt%).Y = Py%
            Rect(RectCnt%).Width = Sprite.FrameWidth
            Rect(RectCnt%).Height = Sprite.FrameHeight
            RectCnt% = RectCnt% + 1
         NEXT
         Py% = Py% + Sprite.FrameHeight
         Px% = 0
      NEXT
   ELSE
      Rect(RectCnt%).X = 0
      Rect(RectCnt%).Y = 0
      Rect(RectCnt%).Width = Sprite.FrameWidth
      Rect(RectCnt%).Height = Sprite.FrameHeight
   END IF
END IF
END SUB

SUB GDK_SpriteX_Clone (SourceSprite AS SpriteX, DestSprite AS SpriteX)
DestSprite = SourceSprite
END SUB

SUB GDK_SpriteX_Clone_X (SourceSprite AS SpriteX, DestSprite() AS SpriteX, FirstClone%, NumberOfClones%)
FOR CloneCount% = FirstClone% TO FirstClone% + NumberOfClones% - 1
   DestSprite(CloneCount%) = SourceSprite
NEXT
END SUB

SUB GDK_SpriteX_Set_Scale (Sprite AS SpriteX, XScale%, YScale%)
Sprite.ScaleX = XScale%
Sprite.ScaleY = YScale%
END SUB

SUB GDK_SpriteX_SetRotationPoint (Sprite AS SpriteX, X%, Y%)
Sprite.RotX = X%
Sprite.RotY = Y%
END SUB

SUB GDK_SpriteX_SetVisibility (Sprite AS SpriteX, OnOff%)
Sprite.IsVisible = OnOff%
END SUB

SUB GDK_SpriteX_SetAlpha (Sprite AS SpriteX, Alpha&)
Sprite.Alpha = Alpha&
END SUB

SUB GDK_SpriteX_DrawXY (Sprite AS SpriteX, Rect() AS Rectangle, X%, Y%, Rotation!, AnimationFrame%)
DIM TempVect AS Vector
GDK_Vector_New TempVect, X%, Y%, 0, Rotation!
GDK_SpriteX_Draw Sprite, TempVect, Rect(), AnimationFrame%
END SUB

SUB GDK_SpriteX_Draw (Sprite AS SpriteX, DestVector AS Vector, Rect() AS Rectangle, Frame%)
_CLEARCOLOR Sprite.Alpha, Sprite.File
IF Sprite.IsVisible THEN
   IF Frame% = 0 THEN '// Draw the entire image.
      IF DestVector.Rotation = 0 THEN
         _PUTIMAGE (DestVector.X - (Sprite.RotX * Sprite.ScaleX), DestVector.Y - (Sprite.RotY * Sprite.ScaleY))-((DestVector.X - (Sprite.RotX * Sprite.ScaleX)) + (Sprite.Width * Sprite.ScaleX), (DestVector.Y - (Sprite.RotY * Sprite.ScaleY)) + (Sprite.Height * Sprite.ScaleY)), Sprite.File
      ELSE
         Rotate_Scale_AroundPoint DestVector.X, DestVector.Y, Sprite.File, DestVector.Rotation, Sprite.ScaleX, Sprite.ScaleY, Sprite.RotX, Sprite.RotY
      END IF
   ELSE '// Draw a specific frame.
      IF DestVector.Rotation = 0 THEN
         _PUTIMAGE (DestVector.X - (Sprite.RotX * Sprite.ScaleX), DestVector.Y - (Sprite.RotY * Sprite.ScaleY))-((DestVector.X - (Sprite.RotX * Sprite.ScaleX)) + (Sprite.FrameWidth * Sprite.ScaleX), (DestVector.Y - (Sprite.RotY * Sprite.ScaleY)) + (Sprite.FrameHeight * Sprite.ScaleY)), Sprite.File, , (Rect(Frame% - 1).X, Rect(Frame% - 1).Y)-(Rect(Frame% - 1).X + Rect(Frame% - 1).Width, Rect(Frame% - 1).Y + Rect(Frame% - 1).Height)
      ELSE
         DIM TmpImage AS LONG
         TmpImage = _NEWIMAGE(Sprite.FrameWidth * Sprite.ScaleX, Sprite.FrameHeight * Sprite.ScaleY, 32)
         OldDest& = _DEST
         _DEST TmpImage
         _PUTIMAGE (0, 0)-(Sprite.FrameWidth * Sprite.ScaleX, Sprite.FrameHeight * Sprite.ScaleY), Sprite.File, , (Rect(Frame% - 1).X, Rect(Frame% - 1).Y)-(Rect(Frame% - 1).X + Rect(Frame% - 1).Width, Rect(Frame% - 1).Y + Rect(Frame% - 1).Height)
         _DEST OldDest&
         Rotate_Scale_AroundPoint DestVector.X, DestVector.Y, TmpImage, DestVector.Rotation, Sprite.ScaleX, Sprite.ScaleY, Sprite.RotX, Sprite.RotY
         _FREEIMAGE TmpImage
      END IF
   END IF
END IF
END SUB

SUB GDK_SpriteX_Hide (Handle AS SpriteX)
Handle.IsVisible = 0
END SUB

SUB GDK_SpriteX_Show (Handle AS SpriteX)
Handle.IsVisible = -1
END SUB

'##########################################################################################################################
'// Image ROTATION/ZOOM FUNCTION BY GALLEON
'##########################################################################################################################

SUB Rotate_Scale_AroundPoint (X AS LONG, Y AS LONG, Image AS LONG, Rotation AS SINGLE, ScaleX AS SINGLE, ScaleY AS SINGLE, PointX AS LONG, PointY AS LONG)
DEFSNG A-Z
DIM pX(3) AS SINGLE: DIM pY(3) AS SINGLE
DIM W AS LONG, H AS LONG, I AS LONG, X2 AS LONG, Y2 AS LONG
W = _WIDTH(Image): H = _HEIGHT(Image)
pX(0) = -PointX: pY(0) = -PointY: pX(1) = -PointX: pY(1) = -PointY + H - 1: pX(2) = -PointX + W - 1: pY(2) = -PointY + H - 1: pX(3) = -PointX + W - 1: pY(3) = -PointY 'Set dest screen points
Radians = -Rotation / 57.29578: SINr = SIN(Radians): COSr = COS(Radians) 'Precalculate SIN & COS of angle
FOR I = 0 TO 3
   pX(I) = pX(I) * ScaleX: pY(I) = pY(I) * ScaleY 'Scale
   X2 = pX(I) * COSr + SINr * pY(I): pY(I) = pY(I) * COSr - pX(I) * SINr: pX(I) = X2 'Rotate Dest Points
   pX(I) = pX(I) + X: pY(I) = pY(I) + Y 'Translate Dest Points
NEXT
_MAPTRIANGLE (0, 0)-(0, H - 1)-(W - 1, H - 1), Image TO(pX(0), pY(0))-(pX(1), pY(1))-(pX(2), pY(2))
_MAPTRIANGLE (0, 0)-(W - 1, 0)-(W - 1, H - 1), Image TO(pX(0), pY(0))-(pX(3), pY(3))-(pX(2), pY(2))
END SUB

'##########################################################################################################################
'// Path based movement v.02
'##########################################################################################################################

SUB GDK_Path_New (Path AS Path, PathPoint() AS PathPoint, NumPoints%, Reverse%, Repeat%, Relative%)
IF Relative% THEN READ Path.Vector.X, Path.Vector.Y, Path.Vector.Speed
FOR i% = 0 TO NumPoints% - 1
   READ PathPoint(i%).X, PathPoint(i%).Y, PathPoint(i%).Speed
NEXT
IF Relative% THEN
   Path.TargetVector.X = Path.Vector.X + PathPoint(0).X
   Path.TargetVector.Y = Path.Vector.Y + PathPoint(0).Y
   Path.Vector.Rotation = -atan2(Path.Vector.Y - Path.TargetVector.Y, Path.Vector.X - Path.TargetVector.X) + (2 * ATN(1))
ELSE
   Path.Vector.X = PathPoint(0).X
   Path.Vector.Y = PathPoint(0).Y
   Path.Vector.Speed = PathPoint(0).Speed
   Path.Vector.Rotation = -atan2(PathPoint(0).Y - PathPoint(1).Y, PathPoint(0).X - PathPoint(1).X) + (2 * ATN(1))
   Path.TargetVector.X = PathPoint(1).X
   Path.TargetVector.Y = PathPoint(1).Y
END IF
Path.LastVector = Path.Vector
Path.NumPoints = NumPoints%
Path.Reverse = Reverse%
Path.Repeat = Repeat%
Path.Relative = Relative%
END SUB


SUB GDK_Path_Update (Path AS Path, PathPoint() AS PathPoint)
IF Path.Relative THEN '// Relative movement
   IF NOT Path.HitTargetX THEN IF IsWithinRange(Path.TargetVector.X, Path.LastVector.X, Path.Vector.X) THEN Path.HitTargetX = -1
   IF NOT Path.HitTargetY THEN IF IsWithinRange(Path.TargetVector.Y, Path.LastVector.Y, Path.Vector.Y) THEN Path.HitTargetY = -1
   IF Path.HitTargetX AND Path.HitTargetY THEN
      IF Path.CurrentPoint < Path.NumPoints - 1 THEN
         Path.TargetVector.X = Path.Vector.X + PathPoint(Path.CurrentPoint + 1).X
         Path.TargetVector.Y = Path.Vector.Y + PathPoint(Path.CurrentPoint + 1).Y
         Path.Vector.Rotation = -atan2(Path.Vector.Y - Path.TargetVector.Y, Path.Vector.X - Path.TargetVector.X) + (2 * ATN(1))
         Path.Vector.Speed = PathPoint(Path.CurrentPoint).Speed
         Path.CurrentPoint = Path.CurrentPoint + 1
      ELSE '// Last point
         IF Path.Repeat THEN
            Path.CurrentPoint = 0
            Path.TargetVector.X = Path.Vector.X + PathPoint(0).X
            Path.TargetVector.Y = Path.Vector.Y + PathPoint(0).Y
            Path.Vector.Rotation = -atan2(Path.Vector.Y - Path.TargetVector.Y, Path.Vector.X - Path.TargetVector.X) + (2 * ATN(1))
            Path.Vector.Speed = PathPoint(0).Speed
         ELSE
            Path.Vector.Speed = 0
         END IF
      END IF
      Path.HitTargetX = 0
      Path.HitTargetY = 0
   END IF
ELSE '// Co-ordinate based movement
   IF Path.IsReversing THEN
      IF Path.CurrentPoint > 0 THEN
         IF NOT Path.HitTargetX THEN IF IsWithinRange(PathPoint(Path.CurrentPoint - 1).X, Path.LastVector.X, Path.Vector.X) THEN Path.HitTargetX = -1
         IF NOT Path.HitTargetY THEN IF IsWithinRange(PathPoint(Path.CurrentPoint - 1).Y, Path.LastVector.Y, Path.Vector.Y) THEN Path.HitTargetY = -1
         IF Path.HitTargetX AND Path.HitTargetY THEN
            IF Path.CurrentPoint > 1 THEN
               Path.CurrentPoint = Path.CurrentPoint - 1
               Path.Vector.Rotation = -atan2(Path.Vector.Y - PathPoint(Path.CurrentPoint - 1).Y, Path.Vector.X - PathPoint(Path.CurrentPoint - 1).X) + (2 * ATN(1))
            ELSE '// First point
               Path.CurrentPoint = 0
               IF Path.Reverse THEN
                  Path.IsReversing = 0
                  Path.Vector.Rotation = -atan2(Path.Vector.Y - PathPoint(Path.CurrentPoint + 1).Y, Path.Vector.X - PathPoint(Path.CurrentPoint + 1).X) + (2 * ATN(1))
               END IF
            END IF
            Path.HitTargetX = 0
            Path.HitTargetY = 0
            Path.Vector.Speed = PathPoint(Path.CurrentPoint).Speed
         END IF
      END IF
   ELSE
      IF Path.CurrentPoint < Path.NumPoints - 1 THEN
         IF NOT Path.HitTargetX THEN IF IsWithinRange(PathPoint(Path.CurrentPoint + 1).X, Path.LastVector.X, Path.Vector.X) THEN Path.HitTargetX = -1
         IF NOT Path.HitTargetY THEN IF IsWithinRange(PathPoint(Path.CurrentPoint + 1).Y, Path.LastVector.Y, Path.Vector.Y) THEN Path.HitTargetY = -1
         IF Path.HitTargetX AND Path.HitTargetY THEN
            IF Path.CurrentPoint < Path.NumPoints - 2 THEN
               Path.CurrentPoint = Path.CurrentPoint + 1
               Path.Vector.Rotation = -atan2(Path.Vector.Y - PathPoint(Path.CurrentPoint + 1).Y, Path.Vector.X - PathPoint(Path.CurrentPoint + 1).X) + (2 * ATN(1))
            ELSE '// Last point
               Path.CurrentPoint = Path.NumPoints - 1
               IF Path.Reverse THEN
                  Path.IsReversing = -1
                  Path.Vector.Rotation = -atan2(Path.Vector.Y - PathPoint(Path.CurrentPoint - 1).Y, Path.Vector.X - PathPoint(Path.CurrentPoint - 1).X) + (2 * ATN(1))
               ELSEIF Path.Repeat THEN
                  Path.CurrentPoint = 0
                  IF Path.Repeat THEN
                     FOR i% = 1 TO Path.NumPoints - 1
                        XDif% = PathPoint(i%).X - PathPoint(i% - 1).X
                        YDif% = PathPoint(i%).Y - PathPoint(i% - 1).Y
                        IF i% = 1 THEN
                           PathPoint(0).X = Path.Vector.X
                           PathPoint(0).Y = Path.Vector.Y
                        END IF
                        PathPoint(i%).X = PathPoint(i% - 1).X + XDif%
                        PathPoint(i%).Y = PathPoint(i% - 1).Y + YDif%
                     NEXT
                  END IF
                  Path.Vector.Rotation = -atan2(Path.Vector.Y - PathPoint(Path.CurrentPoint + 1).Y, Path.Vector.X - PathPoint(Path.CurrentPoint + 1).X) + (2 * ATN(1))
               ELSE '// Stop at end
                  PathPoint(Path.CurrentPoint).Speed = 0
               END IF
            END IF
            Path.Vector.Speed = PathPoint(Path.CurrentPoint).Speed
            Path.HitTargetX = 0
            Path.HitTargetY = 0
         END IF
      END IF
   END IF
END IF
Path.LastVector = Path.Vector
GDK_Vector_Update Path.Vector
END SUB

'// GDK_Path_Update helper function
FUNCTION IsWithinRange% (Target%, MinRange%, MaxRange%)
IF Target% >= MinRange% AND Target% <= MaxRange% THEN
   IsWithinRange% = -1
ELSEIF Target% <= MinRange% AND Target% >= MaxRange% THEN
   IsWithinRange% = -1
ELSE
   IsWithinRange% = 0
END IF
END FUNCTION

'##########################################################################################################################
'SpriteFont engine
'##########################################################################################################################

SUB GDK_SpriteFont_New (FNT AS SPRITEFONT, File$)
GDK_Sprite_New FNT.Image, File$, 13, 8, 13 * 8, 1
GDK_Sprite_Show FNT.Image
FNT.Spacing = 1
FNT.SpaceWidth = 8
END SUB

SUB GDK_SpriteFont_SetAlpha (FNT AS SPRITEFONT, Alpha~&)
GDK_Sprite_SetAlpha FNT.Image, Alpha~&
END SUB

SUB GDK_SpriteFont_SetSpacing (FNT AS SPRITEFONT, Spacing!)
FNT.Spacing = Spacing!
END SUB

SUB GDK_SpriteFont_SetScale (FNT AS SPRITEFONT, Scale!)
FNT.Image.Scale = Scale!
END SUB

SUB GDK_SpriteFont_SetSpaceWidth (FNT AS SPRITEFONT, SpaceWidth!)
FNT.SpaceWidth = SpaceWidth!
END SUB

FUNCTION GDK_PrintWidth (Text$, FNT AS SPRITEFONT)
OldDest& = _DEST
OldSource& = _SOURCE
FONTSTRING$ = " ! #$%&'()*+ ,-./01234567 89:;<=>?@ABC DEFGHIJKLMNO PQRSTUVWXYZ[ \]^-`abcdefg hijklmnopqrs tuvwxyz{|}~ "
FOR i% = 1 TO LEN(Text$)
   LtrVal% = INSTR(FONTSTRING$, MID$(Text$, i%, 1))
   IF LtrVal% THEN
      IF LtrVal% > 1 THEN
         TmpImage& = _NEWIMAGE(((FNT.Image.Width / FNT.Image.XFrameCount) * FNT.Image.Scale), ((FNT.Image.Height / FNT.Image.YFrameCount) * FNT.Image.Scale), 32)
         _DEST TmpImage&
         GDK_Sprite_DrawXY FNT.Image, 0, 0, 0, LtrVal%
         H& = _HEIGHT(TmpImage&) - 1
         W& = _WIDTH(TmpImage&) - 1
         FirstY% = H&
         FirstX% = W&
         LastY% = 0
         LastX% = 0
         _SOURCE TmpImage&
         FOR k% = 0 TO H&
            FOR j% = 0 TO W&
               C& = POINT(j%, k%)
               IF C& <> FNT.Image.Alpha THEN
                  IF j% < FirstX% THEN FirstX% = j%
                  IF j% > LastX% THEN LastX% = j%
                  IF k% < FirstY% THEN FirstY% = k%
                  IF k% > LastY% THEN LastY% = k%
               END IF
            NEXT
         NEXT
         TotalWidth! = TotalWidth! + (LastX% - FirstX%) + FNT.Spacing
         _DEST OldDest&
         _SOURCE OldSource&
         _FREEIMAGE TmpImage&
      ELSE '// a space
         TotalWidth! = TotalWidth! + (FNT.SpaceWidth * FNT.Image.Scale) + FNT.Spacing
      END IF
   END IF
NEXT
GDK_PrintWidth = TotalWidth!
END FUNCTION

FUNCTION GDK_PrintHeight (Text$, FNT AS SPRITEFONT)
OldDest& = _DEST
OldSource& = _SOURCE
FONTSTRING$ = " ! #$%&'()*+ ,-./01234567 89:;<=>?@ABC DEFGHIJKLMNO PQRSTUVWXYZ[ \]^-`abcdefg hijklmnopqrs tuvwxyz{|}~ "
FOR i% = 1 TO LEN(Text$)
   LtrVal% = INSTR(FONTSTRING$, MID$(Text$, i%, 1))
   IF LtrVal% THEN
      IF LtrVal% > 1 THEN
         TmpImage& = _NEWIMAGE(((FNT.Image.Width / FNT.Image.XFrameCount) * FNT.Image.Scale), ((FNT.Image.Height / FNT.Image.YFrameCount) * FNT.Image.Scale), 32)
         _DEST TmpImage&
         GDK_Sprite_DrawXY FNT.Image, 0, 0, 0, LtrVal%
         H& = _HEIGHT(TmpImage&) - 1
         W& = _WIDTH(TmpImage&) - 1
         FirstY% = H&
         FirstX% = W&
         LastY% = 0
         LastX% = 0
         _SOURCE TmpImage&
         FOR k% = 0 TO H&
            FOR j% = 0 TO W&
               C& = POINT(j%, k%)
               IF C& <> FNT.Image.Alpha THEN
                  IF j% < FirstX% THEN FirstX% = j%
                  IF j% > LastX% THEN LastX% = j%
                  IF k% < FirstY% THEN FirstY% = k%
                  IF k% > LastY% THEN LastY% = k%
               END IF
            NEXT
         NEXT
         Height% = LastY% - FirstY%
         IF Height% > MaxHeight% THEN MaxHeight% = Height%
         _DEST OldDest&
         _SOURCE OldSource&
         _FREEIMAGE TmpImage&
      ELSE '// a space
         MaxHeight% = H&
         EXIT FOR
      END IF
   END IF
NEXT
GDK_PrintHeight = MaxHeight%
END FUNCTION



SUB GDK_Print (X!, Y!, Text$, FNT AS SPRITEFONT)
MaxHeight% = GDK_PrintHeight(Text$, FNT)
OldX! = X!
OldDest& = _DEST
OldSource& = _SOURCE
FONTSTRING$ = " ! #$%&'()*+ ,-./01234567 89:;<=>?@ABC DEFGHIJKLMNO PQRSTUVWXYZ[ \]^-`abcdefg hijklmnopqrs tuvwxyz{|}~ "
YOffsetString$ = "gjpqy"
FOR i% = 1 TO LEN(Text$)
   Ltr$ = MID$(Text$, i%, 1)
   LtrVal% = INSTR(FONTSTRING$, Ltr$)
   IF LtrVal% THEN
      IF LtrVal% = 1 THEN '// A space - just move along the X axis the approriate amount
         XDif! = (FNT.SpaceWidth * FNT.Image.Scale) + FNT.Spacing
      ELSE
         TmpImage& = _NEWIMAGE(((FNT.Image.Width / FNT.Image.XFrameCount) * FNT.Image.Scale), ((FNT.Image.Height / FNT.Image.YFrameCount) * FNT.Image.Scale), 32)

         _DEST TmpImage&
         GDK_Sprite_DrawXY FNT.Image, 0, 0, 0, LtrVal%
         H& = _HEIGHT(TmpImage&) - 1
         W& = _WIDTH(TmpImage&) - 1
         FirstY% = H&
         FirstX% = W&
         LastY% = 0
         LastX% = 0

         _SOURCE TmpImage&
         FOR k% = 0 TO H&
            FOR j% = 0 TO W&
               C& = POINT(j%, k%)
               IF C& <> FNT.Image.Alpha THEN
                  IF j% < FirstX% THEN FirstX% = j%
                  IF j% > LastX% THEN LastX% = j%
                  IF k% < FirstY% THEN FirstY% = k%
                  IF k% > LastY% THEN LastY% = k%
               END IF
            NEXT
         NEXT
         _DEST OldDest&
         _SOURCE OldSource&

         LtrHeight% = LastY% - FirstY%
         LtrWidth% = LastX% - FirstX%
         WidthDif% = W& - LtrWidth%
         HeightDif% = H& - LtrHeight%

         IF INSTR(YOffsetString$, Ltr$) THEN
            YLtrHeightDif% = MaxHeight% - (LtrHeight% / 1.75)
         ELSE
            YLtrHeightDif% = MaxHeight% - LtrHeight%
         END IF

         _PUTIMAGE (X!, Y! + YLtrHeightDif%)-(X! + LtrWidth%, Y! + YLtrHeightDif% + LtrHeight%), TmpImage&, , (FirstX%, FirstY%)-(LastX%, LastY%)
         XDif! = LtrWidth% + FNT.Spacing
         _FREEIMAGE TmpImage&

      END IF
   END IF
   X! = X! + XDif!
NEXT
X! = OldX!
END SUB






'##########################################################################################################################
'// END OF LIBRARY!!!
'##########################################################################################################################

Enjoy,

Unseen

Billbo

  • Hero Member
  • *****
  • Posts: 1143
Re: UnseenGDK (Game Development Kit) For QB64
« Reply #651 on: March 03, 2015, 04:54:36 pm »
Unseen,

But you did not update file in your signature. It's still version 1.3.2. Don't get upset for me being picky.

Bill

unseenmachine

  • Hero Member
  • *****
  • Posts: 3648
  • Make the Game not the ENGINE!!!
Re: UnseenGDK (Game Development Kit) For QB64
« Reply #652 on: March 03, 2015, 04:58:47 pm »
Link updated, thanks for the reminder.

Unseen