Lesson 13: Working With Images

Lesson 5 introduced you to the BASIC graphics commands that programmers have had available since the 1980s. While these commands are perfect for creating primitive shapes and colors you are not going to create anything close to photo realistic images with them. QB64 offers a powerful command set for working with and manipulating images.

The _NEWIMAGE Statement

The _NEWIMAGE statement creates an image surface in memory and returns a long integer numeric value as a handle pointing to the image. _NEWIMAGE  requires three parameters:

handle& = _NEWIMAGE(width&, height&, mode%)

width& is the width in pixels of the new image surface.
height& is the height in pixels of the new image surface.
mode% is the type of surface image to create and can be the following:

This course will focus on 32bit color image surfaces only. The other modes are still useful however especially when converting legacy software to operate on today's graphics hardware.

In all of the examples in previous lessons _NEWIMAGE has been used along with the SCREEN statement to create a new graphics window. The SCREEN statement is being instructed to use the image in memory as the default window that _NEWIMAGE created. This image becomes the destination for any screen related statements used.

However, it's possible to use any image created by _NEWIMAGE as the default output screen. The following example illustrates how four images can created and used as the output screen at any time.

( This code can be found at .\tutorial\Lesson13\MultipleScreens.bas )

'*
'* Multiple screens demo
'*

DIM Image&(4) ' 4 image surfaces
DIM Count% '    image counter

'* prepare image surfaces

FOR Count% = 1 TO 4 '                                  cycle 4 times
    Image&(Count%) = _NEWIMAGE(640, 480, 32) '         create a new surface image
   _DEST Image&(Count%) '                              make the surface the destination
   CLS '                                               clear the surface
   LOCATE 2, 2 '                                       position text cursor
   PRINT "This is image number"; Count% '              print the surface number
   CIRCLE (Count% * 100, 300), 50 '                    draw a circle on the surface
NEXT Count%
Count% = 1 '                                           reset image counter

'* display each surface

DO '                                                   main program loop
   SCREEN Image&(Count%) '                             use image as current screen
   LOCATE 4, 2 '                                       position text cursor
   PRINT "Press ENTER to switch to the next screen." ' print directions
   PRINT " Press ESC to exit."
   SLEEP '                                             wait for key stroke
    Count% = Count% + 1 '                              increment image counter
   IF Count% = 5 THEN Count% = 1 '                     keep count within limits
LOOP UNTIL _KEYDOWN(27) '                              leave when escape key pressed
SYSTEM '                                               return to operating system

Line 5 in the example creates an array of long integers to hold the handle value for four surface images. Lines 10 through 17 of the example creates the four surface images in memory and then adds some identifying text and graphics to each image. Line 22 through 30 of the example cycles through the four surface images and makes each one the default output window using the SCREEN statement.

Think on an image surface created in memory with _NEWIMAGE as just another screen surface you can manipulate with graphics and text statements but happens to be hidden from view. It does not matter if the image surface is currently the default screen or not as seen in lines 10 through 17. By making an image surface the destination (more on destination later) it becomes the default image surface for text and graphics statements to work with. This for instance allows you to update images in the background while the user is viewing a completely different image in the default window. Image related statements in QB64 are very powerful.

The _LOADIMAGE Statement

The _LOADIMAGE statement loads an image surface into memory from a specified image file and returns a long integer numeric value as a handle pointing to the image. _LOADIMAGE is capable of loading PNG, BMP, JPG (JPEG), PSD, PIC, PNM, TGA, and GIF graphic file formats.

handle& = _LOADIMAGE(Filename$, mode%)

Filename$ is the name of the image file you want to load and mode is 32 for 32bit color images. There is another mode, 33 for hardware images, that we'll discuss in another lesson.

Type in the following example program that loads an image from a file and then uses that image as the default window screen.

( This code can be found at .\tutorial\Lesson13\LoadimageDemo.bas )

DIM Sky& ' sky.png image handle

Sky& = _LOADIMAGE(".\tutorial\Lesson13\sky.png", 32)

'* currently in screen 0 (text only)

PRINT
PRINT
"The sky.png file was loaded into memory."
PRINT "Press the enter key to use it as the default screen."
SLEEP

'* switch to graphics screen using loaded image

SCREEN Sky&
PRINT
PRINT
"This is the sky.png image loaded by _LOADIMAGE."

Figure 1: The sky image loaded by _LOADIMAGE

The only limit on the number, size, and dimensions of the images you load in is the amount of RAM a computer has.

PNG, and JPG (JPEG), both very popular image file types, support 32 bit color and excellent compression for smaller file sizes. They both also support transparency, or a color that can be designated as invisible to allow other graphics to show through (more on transparency later). However, QB64 only supports transparency with PNG files and not JPG. Because of JPG's compression algorithm many JPGs are "blocky" in appearance which can lead to poor image quality. PNG files on the other hand offer a compression algorithm almost as good as JPG without losing image quality, known as lossless compression.

My first and usually only choice in graphics files is PNG because of their small file size, transparency capabilities and high image quality. Many paint and photo programs out today support loading, converting and saving a myriad of image file types. As a game programmer you will need to have a paint program that you are very familiar with that supports a transparency, or alpha channel, layer.

The _WIDTH and _HEIGHT Statements

Many times you will need to know the dimensions of the images you load into memory. The _WIDTH statement returns the width in pixels of an image and the _HEIGHT statement returns the height in pixels of an image. The following code uses these two statements to create a SCREEN that matches the width and height of a loaded image.

( This code can be found at .\tutorial\Lesson13\WidthHeightDemo.bas )

DIM Sky& '       handle to hold sky image
DIM SkyWidth% '  width of sky image
DIM SkyHeight% ' height of sky image

Sky& = _LOADIMAGE(".\tutorial\Lesson13\sky.png", 32) '    load image into RAM
SkyWidth% = _WIDTH(Sky&) '                                get image width
SkyHeight% = _HEIGHT(Sky&) '                              get image height
SCREEN _NEWIMAGE(SkyWidth%, SkyHeight%, 32) '             create graphics screen
PRINT '                                                   inform user of results
PRINT " This screen matches the dimensions of sky.png."
PRINT
PRINT
" Width  ="; SkyWidth%
PRINT " Height ="; SkyHeight%
SLEEP '                                                   wait for keystroke

It's important to note that _WIDTH and _HEIGHT return the total number of pixels horizontally and vertically respectively. The actual x,y pixel value ranges in an image will be from 0 to _WIDTH - 1 and 0 to _HEIGHT - 1. For example, a 640x480 image will have horizontal pixels ranging from 0 to 639 and vertical pixels ranging from 0 to 479.

The _PUTIMAGE Statement

Now that you know how to create new images and load images from a file it's time to learn how to place them on the screen. It's all good that images can be used as the main window but the real power of images is being able to manipulate them. The _PUTIMAGE statement is going to be your main vehicle for placing and moving images around on the screen. It's an extremely powerful and versatile command and arguably one of the most difficult to comprehend at first.

The most basic use of _PUTIMAGE is to place an image loaded in memory onto the default destination image which is most commonly the main image window.

_PUTIMAGE (x%, y%), ImageHandle&

x% and y% are the coordinates on the destination image, or screen, you wish to place the image. The following example loads an image into memory and places it on the main window surface.

( This code can be found at .\tutorial\Lesson13\PutimageDemo1.bas )

'**      Putimage Demo 1
'**
'** _PUTIMAGE (x%, y%), Image&

DIM Bee& '     the image file
DIM cx%, cy% ' center x,y coordinate for image

Bee& = _LOADIMAGE(".\tutorial\Lesson13\tbee0.png", 32) ' load image file into memory
SCREEN _NEWIMAGE(640, 480, 32) '                         enter a graphics screen
CLS , _RGB32(127, 127, 127) '                            clear the screen with gray
LOCATE 2, 15 '                                           position text cursor
PRINT "An image loaded into memory and placed on the screen."
cx% = (640 - _WIDTH(Bee&)) \ 2 '                         calculate x center position
cy% = (480 - _HEIGHT(Bee&)) \ 2 '                        calculate y center position
_PUTIMAGE (cx%, cy%), Bee& '                             place image onto center of screen
SLEEP '                                                  wait for key stroke
_FREEIMAGE Bee& '                                        remove image from memory
SYSTEM '                                                 return to OS

Figure 2: An image file placed on the screen

Lines 8 through 12 in the example code loads the image and prepares the window surface. Lines 13 and 14 use the _WIDTH and _HEIGHT statements to help calculate the center x,y coordinate for the image loaded in memory. Images, just like the screen, have coordinate 0,0 in the upper left hand corner. If the code would have placed the image at the exact center of the screen 319, 239 the image would not be centered. The upper left hand corner of the image would be there instead. The code needs to shift the image half of its width to the left and half of its height up to truly center the image.

cx% = (640 - _WIDTH(Bee&)) \ 2 '                         calculate x center position

This is a very common method for centering an image onto another image. You simply take the width of the main image, in this case the screen width of 640 and subtract the width of the image being placed onto it which is _WIDTH(Bee&). Integer dividing by 2 gives the left offset needed to center the image horizontally.  Likewise:

cy% = (480 - _HEIGHT(Bee&)) \ 2 '                        calculate y center position

is achieving the same thing with the vertical center point by using the height of the screen and image instead. Once the code has determined the x,y coordinate to place the image then _PUTIMAGE is used.

_PUTIMAGE (cx%, cy%), Bee& '                             place image onto center of screen

Again, this is the most basic form of _PUTIMAGE available and will be used most of the time when moving objects around on the screen.

The _DEST and _SOURCE Statements

Before exploring more of the options available with _PUTIMAGE we need to understand source and destination images first. A destination image is the image that graphics related commands will direct their output to. Think of this as the active image. A source image is the image that is being used in some way to affect the destination image. In the example code given with _PUTIMAGE above this line of code:

_PUTIMAGE (cx%, cy%), Bee& '                             place image onto center of screen

designates the Bee& image as the source and is going to be used to change the SCREEN which is the default destination image. Since no destination was explicitly set in the example code the screen becomes the default destination. A SCREEN statement that creates a window by using _NEWIMAGE will always be the image destination value of 0. The _PUTIMAGE statement also supports supplying the destination image like so:

_PUTIMAGE (cx%, cy%), Bee&, 0 '                          place bee image onto image 0 (the screen)

The above line of code would achieve the exact same effect. The next example code will help to illustrate this better.

( This code can be found at .\tutorial\Lesson13\PutimageDemo2.bas )

'**      Putimage Demo 2
'**
'** _PUTIMAGE (x%, y%), ImageSource&, ImageDestination&

DIM Bee& '     the image file
DIM Square& '  a square image
DIM cx%, cy% ' center x,y coordinates

Bee& = _LOADIMAGE(".\tutorial\Lesson13\tbee0.png", 32) ' load bee image file into memory
Square& = _NEWIMAGE(320, 320, 32) '                      create image smaller than screen in memory
_DEST Square& '                                          square image is now destination
CLS , _RGB32(255, 0, 255) '                              clear square with bright magenta (yuck)
SCREEN _NEWIMAGE(640, 480, 32) '                         enter a graphics screen (becomes new destination)
CLS , _RGB32(127, 127, 127) '                            clear the screen with gray
LOCATE 2, 12 '                                           position text cursor
PRINT "A square image that had a bee image placed onto it first."
cx% = (320 - _WIDTH(Bee&)) \ 2 '                         calculate x center position on square
cy% = (320 - _HEIGHT(Bee&)) \ 2 '                        calculate y center position on square
_PUTIMAGE (cx%, cy%), Bee&, Square& '                    place bee image onto center of square image
cx% = (640 - _WIDTH(Square&)) \ 2 '                      calculate x center position on screen
cy% = (480 - _WIDTH(Square&)) \ 2 '                      calculate y center position on screen
_PUTIMAGE (cx%, cy%), Square& '                          place square image centered on screen
SLEEP '                                                  wait for key stroke
_FREEIMAGE Bee& '                                        remove bee image from memory
_FREEIMAGE Square& '                                     remove square image from memory
SYSTEM '                                                 return to OS

Figure 3: An image on an image on an image

The _DEST statement in line 11 is used to designate the square image created in line 10 as the destination image. Any graphics related command from this point on with see the Square& image as the image to manipulate. The CLS statement in line 12 will therefore clear the Square& image with a bright magenta color.

Line 13 creates a new window surface using _NEWIMAGE. This newly created window surface now becomes the destination image. Line 19 of the example code:

_PUTIMAGE (cx%, cy%), Bee&, Square& '                    place bee image onto center of square image

is bypassing the surface image entirely by assigning Bee& as the source image and Square& as the destination image. The Bee& image will get placed onto the Square& image in the background. In line 22:

_PUTIMAGE (cx%, cy%), Square& '                          place square image centered on screen

the source image, Square&, is placed onto the window surface since no destination was designated. Line 13 designated the window surface as the new default destination so the Square& image gets placed there.

The _SOURCE statement is used to designate an image as the source image. The following example demonstrates how _SOURCE and _DEST can be used to identify images before the _PUTIMAGE statement is called.

( This code can be found at .\tutorial\Lesson13\SourceDestDemo.bas )

'**      _SOURCE and _DEST Demo
'**
'** _PUTIMAGE (x%, y%)

DIM Bee& '     the image file
DIM Square& '  a square image
DIM cx%, cy% ' center x,y coordinates

Bee& = _LOADIMAGE(".\tutorial\Lesson13\tbee0.png", 32) ' load bee image file into memory
Square& = _NEWIMAGE(320, 320, 32) '                      create image smaller than screen in memory
_DEST Square& '                                          square image is now destination
CLS , _RGB32(255, 0, 255) '                              clear square with bright magenta (yuck)
SCREEN _NEWIMAGE(640, 480, 32) '                         enter a graphics screen (becomes new destination)
CLS , _RGB32(127, 127, 127) '                            clear the screen with gray
LOCATE 2, 12 '                                           position text cursor
PRINT "A square image that had a bee image placed onto it first."
cx% = (320 - _WIDTH(Bee&)) \ 2 '                         calculate x center position on square
cy% = (320 - _HEIGHT(Bee&)) \ 2 '                        calculate y center position on square
_SOURCE Bee& '                                           bee image is now source
_DEST Square& '                                          square image in now destination
_PUTIMAGE (cx%, cy%) '                                   place bee image onto center of square image
cx% = (640 - _WIDTH(Square&)) \ 2 '                      calculate x center position on screen
cy% = (480 - _WIDTH(Square&)) \ 2 '                      calculate y center position on screen
_SOURCE Square& '                                        square image is now source
_DEST 0 '                                                window surface is now destination
_PUTIMAGE (cx%, cy%) '                                   place square image centered on screen
SLEEP '                                                  wait for key stroke
_FREEIMAGE Bee& '                                        remove bee image from memory
_FREEIMAGE Square& '                                     remove square image from memory
SYSTEM '                                                 return to OS

The exact same output as seen in Figure 3 above is achieved however this time in lines 21 and 26 of the code _PUTIMAGE was not supplied with a source or destination image to work with.

By predetermining the source image using _SOURCE and the destination image using _DEST, as in done in lines 19 and 20 and again in lines 24 and 25, _PUTIMAGE will use these designations as the default images.

Personally I try to avoid _PUTIMAGE statements without at least a source image identified. This line by itself:

_PUTIMAGE (cx%, cy%)

does not tell me much about what is going on. I am forced to go back through the code to identify the source and destination images myself. However, there will be times when identifying both beforehand may be needed by the code being created.

_SOURCE and _DEST can also be used to identify the current source and destination images.

CurrentSource& = _SOURCE '    return the current source image handle
CurrentDestination& = _DEST ' return the current destination handle

This is handy for subroutines and functions that make changes to different graphic images. At the beginning of a subroutine or function the source and destination images can be saved and then restored before leaving the subroutine or function.

SUB MySubroutine ()
   DIM OriginalSource&, OriginalDest& '  save current source and dest here
    OriginalSource& = _SOURCE '          save the current source image handle
    OriginalDest& = _DEST '              save the current dest image handle
    '...
    '...  code here
    '...
   _SOURCE OriginalSource& '             restore the source image
   _DEST OriginalDest& '                 restore the destination image
END SUB

Resizing an Image With _PUTIMAGE

The _PUTIMAGE statement can accept two coordinate pairs to define an area to place a source image onto a destination image.

_PUTIMAGE (dx1%, dy1%) - (dx2%, dy2%), SourceHandle&, DestHandle&

The (dx1%, dy1%) coordinate pair defines the upper left coordinate of the source image and the (dx2%, dy2%) coordinate pair defines the lower right hand corner. Type in the following example code to see resizing in action.

( This code can be found at .\tutorial\Lesson13\PutimageDemo3.bas )

'**      Putimage Demo 3 - Resizing
'**
'** _PUTIMAGE (dx1%, dy1%) - (dx2%, dy2%), Source&, Dest&

DIM Bee& '                   the image file
DIM dx1%, dy1%, dx2%, dy2% ' x,y coordinates of display box

Bee& = _LOADIMAGE(".\tutorial\Lesson13\tbee0.png", 32) ' load bee image file into memory
SCREEN _NEWIMAGE(640, 480, 32) '                         enter a graphics screen (becomes new destination)
dx1% = (640 - _WIDTH(Bee&)) \ 2 '                        calculate upper left x position
dy1% = (480 - _WIDTH(Bee&)) \ 2 '                        calculate upper left y position
dx2% = dx1% + _WIDTH(Bee&) '                             calculate lower right x position
dy2% = dy1% + _HEIGHT(Bee&) '                            calculate lower right y position
DO '                                                     main loop
   _LIMIT 240 '                                          limit speed to 240 frames per second
   CLS , _RGB32(127, 127, 127) '                         clear the screen with gray
   LOCATE 2, 23 '                                        position text cursor
   PRINT "Resizing an image using _PUTIMAGE." '          display instructions
   LOCATE 3, 14
   PRINT "Use UP/DOWN arrow keys to resize image, ESC to exit."
   _PUTIMAGE (dx1%, dy1%)-(dx2%, dy2%), Bee& '           put image on screen
   IF _KEYDOWN(18432) THEN '                             up arrow key pressed?
        dx1% = dx1% - 1 '                                yes, increase size of display box
        dy1% = dy1% - 1
        dx2% = dx2% + 1
        dy2% = dy2% + 1
   ELSEIF _KEYDOWN(20480) THEN '                         down arrow pressed?
        dx1% = dx1% + 1 '                                yes, decrease size of display box
        dy1% = dy1% + 1
        dx2% = dx2% - 1
        dy2% = dy2% - 1
   END IF
   _DISPLAY '                                            update screen with changes
LOOP UNTIL _KEYDOWN(27)
_FREEIMAGE Bee& '                                        remove bee image from memory
SYSTEM '                                                 return to OS

Figure 4: That's a big bee!

Lines 10 through 13 define a box the same size as the Bee& image. Lines 22 through 32 then increase or decrease the box coordinates depending on if the up or down arrow key is pressed. Line 21:

_PUTIMAGE (dx1%, dy1%)-(dx2%, dy2%), Bee& '           put image on screen

then stretches or squeezes the Bee& image to fix the box contained within the coordinates. In this example the aspect ratio of the image remains intact because the coordinate pairs are resized together. However, if you want, you can resize each dimension independently as the next example illustrates.

( This code can be found at .\tutorial\Lesson13\PutimageDemo4.bas )

'**  Putimage Demo 4 - Resizing independent dimensions
'**
'** _PUTIMAGE (dx1%, dy1%) - (dx2%, dy2%), Source&, Dest&

DIM Bee& '                   the image file
DIM dx1%, dy1%, dx2%, dy2% ' x,y coordinates of display box

Bee& = _LOADIMAGE(".\tutorial\Lesson13\tbee0.png", 32) ' load bee image file into memory
SCREEN _NEWIMAGE(640, 480, 32) '                         enter a graphics screen (becomes new destination)
dx1% = (640 - _WIDTH(Bee&)) \ 2 '                        calculate upper left x position
dy1% = (480 - _WIDTH(Bee&)) \ 2 '                        calculate upper left y position
dx2% = dx1% + _WIDTH(Bee&) '                             calculate lower right x position
dy2% = dy1% + _HEIGHT(Bee&) '                            calculate lower right y position
DO '                                                     main loop
   _LIMIT 240 '                                          limit speed to 240 frames per second
   CLS , _RGB32(127, 127, 127) '                         clear the screen with gray
   LOCATE 2, 23 '                                        position text cursor
   PRINT "Resizing an image using _PUTIMAGE." '          display instructions
   LOCATE 3, 18
   PRINT "Use ARROW keys to resize image, ESC to exit."
   _PUTIMAGE (dx1%, dy1%)-(dx2%, dy2%), Bee& '           put image on screen
   IF _KEYDOWN(18432) THEN '                             up arrow key pressed?
        dy1% = dy1% - 1 '                                yes, increase height
        dy2% = dy2% + 1
   ELSEIF _KEYDOWN(20480) THEN '                         down arrow pressed?
        dy1% = dy1% + 1 '                                yes, decrease height
        dy2% = dy2% - 1
   END IF
   IF _KEYDOWN(19200) THEN '                             left arrow pressed?
        dx1% = dx1% - 1 '                                yes, increase width
        dx2% = dx2% + 1
   ELSEIF _KEYDOWN(19712) THEN '                         right arrow pressed?
        dx1% = dx1% + 1 '                                yes, decrease width
        dx2% = dx2% - 1
   END IF
   _DISPLAY '                                            update screen with changes
LOOP UNTIL _KEYDOWN(27)
_FREEIMAGE Bee& '                                        remove bee image from memory
SYSTEM '                                                 return to OS

Figure 5: Who stepped on the bee?

Flipping an Image With _PUTIMAGE

Playing around with the previous two examples you probably noticed something ... the bee image would flip horizontally and vertically when resizing the image. This is because if the values of either x,y pair crossed each other's path the box will essentially flip. That is, vertically the top left becomes the bottom left and the bottom right becomes the top right. Horizontally the top left becomes the top right and the bottom right becomes the bottom left.

The following code flips the bee image vertically as the bee travels up and down the screen.

( This code can be found at .\tutorial\Lesson13\PutimageDemo5.bas )

'** Putimage Demo 5 - flipping the bee

DIM Sky& '      handle to hold sky image
DIM Bee&(1) '   handle array to hold 2 bee images (0 and 1)
DIM BeeDir% '   direction of bee
DIM BeeX% '     x center location of bee
DIM BeeY% '     y center location of bee
DIM BeeSize! '  size of bee 0 to 2 (0% to 200%)
DIM SizeDir! '  direction size is going in (increasing or decreasing)
DIM WhichBee% ' indicates which bee image to show (array index)
DIM Buzz& '     buzzing sound

Sky& = _LOADIMAGE(".\tutorial\Lesson13\sky.png", 32) '      load sky image into memory
Bee&(0) = _LOADIMAGE(".\tutorial\Lesson13\tbee0.png", 32) ' load first bee image into memory
Bee&(1) = _LOADIMAGE(".\tutorial\Lesson13\tbee1.png", 32) ' load second bee image into memory
Buzz& = _SNDOPEN(".\tutorial\Lesson13\bee.ogg") '           load buzzing sound into memory
BeeX% = 319 '                                               set initial x coordinate of bee
BeeY% = 171 '                                               set initial y coordinate of bee
BeeDir% = -1 '                                              set initial direction of bee (up)
WhichBee% = 1 '                                             set initial bee image to show
BeeSize! = 1 '                                              set initial size of bee (100%)
SizeDir! = .01 '                                            set initial size direction (getting larger)
SCREEN _NEWIMAGE(640, 480, 32) '                            create graphics screen
_SNDLOOP Buzz& '                                            loop the buzzing sound
DO '                                                        begin main loop
   _LIMIT 60 '                                              60 times per second
   _PUTIMAGE (0, 0), Sky& '                                 place sky image on screen (no CLS needed)
    WhichBee% = 1 - WhichBee% '                             bee image index (toggle between 0 and 1)
    BeeSize! = BeeSize! + SizeDir! '                        increase bee size percentage
   IF BeeSize! > 2 OR BeeSize! < .25 THEN '                 bee too big or small?
        SizeDir! = -SizeDir! '                              yes, reverse size direction
   END IF
    Adder% = 135 * BeeSize! \ 2 '                           half size of bee image times percentage
   IF SGN(BeeDir%) = -1 THEN '                              is bee heading up screen?
        '** draw from top left to lower right
       _PUTIMAGE (BeeX% - Adder%, BeeY% - Adder%)-(BeeX% + Adder%, BeeY% + Adder%), Bee&(WhichBee%)
   ELSE '                                                   no, bee is heading down screen
        '** draw from lower right to top left
       _PUTIMAGE (BeeX% + Adder%, BeeY% + Adder%)-(BeeX% - Adder%, BeeY% - Adder%), Bee&(WhichBee%)
   END IF
    BeeY% = BeeY% + BeeDir% '                               increment bee y location
   IF BeeY% = 0 OR BeeY% = 479 THEN '                       has y hit top or bottom of screen?
        BeeDir% = -BeeDir% '                                yes, reverse direction of bee
   END IF
   _DISPLAY '                                               update screen with changes
LOOP UNTIL _KEYDOWN(27) '                                   loop until ESC pressed
_FREEIMAGE Sky& '                                           clean memory before leaving
_FREEIMAGE Bee&(0)
_FREEIMAGE Bee&(1)
_SNDCLOSE Buzz&
SYSTEM '                                                    return to operating system

Figure 6: The bee now has a sense of direction

_PUTIMAGE always draws images according to the direction of the coordinate pairs given to it. If the bee is heading upward the coordinates given to _PUTIMAGE match the image's original orientation, that is the first coordinate pair is located at the top left as compared to the second coordinate pair.

'** draw from top left to lower right
_PUTIMAGE (BeeX% - Adder%, BeeY% - Adder%)-(BeeX% + Adder%, BeeY% + Adder%), Bee&(WhichBee%)

However, when the bee is traveling in a downward direction the coordinate pairs are reversed which in effect flips the bee image vertically.

'** draw from lower right to top left
_PUTIMAGE (BeeX% + Adder%, BeeY% + Adder%)-(BeeX% - Adder%, BeeY% - Adder%), Bee&(WhichBee%)

Figure 7 below shows a visual representation of this.

Figure 7: Flipping the bee

Therefore it's possible to flip an image horizontally, vertically, or both at the same time by manipulating the starting and ending coordinate pair values. The next example shows _PUTIMAGE doing just that. Use your mouse to move the bee around and manipulate the image in the center of the screen.

( This code can be found at .\tutorial\Lesson13\PutimageDemo6.bas )

'** Putimage Demo 6 - Image flipping in all four directions

'--------------------------------
'- Variable Declaration Section -
'--------------------------------

DIM Sky& '      handle to hold sky image
DIM Bee& '      handle to hold bee image
DIM Arrows& '   handle to hold arrows image
DIM BeeX% '     x center location of bee
DIM BeeY% '     y center location of bee
DIM Angle% '    angle in degrees from bee to center of screen

'----------------------------
'- Main Program Begins Here -
'----------------------------

Sky& = _LOADIMAGE(".\tutorial\Lesson13\sky.png", 32) '       load sky image into RAM
Arrows& = _LOADIMAGE(".\tutorial\Lesson13\arrows.png", 32) ' load arrows image into RAM
Bee& = _LOADIMAGE(".\tutorial\Lesson13\tbee0.png", 32) '     load bee image into RAM
BeeX% = 319 '                                                set initial x coordinate of bee
BeeY% = 70 '                                                 set initial y coordinate of bee
SCREEN _NEWIMAGE(640, 480, 32) '                             create graphics screen
DO '                                                         begin main loop
   CLS '                                                     clear the screen
   _LIMIT 60 '                                               60 times per second
   _PUTIMAGE (0, 0), Sky& '                                  place sky image on screen
   _PUTIMAGE (BeeX% - 67, BeeY% - 67)-(BeeX% + 68, BeeY% + 68), Bee& ' place bee
    Angle% = INT(GETANGLE#(319, 239, BeeX%, BeeY%)) '        get angle from center screen to bee
   LOCATE 1, 1 '                                             position cursor
   PRINT "Angle ="; Angle% '                                 show user current angle
   LOCATE 2, 1 '                                             position cursor
   SELECT CASE Angle% '                                      in which quadrant does angle fall?
       CASE 0 TO 90 '                                        quadrant 1
           _PUTIMAGE (252, 172)-(387, 307), Arrows& '        normal image placement
           PRINT "Normal image placement"
       CASE 91 TO 180 '                                      quadrant 2
           _PUTIMAGE (252, 307)-(387, 172), Arrows& '        flip image vertically
           PRINT "Arrows image flipped vertically"
       CASE 181 TO 270 '                                     quadrant 3
           _PUTIMAGE (387, 307)-(252, 172), Arrows& '        flip image horizontally and vertically
           PRINT "Arrows image flipped vertically and horizontally"
       CASE 271 TO 359 '                                     quadrant 4
           _PUTIMAGE (387, 172)-(252, 307), Arrows& '        flip image horizontally
           PRINT "Arrows image flipped horizontally"
   END SELECT
   WHILE _MOUSEINPUT: WEND '                                 get latest mouse update
    BeeX% = _MOUSEX '                                        save current mouse x location
    BeeY% = _MOUSEY '                                        save current mouse y location
   _DISPLAY '                                                update screen with changes
LOOP UNTIL _KEYDOWN(27) '                                    loop until ESC pressed
_FREEIMAGE Sky& '                                            clean memory before leaving
_FREEIMAGE Bee&
_FREEIMAGE Arrows&
SYSTEM '                                                     return to Windows

'-----------------------------------
'- Function and Subroutine section -
'-----------------------------------

FUNCTION GETANGLE# (x1#, y1#, x2#, y2#)

    '*
    '* Returns the angle in degrees from 0 to 359.9999.... between 2 given coordinate pairs.
    '* Adapted from a function by Rob, aka Galleon, located in the QB64 Wiki
    '*

   IF y2# = y1# THEN '                                       both Y values same?
       IF x1# = x2# THEN '                                   yes, both X values same?
           EXIT FUNCTION '                                   yes, points are same, no angle
       END IF
       IF x2# > x1# THEN '                                   second X value greater?
            GETANGLE# = 90 '                                 yes, then must be 90 degrees
       ELSE '                                                no, second X value is less
            GETANGLE# = 270 '                                then must be 270 degrees
       END IF
       EXIT FUNCTION '                                       leave function
   END IF
   IF x2# = x1# THEN '                                       both X values same?
       IF y2# > y1# THEN '                                   second Y value greater?
            GETANGLE# = 180 '                                yes, then must be 180 degrees
       END IF
       EXIT FUNCTION '                                       leave function
   END IF
   IF y2# < y1# THEN '                                       second Y value less?
       IF x2# > x1# THEN '                                   yes, second X value greater?
            GETANGLE# = ATN((x2# - x1#) / (y2# - y1#)) * -57.2957795131 ' yes, compute angle
       ELSE '                                                no, second X value less
            GETANGLE# = ATN((x2# - x1#) / (y2# - y1#)) * -57.2957795131 + 360 ' compute angle
       END IF
   ELSE '                                                    no, second Y value greater
        GETANGLE# = ATN((x2# - x1#) / (y2# - y1#)) * -57.2957795131 + 180 ' compute angle
   END IF

END FUNCTION

Figure 8: Flipping an image horizontally, vertically, or both at the same time

The center Arrows& image will flip depending on which of the four quadrants the bee is in. As you can see it's possible to create three mirror images of an original image using this method. This comes in very handy when working with game graphics. Why draw Mario images running right and left when you can just create images for one direction then flip them for the other or perhaps a space ship that need to go in all four directions. Use one spaceship image and then mirror the other three directions as needed.

Copy and Paste With _PUTIMAGE

The full command syntax for _PUTIMAGE is:

_PUTIMAGE (dx1%, dy1%)-(dx2%, dy2%), Source&, Dest&, (sx1%, sy1%)-(sx2%, sy2%)

dx1%    - the first corner x coordinate within the destination image
dy1%    - the first corner y coordinate within the destination image
dx2%    - the second corner x coordinate within the destination image
dy2%    - the second corner y coordinate within the destination image
Source& - the source image handle to be placed within the destination image
Dest&   - the destination image handle where the source image is to be placed
sx1%    - the first corner x coordinate within the source image
sy1%    - the first corner y coordinate within the source image
sx2%    - the second corner x coordinate within the source image
sy2%    - the second corner y coordinate within the source image

When I first encountered _PUTIMAGE I was a bit intimidated by the construct of this statement. However with a little bit of playing and familiarity this statement soon became my favorite. The command syntax you see above allows for copying a portion of one image and pasting to another while at the same time flipping and resizing the copied image. Very, very powerful.

Included in the .\tutorial\Lesson13\ directory is a graphics file called flags.PNG. There are eight separate images of a waving flag contained in it as seen in Figure 9 below.

Figure 9: Eight flag images

Using _PUTIMAGE it is possible to copy each individual flag image and paste that image to another image. The image in Figure 9 is referred to as a sprite sheet and we'll discuss them in more detail in a later lesson.

Type in the following example code that copies the first two flag images and pastes them to the current window surface. Press a key to advance to the next flag image.

( This code can be found at .\tutorial\Lesson13\GetFlag.bas )

CONST WHITE = _RGB32(255, 255, 255) ' define color white

DIM AllFlags& '                       an image containing 8 flag sprites

AllFlags& = _LOADIMAGE(".\tutorial\Lesson13\flags.png", 32) '        load the sprite sheet into RAM
SCREEN _NEWIMAGE(256, 199, 32) '                                     create screen size of individual flag
CLS , WHITE '                                                        clear screen with white background
_PUTIMAGE (0, 0)-(255, 198), AllFlags&, _DEST, (0, 0)-(255, 198) '   copy/paste first flag image onto screen
SLEEP '                                                              wait for a key stroke
CLS , WHITE '                                                        clear screen with white background
_PUTIMAGE (0, 0)-(255, 198), AllFlags&, _DEST, (256, 0)-(511, 198) ' copy/paste second flag image onto screen
SLEEP '                                                              wait for a key stroke
_FREEIMAGE AllFlags& '                                               remove sprite sheet from RAM
SYSTEM '                                                             return to operating system

Figure 10: The first _PUTIMAGE statement at work

The first _PUTIMAGE statement as described in Figure 10 above has been instructed to copy a portion of the AllFlags& image and place that portion of the source image onto the screen designated as _DEST. Since a destination image was not specifically created using _DEST the destination image becomes the default screen.

Figure 11: The second _PUTIMAGE statement at work

The second _PUTIMAGE statement as see in Figure 11 above has once again been instructed to copy a portion of the source image AllFlags&. Notice that the first coordinate pair values have not changed since the destination, the screen in this case, has not changed. The second source coordinate pair however has changed to reflect the location of the second flag image on the overall AllFlags& image.

In the following example all individual flag images are copied from the master image and placed into an array. The flag images contained in the array are then displayed one after another to create an animation.

( This code can be found at .\tutorial\Lesson13\WavingFlag.bas )

DIM AllFlags& ' image containing animations of flag
DIM Flags&(7) ' array containing individual frames of flag animation
DIM Count% '    generic counter
DIM Banner& '   Star Spangled Banner music

AllFlags& = _LOADIMAGE(".\tutorial\Lesson13\flags.png", 32) ' load image into memory
Banner& = _SNDOPEN(".\tutorial\Lesson13\anthem.ogg") '        load patriotic music into memory
DO '                                                          start image load loop
    Flags&(Count%) = _NEWIMAGE(256, 199, 32) '                create top row flag image holder
    Flags&(Count% + 4) = _NEWIMAGE(256, 199, 32) '            create bottom row flag image holder
    '*
    '* Get top row flag and place in appropriate Flags&() image
    '*
   _PUTIMAGE (0, 0)-(255, 198), AllFlags&, Flags&(Count%), (Count% * 256, 0)-(Count% * 256 + 255, 198)
    '*
    '* Get bottom row flag and place in appropriate Flags&() image
    '*
   _PUTIMAGE (0, 0)-(255, 198), AllFlags&, Flags&(Count% + 4), (Count% * 256, 199)-(Count% * 256 + 255, 397)
    Count% = Count% + 1 '                                     increment to next array index
LOOP UNTIL Count% = 4 '                                       leave loop when count exceeded
SCREEN _NEWIMAGE(256, 199, 32) '                              create graphics screen
_TITLE "All rise for our national anthem" '                   give window a title
_DELAY .5 '                                                   slight delay before screen move
_SCREENMOVE _MIDDLE '                                         move screen to middle of desktop
Count% = 0 '                                                  reset array index counter
_SNDPLAY Banner& '                                            play patriotic music
DO '                                                          begin flag waving loop
   CLS , _RGB32(255, 255, 255) '                              clear screen with white background
   _LIMIT 10 '                                                10 frames per second
   _PUTIMAGE (0, 0), Flags&(Count%) '                         place flag image on screen
   _DISPLAY '                                                 update screen with changes
    Count% = Count% + 1 '                                     increment array index counter
   IF Count% = 8 THEN Count% = 0 '                            keep index within limits
LOOP UNTIL _KEYDOWN(27) '                                     leave loop when ESC pressed
FOR Count% = 0 TO 7 '                                         cycle through all array indexes
   _FREEIMAGE Flags&(Count%) '                                free flag images from RAM (cleanup)
NEXT Count%
_SNDCLOSE Banner& '                                           free music from RAM (cleanup)
SYSTEM '                                                      return to Windows

Figure 12: All rise

Using _PUTIMAGE to pull a series of images from a master image and then store them in memory for later use is very common in game programming. It's an efficient way to store many images within one image file. Instead of keeping track of eight individual flag images that need to be loaded one file can be loaded and then the flag images can be parsed out using _PUTIMAGE. Many times in games you'll see company logos being displayed before the game starts. Usually what is happening in the background is the images and sounds (the assets) are being loaded into memory for later use (DOOM WAD files for instance). Displaying cut scenes is another way to distract the player while the next level's assets are being loaded.

The _PUTIMAGE statement takes some time to master and I'm sure the _PUTIMAGE QB64 Wiki page will be your best friend until you do.

Note: Since I live in the United States and am a former Marine I'm obviously biased to create the American flag and have the American national anthem playing in the background. I welcome everyone from all over this big blue marble of ours to use this tutorial regardless of your country's political standing in the world. Find (or create) some waving flag images of your country's flag and create a sprite sheet to use in this code instead. Have your national anthem play in the background as well. If you do this please post your source code and image and sound assets to the QB64 forum so we can all see your flag waving and listen to your anthem. Hopefully some day we wave one united flag for mankind as we venture beyond our Earthly boundaries.

The _COPYIMAGE Statement

The _COPYIMAGE statement is used to create a copy of any image in memory which includes the entire screen. Type in the following example program to see how _COPYIMAGE is used.

( This code can be found at .\tutorial\Lesson13\CloneTrooper.bas )

CONST Gray = _RGB32(127, 127, 127) ' define colors
CONST RED = _RGB32(255, 0, 0)

DIM Trooper& '      trooper sprite sheet
DIM Walking&(5) '   walking trooper images
DIM Falling&(5) '   falling trooper images
DIM Standing& '     trooper just standing around
DIM Clone& '        a cloned trooper
DIM AllRight& '     "all right" voice
DIM Blaster& '      blaster sound
DIM MoveAlong& '    "move along" voice
DIM WhatsGoingOn& ' "do you know what's going on?" voice
DIM Uuhhh& '        clone removal sound
DIM Count% '        generic counter
DIM x!, y% '        coordinates of image box for walking trooper

Trooper& = _LOADIMAGE(".\tutorial\Lesson13\trooper.png", 32) '  load the sprite sheet
Standing& = _NEWIMAGE(32, 68, 32) '                             create the standing image
_PUTIMAGE , Trooper&, Standing&, (192, 0)-(223, 67) '           extract the standing image
FOR Count% = 0 TO 5 '                                           cycle through six more images
    Walking&(Count%) = _NEWIMAGE(32, 68, 32) '                  create walking image cell
    Falling&(Count%) = _NEWIMAGE(46, 68, 32) '                  create falling image cell
   _PUTIMAGE , Trooper&, Walking&(Count%), (32 * Count%, 0)-(32 * Count% + 31, 67) '   extract walking image
   _PUTIMAGE , Trooper&, Falling&(Count%), (46 * Count%, 68)-(46 * Count% + 45, 135) ' extract falling image
NEXT Count%
_FREEIMAGE Trooper& '                                           sprite sheet no longer needed
AllRight& = _SNDOPEN(".\tutorial\Lesson13\allright.ogg") '      load the sound files
Blaster& = _SNDOPEN(".\tutorial\Lesson13\blaster.ogg")
MoveAlong& = _SNDOPEN(".\tutorial\Lesson13\movealong.ogg")
WhatsGoingOn& = _SNDOPEN(".\tutorial\Lesson13\whatsgoingon.ogg")
Uuhhh& = _SNDOPEN(".\tutorial\Lesson13\uuhhh.ogg")
_SNDPLAY MoveAlong& '                                           play sound
SCREEN _NEWIMAGE(440, 230, 32) '                                enter graphics screen
x! = 48 '                                                       set upper left x location
y% = 102 '                                                      set upper left y location
Count% = 0 '                                                    reset counter
DO '                                                            walking forward loop
   _LIMIT 15 '                                                  15 frames per second
   CLS , Gray '                                                 clear with gray
    x! = x! - .47 '                                             increase size of image box
    y% = y% - 1
   _PUTIMAGE (x!, y%)-(96 - x!, 204 - y%), Walking&(Count%) '   show walking trooper within box limits
    Count% = Count% + 1 '                                       increment counter
   IF Count% = 6 THEN Count% = 0 '                              reset if counter exceeds limit
   _DISPLAY '                                                   update screen with changes
LOOP UNTIL y% = 0
_AUTODISPLAY '                                                  auto update screen
CLS , Gray '                                                    clear with gray
_PUTIMAGE (0, 0)-(95, 204), Standing& '                         show trooper in standing position
LOCATE 14, 10 '                                                 position text cursor
PRINT "Press any key to clone the trooper."; '                  display instructions
SLEEP '                                                         wait for key stroke
_SNDPLAY AllRight& '                                            play sound
Clone& = _COPYIMAGE(Standing&) '                                create a copy of the standing image
_PUTIMAGE (120, 0)-(216, 204), Clone& '                         place copy on the screen
LOCATE 14, 10 '                                                 position text cursor
PRINT "Press any key to remove the clone. "; '                  display instructions
SLEEP '                                                         wait for key stroke
_SNDPLAY Blaster& '                                             play blaster sound (uh oh)
FOR Count% = 440 TO 150 STEP -1 '                               cycle from right side of screen to clone
   CLS , Gray '                                                 clear with gray
   _PUTIMAGE (0, 0)-(95, 204), Standing& '                      place standing trooper
   _PUTIMAGE (120, 0)-(216, 204), Clone& '                      place his clone
   LINE (Count%, 100)-(Count% + 100, 104), RED, BF '            draw blaster beam
   _DISPLAY '                                                   update screen with changes
NEXT Count%
_SNDPLAY Uuhhh& '                                               play ugh sound
FOR Count% = 0 TO 5 '                                           cycle through falling images
   _LIMIT 15 '                                                  15 frames per second
   CLS , Gray '                                                 clear with gray
   _PUTIMAGE (0, 0)-(95, 204), Standing& '                      place the standing trooper

    _PUTIMAGE (113, 0)-(250, 204), Falling&(Count%) '           place the falling trooper
   _DISPLAY '                                                   update screen with changes

NEXT Count%

_DELAY 1 '                                                      delay for 1 second
_SNDPLAY WhatsGoingOn& '                                        play confused trooper sound
_DELAY 4 '                                                      delay for 4 seconds
FOR Count% = 0 TO 5 '                                           cycle through standing and falling images
   _FREEIMAGE Walking&(Count%) '                                remove all walking images from memory
   _FREEIMAGE Falling&(Count%) '                                remove all falling images from memory
NEXT Count%
_FREEIMAGE Standing& '                                          remove all sound files from memory
_FREEIMAGE Clone&
_SNDCLOSE AllRight&
_SNDCLOSE Blaster&
_SNDCLOSE MoveAlong&
SNDCLOSE WhatsGoingOn&
_SNDCLOSE Uuhhh&
SYSTEM '                                                        return to operating system

Figure 13: Cloned Storm Trooper

LOL, that's one way to remove a clone I guess! Yes, most of this example was for fun. I love how easy it is to use QB64 to create something silly like this.

The line of code relating to the _COPYIMAGE statement is 54:

Clone& = _COPYIMAGE(Standing&) '                                create a copy of the standing image

_COPYIMAGE can copy any valid image which also includes the screen. This is handy if you need a quick copy of the screen before an action is taken. This way the user can select "undo" in your program and you can simply place this copy back onto the screen.

The _SCREENIMAGE Statement (Windows only)

The _SCREENIMAGE statement is used to take a snapshot of the computer's desktop. _SCREENIMAGE can be used with no parameters to grab the entire desktop.

Desktop& = _SCREENIMAGE '                 grab an image of the desktop

By supplying coordinates a portion of the desktop can be grabbed.

Desktop& = _SCREENIMAGE(0, 0, 639, 479) ' upper left 640x480 area of desktop

Here's an example that uses _SCREENIMAGE to play a prank on your friends. Use your mouse to click around on the screen. Pressing the ESC key will end the program.

( This code can be found at .\tutorial\Lesson13\ScreenImagePrank.bas )

'** _SCREENIMAGE Prank Demo

DIM Desktop& '    desktop screen shot
DIM BulletHole& ' bullet hole image
DIM GunShot& '    gun shot sound
DIM x%, y% '      x,y location of bullet hole

Desktop& = _SCREENIMAGE '                                               grab screen shot
SCREEN Desktop& '                                                       create screen from screen shot
_FULLSCREEN '                                                           go full screen
BulletHole& = _LOADIMAGE(".\tutorial\Lesson13\bullethole.png", 32) '    load bullet hole image
GunShot& = _SNDOPEN(".\tutorial\Lesson13\gunshot.ogg") '                load gun shot sound
DO '                                                                    main program loop
   _LIMIT 30 '                                                          30 FPS
   WHILE _MOUSEINPUT: WEND '                                            get latest mouse information
   IF _MOUSEBUTTON(1) THEN '                                            left mouse button pressed?
        x% = _MOUSEX '                                                  yes, get mouse X coordinate
        y% = _MOUSEY '                                                  get mouse Y coordinate
       _PUTIMAGE (x% - 12, y% - 12)-(x% + 12, y% + 12), BulletHole& '   draw bullet hole at mouse pointer
       _SNDPLAY GunShot& '                                              give report
   END IF
LOOP UNTIL _KEYDOWN(27) '                                               leave when ESC pressed
SCREEN 0, 0, 0, 0 '                                                     enter text screen
_FREEIMAGE Desktop& '                                                   remove image from memory
_FREEIMAGE BulletHole& '                                                remove image from memory
_SNDCLOSE GunShot& '                                                    remove sound from memory
SYSTEM '                                                                return to Windows

When the unsuspecting user of your prank clicks on the "desktop" a bullet hole will appear with a gun shot heard. Eventually they will press the escape key and the program will terminate back to the original desktop leaving the user baffled. I put a program similar to this on my wife's computer and had Task Scheduler run it once a day. Her version had a timer that would end the program after one minute so by the time she came and got me to show what was happening everything was fine. Funny stuff ... until she found out!

NOTE: Be careful using a program like this in your work environment. System administrators have much less of a sense of humor these days because of all the attacks (phishing, key loggers, ransomware, etc..) they have to deal with. A simple program like this may get you in hot water, fired, or even worse, labeled a "hacker" and charged as such.

The _SAVEIMAGE Statement (PE only)

Note: The _SAVEIMAGE statement only works with QB64 Phoenix Edition versions 3.9.0 and above. The statement is supported in Windows, Linux, and MacOS.

Now that you've created an image that Rembrandt would be envious of you'll want to save it to your hard drive. _SAVEIMAGE supports six image file formats (you can click on each one to learn more about the format):

The syntax of _SAVEIMAGE is:

_SAVEIMAGE Filename$, ImageHandle&, Requirements$

_SAVEIMAGE only requires the Filename$ parameter with ImageHandle& and Requirements$ being optional. If you don't supply an image format extension from the list above the .PNG image file format is used by default. Filename$ is a literal or variable string containing the name and optional location of the file. For example:

_SaveImage "C:\Images\MyMasterpiece" '     save the screen in .PNG format

The ImageHandle& parameter defines the image to be saved. If the ImageHandle& parameter is omitted then the current _DISPLAY function value is used (the current screen). To save an image other than the screen:

_SaveImage "MyImage.BMP", MyImage& '       save MyImage as a BMP image file

The Requirements$ parameter is used to instruct _SAVEIMAGE as to which file format to save the image file. Requirements$ can be "PNG", "QOI", "BMP", "TGA", "JPG", or "HDR". For example, the following line of code performs the same function as the previous example:

_SaveImage "MyImage", MyImage&, "BMP" '    save MyImage as a BMP image file

If a file image format extension is supplied in Filename$ it will override the image type  in Requirements$. For example:

_SaveImage "MyImage.BMP", MyImage, "PNG" ' BMP will override PNG

MyImage& will be saved as a BMP image file even though Requirements$ specified the PNG image type. Image extensions contained in Filename$ take precedence over Requirements$.

The _FREEIMAGE Statement

I'm sure you have noticed by now that every example has used the _FREEIMAGE statement. The _FREEIMAGE statement is used to remove images from memory. You should get into the habit of removing all assets (images, sounds, fonts, etc..) from the computer before your program terminates. While all operating systems today have a file manager that does a good job of cleaning up after program termination and most languages have "garbage collection" as well, you should not rely on these to do your dirty work. It's lazy for one and could result in making your user's computer unstable.

Note: You should also free any assets from subroutines and functions that create them for local use before you exit the subroutine or function. Not doing so will result in the asset being created again and again which will eventually fill your user's memory up causing either a program or operating system crash.

Your Turn

You were just hired as a contract graphics programmer by a rather large gaming company. The company is currently working on a mobile chess platform and want to do something about the chess board supplied by their art department. Figure 14 below is the chess board graphic that was supplied by the art department but rejected by the team leader.

Figure 14: The chess board created by the art department

The team leader feels that the board looks too repetitive and the tiles need some randomness to them. The art department sent you a graphic file called "chess.png" located in your .\tutorial\Lesson13\ directory. Figure 15 below describes what is contained in the file.

Figure 15: Description of the chess.png file the art department sent you

The team leader has sent you the following requirements to accomplish:

The team leader has given you a three day deadline to complete this assignment.

Some things to consider:

Your program should include a small proof of concept code in the main program section. Your team leader will be able to press a key to see the chess board being created randomly over and over again when "MakeChessBoard" is called until he/she is satisfied the code is working properly. Figure 16 below is an example of the proof of concept.

Figure 16: The program as submitted for approval

Commands and Concepts Learned