Modules List

Started by markcwm, June 13, 2017, 01:52:42

Previous topic - Next topic

col

A great list!!
But the better place for the D3D11Max2DDriverhas been
https://github.com/davecamp/srs.mod for quite some time.

Feel free to update the link and maybe delete this post to keep things tidy.
https://github.com/davecamp

"When you observe the world through social media, you lose your faith in it."

markcwm

Thanks for that col.

No I don't need to delete anyone's posts, all the link are on page 1 anyway.

Naughty Alien

..very nice but a little bit messy to scroll trough pages and check each individual link...maybe some 'toolbox' section on web site is needed ?

markcwm

I don't know how to do that and if I could I probably couldn't edit it, maybe a page on the Bmx wikibooks or Brucey could add it on his new website.

I created a Toolbox clone here http://www.syntaxbomb.com/index.php/topic,81.0.html

ms62

Just a suggestion. Sometimes in future, we need to seperate modules that work with original BlitzMax from those that work with NG version. I think strategically make sense to gradully ignore or forget the original one and concenterate effort on NG.

For NG, a good installer that adds path helps beginers. It is good that wingw is inside its folder. I totally removed the original blitzmax and have decided to exclusivly use NG. I don't know what NG stands for  ;D


RonTek

I saw the older one on the old forum/wasted.nz, great list. Thanks markcwm!

Quote from: ms62 on October 01, 2017, 23:16:48
NG. I don't know what NG stands for  ;D

Next Gen.. in English, but telling it or abbreviating it in Japanese, it could be a bit on the downside, as NG also means "No Good".  ;)


Steve Elliott

lol I always thought it was a crap name.
Win11 64Gb 12th Gen Intel i9 12900K 3.2Ghz Nvidia RTX 3070Ti 8Gb
Win11 16Gb 12th Gen Intel i5 12450H 2Ghz Nvidia RTX 2050 8Gb
Win10/Linux Mint 16Gb 4th Gen Intel i5 4570 3.2GHz, Nvidia GeForce GTX 1050 2Gb
Linux Mint 8Gb Celeron Intel UHD Graphics 600
macOS Sonoma 32Gb Apple M2 Max
Spectrum Next 2Mb

RonTek

#22
Quote from: Steve Elliott on October 02, 2017, 00:27:15
lol I always thought it was a crap name.

Same here Steve, at first.  ;D I found out reading the description a while back here and on the old forum thread.

ms62


Derron

Quote from: Steve Elliott on October 02, 2017, 00:27:15
lol I always thought it was a crap name.


So Star Trek TNG also is a crap name? How dare you!




But hey - BMX NG is open source, so you could always fork it (including using the upcoming patches after your fork) and rename it to a better suiting name. Think with todays "always on"-mentality it matters to be known to the world - or at least being "searchable". So you wont blame "Gambas" to have a "generic" name but as it got famous, the second entry for "gambas" on google(.de) is the wiki entry of the programming language.


In this case, "NG" already is a well known abbreviation which means it "supports" being remarkable without needing to remind long words. Also older people should know "BMX" from the 80s bicycles. So together "BMX NG" forms something the brain knows - but with a different meaning (like "Gambas"). But it is still something, which makes the "BMX NG" (speaking of our beloved Brucey-toolchain) sit on #1 (and #2 and ...) of the google search results.

[/size][size=78%]Main problem is of course, that only we would search the term "BMX NG" now ...making it not as much prominent as needed. Not to talk about the missing "ecology" around the language (speaking of IDE integration, automated installers, tutorials, famous "made with"-games, ...).[/size]
[/size]
[/size]
[/size][size=78%]bye[/size]
[/size][size=78%]Ron [/size]

Baggey

Is there anything for using SDL in Blitzmax NG?

Baggey
Running a PC that just Aint fast enough!? i7 4Ghz Quad core 32GB ram  2x1TB SSD and NVIDIA Quadro K1200 on Acer 24" . DID Technology stop! Or have we been assimulated!

Windows10, Parrot OS, Amiga mini, ZX Spectrum 48k, C64, ORIC Atmos 48K, Enterprise 128K, The SID chip. Im Misunderstood!

Derron

sdl.mod

it is shipped with NG


bye
Ron

Hotcakes

Quote from: markcwm on June 13, 2017, 01:56:55Public Domain part of Grey Alien Framework
The latest version is v1.13, here:
'BLITZ MAX *PUBLIC DOMAIN* COMMON CODE (Functions)
'Used in the Grey Alien Blitzmax Game Framework.
'Composition, explanations and some modifications by Jake Birkett (Grey Alien).
'Code credited to authors but is not copyright.
'V1.13 Released 18/01/11

'Note that many of these functions need Windows API calls declared as Extern.
'You'll have to add those yourself if you want to use the functions.

'by Manel Ib  ez for use with ccFastRand()
Extern "C"
    Function crndseed:Int(val:Int) = "srand"
    Function _crand:Int () = "rand"
End Extern

'By Bruce Henderson for use with ccGetSharedUserDataFolder()
?MacOS
Extern
    Const kUserDomain:Int = -32763
    Const kApplicationSupportFolderType:Int = Asc("a") Shl 24 | Asc("s") Shl 16 | Asc("u") Sh
   
    l 8 | Asc("p")
    Const kSharedUserDataFolderType:Int = Asc("s") Shl 24 | Asc("d") Shl 16 | Asc( "a") Shl 8 | Asc("t")
    Function FSFindFolder:Int( vRefNum:Int ,folderType:Int ,createFolder:Int ,foundRef:Byte Ptr )
    Function FSRefMakePath:Int( ref:Byte Ptr,path:Byte Ptr, maxPath:Int )
End Extern
?

'From Windows
?win32
Extern "win32"
    Global _bbusew:Int 'Defined in 'blitz.mod\blitz_app.c'.

    Function CloseLibrary(hLib%) = "FreeLibrary@4"
    Function GetEnvironmentVariable(lpName$z, lpBuffer:Byte Ptr, nSize%) = "GetEnvironmentVariableA@12"
    Function GetVersionExA(infoex:Byte Ptr)
    Function RegOpenKey%(hKeyParent%,SubKey$z,phkResult:Byte Ptr)="RegOpenKeyA@12"
    Function RegCloseKey%(hKey%)="RegCloseKey@4"
    Function RegQueryValueEx%(hKey%,ValueName$z,Reserved%,nType:Byte Ptr,ValueBytes:Byte Ptr,ValueSize:Byte Ptr)="RegQueryValueExA@24"
    Function SHGetFolderPathA:Int(hwndOwner:Int, nFolder:Int, hToken:Int, dwFlags:Int, pszPath:Byte Ptr)
    Function SHGetFolderPathW:Int(hwndOwner:Int, nFolder:Int, hToken:Int, dwFlags:Int, pszPath:Byte Ptr)
    Function SHGetPathFromIDListA(pidList:Int, lpBuffer:Byte Ptr)
    Function SHGetPathFromIDListW(pidList:Int, lpBuffer:Byte Ptr)
    Function SHGetSpecialFolderLocation(hwndOwner%, nFolder%, pIdl:Byte Ptr)
End Extern

'For use with SHGetFolderPath
Const SHGFP_TYPE_CURRENT:Int = 0
Const SHGFP_TYPE_DEFAULT:Int = 1
?

?Win32
Const HKEY_LOCAL_MACHINE% = -2147483646

'For use with ccGetSpecialFolder
Const CSIDL_DESKTOP% = $0
Const CSIDL_INTERNET% = $1
Const CSIDL_PROGRAMS% = $2
Const CSIDL_CONTROLS% = $3
Const CSIDL_PRINTERS% = $4
Const CSIDL_PERSONAL% = $5
Const CSIDL_FAVORITES% = $6
Const CSIDL_STARTUP% = $7
Const CSIDL_RECENT% = $8
Const CSIDL_SENDTO% = $9
Const CSIDL_BITBUCKET% = $A
Const CSIDL_STARTMENU% = $B
Const CSIDL_DESKTOPDIRECTORY% = $10
Const CSIDL_DRIVES% = $11
Const CSIDL_NETWORK% = $12
Const CSIDL_NETHOOD% = $13
Const CSIDL_FONTS% = $14
Const CSIDL_TEMPLATES% = $15
Const CSIDL_COMMON_STARTMENU% = $16
Const CSIDL_COMMON_PROGRAMS% = $17
Const CSIDL_COMMON_STARTUP% = $18
Const CSIDL_COMMON_DESKTOPDIRECTORY% = $19
Const CSIDL_APPDATA% = $1A
Const CSIDL_PRINTHOOD% = $1B
Const CSIDL_LOCAL_APPDATA% = $1C
Const CSIDL_ALTSTARTUP% = $1D
Const CSIDL_COMMON_ALTSTARTUP% = $1E
Const CSIDL_COMMON_FAVORITES% = $1F
Const CSIDL_INTERNET_CACHE% = $20
Const CSIDL_COOKIES% = $21
Const CSIDL_HISTORY% = $22
Const CSIDL_COMMON_APPDATA% = $23
?

?win32
Type TOSVersionInfoEx
    Field dwOSVersionInfoSize:Int
    Field dwVerMajor:Int
    Field dwVerMinor:Int
    Field dwBuildNumber:Int
    Field dwPlatformId:Int

    Field szCSDVersion:Int

    Field pad0:Long
    Field pad1:Long
    Field pad2:Long
    Field pad3:Long
    Field pad4:Long
    Field pad5:Long
    Field pad6:Long
    Field pad7:Long
    Field pad8:Long
    Field pad9:Long
    Field pad10:Long
    Field pad11:Long
    Field pad12:Long
    Field pad13:Long
    Field pad14:Long
    Field pad15:Int

    Field wServicePackMajor:Short
    Field wServicePackMinor:Short
    Field wSuiteMask:Short
    Field wProductType:Byte
    Field wReserved:Byte
End Type
?

?win32
'AERO SPECIFIC
'by col (Dave) from BlitzMaz forums
Global DwmapiDLL:Int = LoadLibraryA("dwmapi.dll")
Global FlushAero()
Global IsAeroEnabled(pfEnabled:Int Var)
Global EnableAero(uCompositionAction:Int)

If DwmapiDLL
    FlushAero = GetProcAddress(DwmapiDLL,"DwmFlush")
    IsAeroEnabled = GetProcAddress(DwmapiDLL,"DwmIsCompositionEnabled")
    EnableAero = GetProcAddress(DwmapiDLL,"DwmEnableComposition")
EndIf

Global AeroState%
If DwmapiDLL IsAeroEnabled(AeroState)
'END OF AERO SPECIFIC
?

?Win32
'For Borderless Window (by BlitzSupport, James Boyd)
Type MONITORINFO
    Field cbSize:Int

    Field rcMonitorLeft:Int
    Field rcMonitorTop:Int
    Field rcMonitorRight:Int
    Field rcMonitorBottom:Int

    Field rcWorkLeft:Int
    Field rcWorkTop:Int
    Field rcWorkRight:Int
    Field rcWorkBottom:Int

    Field dwFlags:Int
End Type


'Win32 constants...
Const MONITOR_DEFAULTTONEAREST:Int = 2

Const GWL_STYLE:Int                    = -16
Const GWL_EXSTYLE:Int                = -20

Const HWND_TOP:Int                    = 0
Const SWP_FRAMECHANGED:Int            = $20

Const WS_POPUP:Int                    = $80000000
Const WS_VISIBLE:Int                = $10000000
Const WS_CAPTION:Int                = $C00000
Const WS_THICKFRAME:Int                = $00040000
Const WS_MINIMIZE:Int                = $20000000
Const WS_MAXIMIZE:Int                = $01000000
Const WS_SYSMENU:Int                = $80000
Const WS_BORDER:Int = $00800000
Const WS_EX_DLGMODALFRAME:Int        = $00000001
Const WS_EX_CLIENTEDGE:Int            = $200
Const WS_EX_STATICEDGE:Int            = $20000

'Win32 function pointers...
Global FindWindow (lpClassName:Byte Ptr, lpWindowName:Byte Ptr) "win32"
Global MonitorFromWindow (hwnd:Int, dwFlags:Int)                "win32"
Global GetMonitorInfo (hMonitor:Int, lpmi:Byte Ptr)                "win32"
Global GetWindowLong (hwnd:Int, nIndex:Int)                        "win32"
'Already declared in CommonCode: (JB)
'Global SetWindowLong (hwnd:Int, nIndex:Int, dwNewLong:Int)        "win32"
'Global SetWindowPos (hWnd:Int, hWndInsertAfter:Int, X:Int, Y:Int, cx:Int, cy:Int, uFlags:Int)
?

' -----------------------------------------------------------------------------
' TEmail: Allows you to send an email!
' Based on MaxMail by Ked from the Codearchives. Turned into Type by Jake Birkett.
' -----------------------------------------------------------------------------
Type TEmailer
Rem
    Global from_mail:String = "YOUR EMAIL HERE"
    Global from_name:String = "YOUR NAME HERE"
    Global to_mail:String = "THEIR EMAIL HERE"
    Global to_name:String = "THEIR NAME HERE"
    Global email_subject:String = "From MaxMail"
    Global email_message:String = ..
    "Hello!~r~n~r~nWhat do you think of this very nice email? I~r~n" + ..
    "think it is quite swell!~r~n~r~nGoodbye!"
   
    Global email_mailhost:String = "MAIL HOST HERE"
    Global email_mailport:Int = 25
   
    Print "Connecting..."
    Global mailsocket:TSocket = CreateTCPSocket()
    If Not ConnectSocket(mailsocket, HostIp(email_mailhost), email_mailport)
        Print "Unable to connect!"
        CloseSocket mailsocket
        End
    EndIf
    Print "Socket connected!"
    Global t:TSocketStream=CreateSocketStream(mailsocket)
   
    Global msg:String = ""
       
    msg = t.ReadLine() 3
    Print msg
   
    t.WriteLine("HELO MaxMailer")
    msg = t.ReadLine()
    Print msg
   
    t.WriteLine("MAIL FROM: <" + from_mail + ">")
    msg = t.ReadLine()
    Print msg
   
    t.WriteLine("RCPT TO: <" + to_mail + ">")
    msg = t.ReadLine()
    Print msg
   
    t.WriteLine("DATA")
    msg = t.ReadLine()
    Print msg
   
    t.WriteLine("Date: " + CurrentDate:String() )
    t.WriteLine("From: " + from_name + " <" + from_mail + ">")
    t.WriteLine("To: " + to_name + " <" + to_mail + ">")
    t.WriteLine("Subject: " + email_subject)
    t.WriteLine("X-Mailer: MaxMail")
    t.WriteLine("")
   
    t.WriteLine(email_message)
   
    t.WriteLine("")
    t.WriteLine("")
    t.WriteLine(".")
    msg = t.ReadLine()
    Print msg
   
    t.WriteLine("QUIT")
    msg = t.ReadLine()
    Print msg
   
    CloseStream t
    CloseSocket mailsocket
    Print "Mailed!"
end rem
End Type

' -----------------------------------------------------------------------------
' ccAddLists: Adds one list to another
' By Plash
' -----------------------------------------------------------------------------
Function ccAddLists:Int(dest:TList, from:TList)   
    If dest = Null Or from = Null Or from.Count() = 0 Then Return False
   
    For Local obj:Object = EachIn from       
        dest.AddLast(obj)       
    Next
   
    Return True   
End Function

' -----------------------------------------------------------------------------
' ccCircleHalfWidthAtY: Return half the width of a circle of a specifed radius at a given y coord
' by David Bird (although it's really just a simple formula)
' -----------------------------------------------------------------------------
Function ccCircleHalfWidthAtY:Float( radius:Float, y:Float )
    Return Sqr(radius*radius - y*y )
End Function

' -----------------------------------------------------------------------------
' ccCircleLineIntersect2: Pass in coords for a line and circle and this will tell you if they intersect
' by Oddball (adapted from TomToad's code) modified by Grey Alien
' -----------------------------------------------------------------------------
Function ccCircleLineIntersect2%(x1:Double, y1:Double, x2:Double, y2:Double, px:Double, py:Double, r:Double)
    'I upgraded all params and local variables from Floats to Doubles (Grey Alien)
    Local sx:Double= x2-x1
    Local sy:Double= y2-y1

    Local q:Double= ((px-x1) * (x2-x1) + (py - y1) * (y2-y1)) / (sx*sx + sy*sy)   
    If q < 0.0 Then q = 0.0
    If q > 1.0 Then q = 1.0
   
    Local cx:Double=(1-q)*x1+q*x2
    Local cy:Double=(1-q)*y1 + q*y2
       
    If ccPointToPointDist(px,py,cx,cy) < r
        Return True
    Else
        Return False
    EndIf
End Function

' -----------------------------------------------------------------------------
' ccCopyImage: Creates a copy of a TImage
' by BlackSp1der
' -----------------------------------------------------------------------------
Function ccCopyImage:TImage(image:TImage)
    Local newimage:TImage=CreateImage(image.width,image.height,image.frames.Length,image.flags)
    newimage.handle_x=image.handle_x
    newimage.handle_y=image.handle_y
    newimage.mask_r=image.mask_r
    newimage.mask_g=image.mask_g
    newimage.mask_b=image.mask_b

    For Local frame:Int=0 Until image.Frames.Length
        Local pixmap:TPixmap=LockImage(image,frame)
        'pixmap copy
        newimage.SetPixmap(frame,pixmap.Copy())
        'pixmap clone
        'newimage.pixmaps[frame]=image.pixmaps[frame]
        'newimage.frames[frame]=image.frames[frame]
        'newimage.seqs[frame]=image.seqs[frame]
        UnlockImage(image,frame)
    Next

    Return newimage
EndFunction

' -----------------------------------------------------------------------------
' ccCopyImageRect: Copies part of an image onto another image
' by James Chamblin
' -----------------------------------------------------------------------------
Function ccCopyImageRect(Source:TImage,SX:Int,SY:Int,SWidth:Int,SHeight:Int,Dest:TImage,DX:Int,DY:Int)
    'get the pixmap for the images
    Local SourcePix:TPixmap = LockImage(Source)
    Local DestPix:TPixmap = LockImage(Dest)
   
    'find the dimentions
    Local SourceWidth:Int = PixmapWidth(SourcePix)
    Local SourceHeight:Int = PixmapHeight(SourcePix)
    Local DestWidth:Int = PixmapWidth(DestPix)
    Local DestHeight:Int = PixmapHeight(DestPix)
   
    If SX < SourceWidth And SY < SourceHeight And DX < DestWidth And DY < DestHeight 'make sure rects are on image
        If SX+SWidth > SourceWidth Then SWidth = SourceWidth - SX 'bound the coordinates to the image area
        If SY+SHeight > SourceHeight Then SHeight = SourceHeight - SY
        If DX+SWidth > DestWidth Then SWidth = DestWidth - DX 'Make sure coordinates will fit into the destination
        If DY+SHeight > DestHeight Then SHeight = DestHeight - DY
       
        'find the pitch
        Local SourcePitch:Int = PixmapPitch(SourcePix)
        Local DestPitch:Int = PixmapPitch(DestPix)
   
        'pointers To the first pixel of pixmaps
        Local SourcePtr:Byte Ptr = PixmapPixelPtr(SourcePix) + SY * SourcePitch + SX * 4
        Local DestPtr:Byte Ptr = PixmapPixelPtr(DestPix) + DY * DestPitch + DX * 4
       
        'copy pixels over one line at a time
        For Local i:Int = 1 To SHeight
            MemCopy(DestPtr,SourcePtr,SWidth*4)
            SourcePtr :+ SourcePitch
            DestPtr :+ DestPitch
        Next
    End If
   
    'unlock the buffers
    UnlockImage(Source)
    UnlockImage(Dest)
End Function

' -----------------------------------------------------------------------------
' ccCopyImageToImage: Copies one TImage to another with a variety of modes
' by Dave Munsie
' -----------------------------------------------------------------------------
Function ccCopyImageToImage(Source:TImage,SX:Int,SY:Int,SWidth:Int,SHeight:Int,Dest:TImage,DX:Int,DY:Int,flags:Int=0)
  '
  ' flags: 0 = Normal  1 = Mirror  2 = Flip  3 = Mirror and Flip
  '
  Local SourcePix:TPixmap = LockImage(Source)
  Local DestPix:TPixmap = LockImage(Dest)
  Local SourceWidth:Int = PixmapWidth(SourcePix)
  Local SourceHeight:Int = PixmapHeight(SourcePix)
  Local DestWidth:Int = PixmapWidth(DestPix)
  Local DestHeight:Int = PixmapHeight(DestPix)
  If SX < SourceWidth And SY < SourceHeight And DX < DestWidth And DY < DestHeight
  If SX+SWidth > SourceWidth Then SWidth = SourceWidth - SX
  If SY+SHeight > SourceHeight Then SHeight = SourceHeight - SY
  If DX+SWidth > DestWidth Then SWidth = DestWidth - DX
  If DY+SHeight > DestHeight Then SHeight = DestHeight - DY
  Select flags
   Case 0 ' Normal
    For Local py:Int = 0 To SHeight-1
     For Local px:Int = 0 To SWidth- 1
      WritePixel(DestPix,DX+px,DY+py,ReadPixel(SourcePix,SX+px,SY+py))
     Next
    Next
   Case 1 ' Mirror
    For Local py:Int = 0 To SHeight - 1
     For Local px:Int = 0 To SWidth - 1
      WritePixel(DestPix,DX+px,DY+py,ReadPixel(SourcePix,(SX+(SWidth-1))-px,SY+py))
     Next
    Next
   Case 2 ' Flip
    For Local py:Int = 0 To SHeight - 1
     For Local px:Int = 0 To SWidth - 1
      WritePixel(DestPix,DX+px,DY+py,ReadPixel(SourcePix,SX+px,(SY+(SHeight-1))-py))
     Next
    Next
   Case 3 ' Mirror and Flip
    For Local py:Int = 0 To SHeight - 1
     For Local px:Int = 0 To SWidth - 1
      WritePixel(DestPix,DX+px,DY+py,ReadPixel(SourcePix,(SX+(SWidth-1))-px,(SY+(SHeight-1))-py))
     Next
    Next
  End Select
 EndIf
 UnlockImage(Source)
 UnlockImage(Dest)
End Function

' -----------------------------------------------------------------------------
' ccCreateFrames: Caches an Image or Anim Image in VRAM
' by Ian Duff
' -----------------------------------------------------------------------------
Function ccCreateFrames(image:TImage)
    'Use this to cache an image or animimage in VRAM for quicker drawing later.
    For Local c%=0 Until image.frames.Length
        image.Frame(c)
    Next
End Function

' -----------------------------------------------------------------------------
Rem Adapted from BlitzMaxNG's FileExists, suggested by GWRon.
bbdoc: Checks if a file or directory exists
returns: #True if the file or directory at @path exists
about: Use #FileType to check if the file is a directory or a plain file.
End Rem
' -----------------------------------------------------------------------------
Function ccDirExists:Int(path:String)
    'Remove trailing backslash added by JB. Note this was copied from FixPath() which also checks if it's a root path but I don't want to mess with that.
    path = StripSlash(path)
    Return FileType(path) = FILETYPE_DIR
End Function

' -----------------------------------------------------------------------------
' ccDrawImageArea: Draws part of an image. (faster?)
' by Ian Duff fixed by Grey Alien
' -----------------------------------------------------------------------------
Function ccDrawImageArea(image:TImage, x#, y#, rx#, ry#, rw#, rh#, theframe%=0)
    'This is now just a wrapper function for BlitMax's new DrawSubImageRect() function since BMax V1.36.
    DrawSubImageRect(image, x, y, rw, rh, rx, ry, rw, rh, image.handle_x, image.handle_y, theframe)

Rem
 'Note that this code works fine in DirectX or OpenGL on PCs - it autodetects (Grey Alien).
 'Warning: make sure that none of your images have pixels right on the edge otherwise
 'when drawing clipped, they may leave smear in the clipped area! (Grey Alien).
  Local origin_x#, origin_y# ; GetOrigin (origin_x, origin_y)
  Local tw% = ccDrawImageAreaPow2Size(image.width)
  Local th% = ccDrawImageAreaPow2Size(image.height)
  Local rw1#  = rx + rw
  Local rh1#  = ry + rh
  Local x0# = -image.handle_x, x1# = x0 + rw
  Local y0# = -image.handle_y, y1# = y0 + rh
 
  If rw1 > image.width
    x1 = x0 + rw + image.width - rw1
    rw1 = image.width
  EndIf
   
  If rh1 > image.height
    y1 = y0 + rh + image.height - rh1
    rh1 = image.height
  EndIf
?Win32
  If TD3D7ImageFrame(image.frame(theframe))
    Local frame:TD3D7ImageFrame = TD3D7ImageFrame(image.frame(theframe))
   
    frame.setUV(rx / tw, ry / th, rw1 / tw, rh1 / th)
    frame.Draw x0, y0, x1, y1, x + origin_x, y + origin_y
    frame.setUV(0, 0, image.width / Float(tw), image.height / Float(th))
  Else
?
    Local frameA:TGLImageFrame = TGLImageFrame (image.frame(theframe))
    'Protect against frameA being null due to alt+tab. (Grey Alien)
    If frameA<>Null Then
        frameA.u0 = rx / tw
        frameA.v0 = ry / th
        frameA.u1 = rw1 / tw
        frameA.v1 = rh1 / th
       
        frameA.Draw x0, y0, x1, y1, x + origin_x, y + origin_y
       
        frameA.u0 = 0
        frameA.v0 = 0
        frameA.u1 = image.width / Float(tw)
        frameA.v1 = image.height / Float(th)
    EndIf
?Win32
  EndIf
?
 
  Function ccDrawImageAreaPow2Size%(n%)
    Local ry% = 1
   
    While ry < n
      ry :* 2
    Wend
   
    Return ry
  End Function
End Rem

End Function

' -----------------------------------------------------------------------------
' ccDrawImageRect: Draws part of an image. (slow? See also ccDrawImageArea())
' by TonyG
' -----------------------------------------------------------------------------
Function ccDrawImageRect(image:TImage,x:Int,y:Int,xs:Int,ys:Int,width:Int,height:Int)
    DrawImage LoadImage(PixmapWindow(LockImage(image),xs,ys,width,height)),x,y
End Function

' -----------------------------------------------------------------------------
' ccDrawOnPixmap: Allows you to draw an image on a pixmap whilst retaining alpha properties
' By MichaelB
' -----------------------------------------------------------------------------
Function ccDrawOnPixmap(image:TImage, framenr:Int = 0, Pixmap:TPixmap, x:Int, y:Int, alpha:Float = 1.0, light:Float = 1.0)
      Local TempPix:TPixmap = Null
      If image = Null Then Throw "image doesnt exist"
      If framenr = 0 Then TempPix = LockImage(image)
      If framenr > 0 Then TempPix = LockImage(image, Framenr)
      For Local i:Int = 0 To ImageWidth(image) - 1
        For Local j:Int = 0 To ImageHeight(image) - 1
          If x + i < pixmap.width And y + j < pixmap.height
            Local sourcepixel:Int = ReadPixel(TempPix, i,j)
            Local destpixel:Int = ReadPixel(pixmap, x+i,y+j)
            Local destA:Float = ARGB_Alpha(destpixel)
            Local sourceA:Float = ARGB_Alpha(sourcepixel) * alpha
            If sourceA = 255 Then destA = 0
            'remove comment to remove unneeded calculations
            'but only when light/alpha not used!
'            If sourceA <> 255 And sourceA <> 0
                Local destR:Float = ARGB_Red(destpixel)
                Local destG:Float = ARGB_Green(destpixel)
                Local destB:Float = ARGB_Blue(destpixel)
                Local SourceR:Float = ARGB_Red(Sourcepixel)
                Local SourceG:Float = ARGB_Green(Sourcepixel)
                Local SourceB:Float = ARGB_Blue(Sourcepixel)
                    Local AlphaSum:Int = destA + sourceA

                    sourceR = (sourceR * light * sourceA / AlphaSum) + destA / AlphaSum * (destR * destA / AlphaSum)
                    sourceG = (sourceG * light * sourceA / AlphaSum) + destA / AlphaSum * (destG * destA / AlphaSum)
                    sourceB = (sourceB * light * sourceA / AlphaSum) + destA / AlphaSum * (destB * destA / AlphaSum)
                    If AlphaSum > 255 Then AlphaSum = 255
                    sourcepixel = ARGB_Color(AlphaSum, SourceR, sourceG, sourceB)
'            EndIf
            If SourceA <> 0 Then WritePixel(Pixmap, x + i, y + j, sourcepixel)
          EndIf
        Next
      Next
      If framenr = 0 UnlockImage(image)
      If framenr > 0 UnlockImage(image, framenr)
End Function

Function ARGB_Alpha:Int(ARGB:Int)
 Return (argb Shr 24) & $ff
End Function

Function ARGB_Red:Int(ARGB:Int)
  Return (argb Shr 16) & $ff
End Function

Function ARGB_Green:Int(ARGB:Int)
  Return (argb Shr 8) & $ff
End Function

Function ARGB_Blue:Int(ARGB:Int)
 Return (argb & $ff)
End Function

Function ARGB_Color:Int(alpha:Int,red:Int,green:Int,blue:Int)
 Return (Int(alpha * $1000000) + Int(RED * $10000) + Int(green * $100) + Int(blue))
End Function

' -----------------------------------------------------------------------------
' ccDrawTextSpaced: DrawText with a specified space between each character
' By Marius Winkelmann
' -----------------------------------------------------------------------------
Function ccDrawTextSpaced(t$,x#,y#, space:Int=0)
    'Same as the built in BMax DrawText except you can specify the space between each char.

    Function ccDrawTextSpacedDraw(font:TImageFont, text$,x#,y#,ix#,iy#,jx#,jy#, space:Int )
        For Local i:Int=0 Until text.Length
       
            Local n:Int=font.CharToGlyph( text[i] )
            If n<0 Continue
           
            Local glyph:TImageGlyph=font.LoadGlyph(n)
            Local image:TImage=glyph._image
           
            If image
                Local frame:TImageFrame=image.Frame(0)
                If frame
                    Local tx#=glyph._x*ix+glyph._y*iy+(i*space)
                    Local ty#=glyph._x*jx+glyph._y*jy           
                    'frame.Draw 0,0,image.width,image.height,x+tx,y+ty
                    ccDrawImageArea(image, x+tx, y+ty, 0, 0, image.width, image.height, 0)
                EndIf
            EndIf
           
            x:+glyph._advance*ix
            y:+glyph._advance*jx
        Next       
    EndFunction
   
    Local gc:TMax2DGraphics = TMax2DGraphics.Current()   

    ccDrawTextSpacedDraw GetImageFont(), t,..
    x+gc.origin_x+gc.handle_x*gc.tform_ix+gc.handle_y*gc.tform_iy,..
    y+gc.origin_y+gc.handle_x*gc.tform_jx+gc.handle_y*gc.tform_jy,..
    gc.tform_ix,gc.tform_iy,gc.tform_jx,gc.tform_jy, space
End Function

' -----------------------------------------------------------------------------
' ccDrawTextSpacedRounded: DrawText with a specified space between each character.  X coord is rounded before drawing each character.
' (By Marius Winkelmann modified by Grey Alien)
' -----------------------------------------------------------------------------
Function ccDrawTextSpacedRounded(t$,x#,y#, space:Int=0)
    'Same as the built in BMax DrawText except you can specify the space between each char.
    'Rounds the X coord before drawing; good if you are using scaled down fonts.
    Function ccDrawTextSpacedRoundedLocalDraw(font:TImageFont, text$,x#,y#,ix#,iy#,jx#,jy#, space:Int )
        For Local i:Int=0 Until text.Length
       
            Local n:Int=font.CharToGlyph( text[i] )
            If n<0 Continue
           
            Local glyph:TImageGlyph=font.LoadGlyph(n)
            Local image:TImage=glyph._image
           
            If image
                Local frame:TImageFrame=image.Frame(0)
                If frame
                    Local tx#=glyph._x*ix+glyph._y*iy+(i*space)
                    Local ty#=glyph._x*jx+glyph._y*jy           
                    'frame.Draw 0,0,image.width,image.height,Floor(x+tx),y+ty
                    ccDrawImageArea(image, Floor(x+tx), y+ty, 0, 0, image.width, image.height, 0)
                EndIf
            EndIf
           
            x:+glyph._advance*ix
            y:+glyph._advance*jx
        Next       
    EndFunction
   
    Local gc:TMax2DGraphics = TMax2DGraphics.Current()   

    ccDrawTextSpacedRoundedLocalDraw GetImageFont(), t,..
    x+gc.origin_x+gc.handle_x*gc.tform_ix+gc.handle_y*gc.tform_iy,..
    y+gc.origin_y+gc.handle_x*gc.tform_jx+gc.handle_y*gc.tform_jy,..
    gc.tform_ix,gc.tform_iy,gc.tform_jx,gc.tform_jy, space
EndFunction

' -----------------------------------------------------------------------------
' ccEnableMaximize: Uses WindowsAPI call to enable maximize button on window
' Thanks go to Gilzu, Diablo and Zawran
' -----------------------------------------------------------------------------
Function ccEnableMaximize(hWnd:Long)
    'Adds the Maximize Button "[]"
    ?Win32
    Local tmp:Int = GetWindowLongA( hWnd, GWL_STYLE )
    tmp = tmp | WS_MAXIMIZEBOX
    SetWindowLongA( hWnd, GWL_STYLE, tmp )
    DrawMenuBar( hWnd )
    ?
End Function

' -----------------------------------------------------------------------------
' ccEnableMinimize: Uses WindowsAPI call to enable minimize button on window
' Thanks go to Gilzu, Diablo and Zawran
' -----------------------------------------------------------------------------
Function ccEnableMinimize(hWnd:Long)
    'Adds the Minimize Button "_"
    ?Win32
    Local tmp:Long = GetWindowLongA( hWnd, GWL_STYLE )
    tmp = tmp | WS_MINIMIZEBOX
    SetWindowLongA( hWnd, GWL_STYLE, tmp )
    DrawMenuBar( hWnd )
    ?
End Function

' -----------------------------------------------------------------------------
' ccFastRand: Faster than BlitzMax Rand()
' by Manel Ib  ez
' -----------------------------------------------------------------------------
Function ccFastRand:Int (start:Int, ende:Int)
    Return _crand() Mod (ende-start+1) + start
End Function

' -----------------------------------------------------------------------------
' ccFastRandSeed: Sets the Seed for ccFastRand()
' by Manel Ib  ez
' -----------------------------------------------------------------------------
Function ccFastRandSeed(seed:Int)
    crndseed(seed)
End Function

' -----------------------------------------------------------------------------
' ccFlushAero: Reduced mouse lag in windowed mode for DX9 and OpenGL
' by col (Dave) from BlitzMax forums
' -----------------------------------------------------------------------------
Function ccFlushAero()
    ?win32
    If AeroState = 1 Then
        If DwmapiDLL FlushAero
    EndIf
    ?
End Function

' -----------------------------------------------------------------------------
' ccFormatNumber: Pass in a floating point number and it will format it with commas to the specified number of decimal places
' by David Maziarka
' -----------------------------------------------------------------------------
Function ccFormatNumber:String(number:Double, decimal:Int=4, comma:Int=0, padleft:Int=0 )
    Assert decimal > -1 And comma > -1 And padleft > -1, "Negative numbers not allowed in Format()"

    Local str:String = number
    Local dl:Int = str.Find(".")
    If decimal = 0 Then decimal = -1
    str = str[..dl+decimal+1]
    If comma
        While dl > comma
            str = str[..dl-comma] + "," + str[dl-comma..]
            dl :- comma
        Wend
    EndIf
    If padleft
        Local paddedLength:Int = padleft+decimal+1
        If paddedLength < str.Length Then str = "Error"
        str = RSet(str,paddedLength)
    EndIf
    Return str
End Function

' -----------------------------------------------------------------------------
' ccGetDirectXVersion: Returns the DirectX version as a string
' By Grey Alien
' -----------------------------------------------------------------------------
Function ccGetDirectXVersion$()
    Local strVersion:String = ""

    ?win32
    'First check for version 9 and below.
    strVersion = ccCheckDirectXVersionUpTo9()
    'Now check for version 10 and above.
    Local DX10Plus:String = ccCheckDirectXVersion10Plus()
    If DX10Plus<>"0" Then strVersion = DX10Plus
    ?

    Return strVersion
End Function

' -----------------------------------------------------------------------------
' ccCheckDirectXVersionUpTo9: Returns a string containing the DX version if it's 9 or less
' By Qube and MichaelB. Modified by Grey Alien.
' -----------------------------------------------------------------------------
Function ccCheckDirectXVersionUpTo9$()
    Local strVersion:String = ""

    ?win32
    Local hbank:TBank = CreateBank(4)
    RegOpenKey(HKEY_LOCAL_MACHINE,"SOFTWARE\Microsoft\DirectX",BankBuf(hbank))
    Local hKey% = PeekInt(hbank,0)
   
    Local value_bank:TBank = CreateBank(100)
    Local value_bank_size:TBank = CreateBank(4)
    Local type_bank:TBank = CreateBank(4)
   
    PokeInt(type_bank,0,0)
    PokeInt(value_bank_size,0,100)
       
    RegQueryValueEx(hKey,"Version",0,BankBuf(type_bank),BankBuf(value_bank),BankBuf(value_bank_size))
   
    Local dx_version:String = ""
    For Local char%=0 To PeekInt(value_bank_size,0)-1
        If PeekByte(value_bank,char)=0 Then Exit
        dx_version = dx_version + Chr(PeekByte(value_bank,char))
    Next
   
    RegCloseKey(hKey)
   
    Select dx_version
        Case "4.02.0095"
            strVersion = "1.0"
        Case "4.03.00.1096"
            strVersion = "2.0a"
        Case "4.04.00.0068"
            strVersion = "3.0"
        Case "4.04.00.0069"
            strVersion = "3.0"
        Case "4.04.00.0070"
            strVersion = "3.0a"
        Case "4.05.00.0155"
            strVersion = "5.0"
        Case "4.05.01.1600"
            strVersion = "5.0"
        Case "4.05.01.1998"
            strVersion = "5.2"
        Case "4.06.02.0436"
            strVersion = "6.1"
        Case "4.06.03.0518"
            strVersion = "6.1a"
        Case "4.07.00.0700"
            strVersion = "7.0"
        Case "4.07.00.0716"
            strVersion = "7.0a"
        Case "4.07.01.3000"
            strVersion = "7.1"
        Case "4.08.00.0400"
            strVersion = "8.0"
        Case "4.08.01.0810"
            strVersion = "8.1"
        Case "4.08.01.0881"
            strVersion = "8.1"
        Case "4.08.01.0901"
            strVersion = "8.1a"
        Case "4.08.02.0134"
            strVersion = "8.2"
        Case "4.09.0000.0900"
            strVersion = "9.0"
        Case "4.09.00.0900"
            strVersion = "9.0"
        Case "4.09.0000.0901"
            strVersion = "9.0a"
        Case "4.09.00.0901"
            strVersion = "9.0a"
        Case "4.09.0000.0902"
            strVersion = "9.0b"
        Case "4.09.00.0902"
            strVersion = "9.0b"
        Case "4.09.00.0903"
            strVersion = "9.0c"
        Case "4.09.0000.0903"
            strVersion = "9.0c"
        Case "4.09.00.0904"
            strVersion = "9.0c"
        Case "4.09.0000.0904"
            strVersion = "9.0c"
    End Select
    ?
   
    Return strVersion
End Function

' -----------------------------------------------------------------------------
' ccCheckDirectXVersion10Plus: Returns a string containing the DX version if it's 10 or higher
' By James Boyd
' -----------------------------------------------------------------------------
Function ccCheckDirectXVersion10Plus$()
    'Modified by Grey Alien
    'Returns 0 if no working DX version of 10 or higher is found.
    Local highest:Int = 0
   
    'Library cleanup stuff...
    ?win32
   
    'Get DX versions 10 and over... until M$ changes things again...   
    For Local loop:Int = 10 To 12 ' Example! Can only guess for future versions!
   
        Local dx:Int = LoadLibraryA ("d3d" + loop + ".dll")
       
        If dx       
            Local DXSuccess:Int () = GetProcAddress (dx, "D3D" + loop + "CreateDevice")
           
            If DXSuccess
                highest = loop
            Else
                'Print "DirectX version " + loop + " library exists but contains no D3D" + loop + "CreateDevice function"
            EndIf
           
            DXSuccess = Null ' Make sure we don't accidentally call D3D*CreateDevice!
           
            If CloseLibrary Then CloseLibrary dx           
        Else
            'Print "DirectX version " + loop + " is NOT installed"   
        EndIf       
    Next   
    ?
   
    Return String(highest)
End Function

' -----------------------------------------------------------------------------
' ccGetEnvVar: Uses Windows API call to return an Environment variable
' by Ian Duff modified by Grey Alien
' -----------------------------------------------------------------------------
Function ccGetEnvVar$(envVar$)
    Local result$= ""
    ?Win32
        Local buff@[64]
       
        Local rtn% = GetEnvironmentVariable(envVar$, buff@, buff.Length)
        If rtn > buff.Length
            buff@ = buff@[..rtn]
            rtn = GetEnvironmentVariable(envVar$, buff@, buff.Length)
        EndIf
       
        Result =  String.FromBytes(buff@, rtn)
    ?
    Return Result 'Mac safe
End Function

' -----------------------------------------------------------------------------
' ccGetMacProfileUserDataFolder: Returns a special Mac folder for storing unshared user data
' By Tor Kristiansen
' -----------------------------------------------------------------------------
Function ccGetMacProfileUserDataFolder:String()
    'Note that it does not have slash on the end!
    ?MacOs
        Local buf:Byte[1024],ref:Byte[80]
       
        If FSFindFolder(kUserDomain, kApplicationSupportFolderType, False, ref) Return Null
        If FSRefMakePath( ref,buf,1024 ) Return Null
       
        Return String.FromCString( buf )
    ?
End Function

' -----------------------------------------------------------------------------
' ccGetSharedUserDataFolder: Returns a special Mac folder for storing shared user data
' By Bruce Henderson
' -----------------------------------------------------------------------------
Function ccGetSharedUserDataFolder:String()
    'Note that it does not have slash on the end!
    ?MacOS
        Local buf:Byte[1024],ref:Byte[80]
       
        If FSFindFolder( kUserDomain, kSharedUserDataFolderType, False, ref ) Return Null
        If FSRefMakePath( ref,buf,1024 ) Return Null
       
        Return String.FromCString( buf )
    ?
End Function

' -----------------------------------------------------------------------------
' ccGetSpecialFolder: Returns a special Windows folder
' By Dave Kirk
' Upgraded by Jake Birkett to support Wide Char (Unicode)
' -----------------------------------------------------------------------------
Function ccGetSpecialFolder:String(folder_id:Int)
    'Warning the Microsoft website says SHGetSpecialFolderLocation "is not supported and may be altered or unavailable in the future.
    'Instead, use SHGetFolderLocation". So use ccGetSpecialFolder2() instead as a preference.   
    ?win32
    Local  idl:TBank = CreateBank (8)
    Local pathbank:TBank
    If _bbusew Then
        pathbank = CreateBank (260 * 2) '260 = MAX_PATH
    Else
        pathbank = CreateBank (260)
    EndIf
    If SHGetSpecialFolderLocation(0, folder_id, BankBuf(idl)) = 0
        Local result:String
        If _bbusew Then
            SHGetPathFromIDListW PeekInt(idl, 0), BankBuf(pathbank)
            result = String.FromWString(Short Ptr(LockBank(pathbank))) + "\"
        Else
            SHGetPathFromIDListA PeekInt(idl, 0), BankBuf(pathbank)
            result = String.FromCString(LockBank(pathbank)) + "\"
        EndIf
        UnlockBank(pathbank)

        Return result
    EndIf
    ?
    Return ""
End Function

' -----------------------------------------------------------------------------
' ccGetSpecialFolder2: Returns a special Windows folder using a newer windows API call.
' By Rafael Navega (Kryzon)
' -----------------------------------------------------------------------------
Function ccGetSpecialFolder2:String(nFolder:Int, dwFlags:Int)
    'Note that this function uses SHGetFolderPath which the Microsoft website says is "depreciated"
    'For MyDocuments (CSIDL_PERSONAL) it's best to use the dwFlags of SHGFP_TYPE_CURRENT because the folder
    'may have been moved and SHGFP_TYPE_DEFAULT returns the original location.
?Win32
    Local tempBank:TBank
    Local success:Byte = False
   
    If _bbusew Then
        tempBank = CreateBank( MAX_PATH * 2 ) 'WCHAR
        success = SHGetFolderPathW(0, nFolder, 0, dwFlags, LockBank(tempBank)) = 0
    Else
        tempBank = CreateBank( MAX_PATH )
        success = SHGetFolderPathA(0, nFolder, 0, dwFlags, LockBank(tempBank)) = 0
    EndIf   
    UnlockBank( tempBank )
   
    If success Then
        Local result:String

        If _bbusew Then
            result = String.FromWString( Short Ptr( LockBank( tempBank ) ) )
        Else
            result = String.FromCString( LockBank( tempBank ) )
        EndIf
       
        UnlockBank( tempBank )
        Return result + "\"
    EndIf
?
    Return Null 'Check for a Null result to identify errors.
   
End Function

' -----------------------------------------------------------------------------
' ccGetVersionString: Returns the Windows version in a string
' By Dave Kirk updated by Grey Alien
' -----------------------------------------------------------------------------
Function ccGetVersionString:String()
    Const VER_PLATFORM_WIN32s% = 0
    Const VER_PLATFORM_WIN32_WINDOWS% = 1
    Const VER_PLATFORM_WIN32_NT% = 2

    Local versionName:String

    ?win32
    Local VersionInfo:TOSVersionInfoEx=New TOSVersionInfoEx
    VersionInfo.dwOSVersionInfoSize=SizeOf(VersionInfo)
   
    GetVersionExA(VersionInfo)
    Select versionInfo.dwPlatformID
        Case VER_PLATFORM_WIN32s; VersionName = "Win32s"
        Case VER_PLATFORM_WIN32_NT; VersionName = "Windows NT"
               
        Select VersionInfo.dwVerMajor
            Case 4; VersionName = "Windows NT"
            Case 5;
                Select versionInfo.dwVerMinor
                    Case 0; versionName = "Windows 2000"
                    Case 1; versionName = "Windows XP"
                    '64-bit, but returns just "Windows XP" to be compatible with TGame.Init().
                    'This is also Windows Server 2003 (and R2), and Windows Home Server.
                    Case 2; versionName = "Windows XP"
                End Select
            Case 6;
                Select VersionInfo.dwVerMinor
                    Case 0; versionName = "Windows Vista" 'Also Windows Server 2008
                    Case 1; versionName = "Windows 7" 'Also Windows Server 2008 R2
                    Case 2; versionName = "Windows 8" 'Also Windows Server 2012
                    'FOR SOME REASON THIS DOESN'T WORK (reason is below). I'm using 8.1 but it returns dwVerMinor of 2
                    Case 3; versionName = "Windows 8.1" 'Also Windows Server 2012 R2
                End Select
            'This doesn't work because GetVersionExA() returns a maximum version of Windows 8 (Major 6 Minor 2) unless
            'you use this to added a manifest to your exe: https://msdn.microsoft.com/en-us/library/windows/desktop/dn481241(v=vs.85).aspx   
            Case 10;
                Select VersionInfo.dwVerMinor
                    Case 0; versionName = "Windows 10" 'Also Windows Server Technical Preview
                End Select
        End Select
         
        Case VER_PLATFORM_WIN32_WINDOWS
            Select VersionInfo.dwVerMinor
                Case 0; VersionName = "Windows 95"
                Case 90; VersionName = "Windows ME"
                Case 10; VersionName = "Windows 98"
            End Select
    End Select
    ?
    Return VersionName
End Function

' -----------------------------------------------------------------------------
' ccMakeWindowBorderless()
' By James Boyd
' NOTE: THIS DOESN'T WORK PROPERLY!
' -----------------------------------------------------------------------------
Function ccMakeWindowBorderless()
    ?Win32
    Local user32:Int = LoadLibraryA ("user32.dll")
    If user32
        FindWindow = GetProcAddress (user32, "FindWindowA")
        MonitorFromWindow    = GetProcAddress (user32, "MonitorFromWindow")
        GetMonitorInfo        = GetProcAddress (user32, "GetMonitorInfoA")
        GetWindowLong = GetProcAddress (user32, "GetWindowLongA")
        'These are already defined in CommonCode 'JB
'        SetWindowLong        = GetProcAddress (user32, "SetWindowLongA")
'        SetWindowPos        = GetProcAddress (user32, "SetWindowPos")
       
        If Not (FindWindow And MonitorFromWindow And GetMonitorInfo And GetWindowLong And SetWindowLong And SetWindowPos)
            Print "Missing function!"
            End
        EndIf       
    EndIf
   
    ' AppTitle allocated as C-string...   
    Local cbytes:Byte Ptr = AppTitle.ToCString ()   
    ' Find app window...   
    Local appwindow:Int = FindWindow (Null, cbytes)   
    ' Free C-string memory...
    MemFree cbytes   
    ' Find which monitor the app window is on...   
    Local monitor:Int = MonitorFromWindow (appwindow, MONITOR_DEFAULTTONEAREST)   
    ' Monitor info...   
    Local mi:MONITORINFO = New MONITORINFO
    mi.cbSize = SizeOf (MONITORINFO)   
    GetMonitorInfo monitor, mi   
    ' Read window style/extended style...   
    Local style:Int = GetWindowLong (appwindow, GWL_STYLE)
    Local exstyle:Int    = GetWindowLong (appwindow, GWL_EXSTYLE)   
    ' Prepare to remove unwanted styles...   
    style = style And Not (WS_CAPTION | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE | WS_SYSMENU)
    exstyle = exstyle And Not (WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE)
    ' Remove unwanted styles...   
    SetWindowLong (appwindow, GWL_STYLE, style | WS_POPUP | WS_VISIBLE | SWP_FRAMECHANGED)
    SetWindowLong (appwindow, GWL_EXSTYLE, exstyle)
    ' Update window...   
'    SetWindowPos appwindow, HWND_TOP, mi.rcMonitorLeft, mi.rcMonitorTop, mi.rcMonitorRight - mi.rcMonitorLeft, mi.rcMonitorBottom - mi.rcMonitorTop, 0
    SetWindowPos appwindow, HWND_TOP, 0, 0, DesktopWidth(), DesktopHeight(), SWP_FRAMECHANGED 'JB

    ccPrint("Borderless Window=" + mi.rcMonitorLeft + "," + mi.rcMonitorTop + " " + (mi.rcMonitorRight - mi.rcMonitorLeft) + "x" + (mi.rcMonitorBottom - mi.rcMonitorTop))

    'Needs a fix something like this to change the D3Device attached to the window, but this is a bodge in many ways (JB).
    Local my_driver:TD3D9GraphicsDriver = D3D9GraphicsDriver()
    Local my_graphics:TD3D9Graphics = my_driver.Graphics()
    my_graphics._width = DesktopWidth()
    my_graphics._height = DesktopHeight()
    my_graphics.Attach(appwindow, 0)
    ?
End Function

' -----------------------------------------------------------------------------
' ccPointToPointDist: Returns the distance between two points
' by Oddball modified by Grey Alien.
' -----------------------------------------------------------------------------
Function ccPointToPointDist:Double(x1:Double, y1:Double, x2:Double, y2:Double)
    'Upgraded Float params and variables to doubles (Grey Alien)
    Local dx:Double= x1-x2
    Local dy:Double= y1-y2
    Return Sqr(dx*dx + dy*dy)
End Function

' -----------------------------------------------------------------------------
' ccPrintGraphicsModes: Outputs all available graphics modes in the Output window
' by xlsior
' -----------------------------------------------------------------------------
Function ccPrintGraphicsModes()
    Local x%,wid%,hei%,dep%,her%
    For x=0 To CountGraphicsModes()-1
        GetGraphicsMode(x,wid,hei,dep,her)
        Print x+" Width: "+wid+" Height: "+hei+" Depth: "+dep+" Hertz: "+her
    Next
End Function

' -----------------------------------------------------------------------------
' ccRound: Gives proper rounding of Float to Integer without bankers rounding
' By Beaker
' -----------------------------------------------------------------------------
Function ccRound%(flot#)
    Return Floor(flot+0.5)
End Function

' -----------------------------------------------------------------------------
' ccRoundDouble: Allows you to round a float to a certain number of decimal places
' By Dreamora (modified to doubles by Grey Alien)
' -----------------------------------------------------------------------------
Function ccRoundDouble:Float(number:Double, decimals:Int)
    Local t:Int = 10^decimals
    Local result:Double = Int(number * t + 0.5 * Sgn(number))
    Return result / t
End Function

' -----------------------------------------------------------------------------
' ccRoundFloat: Allows you to round a float to a certain number of decimal places
' By Dreamora
' -----------------------------------------------------------------------------
Function ccRoundFloat:Float(number:Float, decimals:Int)
    Local t:Int = 10^decimals
    Local result:Float = Int(number * t + 0.5 * Sgn(number))
    Return result / t
End Function

' -----------------------------------------------------------------------------
' ccUltraDrawPixmapOnPixmap: Draws source pixmap onto destination pixmap
' By AdamRedwoods
' Modified by Grey Alien to handle alpha on alpha
' -----------------------------------------------------------------------------
Function ccUltraDrawPixmapOnPixmap(spix:TPixmap, pixmap:TPixmap, x:Int, y:Int) NoDebug
    '' if your pixmaps are rgba8888 then it will work faster
    '' ARGB is byte order
    '' non-multiplied alpha
    'Note by JB: I'm not sure the opacity is being handled correctly so I removed it.
    Local sourcepixel:Int Ptr, osp:Int Ptr
    Local destpixel:Int Ptr, dsp:Int Ptr
    Local sAlpha:Int
   
    If (Not spix Or Not pixmap) Then Return
    If spix.format<>PF_RGBA8888 spix = ConvertPixmap(spix, PF_RGBA8888 )
    If pixmap.format<>PF_RGBA8888 pixmap = ConvertPixmap(pixmap, PF_RGBA8888 )

    Local sWidth:Int=spix.width
    Local sHeight:Int=spix.height
    Local dWidth:Int=pixmap.width
    Local dHeight:Int=pixmap.height
    sourcepixel=Int Ptr(PixmapPixelPtr(spix,0,0))
    destpixel=Int Ptr(PixmapPixelPtr(pixmap,0,0))
    Local sRowInts:Int= spix.pitch Shr 2 '' 4 bytes to int
    Local dRowInts:Int= pixmap.pitch Shr 2

    ''crop the image
    If ((x + sWidth) >= dWidth) Then sWidth = dWidth - x '-2 'if you get wraparound issues
    If ((y + sHeight) >= dHeight) Then sHeight = dHeight - y
   
    If(y<0)
        y = Abs(y)
        sourcepixel :+(y*sRowInts)
        sHeight :-y
        y=0
    EndIf
   
    If(x<0)
        sourcepixel :+(-x)
        sWidth :+x
        x=0
    EndIf
   
    destpixel = destpixel + x +(y*dRowInts)
    dsp = destpixel
    osp = sourcepixel

    'Note that original code didn't have -1 after sHeight and SWidth (maybe because it was checking for odd length and aborting anyway?
    'but it was bugged in the way I used it and sometimes showed stray pixels)
    For Local j:Int = 0 To (sHeight - 1)
        For Local i:Int = 0 To (sWidth - 1)' Step 2 'dRowInts
            Local sPixel:Int = sourcepixel[i]
            sAlpha = (sPixel Shr 24) & $000000ff' & opacity
            If sAlpha = 0 Then 'transparent
                'leave destination alone
            ElseIf sAlpha = 255 'solid
                'copy source directly to dest
                destpixel[i] = sPixel
            Else
                Local dPixel:Int = destpixel[i]
                Local dAlpha:Int = dPixel Shr 24 & $000000ff
               
                If dAlpha = 0 Then
                    'destination is transparent so just copy the pixel across.
                    destpixel[i] = sPixel
                Else
                    Local inverseAlpha:Int = 256 - sAlpha 'If I use 255 then even if dest alpha is 255, answer ends up as 254 due to truncation I guess. So I used 256 which results a solid 255 result.
                    Local finalAlpha:Int = sAlpha + ((inverseAlpha * dAlpha) Shr 8)

                    'New JB code
                    Local sr:Int = (sPixel Shr 16) & $FF
                    Local sg:Int = (sPixel Shr 8) & $FF
                    Local sb:Int = sPixel & $FF
                    Local dr:Int = (dPixel Shr 16) & $FF
                    Local dg:Int = (dPixel Shr 8) & $FF
                    Local db:Int = dPixel & $FF

                    'composite
                    Local cr:Int = ((inverseAlpha * dr) + (sAlpha * sr)) Shr 8
                    Local cg:Int = ((inverseAlpha * dg) + (sAlpha * sg)) Shr 8
                    Local cb:Int = ((inverseAlpha * db) + (sAlpha * sb)) Shr 8
                   
                    destpixel[i] = (finalAlpha Shl 24) | (cr Shl 16) | (cg Shl 8) | cb

                    'combine all channels back into a pixel

Rem                   
                    ''''straight alpha (unmultiplied)
'                    Local dAlpha:Int = dPixel Shr 24 & $000000ff ''untested: alpha onto alpha                   
'                    Local fa:Int = sAlpha + ((256 - sAlpha) * dAlpha) Shr 8 ''untested: alpha onto alpha
                    Local srb:Int = sPixel & $00ff00ff
                    Local sg:Int = sPixel & $0000ff00
                    Local drb:Int = dPixel & $00ff00ff
                    Local dg:Int = dPixel & $0000ff00
                   
'                    Local orb:Int = (drb + (((srb - drb) * sAlpha + $00800080) Shr 8)) & $00ff00ff
'                    Local og:Int = (dg + (((sg - dg) * sAlpha + $00008000) Shr 8)) & $0000ff00
                    Local orb:Int = (drb + (((srb - drb) * fa + $00800080) Shr 8)) & $00ff00ff
                    Local og:Int = (dg + (((sg - dg) * fa + $00008000) Shr 8)) & $0000ff00

'                    destpixel[i] = orb | og | $ff000000 ''no need for alpha blending if its on static bg
end rem
                EndIf
            EndIf
Rem                   
            ''lets do it again
            If (i >= dWidth And (sWidth & 1))
                ''odd length, dont draw
            Else
                sPixel = sourcepixel[i+1]
                sAlpha = (sPixel Shr 24) & $000000ff & opacity
       
                dPixel:Int = destpixel[i + 1]
                srb:Int = sPixel & $00ff00ff
                sg:Int = sPixel & $0000ff00
                drb:Int = dPixel & $00ff00ff
                dg:Int = dPixel & $0000ff00
               
                orb:Int = (drb + (((srb - drb) * sAlpha + $00800080) Shr 8)) & $00ff00ff
                og:Int = (dg + (((sg - dg ) * sAlpha + $00008000) Shr 8)) & $0000ff00

                destpixel[i + 1] = orb | og | $ff000000
            EndIf
end rem
        Next
        sourcepixel = osp + sRowInts * j ''need these to truncate off any extra bytes
        destpixel = dsp + dRowInts*j         
    Next
End Function

' -----------------------------------------------------------------------------
' ccVWait: Uses DirectX to wait for a vertical blank
' by Skidracer updated by GreyAlien
' -----------------------------------------------------------------------------
Function ccVWait()
    'Only works in DirectX graphics mode.
    'This shouldn't really be needed any more as Flip 1 now always waits for VSync
    'in Full Screen and Windowed mode.
    ?Win32
    If TD3D7Max2DDriver(_max2dDriver)
'        PrimaryDevice.ddraw.WaitForVerticalBlank DDWAITVB_BLOCKBEGIN,0 'no longer works since new DX7 module
        D3D7GraphicsDriver().DirectDraw7().WaitForVerticalBlank DDWAITVB_BLOCKBEGIN,0   
    EndIf
    ?
End Function

'////////////////////////////
'Version History
'////////////////////////////

'1.10
'- 20/01/09 Public Domain code moved to here from CommonCode.bmx
'- 20/01/09 ccRoundFloat() fixed to work for negative numbers.

'* Everything above was added/changed by JB.
'* Everything below should have the initials of the programmer making the addition/change.

'1.11
'- 12/12/09 Fixed ccDrawTextSpaced() for BMax 1.36.  Thanks redspark.
'- 12/12/09 Fixed ccDrawTextSpacedRounded() for BMax 1.36.  Thanks redspark.
'- 12/12/09 Turned ccDrawImageArea() into a wrapper function for DrawSubImageRect() for BMax 1.36.  Thanks redspark.
'- 12/12/09 Updated ccGetVersionString() to take into account Windows 7 and XP 64-bit (64-bit untested).  Thanks therevills.

'1.12
'- 20/04/10 Fixed ccDrawImageArea() to correcly use an image's existing handle.
'- 20/09/10 Moved some Mac constants here.
'- 27/09/10 Moved some Windows constant, externs and Types here.

'1.13
'- 01/18/11 Added ccGetMacProfileUserDataFolder().  Thanks Tor.
'- 26/03/11 Added TEmailer.
'- 08/10/12 Added ccFlushAero and related declarations.
'- 08/10/12 Updated ccGetDirectXVersion() to add in some missing versions and to possibly fix some early versions that were missing some zeros.
'- 09/10/12 Added ccCheckDirectXVersion10Plus()
'- 09/10/12 Added ccCheckDirectXVersionUpTo9() and moved code from GetDirectXVersion() into it.  Also GetDirectXVersion() calls
'  ccCheckDirectXVersion10Plus().
'- 09/10/12 ccGetVersionString() now supports Windows 8
'- 02/04/15 Upgraded ccGetSpecialFolder to support Wide Char (Unicode)
'- 02/04/15 Added ccGetSpecialFolder2()
'- 27/07/15 Updated ccGetVersionString() to support Windows 8.1 and Windows 10 (untested)
'- 29/07/15 Added ccMakeWindowBorderless() (windows only) but it's bugged.
'- 13/03/17 Added ccUltraDrawPixmapOnPixmap()
'- 13/03/17 Added ccRoundDouble()
'- 23/02/24 Added ccDirExists()