Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Pi-in-the-Sky Graphics Demonstration Program - PE Edition
#1
This is the last of my old programs from .org.  Seasoned members may remember it for its entertaining (?) whimsicality.  It is slightly updated for this PE Edition.

The program was created to demonstrate the amazing graphics capabilities of QB64, using the simple coding techniques  of the QB64 _MAPTRIANGLE statement: the 3D _MAPTRIANGLE method gives a convincing 3D perspective view.  Both 2D and 3D _MAPTRIANGLE methods are used and the advantages of the 3D method are evident.

Unzip the file and extract the folder into your PEQB64 directory.  In the IDE make sure that you have the Run Option “Save EXE in source folder” checked.  At program start there is a delay while the disk files are read and loaded into memory and image manipulations are performed.

.zip   Pi-in-the-Sky PE Edition.zip (Size: 18.08 MB / Downloads: 13)


   

The video shows a short excerpt of the running program.



The program features a number of animations (some 2D and some 3D) enhanced in some cases with accompanying audio. 

The scene a landscape within which a variety of animations will occur.  It takes approximately 10 mins to run through all of the animation sequences.  There are earthly animations and celestial animations.  During the celestial animations, there may be ghostly appearances in the terrestrial graveyard.

In the blue text I give details of the program coding methods, descriptions of the animations and background information.  You do not need to read the blue text to run and enjoy (well, maybe!) the program.


I started this project purely because the phrase "pi in the sky" popped into my head, and so started coding to produce a pi symbol randomly rotating about three axes in 3D.  The obvious QB64 method is _MAPTRIANGLE(3D).  All you have to do is work out the mathematics of rotations about the three Cartesian co-ordinates and plug the resulting corner positions into _MAPTRIANGLE(3D).  The surface of the image is everywhere flat, but its corners move freely in the 3D space of _MAPTRIANGLE(3D), and as (vanishing point) perspective is coded into the _MAPTRIANGLE(3D) method, a very good-looking display is produced.  I must emphasise that this QB64 method is so well produced that it can be used by novice and low-skill coders.  In the Skill Range Venn Diagram, I sit in the low-skill sector, and I cannot do the real-3D stuff of our competent members.

To do this project I have had to go back to school-level calculus, geometry & algebra; oh, happy days!  Having got the pi animation working, I then set about adding other features to demonstrate what can done with QB64 graphics.  The final project uses both software and hardware imaging, and for the hardware images both _MAPTRIANGLE(2D) and _MAPTRIANGLE(3D).  The program is designed to show how such images will interact.  The program also uses a load of _MEM object processing in order to manipulate images, both at initiation and on-the-fly in real time.

Background Image
The graphical animations take place in front of a background image.  This background (a landscape with added features) is software (,32 type) and has a single _PUTIMAGE directly after creating the 32-bit screen.  This image stays displayed despite the running loop executing a _DISPLAY at each cycle (30 fps).

pi Animation
In order to change colour as the pi moves around, real-time editing of the image file is required.  This is achieved by _MEM object manipulation each display cycle.  _MEM processing can only be achieved with software images, whereas the pi image is hardware.  So, firstly a software image is created at initiation and then at each cycle, a _MEM object of the software image is taken, that object is manipulated and the software image is copied to hardware and that image is displayed.  Both the _MEM object and the hardware image are freed each cycle at the earliest opportunity.  This method is repeated for all other real-time image manipulations.

Earthly and Celestial Animations
There are both earth-bound and celestial animations.  The earth-bound animations (along with clouds and some rain) are continuous, whereas the celestial animations cycle in a random manner.

Earthly Animations
Beehive
Bees emerge and swarm from a suspended beehive in the foreground.  The bees fly in the 3D space of _MAPTRIANGLE(3D) and both the hive and the (QB64) bee images are hardware (3D).  After emerging in an outward direction the bees turn and fly in the opposite direction away from the viewer "into" the screen.  Bees in front of the hive occlude it, and behind the hive they are occluded by it.  As the hive image is a flat object, a bee moving from directly in front of to directly behind the hive travels right through it.  The bees all appear to move to the right as they move away, but this is just the perspective.  All the bees return to the hive after their flight out.  In order to achieve such paths, the bees are flying in parabolic curves in the 3D space.  There is the sound of humming bees, the more bes that are out the louder they sound.
Fountain
A fountain squirts droplets of water into the pond.  There are 500 droplets of water each moving under gravity in the _MAPTRIANGLE(3D) space.  Although as many droplets are sent behind the fountain as in the front, it looks as if they only fall at the front.  This is just an artefact of the perspective.
Windmill
The moving windmill sails clearly show the 3D and perspective effects  of _MAPTRIANGLE(3D).  The sails appear to move in and out as they rotate and are smaller the further away they are.  As the bees, fountain droplets and windmill sails are _MAPTRIANGLE(3D) images, they occlude each other dependent upon which is further away.  The windmill itself is not a 3D object but part of the software background.  The industrious Miller Heitor looks out from the windmill.
Clouds and Rain
Clouds pass above.  They are slightly transparent so that objects behind can still be seen.  One of the clouds is rain-bearing and a shower of 500 raindrops passes through.  The clouds and raindrops are not 3D, and occlusions occur based upon order in which the _PUTIMAGE functions occur.
Flower Growth
As the rain passes, flowers can spring up in the earth.  Flower images are 2D.
Rainbow
When the rain is in just the right place, a rainbow appears.  The rainbow is a _MAPTRIANGLE(3D) image and occlusions with other such objects are dependent upon distance into the screen.
Graveyard
Ghostly images appear in the graveyard when certain celestial events take place.  The gravestone images are part of the background 2D image.

Celestial Animations
At times, celestial animations occur.
Concorde
Fly-past of a supersonic passenger aircraft.  The Concorde image is 2D.  The aircraft creates a sonic boom.  A ghostly image of Douglas Bader appears in the graveyard.  Eventually the image disappears into thin air.  This graphic effect is achieved, again, by _MEM object real-time processing (in this case changing alpha sequentially).  Images here are 2D.
ET
A silhouette from a well-known science fiction film travels across the sky.  The image is 2D.  A ghostly film director appears in the graveyard.
Star Trek
The spacecraft from a well-known science-fiction television series moves through the _MAPTRIANGLE(3D) space coming from the distance.  Members of the crew appear in the graveyard.  Because the graveyard images are small and transparent, it is rather difficult to recognise who they are.  From left to right they are McCoy, Uhura, Kirk, Sulu and Spock.
ISS
The 2D International Space Station passes overhead.  The sound is that of Sputnik 1.  Cosmonaut Yuri Gagarin appears in the graveyard.
Meteors
A 3D meteor shower occurs while Galileo looks on from the grave.
Transit
A transit of Venus occurs.  This is a very rare event, the last occurring in 2012 and the next due in 2117, so we are very privileged.  The goddess appears in the graveyard.
Thunderbirds
A bomb falls onto the windmill.  Call for action from a well-known science-fiction television series.  Help arrives and the bomb is safely removed.  All images are 2D.  The graveyard crew are Alan, Scott, Virgil, Gordon and John.
Zodiac
The signs of the Zodiac circle in the heavens.  The image is the surface of an open-ended cylinder.  This is the only non-flat 3D image in this program, and the real-3D effect requires multiple _MAPTRIANGLE(3D) processes.  The Zodiac sign at the front is brightened, and this effect is, again, produced by real-time _MEM processing.  In the video you can see how the Zodiac and pi images have a real 3D look with correct perspective and occlusion.  Zodiac symbols of the prominent sign appear in the graveyard.  For you I see a romantic liaison with a group from the shoe-making industry.  Cobblers!
UFO
An alien spacecraft arrives and settles for a moment, and after probing the environment it lifts off and flies away.  The image is _MAPTRIANGLE(3D) and occlusions with the windmill sails are correct.  In order to make the landing, the spacecraft follows a helical path (circular x-, z- path and linear y- path).  The arrival of this alien craft arouses the interest of two FBI special agents.
Spotlight
A spotlight illuminates the sky and reveals a pertinent message.  The spotlight image is only 2D, and would have been better as 3D but is done this way to show the limitations.  Again, _MEM processing is required to make the message image respond to the spotlight. 


Discussion

This was a tinkering project.  As ideas came, I'd change to new areas of coding and then return to unfinished parts.  This is a bad method to do projects.  Returning to old parts, you don't quite remember exactly what you previously did and end up making mistakes.  But it is what it is.  If left running, the program will cycle through the animations randomly, but I note that it crashes out at the start of the third cycle, so clearly there remains at least one error.

Code: (Select All)
'Pi-in-the-Sky PE Edition Graphics Program by Magdha 2026-01-17 ex Qwerkey
'A Program which compares the use of _MAPTRIANGLE(2D) and _MAPTRIANGLE(3D)
'in an amusing and entertaining way.
'The use of _MEM object processing for graphics is illustrated.
'Acknowledgements: findsounds.com, freesound.org, freepik.com, pinclipart.com, imgbin.com, kissclipart.com, pngimg.com, vectorstock.com, sciencealert.com, startrek.com

CONST False = 0, True = NOT False
CONST XScreen% = 1100, YScreen% = 800, ZOffset% = -620
CONST PiSizeLess1% = 499, PiDisp% = 100, SunSize%% = 500, AmblinHalf%% = 50
CONST RBee% = 120, CBee% = 80
CONST BeeEntX% = -350, BeeEntY% = -250, HiveWidth% = 1009, HiveHeight% = 589, BWidth% = 350
CONST FountX% = -128, FountY% = -230, G! = 0.01
CONST ZodHeight% = 70, SpotRad% = 80, WQB64X% = 500, WQB64Y% = 350
CONST QB64X% = 300, QB64Y% = 50, UFOHalfX% = 150, UFOHalfY% = 60, UFORad% = 700
CONST Wind% = 150, WindX% = 550, WindHeight% = 280, SailX% = 44, SailY% = -154

'Derived Constant Variables:
CONST Zeta! = 0.07 * _PI 'Derived CONST (using formulae)
CONST ABee! = -4 * CBee% / (RBee% * RBee%), HX1% = -50 - (XScreen% / 2), HY1% = 300 - (YScreen% / 2)
CONST HX2% = HX1% + BWidth%, HY3% = HY1% - (BWidth% * HiveHeight% / HiveWidth%)
CONST ZBow% = ZOffset% + 100, ZodWidth% = ZodHeight% * 300 / 240, ZRad! = 12 * ZodWidth% / (2 * _PI)
CONST SpotInc! = 2 * _PI / 100, LampX% = XScreen% - 50, LampY% = YScreen% - 220
CONST Iota! = -0.23 * _PI, WindY% = YScreen% - 294, MillBombX1% = WindX% + 17, MillBombY1% = WindY% + 8

DIM Clouds&(15), CloudPos!(15, 2), CloudGo%%(15), RedGreenBlue!(5), Raindrops!(500, 1), Fountain!(500, 6)
DIM AmblinPos!(3), Enterprise!(2), Flora!(9, 5), FloraCount%(9), QB64Bees!(500, 4), Buzz%%(500), ConcordePos!(1)
DIM Perseids!(30, 6), Transit!(1), Virgil!(10), ZodiacSymImg&(12), SpotLight!(1)
DIM DispOrder%%(9), GraveImg&(5, 1), CrewImg&(5), TracyImg&(5), UFOImg&(3), LogoImg&(4)
DIM PiMem AS _MEM, PiOff AS _OFFSET, CMem AS _MEM, COff AS _OFFSET
DIM SHARED DispTrans!(8, 2), DoAnime%%

_TITLE "Pi in the Sky"
$EXEICON:'.\pi.ico'
RANDOMIZE (TIMER)

'Load (and manipulate) image files and load sounds
PRINT "Loading Files..."; 'The loading and manipulation of many image files takes a little time

'ET Image
TempImg1& = _LOADIMAGE("cyclist.png", 32) 'Software image
TempImg& = _NEWIMAGE(2 * AmblinHalf%% + 1, 2 * AmblinHalf%% + 1, 32)
_DEST TempImg&
_PUTIMAGE , TempImg1&
_FREEIMAGE TempImg1&
AmblinImg& = HardwareImage&(TempImg&) 'Convert image to hardware
'Wheels Image
TempImg1& = _NEWIMAGE(26, 2, 32)
_DEST TempImg1&
COLOR _RGB32(0, 0, 0), _RGBA32(0, 0, 0, 0)
CLS
LINE (0, 0)-(25, 1), , BF
TempImg& = _NEWIMAGE(27, 27, 32)
_DEST TempImg&
COLOR _RGB32(0, 0, 0), _RGBA32(0, 0, 0, 0)
CLS
CIRCLE (13, 13), 3
PAINT (13, 13)
CIRCLE (13, 13), 10
CIRCLE (13, 13), 13
PAINT (1, 13)
_PUTIMAGE (1, 12), TempImg1&
_MAPTRIANGLE (0, 0)-(25, 0)-(0, 1), TempImg1& TO(13, 1)-(14, 25)-(12, 1)
_MAPTRIANGLE (25, 1)-(0, 1)-(25, 0), TempImg1& TO(13, 25)-(12, 1)-(14, 25)
_MAPTRIANGLE (0, 0)-(25, 0)-(0, 1), TempImg1& TO(5, 5)-(22, 21)-(4, 5)
_MAPTRIANGLE (25, 1)-(0, 1)-(25, 0), TempImg1& TO(21, 21)-(4, 5)-(22, 21)
_MAPTRIANGLE (0, 0)-(25, 0)-(0, 1), TempImg1& TO(21, 5)-(5, 22)-(21, 4)
_MAPTRIANGLE (25, 1)-(0, 1)-(25, 0), TempImg1& TO(5, 21)-(21, 4)-(5, 22)
_FREEIMAGE TempImg1&
SpokesImg& = HardwareImage&(TempImg&)
SpielbergImg& = _NEWIMAGE(42, 110, 32)
_DEST SpielbergImg&
_PUTIMAGE , _LOADIMAGE("director.png", 32)
'Now manipulate image using _MEM processing
CMem = _MEMIMAGE(SpielbergImg&)
COff = 0
'Check for image background:
'If background set alpha (transparency) to zero
'Else set alpha to 120 to give a semi-transparent (ghostly) image
WHILE COff < CMem.SIZE
    IF _MEMGET(CMem, CMem.OFFSET + COff + 3, _UNSIGNED _BYTE) < 50 THEN
        _MEMPUT CMem, CMem.OFFSET + COff + 3, 0 AS _UNSIGNED _BYTE 'Alpha
    ELSE
        _MEMPUT CMem, CMem.OFFSET + COff + 3, 120 AS _UNSIGNED _BYTE 'Alpha
    END IF
    COff = COff + 4
WEND
_MEMFREE CMem 'Always free memory of _MEM object once manipulation is done
ETSound& = _SNDOPEN("eetea.mp3")

'Concorde Image
TempImg& = _NEWIMAGE(250, 1180, 32)
_DEST TempImg&
COLOR _RGBA32(180, 180, 210, 60), _RGBA32(0, 0, 0, 0)
CLS
_PUTIMAGE (0, 380)-(240, 416), _LOADIMAGE("concorde.png", 32)
LINE (244, 386)-(40, 1179)
LINE (244, 386)-(91, 0)
LINE (245, 386)-(41, 1179)
LINE (245, 386)-(92, 0)
LINE (246, 386)-(42, 1179)
LINE (246, 386)-(92, 0)
LINE (247, 386)-(43, 1179)
LINE (247, 386)-(93, 0)
LINE (248, 386)-(44, 1179)
LINE (248, 386)-(94, 0)
ConcordeImg& = HardwareImage&(TempImg&)
BaderImg& = _NEWIMAGE(42, 110, 32)
_DEST BaderImg&
_PUTIMAGE , _LOADIMAGE("bader.png", 32)
CMem = _MEMIMAGE(BaderImg&)
COff = 0
WHILE COff < CMem.SIZE
    IF _MEMGET(CMem, CMem.OFFSET + COff + 3, _UNSIGNED _BYTE) < 50 THEN
        _MEMPUT CMem, CMem.OFFSET + COff + 3, 0 AS _UNSIGNED _BYTE 'Alpha
    ELSE
        _MEMPUT CMem, CMem.OFFSET + COff + 3, 120 AS _UNSIGNED _BYTE 'Alpha
    END IF
    COff = COff + 4
WEND
_MEMFREE CMem
BoomSound& = _SNDOPEN("boom.mp3")

'Thunderbird2 Image
TempImg& = _LOADIMAGE("flyingbird.png", 32)
CMem = _MEMIMAGE(TempImg&)
COff = 0
'Check for image foreground:
'If not foreground set alpha (transparency) to zero (background)
WHILE COff < CMem.SIZE
    B0~%% = _MEMGET(CMem, CMem.OFFSET + COff, _UNSIGNED _BYTE)
    B1~%% = _MEMGET(CMem, CMem.OFFSET + COff + 1, _UNSIGNED _BYTE)
    B2~%% = _MEMGET(CMem, CMem.OFFSET + COff + 2, _UNSIGNED _BYTE)
    IF B0~%% + B1~%% + B2~%% > 750 THEN
        _MEMPUT CMem, CMem.OFFSET + COff + 3, 0 AS _UNSIGNED _BYTE 'Alpha
    END IF
    COff = COff + 4
WEND
ThunderImg& = HardwareImage&(TempImg&)
'Bomb Image
BombImg& = _LOADIMAGE("bomb.png", 33)
'Windmill Bomb Image
MillBombImg& = _LOADIMAGE("windmillbomb.png", 33)
'Magnet Image
MagnetImg& = _LOADIMAGE("magnet.png", 33)
'Chain Image
TempImg1& = _LOADIMAGE("link.png", 32)
TempImg& = _NEWIMAGE(10, 400, 32)
_DEST TempImg&
FOR K%% = 0 TO 19
    _PUTIMAGE (0, K%% * 20)-(9, (K%% + 1) * 20), TempImg1&
NEXT K%%
_FREEIMAGE TempImg1&
ChainImg& = HardwareImage&(TempImg&)
'Tracy Brothers Images
TempImg1& = _LOADIMAGE("bros.png", 32)
FOR K%% = 1 TO 5
    'All grave images must be software
    READ CrewDat%%
    TracyImg&(CrewDat%%) = _NEWIMAGE(42, 110, 32)
    _DEST TracyImg&(CrewDat%%)
    _PUTIMAGE , TempImg1&, , (10 + (K%% - 1) * 116, 8)-(12 + (K%% - 1) * 116 + 103, 323)
    CMem = _MEMIMAGE(TracyImg&(CrewDat%%))
    COff = 0
    WHILE COff < CMem.SIZE
        IF _MEMGET(CMem, CMem.OFFSET + COff + 3, _UNSIGNED _BYTE) < 50 THEN
            _MEMPUT CMem, CMem.OFFSET + COff + 3, 0 AS _UNSIGNED _BYTE 'Alpha
        ELSE
            _MEMPUT CMem, CMem.OFFSET + COff + 3, 140 AS _UNSIGNED _BYTE 'Alpha
        END IF
        COff = COff + 4
    WEND
    _MEMFREE CMem
NEXT K%%
_FREEIMAGE TempImg1&
BombSound& = _SNDOPEN("bombdrop.mp3")
_SNDVOL BombSound&, 0.5
TunderbirdsSound& = _SNDOPEN("birdsong.mp3")

'Star Trek Image
TempImg& = _LOADIMAGE("starship.png", 32)
CMem = _MEMIMAGE(TempImg&)
COff = 0
WHILE COff < CMem.SIZE
    B0~%% = _MEMGET(CMem, CMem.OFFSET + COff, _UNSIGNED _BYTE)
    B1~%% = _MEMGET(CMem, CMem.OFFSET + COff + 1, _UNSIGNED _BYTE)
    B2~%% = _MEMGET(CMem, CMem.OFFSET + COff + 2, _UNSIGNED _BYTE)
    IF B0~%% + B1~%% + B2~%% < 40 THEN
        _MEMPUT CMem, CMem.OFFSET + COff + 3, 0 AS _UNSIGNED _BYTE 'Alpha
    END IF
    COff = COff + 4
WEND
StarTrekImg& = HardwareImage&(TempImg&)
'Star Trek Crew Images
TempImg1& = _LOADIMAGE("crew.png", 32)
FOR K%% = 1 TO 5
    'All grave images here must be software (converted to hardware during calc)
    READ CrewDat%%
    CrewImg&(CrewDat%%) = _NEWIMAGE(42, 110, 32)
    _DEST CrewImg&(CrewDat%%)
    _PUTIMAGE , TempImg1&, , (12 + (K%% - 1) * 195, 0)-(12 + (K%% - 1) * 195 + 177, 474)
    CMem = _MEMIMAGE(CrewImg&(CrewDat%%))
    COff = 0
    WHILE COff < CMem.SIZE
        IF _MEMGET(CMem, CMem.OFFSET + COff + 3, _UNSIGNED _BYTE) < 50 THEN
            _MEMPUT CMem, CMem.OFFSET + COff + 3, 0 AS _UNSIGNED _BYTE 'Alpha
        ELSE
            _MEMPUT CMem, CMem.OFFSET + COff + 3, 140 AS _UNSIGNED _BYTE 'Alpha
        END IF
        COff = COff + 4
    WEND
    _MEMFREE CMem
NEXT K%%
_FREEIMAGE TempImg1&
TrekSound& = _SNDOPEN("tvtheme.mp3")

'ISS Image
TempImg& = _LOADIMAGE("iss1.png", 32)
CMem = _MEMIMAGE(TempImg&)
COff = 0
WHILE COff < CMem.SIZE
    B0~%% = _MEMGET(CMem, CMem.OFFSET + COff, _UNSIGNED _BYTE)
    B1~%% = _MEMGET(CMem, CMem.OFFSET + COff + 1, _UNSIGNED _BYTE)
    B2~%% = _MEMGET(CMem, CMem.OFFSET + COff + 2, _UNSIGNED _BYTE)
    IF B0~%% + B1~%% + B2~%% < 40 THEN
        _MEMPUT CMem, CMem.OFFSET + COff + 3, 0 AS _UNSIGNED _BYTE 'Alpha
    END IF
    COff = COff + 4
WEND
ISSImg& = HardwareImage&(TempImg&)
CosmonautImg& = _NEWIMAGE(42, 110, 32)
_DEST CosmonautImg&
_PUTIMAGE , _LOADIMAGE("yuri.png", 32)
CMem = _MEMIMAGE(CosmonautImg&)
COff = 0
WHILE COff < CMem.SIZE
    IF _MEMGET(CMem, CMem.OFFSET + COff + 3, _UNSIGNED _BYTE) < 50 THEN
        _MEMPUT CMem, CMem.OFFSET + COff + 3, 0 AS _UNSIGNED _BYTE 'Alpha
    ELSE
        _MEMPUT CMem, CMem.OFFSET + COff + 3, 120 AS _UNSIGNED _BYTE 'Alpha
    END IF
    COff = COff + 4
WEND
_MEMFREE CMem
SputnikSound& = _SNDOPEN("sputnik.mp3")

'Meteor Image
MeteorImg& = _LOADIMAGE("meteor.png", 33)
GalileoImg& = _NEWIMAGE(42, 110, 32)
_DEST GalileoImg&
_PUTIMAGE , _LOADIMAGE("galileo.png", 32)
CMem = _MEMIMAGE(GalileoImg&)
COff = 0
WHILE COff < CMem.SIZE
    IF _MEMGET(CMem, CMem.OFFSET + COff + 3, _UNSIGNED _BYTE) < 50 THEN
        _MEMPUT CMem, CMem.OFFSET + COff + 3, 0 AS _UNSIGNED _BYTE 'Alpha
    ELSE
        _MEMPUT CMem, CMem.OFFSET + COff + 3, 120 AS _UNSIGNED _BYTE 'Alpha
    END IF
    COff = COff + 4
WEND
_MEMFREE CMem
MeteorWindSound& = _SNDOPEN("gust.mp3")
MeteorSound& = _SNDOPEN("meaty_or.mp3")

'Venus Image
TempImg& = _NEWIMAGE(5, 5, 32)
_DEST TempImg&
COLOR _RGBA32(0, 0, 0, 255), _RGBA32(100, 100, 100, 0)
CLS
CIRCLE (2, 2), 2
PAINT (2, 2)
VenusImg& = HardwareImage&(TempImg&)
BotticelliImg& = _NEWIMAGE(42, 110, 32)
_DEST BotticelliImg&
_PUTIMAGE , _LOADIMAGE("venus.png", 32)
CMem = _MEMIMAGE(BotticelliImg&)
COff = 0
WHILE COff < CMem.SIZE
    IF _MEMGET(CMem, CMem.OFFSET + COff + 3, _UNSIGNED _BYTE) < 50 THEN
        _MEMPUT CMem, CMem.OFFSET + COff + 3, 0 AS _UNSIGNED _BYTE 'Alpha
    ELSE
        _MEMPUT CMem, CMem.OFFSET + COff + 3, 120 AS _UNSIGNED _BYTE 'Alpha
    END IF
    COff = COff + 4
WEND
_MEMFREE CMem
VenusSound& = _SNDOPEN("holst_v.mp3")

'UFO Image
TempImg& = _LOADIMAGE("ufo.png", 32)
CMem = _MEMIMAGE(TempImg&)
COff = 0
WHILE COff < CMem.SIZE
    IF _MEMGET(CMem, CMem.OFFSET + COff + 3, _UNSIGNED _BYTE) > 50 THEN
        _MEMPUT CMem, CMem.OFFSET + COff + 1, (_MEMGET(CMem, CMem.OFFSET + COff, _UNSIGNED _BYTE) * 0.7) AS _UNSIGNED _BYTE 'Blue
        _MEMPUT CMem, CMem.OFFSET + COff + 1, (_MEMGET(CMem, CMem.OFFSET + COff + 1, _UNSIGNED _BYTE) * 0.1) AS _UNSIGNED _BYTE 'Green
        _MEMPUT CMem, CMem.OFFSET + COff + 2, (_MEMGET(CMem, CMem.OFFSET + COff + 2, _UNSIGNED _BYTE) * 0.7) AS _UNSIGNED _BYTE 'Red
    ELSE
        _MEMPUT CMem, CMem.OFFSET + COff + 3, 0 AS _UNSIGNED _BYTE 'Alpha
    END IF
    COff = COff + 4
WEND
UFOImg&(0) = HardwareImage&(TempImg&)
TempImg& = _LOADIMAGE("ufo.png", 32)
CMem = _MEMIMAGE(TempImg&)
COff = 0
WHILE COff < CMem.SIZE
    IF _MEMGET(CMem, CMem.OFFSET + COff + 3, _UNSIGNED _BYTE) > 50 THEN
        _MEMPUT CMem, CMem.OFFSET + COff + 1, (_MEMGET(CMem, CMem.OFFSET + COff, _UNSIGNED _BYTE) * 0.95) AS _UNSIGNED _BYTE 'Blue
        _MEMPUT CMem, CMem.OFFSET + COff + 1, (_MEMGET(CMem, CMem.OFFSET + COff + 1, _UNSIGNED _BYTE) * 0.1) AS _UNSIGNED _BYTE 'Green
        _MEMPUT CMem, CMem.OFFSET + COff + 2, (_MEMGET(CMem, CMem.OFFSET + COff + 2, _UNSIGNED _BYTE) * 0.95) AS _UNSIGNED _BYTE 'Red
    ELSE
        _MEMPUT CMem, CMem.OFFSET + COff + 3, 0 AS _UNSIGNED _BYTE 'Alpha
    END IF
    COff = COff + 4
WEND
UFOImg&(1) = HardwareImage&(TempImg&)
TempImg1& = _LOADIMAGE("foxylady.png", 32)
FOR K%% = 2 TO 3
    UFOImg&(K%%) = _NEWIMAGE(42, 110, 32)
    _DEST UFOImg&(K%%)
    _PUTIMAGE , TempImg1&, , ((K%% - 2) * 317, 0)-((K%% - 2) * 317 + 291, 577)
    CMem = _MEMIMAGE(UFOImg&(K%%))
    COff = 0
    WHILE COff < CMem.SIZE
        IF _MEMGET(CMem, CMem.OFFSET + COff + 3, _UNSIGNED _BYTE) < 50 THEN
            _MEMPUT CMem, CMem.OFFSET + COff + 3, 0 AS _UNSIGNED _BYTE 'Alpha
        ELSE
            _MEMPUT CMem, CMem.OFFSET + COff + 3, 120 AS _UNSIGNED _BYTE 'Alpha
        END IF
        COff = COff + 4
    WEND
    _MEMFREE CMem
NEXT K%%
AlienImg& = _NEWIMAGE(42, 110, 32)
_PUTIMAGE , _LOADIMAGE("alien.jpg", 32), AlienImg&
CMem = _MEMIMAGE(AlienImg&)
COff = 0
WHILE COff < CMem.SIZE
    IF _MEMGET(CMem, CMem.OFFSET + COff + 2, _UNSIGNED _BYTE) > 230 AND _MEMGET(CMem, CMem.OFFSET + COff + 1, _UNSIGNED _BYTE) > 230 AND _MEMGET(CMem, CMem.OFFSET + COff, _UNSIGNED _BYTE) > 230 THEN
        _MEMPUT CMem, CMem.OFFSET + COff + 3, 0 AS _UNSIGNED _BYTE 'Alpha
        _MEMPUT CMem, CMem.OFFSET + COff, 0 AS _UNSIGNED _BYTE 'Blue
    ELSE
        _MEMPUT CMem, CMem.OFFSET + COff + 3, 120 AS _UNSIGNED _BYTE 'Alpha
    END IF
    COff = COff + 4
WEND
_MEMFREE CMem
XSound& = _SNDOPEN("xsound.mp3")
XCallSound& = _SNDOPEN("xcalling.mp3")
XMachSound& = _SNDOPEN("xmachine.mp3")

'Zodiac Images
TempImg1& = _LOADIMAGE("zodiac.png", 32)
ZodiacTmpImg& = _NEWIMAGE(12 * ZodWidth%, ZodHeight%, 32)
_DEST ZodiacTmpImg&
FOR K%% = 4 TO 12
    _PUTIMAGE ((K%% - 4) * ZodWidth% + 5, 5)-((K%% - 3) * ZodWidth% - 5, ZodHeight% - 5), TempImg1&, , (((K%% - 1) MOD 3) * 344, ((K%% - 1) \ 3) * 255 + 5)-(((K%% - 1) MOD 3) * 344 + 290, ((K%% - 1) \ 3) * 255 + 5 + 230)
NEXT K%%
FOR K%% = 1 TO 3
    _PUTIMAGE ((K%% + 8) * ZodWidth% + 5, 5)-((K%% + 9) * ZodWidth% - 5, ZodHeight% - 5), TempImg1&, , (((K%% - 1) MOD 3) * 344, ((K%% - 1) \ 3) * 255 + 5)-(((K%% - 1) MOD 3) * 344 + 290, ((K%% - 1) \ 3) * 255 + 5 + 230)
NEXT K%%
CMem = _MEMIMAGE(ZodiacTmpImg&)
COff = 0
WHILE COff < CMem.SIZE
    IF _MEMGET(CMem, CMem.OFFSET + COff + 3, _UNSIGNED _BYTE) > 180 THEN
        _MEMPUT CMem, CMem.OFFSET + COff, 152 AS _UNSIGNED _BYTE 'Blue
        _MEMPUT CMem, CMem.OFFSET + COff + 1, 202 AS _UNSIGNED _BYTE 'Green
        _MEMPUT CMem, CMem.OFFSET + COff + 2, 204 AS _UNSIGNED _BYTE 'Red
    ELSE
        _MEMPUT CMem, CMem.OFFSET + COff, 50 AS _UNSIGNED _BYTE 'Blue
        _MEMPUT CMem, CMem.OFFSET + COff + 1, 50 AS _UNSIGNED _BYTE 'Green
        _MEMPUT CMem, CMem.OFFSET + COff + 2, 100 AS _UNSIGNED _BYTE 'Red
    END IF
    _MEMPUT CMem, CMem.OFFSET + COff + 3, 100 AS _UNSIGNED _BYTE 'Alpha
    COff = COff + 4
WEND
_MEMFREE CMem
_FREEIMAGE TempImg1&
'Zodiac Symbols
TempImg1& = _LOADIMAGE("zodiacsym.png", 32)
FOR K%% = 1 TO 12
    TempImg& = _NEWIMAGE(40, 40, 32)
    _DEST TempImg&
    _PUTIMAGE , TempImg1&, , (((K%% - 1) MOD 4) * 250 + 20, ((K%% - 1) \ 4) * 328 + 40)-(((K%% - 1) MOD 4) * 250 + 20 + 210, ((K%% - 1) \ 4) * 328 + 40 + 180)
    ZodiacSymImg&(K%%) = HardwareImage&(TempImg&)
NEXT K%%
_FREEIMAGE TempImg1&
MysticSound& = _SNDOPEN("holst_n.mp3")

'Beam Image
TempImg& = _NEWIMAGE(501, 51, 32)
_DEST TempImg&
COLOR _RGBA32(200, 200, 100, 70), _RGBA32(200, 200, 100, 70)
CLS
BeamImg& = HardwareImage&(TempImg&)
'Spot Image
TempImg& = _NEWIMAGE(2 * SpotRad% + 1, 2 * SpotRad% + 1, 32)
_DEST TempImg&
COLOR _RGBA32(200, 200, 100, 120), _RGBA32(200, 200, 100, 0)
CLS
CIRCLE (SpotRad%, SpotRad%), SpotRad%
PAINT (SpotRad%, SpotRad%)
SpotImg& = HardwareImage&(TempImg&)
'Spotlight Image
SpotlightTmpImg& = _LOADIMAGE("spotlight.png", 32)
CMem = _MEMIMAGE(SpotlightTmpImg&)
COff = 0
WHILE COff < CMem.SIZE
    IF _MEMGET(CMem, CMem.OFFSET + COff + 3, _UNSIGNED _BYTE) < 100 THEN _MEMPUT CMem, CMem.OFFSET + COff + 3, 0 AS _UNSIGNED _BYTE 'Alpha
    COff = COff + 4
WEND
_MEMFREE CMem
'BlueSkies Image
RedPhoenix& = _LOADIMAGE("Red Phoenix.png", 32)
BluePhoenix& = _NEWIMAGE(200, 200, 32)
_DEST BluePhoenix&
COLOR _RGBA32(100, 100, 100, 100), _RGBA32(100, 100, 100, 0)
CLS
_PUTIMAGE , RedPhoenix&
_SOURCE BluePhoenix&
FOR PX% = 0 TO 199
    FOR PY% = 0 TO 199
        Col~& = POINT(PX%, PY%)
        IF _ALPHA32(Col~&) > 20 THEN
            PSET (PX%, PY%), _RGBA32(20, 20, 250, 200)
        ELSE
            PSET (PX%, PY%), _RGBA32(0, 0, 0, 0)
        END IF
    NEXT PY%
NEXT PX%
QB64TempImg& = _NEWIMAGE(WQB64X%, WQB64Y%, 32)
_DEST QB64TempImg&
COLOR _RGBA32(40, 40, 250, 100), _RGBA32(0, 0, 0, 0)
CLS
_FONT _LOADFONT("arialbd.ttf", 100)
_PRINTSTRING (120, 10), "QB64"
_FONT _LOADFONT("arialbd.ttf", 60)
_PRINTSTRING (10, 140), "Phoenix"
_PRINTSTRING (10, 200), "Edition"
_PUTIMAGE (270, 130)-(470, 330), BluePhoenix&
_FREEIMAGE BluePhoenix&
_FREEIMAGE RedPhoenix&
'Logo Images
FOR K%% = 1 TO 4
    TempImg1& = _NEWIMAGE(102, 108, 32)
    _DEST TempImg1&
    COLOR _RGBA32(0, 0, 0, 54)
    SELECT CASE K%%
        CASE 1
            'Q
            LINE (12, 12)-(36, 84), , BF
            LINE (69, 12)-(87, 84), , BF
            LINE (63, 38)-(68, 84), , BF
            LINE (37, 12)-(68, 25), , BF
            LINE (37, 71)-(62, 84), , BF
            LINE (37, 85)-(62, 99), , BF
        CASE 2
            'B
            LINE (8, 12)-(32, 84), , BF
            LINE (64, 12)-(77, 84), , BF
            LINE (78, 12)-(88, 39), , BF
            LINE (78, 59)-(88, 84), , BF
            LINE (33, 12)-(63, 25), , BF
            LINE (33, 39)-(63, 57), , BF
            LINE (33, 72)-(63, 84), , BF
        CASE 3
            '6
            LINE (12, 12)-(36, 85), , BF
            LINE (68, 44)-(94, 85), , BF
            LINE (37, 12)-(94, 25), , BF
            LINE (37, 44)-(67, 58), , BF
            LINE (37, 71)-(67, 85), , BF
        CASE ELSE
            '4
            LINE (8, 12)-(31, 58), , BF
            LINE (63, 12)-(88, 85), , BF
            LINE (32, 38)-(62, 58), , BF
    END SELECT
    TempImg& = _NEWIMAGE(51, 54, 32)
    _DEST TempImg&
    _PUTIMAGE , TempImg1&
    LogoImg&(K%%) = _COPYIMAGE(TempImg&, 33)
    _FREEIMAGE TempImg1&
    _FREEIMAGE TempImg&
NEXT K%%
BlueSkiesSound& = _SNDOPEN("reeves.mp3")

'Raindrop Image
TempImg& = _NEWIMAGE(2, 3, 32)
_DEST TempImg&
COLOR _RGBA32(150, 120, 20, 140), _RGBA32(100, 100, 100, 0)
CLS
PSET (1, 0)
LINE (0, 1)-(1, 2), , B
DropImg& = HardwareImage&(TempImg&)
'Flower Image
TempImg& = _NEWIMAGE(14, 30, 32)
_DEST TempImg&
_PUTIMAGE , _LOADIMAGE("corn.png", 32)
CornImg& = HardwareImage&(TempImg&)

'Rainbow Image
TempImg& = _NEWIMAGE(501, 301, 32)
_DEST TempImg&
COLOR _RGBA32(255, 0, 0, 0), _RGBA32(0, 0, 0, 0)
CLS
FOR K%% = 0 TO 127
    SELECT CASE K%%
        CASE 0 TO 58
            COLOR _RGBA32(255 - 2 * K%%, 15 + CINT(4.4 * K%%), 0, 80)
        CASE 59 TO 116
            COLOR _RGBA32(0, 255 - 1.8 * (K%% - 58), 15 + CINT(4.4 * (K%% - 58)), 80)
        CASE ELSE
            COLOR _RGBA32(15 + CINT(13.5 * (K%% - 116)), 0, 200 - 2 * (K%% - 116), 80)
    END SELECT
    CIRCLE (249, 300), 250 - CINT(80 * K%% / 127)
    CIRCLE (250, 300), 250 - CINT(80 * K%% / 127)
    CIRCLE (251, 300), 250 - CINT(80 * K%% / 127)
NEXT K%%
RainbowImg& = HardwareImage&(TempImg&)

'Flying Bee Image
TempImg1& = _LOADIMAGE("QB64Bee-Alpha.png", 32)
WBee% = _WIDTH(TempImg1&) - 1
HBee% = _HEIGHT(TempImg1&) - 1
TempImg& = _NEWIMAGE(_WIDTH(TempImg1&), _HEIGHT(TempImg1&), 32)
_DEST TempImg&
COLOR _RGBA32(200, 200, 200, 150), RGBA32(0, 0, 0, 0)
CLS
_PUTIMAGE , TempImg1&
_FREEIMAGE TempImg1&
BeeImg& = HardwareImage&(TempImg&)
'Hive Image
TempImg2& = _LOADIMAGE("branch.png", 32)
CMem = _MEMIMAGE(TempImg2&)
COff = 0
WHILE COff < CMem.SIZE
    B0~%% = _MEMGET(CMem, CMem.OFFSET + COff, _UNSIGNED _BYTE) 'Blue
    B1~%% = _MEMGET(CMem, CMem.OFFSET + COff + 1, _UNSIGNED _BYTE) 'Green
    B2~%% = _MEMGET(CMem, CMem.OFFSET + COff + 2, _UNSIGNED _BYTE) 'Red
    B3~%% = _MEMGET(CMem, CMem.OFFSET + COff + 3, _UNSIGNED _BYTE) 'Alpha
    IF B0~%% + B1~%% + B2~%% > 690 THEN
        _MEMPUT CMem, CMem.OFFSET + COff + 3, 0 AS _UNSIGNED _BYTE 'Alpha
    END IF
    COff = COff + 4
WEND
_MEMFREE CMem
TempImg1& = _LOADIMAGE("blackhive.png", 32)
CMem = _MEMIMAGE(TempImg1&)
COff = 0
WHILE COff < CMem.SIZE
    B0~%% = _MEMGET(CMem, CMem.OFFSET + COff, _UNSIGNED _BYTE) 'Blue
    B1~%% = _MEMGET(CMem, CMem.OFFSET + COff + 1, _UNSIGNED _BYTE) 'Green
    B2~%% = _MEMGET(CMem, CMem.OFFSET + COff + 2, _UNSIGNED _BYTE) 'Red
    B3~%% = _MEMGET(CMem, CMem.OFFSET + COff + 3, _UNSIGNED _BYTE) 'Alpha
    IF B0~%% + B1~%% + B2~%% < 30 THEN
        _MEMPUT CMem, CMem.OFFSET + COff + 3, 0 AS _UNSIGNED _BYTE 'Alpha
    END IF
    COff = COff + 4
WEND
_MEMFREE CMem
TempImg& = _NEWIMAGE(HiveWidth% + 1, HiveHeight% + 1, 32)
_DEST TempImg&
_PUTIMAGE (600, 150), TempImg1&
_PUTIMAGE (0, 0), TempImg2&
HiveImg& = HardwareImage&(TempImg&)
_FREEIMAGE TempImg2&
_FREEIMAGE TempImg1&
HiveSound& = _SNDOPEN("beehive.mp3")

'Fountain Drop Image
TempImg1& = _LOADIMAGE("droplet.png", 32)
W% = _WIDTH(TempImg1&) - 1
H% = _HEIGHT(TempImg1&) - 1
TempImg& = _NEWIMAGE(W% + 1, H% + 1, 32)
_DEST TempImg&
_PUTIMAGE , TempImg1&
CMem = _MEMIMAGE(TempImg&)
COff = 0
WHILE COff < CMem.SIZE
    IF _MEMGET(CMem, CMem.OFFSET + COff + 3, _UNSIGNED _BYTE) <> 0 THEN _MEMPUT CMem, CMem.OFFSET + COff + 3, 80 AS _UNSIGNED _BYTE 'Alpha
    COff = COff + 4
WEND
DropletImg& = HardwareImage&(TempImg&)
' _MEMFREE CMem Already freed by HardwareImage& (_freeimage)
_FREEIMAGE TempImg1&
'Fountain Image
FountainImg& = _LOADIMAGE("fountain2.png", 33)

'Windmill Sails Image
TempImg& = _NEWIMAGE(300, 300, 32)
_DEST TempImg&
_PUTIMAGE , _LOADIMAGE("sails.png", 32)
SailsImg& = HardwareImage&(TempImg&)

'Pi Image
TempImg1& = _LOADIMAGE("pi1.png", 32)
PiTempImg& = _NEWIMAGE(PiSizeLess1% + 1, PiSizeLess1% + 1, 32)
_DEST PiTempImg&
_PUTIMAGE , TempImg1&
_FREEIMAGE TempImg1&
PiMem = _MEMIMAGE(PiTempImg&) 'Will not allow hardware image for _MEM object processing
PiOff = 0
WHILE PiOff < PiMem.SIZE
    IF _MEMGET(PiMem, PiMem.OFFSET + PiOff + 1, _UNSIGNED _BYTE) > 20 THEN
        _MEMPUT PiMem, PiMem.OFFSET + PiOff + 3, 255 AS _UNSIGNED _BYTE 'Alpha
        _MEMPUT PiMem, PiMem.OFFSET + PiOff + 2, 0 AS _UNSIGNED _BYTE 'Red
        _MEMPUT PiMem, PiMem.OFFSET + PiOff + 1, 255 AS _UNSIGNED _BYTE 'Green
        _MEMPUT PiMem, PiMem.OFFSET + PiOff + 0, 0 AS _UNSIGNED _BYTE 'Blue
    ELSE
        _MEMPUT PiMem, PiMem.OFFSET + PiOff + 3, 0 AS _UNSIGNED _BYTE 'Alpha
    END IF
    PiOff = PiOff + 4
WEND
PiImg& = _COPYIMAGE(PiTempImg&, 33)

'Cloud Images
FOR K%% = 0 TO 15
    READ X1%, Y1%, X2%, Y2%
    W% = X2% - X1% + 1 'The +1's are needed
    H% = Y2% - Y1% + 1
    TempImg& = _NEWIMAGE(W%, H%, 32)
    _DEST TempImg&
    _PUTIMAGE (0, 0)-(W% - 1, H% - 1), _LOADIMAGE("mccloud.jpg", 32), , (X1%, Y1%)-(X2%, Y2%)
    CMem = _MEMIMAGE(TempImg&) 'Don't need to DIM CMem each image
    COff = 0
    WHILE COff < CMem.SIZE 'The clouds different this way from previous) - must be because of placing onto screen peviously
        B0~%% = _MEMGET(CMem, CMem.OFFSET + COff, _UNSIGNED _BYTE) 'Blue
        B1~%% = _MEMGET(CMem, CMem.OFFSET + COff + 1, _UNSIGNED _BYTE) 'Green
        B2~%% = _MEMGET(CMem, CMem.OFFSET + COff + 2, _UNSIGNED _BYTE) 'Red
        IF B2~%% >= 30 AND B2~%% <= 80 AND B1~%% >= 170 AND B1~%% <= 210 AND B0~%% >= 230 THEN
            _MEMPUT CMem, CMem.OFFSET + COff + 3, 0 AS _UNSIGNED _BYTE 'Alpha
        ELSE
            _MEMPUT CMem, CMem.OFFSET + COff + 3, 100 AS _UNSIGNED _BYTE 'Alpha
            IF K%% = 0 THEN 'Dark Rain-cloud
                _MEMPUT CMem, CMem.OFFSET + COff, CINT(0.7 * B0~%%) AS _UNSIGNED _BYTE
                _MEMPUT CMem, CMem.OFFSET + COff + 1, CINT(0.7 * B1~%%) AS _UNSIGNED _BYTE
                _MEMPUT CMem, CMem.OFFSET + COff + 2, CINT(0.7 * B2~%%) AS _UNSIGNED _BYTE
            END IF
        END IF
        COff = COff + 4
    WEND
    IF K%% >= 12 THEN
        READ X1%, Y1%, X2%, Y2%
        FOR N% = X1% TO X2%
            FOR M% = Y1% TO Y2%
                COff = 4 * (N% + M% * W%)
                _MEMPUT CMem, CMem.OFFSET + COff + 3, 0 AS _UNSIGNED _BYTE 'Alpha
            NEXT M%
        NEXT N%
        IF K%% = 15 THEN
            READ X1%, Y1%, X2%, Y2%
            FOR N% = X1% TO X2%
                FOR M% = Y1% TO Y2%
                    COff = 4 * (N% + M% * W%)
                    _MEMPUT CMem, CMem.OFFSET + COff + 3, 0 AS _UNSIGNED _BYTE 'Alpha
                NEXT M%
            NEXT N%
            READ X1%, Y1%, X2%, Y2%
            FOR N% = X1% TO X2%
                FOR M% = Y1% TO Y2%
                    COff = 4 * (N% + M% * W%)
                    _MEMPUT CMem, CMem.OFFSET + COff + 3, 0 AS _UNSIGNED _BYTE 'Alpha
                NEXT M%
            NEXT N%
        END IF
        _MEMFREE CMem
    END IF
    Clouds&(K%%) = HardwareImage&(TempImg&)
NEXT K%%

'Background Images
'Moon Image
MoonTmpImg& = _NEWIMAGE(89, 99, 32)
_DEST MoonTmpImg&
COLOR _RGBA32(200, 200, 200, 0), RGBA32(0, 0, 0, 0)
CLS
_PUTIMAGE , _LOADIMAGE("moon.png", 32)
CMem = _MEMIMAGE(MoonTmpImg&)
COff = 0
WHILE COff < CMem.SIZE
    B0~%% = _MEMGET(CMem, CMem.OFFSET + COff, _UNSIGNED _BYTE)
    B1~%% = _MEMGET(CMem, CMem.OFFSET + COff + 1, _UNSIGNED _BYTE)
    B2~%% = _MEMGET(CMem, CMem.OFFSET + COff + 2, _UNSIGNED _BYTE)
    IF B0~%% + B1~%% + B2~%% < 80 THEN
        _MEMPUT CMem, CMem.OFFSET + COff + 3, 0 AS _UNSIGNED _BYTE 'Alpha
    END IF
    COff = COff + 4
WEND
_MEMFREE CMem
'Background Mask Image
MaskTmpImg& = _NEWIMAGE(XScreen%, YScreen%, 32)
_DEST MaskTmpImg&
COLOR _RGB32(100, 100, 100), _RGBA32(0, 0, 0, 50)

'Initialisations
'Set clouds start positions (some to left of screen) & speeds
FOR K%% = 1 TO 15
    CloudPos!(K%%, 0) = (RND * (XScreen% + _WIDTH(Clouds&(K%%)))) - _WIDTH(Clouds&(K%%)) - 5
    CloudPos!(K%%, 1) = RND * 350 + 10
    CloudPos!(K%%, 2) = 0.3 + 0.03 * (RND - 0.5)
    CloudGo%%(K%%) = True
NEXT K%%
CloudPos!(0, 0) = -_WIDTH(Clouds&(0)) - 5
CloudPos!(0, 1) = RND * 350 + 10
CloudPos!(0, 2) = 0.3 + 0.03 * (RND - 0.5)
CloudGo%%(0) = True
Puddle% = YScreen% - 110
FOR N% = 0 TO 500
    Raindrops!(N%, 1) = CINT((Puddle% - (CloudPos!(0, 1) + 36)) * RND)
    Raindrops!(N%, 0) = 5 + CINT(86 * RND)
NEXT N%

'Pi coordinates
Phi! = _PI(0.1)
'Initial Pi colour
RedGreenBlue!(2) = 30 + CINT(223 * RND)
RedGreenBlue!(1) = 30 + CINT(223 * RND)
RedGreenBlue!(0) = 30 + CINT(223 * RND)
RedGreenBlue!(5) = -0.701
RedGreenBlue!(4) = -0.797
RedGreenBlue!(3) = -0.887

'Flowers
FOR K%% = 0 TO 9
    FloraCount%(K%%) = 0
NEXT K%%
Blooming%% = False

'Fountain
FOR N% = 0 TO 500
    Fountain!(N%, 0) = 0
    Fountain!(N%, 1) = 100 'Start height
    Fountain!(N%, 1) = -101
    Fountain!(N%, 3) = 0.2 + 0.15 * (RND - 0.5)
    Fountain!(N%, 4) = 0.6 + 0.2 * (RND - 0.5)
    Fountain!(N%, 5) = _PI(1) + _PI(2) * RND
NEXT N%
WFount% = _WIDTH(DropletImg&) - 1
HFount% = _HEIGHT(DropletImg&) - 1
FX1% = FountX% - 8
FX2% = 8 + FountX%
FY1% = FountY% - 100

CALL OffScreen
DispOrder%%(0) = 10
FOR K%% = 1 TO 9
    DispOrder%%(K%%) = K%%
NEXT K%%
MinGrave%% = 0
DispIndex%% = 10
PauseCount% = 0
PauseStop% = 600
DoBuzz%% = False
Swarm% = 0
DoSwarm% = 0
PauseSwarm% = 150
DoFount%% = False
PauseFont% = 300
WaitFont% = 0
ZBow1! = ZOffset% - 500

'Screen (Hardware 2nd)
SCREEN _NEWIMAGE(XScreen%, YScreen%, 32)
_SCREENMOVE 20, 5
_DEST 0
_DISPLAYORDER _SOFTWARE , _HARDWARE
'Draw Background
'Background is software and is only put once
'Other images are hardware and put each cycle
Ysun% = CINT(700 * SunSize% / 1000)
_PUTIMAGE (XScreen% - SunSize%, 0)-(XScreen% - 1, Ysun%), _LOADIMAGE("brightsun.png", 32)
LINE (0, 0)-(XScreen% - SunSize%, YScreen% - 1), _RGB32(58, 161, 255), BF
LINE (XScreen% - SunSize%, Ysun%)-(XScreen% - 1, YScreen% - 1), _RGB32(58, 161, 255), BF
_PUTIMAGE (100, 70)-(154, 130), MoonTmpImg&
_FREEIMAGE MoonTmpImg&
_PUTIMAGE (0, YScreen% - 1 - 350)-(XScreen% - 1, YScreen% - 1), _LOADIMAGE("landscape2a.png", 32)
FOR K%% = 1 TO 5
    _PUTIMAGE (680 + K%% * 70, YScreen% - 140 - ABS(K%% - 3) * 14), _LOADIMAGE("gravestone.png", 32)
    _MAPTRIANGLE (0, 0)-(57, 0)-(0, 69), _LOADIMAGE("soil.png", 32) TO(678 + K%% * 70, YScreen% - 42 - ABS(K%% - 3) * 14)-(678 + K%% * 70 + 58, YScreen% - 42 - ABS(K%% - 3) * 14)-(678 + K%% * 70 - 2, YScreen% - 42 - ABS(K%% - 3) * 14 + 69)
    _MAPTRIANGLE (57, 69)-(0, 69)-(57, 0), _LOADIMAGE("soil.png", 32) TO(678 + K%% * 70 + 60, YScreen% - 42 - ABS(K%% - 3) * 14 + 69)-(678 + K%% * 70 - 2, YScreen% - 42 - ABS(K%% - 3) * 14 + 69)-(678 + K%% * 70 + 58, YScreen% - 42 - ABS(K%% - 3) * 14)
NEXT K%%
_PUTIMAGE (890, YScreen% - 154)-(944, YScreen% - 55), _LOADIMAGE("gravestone.png", 32)
_PUTIMAGE (324, YScreen% - 100), _LOADIMAGE("pond.png", 32)
_PUTIMAGE (LampX% - 20, LampY% - 20), SpotlightTmpImg&
SpotlightImg& = HardwareImage&(SpotlightTmpImg&)
_PUTIMAGE , MaskTmpImg&
_FREEIMAGE MaskTmpImg&
_FREEIMAGE MoonTmpImg&
TempImg& = _LOADIMAGE("windmill.png", 32) 'Windmill must not occlude flowers or be occluded by spotlight beam
CMem = _MEMIMAGE(TempImg&)
WHILE COff < CMem.SIZE
    IF _MEMGET(CMem, CMem.OFFSET + COff + 3, _UNSIGNED _BYTE) < 230 THEN _MEMPUT CMem, CMem.OFFSET + COff + 3, 0 AS _UNSIGNED _BYTE 'Alpha
    COff = COff + 4
WEND
_MEMFREE CMem
_PUTIMAGE (WindX%, WindY%)-(WindX% + CINT(WindHeight% * _WIDTH(TempImg&) / _HEIGHT(TempImg&)), WindY% + WindHeight%), TempImg&
_FREEIMAGE TempImg&

$CHECKING:OFF
'Checking off to help quicken up _MEM processing & reduce CPU load

'Now actually run working loop
WHILE INKEY$ = "" 'Press any key to terminate
    _LIMIT 30

    'Pi position & orientation
    X0! = 200 * COS(Alpha!)
    Y0! = 70 * COS(Beta!) + 105
    'Rotate in Z-axis
    PX1! = -PiDisp%
    PY1! = PiDisp%
    CALL Twist(Theta!, PX1!, PY1!)
    PX2! = PiDisp%
    PY2! = PiDisp%
    CALL Twist(Theta!, PX2!, PY2!)
    PX3! = -PiDisp%
    PY3! = -PiDisp%
    CALL Twist(Theta!, PX3!, PY3!)
    PX4! = PiDisp%
    PY4! = -PiDisp%
    CALL Twist(Theta!, PX4!, PY4!)
    'Rotate in Y-axis
    PZ1! = 0
    CALL Twist(Phi!, PZ1!, PX1!)
    PZ2! = 0
    CALL Twist(Phi!, PZ2!, PX2!)
    PZ3! = 0
    CALL Twist(Phi!, PZ3!, PX3!)
    PZ4! = 0
    CALL Twist(Phi!, PZ4!, PX4!)
    'Rotate in X-axis
    CALL Twist(Chi!, PY1!, PZ1!)
    CALL Twist(Chi!, PY2!, PZ2!)
    CALL Twist(Chi!, PY3!, PZ3!)
    CALL Twist(Chi!, PY4!, PZ4!)
    PX1! = PX1! + X0!
    PX2! = PX2! + X0!
    PX3! = PX3! + X0!
    PX4! = PX4! + X0!
    PY1! = PY1! + Y0!
    PY2! = PY2! + Y0!
    PY3! = PY3! + Y0!
    PY4! = PY4! + Y0!
    PZ1! = PZ1! + ZOffset%
    PZ2! = PZ2! + ZOffset%
    PZ3! = PZ3! + ZOffset%
    PZ4! = PZ4! + ZOffset%

    'Draw Images
    '_DEST 0 Not needed

    'Rainbow Image
    IF CloudGo%%(0) AND CloudPos!(0, 0) > 10 AND CloudPos!(0, 0) < 320 THEN
        _MAPTRIANGLE (0, 0)-(499, 0)-(0, 299), RainbowImg& TO(-700, 50, ZBow%)-(-300, 50, ZBow1!)-(-700, -300, ZBow%)
        _MAPTRIANGLE (499, 299)-(0, 299)-(499, 0), RainbowImg& TO(-300, -300, ZBow1!)-(-700, -300, ZBow%)-(-300, 50, ZBow1!)
    END IF

    'Animations
    SELECT CASE DoAnime%%
        CASE 1
            'Concorde
            _PUTIMAGE (DispTrans!(0, 0), DispTrans!(0, 1)), ConcordeImg&
        CASE 2
            'Ee, Tea!
            _PUTIMAGE (DispTrans!(0, 0), DispTrans!(0, 1)), AmblinImg&
            _MAPTRIANGLE (0, 0)-(26, 0)-(0, 26), SpokesImg& TO(DispTrans!(1, 0), DispTrans!(1, 1))-(DispTrans!(2, 0), DispTrans!(2, 1))-(DispTrans!(3, 0), DispTrans!(3, 1))
            _MAPTRIANGLE (26, 26)-(0, 26)-(26, 0), SpokesImg& TO(DispTrans!(4, 0), DispTrans!(4, 1))-(DispTrans!(3, 0), DispTrans!(3, 1))-(DispTrans!(2, 0), DispTrans!(2, 1))
            _MAPTRIANGLE (0, 0)-(26, 0)-(0, 26), SpokesImg& TO(DispTrans!(5, 0), DispTrans!(5, 1))-(DispTrans!(6, 0), DispTrans!(6, 1))-(DispTrans!(7, 0), DispTrans!(7, 1))
            _MAPTRIANGLE (26, 26)-(0, 26)-(26, 0), SpokesImg& TO(DispTrans!(8, 0), DispTrans!(8, 1))-(DispTrans!(7, 0), DispTrans!(7, 1))-(DispTrans!(6, 0), DispTrans!(6, 1))
        CASE 3
            'Star Trek
            _MAPTRIANGLE (0, 0)-(452, 0)-(0, 196), StarTrekImg& TO(DispTrans!(1, 0), DispTrans!(1, 1), DispTrans!(1, 2))-(DispTrans!(2, 0), DispTrans!(1, 1), DispTrans!(1, 2))-(DispTrans!(1, 0), DispTrans!(3, 1), DispTrans!(1, 2))
            _MAPTRIANGLE (452, 196)-(0, 196)-(452, 0), StarTrekImg& TO(DispTrans!(2, 0), DispTrans!(3, 1), DispTrans!(1, 2))-(DispTrans!(1, 0), DispTrans!(3, 1), DispTrans!(1, 2))-(DispTrans!(2, 0), DispTrans!(1, 1), DispTrans!(1, 2))
        CASE 4
            'ISS
            _PUTIMAGE (DispTrans!(0, 0), DispTrans!(0, 1)), ISSImg&
        CASE 5
            'Meteors
            FOR K%% = 0 TO 30
                XDum1! = Perseids!(K%%, 0) - Perseids!(K%%, 6)
                XDum! = Perseids!(K%%, 0) + Perseids!(K%%, 6)
                YDum1! = Perseids!(K%%, 1) - Perseids!(K%%, 6) + 300
                YDum! = Perseids!(K%%, 1) + Perseids!(K%%, 6) + 300
                _MAPTRIANGLE (0, 0)-(35, 0)-(0, 35), MeteorImg& TO(XDum1!, YDum!, Perseids!(K%%, 2))-(XDum!, YDum!, Perseids!(K%%, 2))-(XDum1!, YDum1!, Perseids!(K%%, 2))
                _MAPTRIANGLE (35, 35)-(0, 35)-(35, 0), MeteorImg& TO(XDum!, YDum1!, Perseids!(K%%, 2))-(XDum1!, YDum1!, Perseids!(K%%, 2))-(XDum!, YDum!, Perseids!(K%%, 2))
            NEXT K%%
        CASE 6
            'Transit
            _PUTIMAGE (DispTrans!(0, 0), DispTrans!(0, 1)), VenusImg&
        CASE 7
            'Thunderbird
            IF BombsAway%% = 2 THEN
                _PUTIMAGE (MillBombX1%, MillBombY1%), MillBombImg&
            ELSE
                _PUTIMAGE (DispTrans!(1, 0), DispTrans!(1, 1)), BombImg&
            END IF
            _PUTIMAGE (DispTrans!(3, 0), DispTrans!(3, 1))-(DispTrans!(4, 0), DispTrans!(4, 1)), ChainImg&, , (0, DispTrans!(5, 1))-(9, 399)
            _PUTIMAGE (DispTrans!(2, 0), DispTrans!(2, 1)), MagnetImg&
            _PUTIMAGE (DispTrans!(0, 0), DispTrans!(0, 1)), ThunderImg&
        CASE 8
            'Zodiac
            FOR N% = 1 TO 100
                X1! = (N% - 1) * 12 * ZodWidth% / 100
                X2! = N% * 12 * ZodWidth% / 100
                Y2! = 0
                Y4! = ZodHeight%
                Psi! = _PI(0.5) + (N% - 1) * _PI(2) / 100 - Pip!
                DeltaPsi! = _PI(2) / 100
                X11! = ZRad! * COS(Psi!)
                Z11! = ZRad! * SIN(Psi!) + ZOffset% - 20
                Y12! = 250
                X12! = ZRad! * COS(Psi! + DeltaPsi!)
                Z12! = ZRad! * SIN(Psi! + DeltaPsi!) + ZOffset% - 20
                Y14! = Y12! - ZodHeight%
                _MAPTRIANGLE (X1!, Y2!)-(X2!, Y2!)-(X1!, Y4!), ZodiacImg& TO(X11!, Y12!, Z11!)-(X12!, Y12!, Z12!)-(X11!, Y14!, Z11!)
                _MAPTRIANGLE (X2!, Y4!)-(X1!, Y4!)-(X2!, Y2!), ZodiacImg& TO(X12!, Y14!, Z12!)-(X11!, Y14!, Z11!)-(X12!, Y12!, Z12!)
            NEXT N%
            _PUTIMAGE (896, 680), ZodiacSymImg&(Sym%%)
        CASE 9
            'UFO
            _MAPTRIANGLE (0, 0)-(299, 0)-(0, 156), UFOImg&(UNorm%%) TO(DispTrans!(1, 0), DispTrans!(1, 1), DispTrans!(1, 2))-(DispTrans!(2, 0), DispTrans!(2, 1), DispTrans!(1, 2))-(DispTrans!(3, 0), DispTrans!(3, 1), DispTrans!(1, 2))
            _MAPTRIANGLE (299, 156)-(0, 156)-(299, 0), UFOImg&(UNorm%%) TO(DispTrans!(4, 0), DispTrans!(4, 1), DispTrans!(1, 2))-(DispTrans!(3, 0), DispTrans!(3, 1), DispTrans!(1, 2))-(DispTrans!(2, 0), DispTrans!(2, 1), DispTrans!(1, 2))
        CASE 10
            'Spotlight (Would be better 3D)
            IF DispTrans!(0, 0) > 0 THEN
                _PUTIMAGE (QB64X%, QB64Y%), QB64Img&
                _PUTIMAGE (DispTrans!(0, 0), DispTrans!(0, 1)), SpotImg&
                FOR N% = 1 TO 100
                    F9! = DispTrans!(1, 0) - (N% - 1) * SpotInc!
                    G9! = DispTrans!(1, 0) - N% * SpotInc!
                    _MAPTRIANGLE (0, 0)-(500, 0)-(0, 50), BeamImg& TO(SpotLight!(0) - SpotRad% * SIN(G9!), SpotLight!(1) - SpotRad% * COS(G9!))-(LampX%, LampY%)-(SpotLight!(0) - SpotRad% * SIN(F9!), SpotLight!(1) - SpotRad% * COS(F9!))
                NEXT N%
                _FREEIMAGE QB64Img&
                _PUTIMAGE (LampX% - 20, LampY% - 20), SpotlightImg&
                FOR K%% = 1 TO 4
                    _PUTIMAGE (752 + K%% * 70, 670), LogoImg&(K%%)
                NEXT K%%
            END IF
    END SELECT

    'Clouds
    FOR K%% = 0 TO 15
        IF CloudGo%%(K%%) THEN
            _PUTIMAGE (CINT(CloudPos!(K%%, 0)), CINT(CloudPos!(K%%, 1))), Clouds&(K%%)
            IF K%% = 0 AND (CloudPos!(0, 0) < MillBombX1% - 100 OR CloudPos!(0, 0) > MillBombX1% + 130) THEN
                'Rain
                FOR N% = 0 TO 500
                    _PUTIMAGE (CINT(CloudPos!(0, 0) + Raindrops!(N%, 0)), CINT(CloudPos!(0, 1) + 36 + Raindrops!(N%, 1))), DropImg&
                NEXT N%
            END IF
        END IF
    NEXT K%%

    'Flowers
    FOR K%% = 0 TO 9
        IF FloraCount%(K%%) > 1 AND FloraCount%(K%%) < 300 THEN
            _PUTIMAGE (Flora!(K%%, 3), Flora!(K%%, 4))-(Flora!(K%%, 5), Flora!(K%%, 1)), CornImg&
        END IF
    NEXT K%%

    'Pi
    _MAPTRIANGLE _SEAMLESS(0, 0)-(PiSizeLess1%, 0)-(0, PiSizeLess1%), PiImg& TO(PX1!, PY1!, PZ1!)-(PX2!, PY2!, PZ2!)-(PX3!, PY3!, PZ3!)
    _MAPTRIANGLE _SEAMLESS(PiSizeLess1%, PiSizeLess1%)-(0, PiSizeLess1%)-(PiSizeLess1%, 0), PiImg& TO(PX4!, PY4!, PZ4!)-(PX3!, PY3!, PZ3!)-(PX2!, PY2!, PZ2!)
    _FREEIMAGE PiImg&

    'Hive & Bees
    _MAPTRIANGLE (0, 0)-(HiveWidth%, 0)-(0, HiveHeight%), HiveImg& TO(HX1%, HY1%, ZOffset%)-(HX2%, HY1%, ZOffset%)-(HX1%, HY3%, ZOffset%)
    _MAPTRIANGLE (HiveWidth%, HiveHeight%)-(0, HiveHeight%)-(HiveWidth%, 0), HiveImg& TO(HX2%, HY3%, ZOffset%)-(HX1%, HY3%, ZOffset%)-(HX2%, HY1%, ZOffset%)
    FOR N% = 0 TO 500
        IF Buzz%%(N%) THEN
            'z-axiz rotation about x = -r/2 (epsilon):
            XDum! = QB64Bees!(N%, 0) + RBee% / 2
            YDum! = 0
            CALL Twist(QB64Bees!(N%, 4), XDum!, YDum!)
            'y-axis rotation about x = -r/2 (zeta):
            ZDum! = QB64Bees!(N%, 2)
            CALL Twist(Zeta!, XDum!, ZDum!)
            ZDum! = ZOffset% + ZDum!
            XDum1! = BeeEntX% + XDum! - 10
            XDum! = BeeEntX% + XDum! + 10
            YDum1! = BeeEntY% + YDum! - 10
            YDum! = BeeEntY% + YDum! + 10
            _MAPTRIANGLE (0, 0)-(WBee%, 0)-(0, HBee%), BeeImg& TO(XDum1!, YDum!, ZDum!)-(XDum!, YDum!, ZDum!)-(XDum1!, YDum1!, ZDum!)
            _MAPTRIANGLE (WBee%, HBee%)-(0, HBee%)-(WBee%, 0), BeeImg& TO(XDum!, YDum1!, ZDum!)-(XDum1!, YDum1!, ZDum!)-(XDum!, YDum!, ZDum!)
        END IF
    NEXT N%

    'Fountain
    _MAPTRIANGLE (0, 0)-(89, 0)-(0, 321), FountainImg& TO(FX1%, FountY%, ZOffset%)-(FX2%, FountY%, ZOffset%)-(FX1%, FY1%, ZOffset%)
    _MAPTRIANGLE (89, 321)-(0, 321)-(90, 0), FountainImg& TO(FX2%, FY1%, ZOffset%)-(FX1%, FY1%, ZOffset%)-(FX2%, FountY%, ZOffset%)
    FOR N% = 0 TO 500
        IF Fountain!(N%, 1) > -100 THEN
            ZDum! = Fountain!(N%, 2) + ZOffset%
            XDum1! = Fountain!(N%, 6) - 4
            XDum! = Fountain!(N%, 6) + 4
            YDum1! = Fountain!(N%, 1) - 4 + FountY%
            YDum! = Fountain!(N%, 1) + 4 + FountY%
            _MAPTRIANGLE (0, 0)-(WFount%, 0)-(0, HFount%), DropletImg& TO(XDum1!, YDum1!, ZDum!)-(XDum!, YDum1!, ZDum!)-(XDum1!, YDum!, ZDum!)
            _MAPTRIANGLE (WFount%, HFount%)-(0, HFount%)-(WFount%%, 0), DropletImg& TO(XDum!, YDum!, ZDum!)-(XDum1!, YDum!, ZDum!)-(XDum!, YDum1!, ZDum!)
        END IF
    NEXT N%

    'Windmill
    _MAPTRIANGLE _SEAMLESS(0, 0)-(299, 0)-(0, 299), SailsImg& TO(WX1!, WY1!, WZ1!)-(WX2!, WY2!, WZ2!)-(WX3!, WY3!, WZ3!)
    _MAPTRIANGLE _SEAMLESS(299, 299)-(0, 299)-(299, 0), SailsImg& TO(WX4!, WY4!, WZ4!)-(WX3!, WY3!, WZ3!)-(WX2!, WY2!, WZ2!)

    'Graven Images
    IF MinGrave%% > 0 THEN
        M1% = 110 - (GraveCount% - GraveDisp%)
        M2% = M1% + 15
        FOR K%% = MinGrave%% TO MaxGrave%%
            GX% = 756 + (K%% - 1) * 70
            GY% = 650 + 109
            SELECT CASE GraveCount%
                CASE GraveDisp% + 110 'Raise & disappear are set at 110 cycles
                    'Finish
                    _FREEIMAGE GraveImg&(K%%, 0)
                    _FREEIMAGE GraveImg&(K%%, 1)
                    MinGrave%% = 0
                CASE IS > GraveDisp%
                    'Disappear into thin air - CMem manipulation for each image displayed
                    _FREEIMAGE GraveImg&(K%%, 1)
                    CMem = _MEMIMAGE(GraveImg&(K%%, 0))
                    FOR M% = M1% TO M2%
                        IF M% <= 109 THEN
                            FOR N% = 0 TO 41
                                COff = 4 * (N% + M% * 42) + CMem.OFFSET
                                IF _MEMGET(CMem, COff, _UNSIGNED _BYTE) > 0 THEN _MEMPUT CMem, COff + 3, (M2% - M%) * 160 / 15 AS _UNSIGNED _BYTE 'Alpha (Use Blue as marker)
                            NEXT N%
                        END IF
                    NEXT M%
                    _MEMFREE CMem
                    GraveImg&(K%%, 1) = _COPYIMAGE(GraveImg&(K%%, 0), 33)
                    _PUTIMAGE (GX%, 650), GraveImg&(K%%, 1)
                CASE IS < 110 'Grave images timed on GraveCount% not AnimeCount%
                    'Raise from the Dead
                    _PUTIMAGE (GX%, GY% - GraveCount%)-(GX% + 41, GY%), GraveImg&(K%%, 1), , (0, 0)-(41, GraveCount%)
                CASE ELSE
                    'Full image Displayed
                    _PUTIMAGE (GX%, 650), GraveImg&(K%%, 1)
            END SELECT
        NEXT K%%
        GraveCount% = GraveCount% + 1
    END IF

    _DISPLAY

    'Now data manipulations
    'Pi Image Colour
    'The Red/Green/Blue parameters of the software Pi image are set by _MEMPUT statements of the _MEM object
    '_MEM processing can only be done on software images
    PiOff = 0
    WHILE PiOff < PiMem.SIZE
        IF _MEMGET(PiMem, PiMem.OFFSET + PiOff + 3, _UNSIGNED _BYTE) <> 0 THEN
            _MEMPUT PiMem, PiMem.OFFSET + PiOff + 2, CINT(RedGreenBlue!(0)) AS _UNSIGNED _BYTE 'Red
            _MEMPUT PiMem, PiMem.OFFSET + PiOff + 1, CINT(RedGreenBlue!(1)) AS _UNSIGNED _BYTE 'Green
            _MEMPUT PiMem, PiMem.OFFSET + PiOff + 0, CINT(RedGreenBlue!(2)) AS _UNSIGNED _BYTE 'Blue
        END IF
        PiOff = PiOff + 4
    WEND
    PiImg& = _COPYIMAGE(PiTempImg&, 33)
    'The line above copies the Pi software image to hardware, ready for display
    'The _MEM processing of the software image and then copy to hardware at each cycle
    'is done for all images that need real-time image manipulation
    'Here we sequence the Red/Green/Blue parameters of the software Pi image
    RedGreenBlue!(2) = RedGreenBlue!(2) + RedGreenBlue!(5)
    IF (RedGreenBlue!(2) < 30 AND RedGreenBlue!(5) < 0) OR (RedGreenBlue!(2) > 253 AND RedGreenBlue!(5) > 0) THEN RedGreenBlue!(5) = -RedGreenBlue!(5)
    RedGreenBlue!(1) = RedGreenBlue!(1) + RedGreenBlue!(4)
    IF (RedGreenBlue!(1) < 30 AND RedGreenBlue!(4) < 0) OR (RedGreenBlue!(1) > 253 AND RedGreenBlue!(4) > 0) THEN RedGreenBlue!(4) = -RedGreenBlue!(4)
    RedGreenBlue!(0) = RedGreenBlue!(0) + RedGreenBlue!(3)
    IF (RedGreenBlue!(0) < 30 AND RedGreenBlue!(3) < 0) OR (RedGreenBlue!(0) > 253 AND RedGreenBlue!(3) > 0) THEN RedGreenBlue!(3) = -RedGreenBlue!(3)
    'Pi rotation angles
    Theta! = PiBand!(Theta! - 0.05)
    Phi! = PiBand!(Phi! + 0.02)
    Chi! = PiBand!(Chi! + 0.022)
    Alpha! = PiBand!(Alpha! + 0.015)
    Beta! = PiBand!(Beta! + 0.017)
    'Animation Parameters
    SELECT CASE DoAnime%%
        CASE 0
            PauseCount% = PauseCount% + 1
            IF PauseCount% = PauseStop% THEN
                PauseCount% = 0
                PauseStop% = 150 + INT(RND * 200)
                RANDOMIZE (TIMER)
                IF DispIndex%% = 10 THEN
                    DispIndex%% = 0
                    FOR K%% = 1 TO 10
                        K3%% = 1 + INT(RND * 9)
                        K4%% = 1 + INT(RND * 9)
                        IF K3%% <> K4%% THEN SWAP DispOrder%%(K3%%), DispOrder%%(K4%%)
                    NEXT K%%
                END IF
                DoAnime%% = DispOrder%%(DispIndex%%)
                DispIndex%% = DispIndex%% + 1
                AnimeCount% = 0
                GraveCount% = 0
                SELECT CASE DoAnime%%
                    CASE 1 'Concorde
                        ConcordePos!(0) = -260
                        ConcordePos!(1) = 0
                        GraveImg&(3, 0) = _COPYIMAGE(BaderImg&, 32)
                        GraveImg&(3, 1) = _COPYIMAGE(BaderImg&, 33)
                        MinGrave%% = 3
                        MaxGrave%% = 3
                        GraveDisp% = 150
                    CASE 2 'ET
                        AmblinPos!(0) = -2 * (AmblinHalf%% + 1) - 30
                        AmblinPos!(1) = 235
                        AmblinPos!(2) = 1.6 + CINT(0.4 * RND)
                        AmblinPos!(3) = -0.4
                        GraveImg&(3, 0) = _COPYIMAGE(SpielbergImg&, 32)
                        GraveImg&(3, 1) = _COPYIMAGE(SpielbergImg&, 33)
                        MinGrave%% = 3
                        MaxGrave%% = 3
                        GraveDisp% = 580
                        _SNDPLAY ETSound&
                    CASE 3 'Star Trek
                        Enterprise!(2) = -5000
                        Enterprise!(1) = -300
                        Enterprise!(0) = -500
                        FOR K%% = 1 TO 5
                            GraveImg&(K%%, 0) = _COPYIMAGE(CrewImg&(K%%), 32)
                            GraveImg&(K%%, 1) = _COPYIMAGE(CrewImg&(K%%), 33)
                        NEXT K%%
                        GraveDisp% = 1240
                    CASE 4 'ISS
                        ISSAngle! = _PI(-0.12)
                        ISS% = -2000
                        DispTrans!(0, 0) = CINT(XScreen% / 2 - 100 - ISS% * SIN(ISSAngle!))
                        DispTrans!(0, 1) = CINT(ISS% * COS(ISSAngle!) - ISS% + 10)
                        GraveImg&(3, 0) = _COPYIMAGE(CosmonautImg&, 32)
                        GraveImg&(3, 1) = _COPYIMAGE(CosmonautImg&, 33)
                        MinGrave%% = 3
                        MaxGrave%% = 3
                        GraveDisp% = 460
                        _SNDLOOP SputnikSound&
                    CASE 5 'Meteors
                        MaxRocks% = 600 + INT(RND * 200)
                        FOR K%% = 0 TO 30
                            Perseids!(K%%, 2) = ZOffset% - 2025
                        NEXT K%%
                        GraveImg&(3, 0) = _COPYIMAGE(GalileoImg&, 32)
                        GraveImg&(3, 1) = _COPYIMAGE(GalileoImg&, 33)
                        GraveDisp% = MaxRocks% - 200
                        _SNDLOOP MeteorWindSound&
                        _SNDLOOP MeteorSound&
                    CASE 6 'Transit
                        Transit!(0) = 966
                        Transit!(1) = 90
                        GraveImg&(3, 0) = _COPYIMAGE(BotticelliImg&, 32)
                        GraveImg&(3, 1) = _COPYIMAGE(BotticelliImg&, 33)
                        MinGrave%% = 3
                        MaxGrave%% = 3
                        GraveDisp% = 960
                        _SNDPLAY VenusSound&
                    CASE 7 'Thunderbirds
                        Virgil!(0) = XScreen% + 150
                        Virgil!(2) = 0.35 + RND * 0.05 'Thunderbird vert vel
                        Virgil!(1) = 200 + 418 * Virgil!(2)
                        Virgil!(3) = 623 'Bomb position
                        Virgil!(4) = -60
                        Virgil(8) = Virgil!(0) + 100 'Chain X- upper
                        Virgil(9) = Virgil!(1) + 30 'Chain y- upper
                        Virgil(10) = -0.2 + (0.05 * RND) 'Magnet vert vel
                        Virgil(6) = Virgil!(0) + 100 - 20 'Magnet  position
                        Virgil(7) = 470 + 418 * Virgil(10)
                        Virgil!(5) = Virgil(7) + 4 - (Virgil!(1) + 30) ' Chain length
                        BombsAway%% = 1
                        FOR K%% = 1 TO 5
                            GraveImg&(K%%, 0) = _COPYIMAGE(TracyImg&(K%%), 32)
                            GraveImg&(K%%, 1) = _COPYIMAGE(TracyImg&(K%%), 33)
                        NEXT K%%
                        GraveDisp% = 620
                    CASE 8 'Zodiac
                        Pip! = _PI(1 / 12)
                        Sym%% = 1
                        OldSym%% = 1
                        CMem = _MEMIMAGE(ZodiacTmpImg&)
                        FOR M% = 0 TO ZodHeight% - 1
                            FOR N% = 5 TO ZodWidth% - 5
                                COff = 4 * (N% + 12 * M% * ZodWidth%)
                                IF _MEMGET(CMem, CMem.OFFSET + COff, _UNSIGNED _BYTE) > 60 THEN
                                    _MEMPUT CMem, CMem.OFFSET + COff, 190 AS _UNSIGNED _BYTE 'Blue For Brightest
                                    _MEMPUT CMem, CMem.OFFSET + COff + 1, 253 AS _UNSIGNED _BYTE 'Green
                                    _MEMPUT CMem, CMem.OFFSET + COff + 2, 255 AS _UNSIGNED _BYTE 'Red
                                    _MEMPUT CMem, CMem.OFFSET + COff + 3, 160 AS _UNSIGNED _BYTE 'Alpha
                                END IF
                            NEXT N%
                        NEXT M%
                        ZodiacImg& = _COPYIMAGE(ZodiacTmpImg&, 33)
                        _MEMFREE CMem
                        _SNDPLAY MysticSound&
                    CASE 9 'UFO
                        Xi! = _PI(0.4)
                        Omicron! = 0
                        UFOY! = 400
                        UNorm%% = 0
                        FOR K%% = 2 TO 3
                            GraveImg&(K%% + 1, 0) = _COPYIMAGE(UFOImg&(K%%), 32)
                            GraveImg&(K%% + 1, 1) = _COPYIMAGE(UFOImg&(K%%), 33)
                        NEXT K%%
                        GraveDisp% = 1240
                    CASE 10 'Spotlight
                        S1! = 0
                        S2! = 0
                        CMem = _MEMIMAGE(QB64TempImg&)
                        _SNDPLAY BlueSkiesSound&
                END SELECT
            END IF
        CASE 1 'Concorde
            ConcordePos!(0) = ConcordePos!(0) + 5
            ConcordePos!(1) = ConcordePos!(1) - 1.25 + (RND - 0.5) * 0.1
            DispTrans!(0, 0) = ConcordePos!(0)
            DispTrans!(0, 1) = ConcordePos!(1)
            IF ConcordePos!(0) > XScreen% + 100 THEN
                CALL OffScreen
            ELSEIF AnimeCount% = 93 THEN
                _SNDPLAY BoomSound&
            END IF
        CASE 2 'ET
            AmblinAngle! = PiBand!(AmblinAngle! + 0.03)
            AmblinPos!(0) = AmblinPos!(0) + AmblinPos!(2)
            AmblinPos!(1) = AmblinPos!(1) + AmblinPos!(3)
            IF AmblinPos!(1) < -2 * (AmblinHalf%% + 1) THEN CALL OffScreen
            DispTrans!(0, 0) = CINT(AmblinPos!(0))
            DispTrans!(0, 1) = CINT(AmblinPos!(1))
            X100! = -13
            Y100! = -13
            X200! = X100! + 26
            Y200! = Y100!
            X300! = X100!
            Y300! = Y100! + 26
            X400! = X100! + 26
            Y400! = Y100! + 26
            CALL Twist(AmblinAngle!, X100!, Y100!)
            CALL Twist(AmblinAngle!, X200!, Y200!)
            CALL Twist(AmblinAngle!, X300!, Y300!)
            CALL Twist(AmblinAngle!, X400!, Y400!)
            DispTrans!(1, 0) = CINT(AmblinPos!(0) + 18 + 13 + X100!)
            DispTrans!(1, 1) = CINT(AmblinPos!(1) + 70 + 13 + Y100!)
            DispTrans!(2, 0) = CINT(AmblinPos!(0) + 18 + 13 + X200!)
            DispTrans!(2, 1) = CINT(AmblinPos!(1) + 70 + 13 + Y200!)
            DispTrans!(3, 0) = CINT(AmblinPos!(0) + 18 + 13 + X300!)
            DispTrans!(3, 1) = CINT(AmblinPos!(1) + 70 + 13 + Y300!)
            DispTrans!(4, 0) = CINT(AmblinPos!(0) + 18 + 13 + X400!)
            DispTrans!(4, 1) = CINT(AmblinPos!(1) + 70 + 13 + Y400!)
            DispTrans!(5, 0) = CINT(AmblinPos!(0) + 68 + 13 + X100!)
            DispTrans!(5, 1) = CINT(AmblinPos!(1) + 50 + 13 + Y100!)
            DispTrans!(6, 0) = CINT(AmblinPos!(0) + 68 + 13 + X200!)
            DispTrans!(6, 1) = CINT(AmblinPos!(1) + 50 + 13 + Y200!)
            DispTrans!(7, 0) = CINT(AmblinPos!(0) + 68 + 13 + X300!)
            DispTrans!(7, 1) = CINT(AmblinPos!(1) + 50 + 13 + Y300!)
            DispTrans!(8, 0) = CINT(AmblinPos!(0) + 68 + 13 + X400!)
            DispTrans!(8, 1) = CINT(AmblinPos!(1) + 50 + 13 + Y400!)
        CASE 3 'Star Trek
            IF Enterprise!(2) < 0 THEN
                Enterprise!(2) = Enterprise!(2) + 2 - Enterprise!(2) / 2000
            ELSE
                Enterprise!(2) = Enterprise!(2) + 2
            END IF
            Enterprise!(1) = Enterprise!(1) + 0.36
            Enterprise!(0) = Enterprise!(0) + 0.607
            DispTrans!(1, 0) = Enterprise!(0)
            DispTrans!(1, 1) = Enterprise!(1)
            DispTrans!(1, 2) = ZOffset% + Enterprise!(2)
            DispTrans!(2, 0) = Enterprise!(0) + 150
            DispTrans!(3, 1) = Enterprise!(1) - 87
            IF Enterprise!(0) > XScreen% / 2 + 10 THEN CALL OffScreen
            IF AnimeCount% = 180 THEN
                _SNDPLAY TrekSound&
                MinGrave%% = 1
                MaxGrave%% = 5
            END IF
        CASE 4 'ISS
            ISSAngle! = ISSAngle! + 0.001
            DispTrans!(0, 0) = CINT(XScreen% / 2 - 100 - ISS% * SIN(ISSAngle!))
            DispTrans!(0, 1) = CINT(ISS% * COS(ISSAngle!) - ISS% + 10)
            IF ISSAngle! > _PI(0.12) THEN
                CALL OffScreen
                _SNDSTOP SputnikSound&
            END IF
        CASE 5 'Meteor Shower
            FOR K%% = 0 TO 30
                IF Perseids!(K%%, 2) = ZOffset% - 2025 AND RND > 0.99 AND AnimeCount% <= MaxRocks% THEN
                    Perseids!(K%%, 0) = 0
                    Perseids!(K%%, 1) = 300
                    Perseids!(K%%, 2) = ZOffset% - 2020
                    Perseids!(K%%, 3) = (RND - 0.5) * 0.8
                    Perseids!(K%%, 4) = (RND - 0.5) * 0.3
                    Perseids!(K%%, 5) = 10 + (RND - 0.5) * 1
                    Perseids!(K%%, 6) = 0 'Meteor size
                ELSEIF Perseids!(K%%, 2) > ZOffset% - 2025 THEN
                    Perseids!(K%%, 0) = Perseids!(K%%, 0) + Perseids!(K%%, 3)
                    Perseids!(K%%, 1) = Perseids!(K%%, 1) + Perseids!(K%%, 4)
                    Perseids!(K%%, 2) = Perseids!(K%%, 2) + Perseids!(K%%, 5)
                    Perseids!(K%%, 4) = Perseids!(K%%, 4) - 0.025 + (RND - 0.5) * 0.002
                    SELECT CASE Perseids!(K%%, 2) - ZOffset%
                        CASE IS < -1800
                            Perseids!(K%%, 6) = (2020 + (Perseids!(K%%, 2) - ZOffset%)) * 5 / 220
                        CASE IS >= 320
                            Perseids!(K%%, 2) = ZOffset% - 2025 'Go back to zero
                        CASE IS > 0
                            Perseids!(K%%, 6) = (320 - (Perseids!(K%%, 2) - ZOffset%)) * 5 / 320
                    END SELECT
                END IF
            NEXT K%%
            IF AnimeCount% = 100 THEN
                MinGrave%% = 3
                MaxGrave%% = 3
            ELSEIF AnimeCount% > MaxRocks% THEN
                K%% = 0
                CALL OffScreen
                WHILE K%% <= 30 AND DoAnime%% = 0 'DoAnime%% = 0 from OffScreen
                    IF Perseids!(K%%, 2) <> ZOffset% - 2025 THEN DoAnime%% = 5
                    K%% = K%% + 1
                WEND
                _SNDSTOP MeteorSound&
                _SNDSTOP MeteorWindSound&
            END IF
        CASE 6 'Transit of Venus
            Transit!(0) = Transit!(0) + 0.05
            Transit!(1) = Transit!(1) + 0.015
            DispTrans!(0, 0) = CINT(Transit!(0))
            DispTrans!(0, 1) = CINT(Transit!(1))
            IF Transit!(0) > 1028 THEN CALL OffScreen
        CASE 7 'Thunderbirds
            SELECT CASE BombsAway%%
                CASE 1
                    Virgil(4) = Virgil(4) + 2.6
                    IF AnimeCount% = 30 THEN _SNDPLAY BombSound&
                    IF Virgil(4) >= 515 THEN
                        Virgil(4) = 515
                        BombsAway%% = 2
                    END IF
                CASE 2
                    IF AnimeCount% = 300 THEN
                        _SNDPLAY TunderbirdsSound&
                        MinGrave%% = 1
                        MaxGrave%% = 5
                    END IF
                    Virgil!(0) = Virgil!(0) - 1.7
                    Virgil!(1) = Virgil!(1) - Virgil!(2)
                    Virgil(6) = Virgil!(0) + 100 - 20 'Magnet  position
                    Virgil(7) = Virgil!(7) - Virgil(10)
                    Virgil(8) = Virgil!(0) + 100 'Chain X- upper
                    Virgil(9) = Virgil!(1) + 30 'Chain y- upper
                    IF Virgil!(0) < 540 THEN
                        BombsAway%% = 3
                        Virgil!(0) = 540
                        Virgil(6) = 620 'Magnet  position
                        Virgil(7) = 470
                    END IF
                    Virgil!(5) = Virgil(7) + 4 - (Virgil!(1) + 30) ' Chain length
                CASE ELSE
                    Virgil!(0) = Virgil!(0) - 1.7
                    Virgil!(1) = Virgil!(1) - Virgil!(2)
                    Virgil(6) = Virgil!(0) + 100 - 20 'Magnet  position
                    Virgil(7) = Virgil!(1) + 30 + Virgil!(5) - 4
                    Virgil(8) = Virgil!(0) + 100 'Chain X- upper
                    Virgil(9) = Virgil!(1) + 30 'Chain y- upper
                    Virgil!(3) = Virgil(6) + 3 'Bomb position
                    Virgil!(4) = Virgil(7) + 45
            END SELECT
            DispTrans!(0, 0) = CINT(Virgil(0))
            DispTrans!(0, 1) = CINT(Virgil(1))
            DispTrans!(1, 0) = CINT(Virgil(3))
            DispTrans!(1, 1) = CINT(Virgil(4))
            DispTrans!(2, 0) = CINT(Virgil(6))
            DispTrans!(2, 1) = CINT(Virgil(7))
            DispTrans!(3, 0) = CINT(Virgil(8))
            DispTrans!(3, 1) = CINT(Virgil(9))
            DispTrans!(4, 0) = CINT(Virgil(8) + 9)
            DispTrans!(4, 1) = CINT(Virgil!(1) + 30 + Virgil!(5))
            DispTrans!(5, 1) = CINT(399 - Virgil(5))
            IF Virgil!(0) < -300 THEN
                CALL OffScreen
                _SNDSTOP TunderbirdsSound&
            END IF
        CASE 8 'Zodiac
            Pip! = PiBand!(Pip! + _PI(0.001))
            IF AnimeCount% = 3000 THEN
                CALL OffScreen
                _FREEIMAGE ZodiacImg&
                CMem = _MEMIMAGE(ZodiacTmpImg&)
                FOR M% = 0 TO ZodHeight% - 1
                    FOR N% = 5 TO ZodWidth% - 5
                        COff = 4 * (N% + 12 * M% * ZodWidth% + (OldSym%% - 1) * ZodWidth%) + CMem.OFFSET
                        IF _MEMGET(CMem, COff, _UNSIGNED _BYTE) > 60 THEN
                            _MEMPUT CMem, COff, 152 AS _UNSIGNED _BYTE 'Blue
                            _MEMPUT CMem, COff + 1, 202 AS _UNSIGNED _BYTE 'Green
                            _MEMPUT CMem, COff + 2, 204 AS _UNSIGNED _BYTE 'Red
                            _MEMPUT CMem, COff + 3, 100 AS _UNSIGNED _BYTE 'Alpha
                        END IF
                    NEXT N%
                NEXT M%
                _MEMFREE CMem
            END IF
            IF Pip! >= 0 THEN
                Sym%% = INT(1 + 12 * Pip! / _PI(2))
            ELSE
                Sym%% = INT(13 + 12 * Pip! / _PI(2))
            END IF
            IF Sym%% <> OldSym%% THEN
                _FREEIMAGE ZodiacImg&
                CMem = _MEMIMAGE(ZodiacTmpImg&)
                FOR M% = 0 TO ZodHeight% - 1
                    FOR N% = 5 TO ZodWidth% - 5
                        COff = 4 * (N% + 12 * M% * ZodWidth% + (OldSym%% - 1) * ZodWidth%) + CMem.OFFSET
                        IF _MEMGET(CMem, COff, _UNSIGNED _BYTE) > 60 THEN
                            _MEMPUT CMem, COff, 152 AS _UNSIGNED _BYTE 'Blue
                            _MEMPUT CMem, COff + 1, 202 AS _UNSIGNED _BYTE 'Green
                            _MEMPUT CMem, COff + 2, 204 AS _UNSIGNED _BYTE 'Red
                            _MEMPUT CMem, COff + 3, 100 AS _UNSIGNED _BYTE 'Alpha
                        END IF
                        COff = 4 * (N% + 12 * M% * ZodWidth% + (Sym%% - 1) * ZodWidth%) + CMem.OFFSET
                        IF _MEMGET(CMem, COff, _UNSIGNED _BYTE) > 60 THEN
                            _MEMPUT CMem, COff, 190 AS _UNSIGNED _BYTE 'Blue For Brightest
                            _MEMPUT CMem, COff + 1, 253 AS _UNSIGNED _BYTE 'Green
                            _MEMPUT CMem, COff + 2, 255 AS _UNSIGNED _BYTE 'Red
                            _MEMPUT CMem, COff + 3, 160 AS _UNSIGNED _BYTE 'Alpha
                        END IF
                    NEXT N%
                NEXT M%
                ZodiacImg& = _COPYIMAGE(ZodiacTmpImg&, 33)
                _MEMFREE CMem
                OldSym%% = Sym%%
            END IF
        CASE 9 'UFO
            'Windmill ought to be hardware 3D for ufo to go behind, but just fly above windmill at all times
            SELECT CASE AnimeCount%
                CASE IS < 1810
                    'Come in to land
                    Xi! = Xi! + 0.002
                    CALL SinCos(Xi!, UFORad%, UFOX!, UFOZ!)
                    UFOX! = UFOX! + 580
                    UFOY! = UFOY! - 0.4
                    IF AnimeCount% = 150 THEN
                        _SNDPLAY XSound&
                        MinGrave%% = 3
                        MaxGrave%% = 4
                    END IF
                CASE IS < 2000
                    'Descend
                    UFOY! = UFOY! - 0.8
                CASE IS < 2020
                    'Settle
                    IF AnimeCount% = 2001 THEN
                        GraveCount% = 0
                        GraveImg&(3, 0) = _COPYIMAGE(AlienImg&, 32)
                        GraveImg&(3, 1) = _COPYIMAGE(AlienImg&, 33)
                        MinGrave%% = 3
                        MaxGrave%% = 3
                        GraveDisp% = 870
                    END IF
                CASE IS < 2300
                    'Ground activity
                    IF UNorm%% = 1 AND AnimeCount% / 15 = AnimeCount% \ 15 THEN
                        UNorm%% = 0
                    ELSEIF UNorm%% = 0 AND (AnimeCount% + 10) / 15 = (AnimeCount% + 10) \ 15 THEN
                        UNorm%% = 1
                    END IF
                    IF AnimeCount% = 2040 THEN
                        _SNDLOOP XMachSound&
                    ELSEIF AnimeCount% = 2299 THEN
                        UNorm%% = 0
                        _SNDSTOP XMachSound&
                    END IF
                CASE IS < 2400
                    'Launch
                    UFOY! = UFOY! + 0.8
                CASE IS < 2500
                    'Tilt ready for flight: Rotate in Z-axis
                    UX1! = -UFOHalfX%
                    UY1! = UFOHalfY%
                    CALL Twist(Omicron!, UX1!, UY1!)
                    UX2! = UFOHalfX%
                    UY2! = UFOHalfY%
                    CALL Twist(Omicron!, UX2!, UY2!)
                    UX3! = -UFOHalfX%
                    UY3! = -UFOHalfY%
                    CALL Twist(Omicron!, UX3!, UY3!)
                    UX4! = UFOHalfX%
                    UY4! = -UFOHalfY%
                    CALL Twist(Omicron!, UX4!, UY4!)
                    Omicron! = Omicron! - 0.002
                CASE IS < 3060
                    'Flight back to alien centre
                    IF AnimeCount% = 2515 THEN _SNDPLAY XCallSound&
                    UFOX! = UFOX! + 0.5
                    UFOY! = UFOY! + 2.7
                    UFOZ! = UFOZ! + 2.3
                CASE ELSE
                    CALL OffScreen
            END SELECT
            IF AnimeCount% < 2400 THEN
                DispTrans!(1, 0) = UFOX! - UFOHalfX%
                DispTrans!(1, 1) = UFOY! + UFOHalfY%
                DispTrans!(2, 0) = UFOX! + UFOHalfX%
                DispTrans!(2, 1) = DispTrans!(1, 1)
                DispTrans!(3, 0) = DispTrans!(1, 0)
                DispTrans!(3, 1) = UFOY! - UFOHalfY%
                DispTrans!(4, 0) = DispTrans!(2, 0)
                DispTrans!(4, 1) = DispTrans!(3, 1)
            ELSE
                DispTrans!(1, 0) = UFOX! + UX1!
                DispTrans!(1, 1) = UFOY! + UY1!
                DispTrans!(2, 0) = UFOX! + UX2!
                DispTrans!(2, 1) = UFOY! + UY2!
                DispTrans!(3, 0) = UFOX! + UX3!
                DispTrans!(3, 1) = UFOY! + UY3!
                DispTrans!(4, 0) = UFOX! + UX4!
                DispTrans!(4, 1) = UFOY! + UY4!
            END IF
            DispTrans!(1, 2) = ZOffset! + UFOZ! - 600
            IF UNorm%% = 1 THEN DispTrans!(1, 2) = DispTrans!(1, 2) + 10
        CASE 10 'Spotlight
            SpotLight!(0) = QB64X% + 0.5 * SpotRad% + ((WQB64X% - SpotRad%) / 2) * (1 + COS(S1!))
            SpotLight!(1) = QB64Y% + 0.5 * SpotRad% + ((WQB64Y% - SpotRad%) / 2) * (1 - COS(S2!))
            D9! = SQR((LampX% - SpotLight!(0)) * (LampX% - SpotLight!(0)) + (LampY% - SpotLight!(1)) * (LampY% - SpotLight!(1)))
            DispTrans!(1, 0) = _ACOS(SpotRad% / D9!) - _ACOS((SpotLight!(1) - LampY%) / D9!)
            DispTrans!(0, 0) = CINT(SpotLight!(0) - SpotRad%)
            DispTrans!(0, 1) = CINT(SpotLight!(1) - SpotRad%)
            FOR N% = 0 TO WQB64X% - 1
                FOR M% = 0 TO WQB64Y% - 1
                    COff = 4 * (N% + M% * WQB64X%) + CMem.OFFSET
                    IF _MEMGET(CMem, COff, _UNSIGNED _BYTE) <> 0 THEN
                        Q0% = QB64X% + N% - SpotLight!(0)
                        Q1% = QB64Y% + M% - SpotLight!(1)
                        IF SQR(Q0% * Q0% + Q1% * Q1%) < SpotRad% THEN
                            _MEMPUT CMem, COff + 3, 255 AS _UNSIGNED _BYTE 'Alpha
                        ELSE
                            _MEMPUT CMem, COff + 3, 0 AS _UNSIGNED _BYTE 'Alpha
                        END IF
                    END IF
                NEXT M%
            NEXT N%
            QB64Img& = _COPYIMAGE(QB64TempImg&, 33)
            S1! = PiBand!(S1! + 0.01)
            S2! = PiBand!(S2! + 0.007)
            IF AnimeCount% = 2405 THEN
                CALL OffScreen
                _MEMFREE CMem
                _FREEIMAGE QB64Img&
            END IF
    END SELECT
    IF DoAnime%% > 0 THEN AnimeCount% = AnimeCount% + 1
    'Clouds
    FOR K%% = 0 TO 15
        IF CloudGo%%(K%%) THEN
            CloudPos!(K%%, 0) = CloudPos!(K%%, 0) + CloudPos!(K%%, 2) + (RND - 0.5) * 0.02
            IF K%% = 0 THEN
                IF CloudPos!(K%%, 0) > MillBombX1% + 128 AND Puddle% = YScreen% - 110 THEN
                    Puddle% = YScreen% - 180
                    FOR N% = 0 TO 500
                        Raindrops!(N%, 1) = CINT((Puddle% - (CloudPos!(0, 1) + 36)) * RND)
                    NEXT N%
                END IF
            END IF
            IF CloudPos!(K%%, 0) > XScreen% + 10 THEN
                CloudGo%%(K%%) = False
            END IF
        ELSEIF RND > 0.99 THEN
            CloudPos!(K%%, 0) = -_WIDTH(Clouds&(K%%)) - 5 'Clouds start off off-screen left
            CloudPos!(K%%, 1) = RND * 350 + 10
            CloudPos!(K%%, 2) = 0.3 + 0.03 * (RND - 0.5)
            IF K%% = 0 THEN
                Puddle% = YScreen% - 110
                FOR N% = 0 TO 500
                    Raindrops!(N%, 1) = CINT((Puddle% - (CloudPos!(0, 1) + 36)) * RND)
                NEXT N%
            END IF
            CloudGo%%(K%%) = True
        END IF
    NEXT K%%
    'Raindrops
    FOR N% = 0 TO 500
        Raindrops!(N%, 1) = Raindrops!(N%, 1) + RND * 0.75
        IF Raindrops!(N%, 1) > Puddle% - (CloudPos!(0, 1) + 36) THEN Raindrops!(N%, 1) = 0
    NEXT N%
    'Rainbow
    ZBow1! = ZOffset% - 500 + 10 * SIN(Sigma!)
    Sigma! = PiBand!(Sigma! + 0.07)
    'Flowers
    FOR K%% = 0 TO 9
        IF FloraCount%(K%%) > 0 THEN 'Growth/Living/Kill
            IF FloraCount%(K%%) = 16 THEN Blooming%% = False 'Stop Blooming
            IF FloraCount%(K%%) < 120 THEN Flora!(K%%, 2) = Flora!(K%%, 2) + 0.25 'Growth
            IF FloraCount%(K%%) < 400 THEN
                XHalf%% = CINT(14 * Flora!(K%%, 2) / 60)
                Flora!(K%%, 3) = Flora!(K%%, 0) - XHalf%%
                Flora!(K%%, 4) = Flora!(K%%, 1) - CINT(Flora!(K%%, 2))
                Flora!(K%%, 5) = Flora!(K%%, 0) + XHalf%%
                FloraCount%(K%%) = FloraCount%(K%%) + 1
            ELSE
                FloraCount%(K%%) = 0 'Kill
            END IF
        ELSEIF FloraCount%(K%%) = 0 AND NOT Blooming%% AND ((CloudPos!(0, 0) > 14 AND CloudPos!(0, 0) < WindX% - 10) OR (CloudPos!(0, 0) > MillBombX1% + 132 AND CloudPos!(0, 0) < XScreen% - 90)) THEN 'Limit to before windmill
            Blooming%% = True
            FloraCount%(K%%) = 1
            Flora!(K%%, 0) = CloudPos!(0, 0) - 5
            Flora!(K%%, 1) = Puddle% + 15 * (RND - 0.5)
            Flora!(K%%, 2) = 0
        END IF
    NEXT K%%
    'Bees
    'About 320 bees out at any one time
    Swarm% = 0
    FOR N% = 0 TO 500
        IF Buzz%%(N%) THEN
            Swarm% = Swarm% + 1
            Eta! = ATN(2 * ABee! * QB64Bees!(N%, 0)) 'Simple atn() works - _ATAN2() not needed and didn't work successfully
            CALL SinCos(Eta!, QB64Bees!(N%, 3), deltaX!, deltaZ!)
            QB64Bees!(N%, 0) = QB64Bees!(N%, 0) + deltaX!
            QB64Bees!(N%, 2) = QB64Bees!(N%, 2) + deltaZ!
            IF QB64Bees!(N%, 2) < QB64Bees!(N%, 1) THEN QB64Bees!(N%, 3) = -0.6 - 0.3 * (RND - 0.5)
            IF QB64Bees!(N%, 0) < -RBee% / 2 THEN Buzz%%(N%) = False
        ELSE
            IF RND > 0.999 AND DoBuzz%% THEN
                Buzz%%(N%) = True
                QB64Bees!(N%, 0) = -RBee% / 2 'X
                QB64Bees!(N%, 2) = CBee% + ABee! * (QB64Bees!(N%, 0) * QB64Bees!(N%, 0)) 'Z
                QB64Bees!(N%, 3) = 0.6 + 0.3 * (RND - 0.5) 'V
                QB64Bees!(N%, 4) = _PI(RND) 'Epsilon: Y-X angle
                QB64Bees!(N%, 1) = -300 - 100 * (RND - 0.5) 'Furthest z- Bee Path (-ve)
            END IF
        END IF
    NEXT N%
    IF Swarm% = 0 THEN
        IF DoSwarm% = 0 THEN _SNDSTOP HiveSound&
        DoSwarm% = DoSwarm% + 1
        IF DoSwarm% = PauseSwarm% THEN
            DoBuzz%% = True
            SwarmTime% = 150 + CINT(RND * 1800)
            BeesOut% = 0
            _SNDLOOP HiveSound&
            _SNDVOL HiveSound&, 0
        END IF
    ELSE
        _SNDVOL HiveSound&, Swarm% / 500
        BeesOut% = BeesOut% + 1
        IF BeesOut% = SwarmTime% THEN
            DoBuzz%% = False
            PauseSwarm% = 150 + CINT(RND * 800)
            DoSwarm% = 0
        END IF
    END IF
    'Fountain
    FOR N% = 0 TO 500
        IF Fountain!(N%, 1) < -100 THEN
            IF RND > 0.98 AND DoFount%% THEN
                Fountain!(N%, 0) = 0
                Fountain!(N%, 1) = 0 ' start height
                Fountain!(N%, 3) = 0.2 + 0.15 * (RND - 0.5)
                Fountain!(N%, 4) = 0.8 + 0.2 * (RND - 0.5)
                Fountain!(N%, 5) = _PI(-0.5) + _PI(2) * (RND - 0.5)
                'rotate -pi to +pi around y- axis
                Fountain!(N%, 2) = 0
                Fountain!(N%, 6) = Fountain!(N%, 0)
                CALL Twist(Fountain!(N%, 5), Fountain!(N%, 6), Fountain!(N%, 2)) 'D1/2 will get changed
                Fountain!(N%, 6) = Fountain!(N%, 6) + FountX%
            END IF
        ELSE
            Fountain!(N%, 0) = Fountain!(N%, 0) + Fountain!(N%, 3)
            Fountain!(N%, 1) = Fountain!(N%, 1) + Fountain!(N%, 4)
            Fountain!(N%, 4) = Fountain!(N%, 4) - G!
            'rotate -pi to +pi around y- axis
            Fountain!(N%, 2) = 0
            Fountain!(N%, 6) = Fountain!(N%, 0)
            CALL Twist(Fountain!(N%, 5), Fountain!(N%, 6), Fountain!(N%, 2)) 'D1/2 will get changed
            Fountain!(N%, 6) = Fountain!(N%, 6) + FountX%
        END IF
    NEXT N%
    IF NOT DoFount%% THEN
        WaitFont% = WaitFont% + 1
        IF WaitFont% = PauseFont% THEN
            DoFount%% = True
            FontTime% = 150 + CINT(RND * 1800)
            FontCount% = 0
        END IF
    ELSE
        FontCount% = FontCount% + 1
        IF FontCount% = FontTime% THEN
            DoFount%% = False
            PauseFont% = 150 + CINT(RND * 800)
            WaitFont% = 0
        END IF
    END IF
    'Windmill
    'Rotate in Z-axis
    WX1! = -Wind%
    WY1! = Wind%
    CALL Twist(Lambda!, WX1!, WY1!)
    WX2! = Wind%
    WY2! = Wind%
    CALL Twist(Lambda!, WX2!, WY2!)
    WX3! = -Wind%
    WY3! = -Wind%
    CALL Twist(Lambda!, WX3!, WY3!)
    WX4! = Wind%
    WY4! = -Wind%
    CALL Twist(Lambda!, WX4!, WY4!)
    'Rotate in Y-axis
    WZ1! = 0
    CALL Twist(Iota!, WZ1!, WX1!)
    WZ2! = 0
    CALL Twist(Iota!, WZ2!, WX2!)
    WZ3! = 0
    CALL Twist(Iota!, WZ3!, WX3!)
    WZ4! = 0
    CALL Twist(Iota!, WZ4!, WX4!)
    WX1! = CINT(WX1! + SailX%)
    WX2! = CINT(WX2! + SailX%)
    WX3! = CINT(WX3! + SailX%)
    WX4! = CINT(WX4! + SailX%)
    WY1! = CINT(WY1! + SailY%)
    WY2! = CINT(WY2! + SailY%)
    WY3! = CINT(WY3! + SailY%)
    WY4! = CINT(WY4! + SailY%)
    WZ1! = CINT(WZ1! + ZOffset%)
    WZ2! = CINT(WZ2! + ZOffset%)
    WZ3! = CINT(WZ3! + ZOffset%)
    WZ4! = CINT(WZ4! + ZOffset%)
    Lambda! = PiBand!(Lambda! - 0.01)

WEND
SYSTEM

FUNCTION HardwareImage& (ImageName&)
    HardwareImage& = _COPYIMAGE(ImageName&, 33)
    _FREEIMAGE ImageName&
END FUNCTION

FUNCTION PiBand! (PiAngle!)
    SELECT CASE PiAngle!
        CASE IS < -_PI
            PiBand! = PiAngle! + _PI(2)
        CASE IS > _PI
            PiBand! = PiAngle! - _PI(2)
        CASE ELSE
            PiBand! = PiAngle!
    END SELECT
END FUNCTION

SUB Twist (Angle!, D1!, D2!) 'D1/2 will get changed
    ' x' = x cos theta -y sin theta;  y' = x sin theta +y cos theta
    DTemp! = D1!
    D1! = DTemp! * COS(Angle!) - D2! * SIN(Angle!)
    D2! = DTemp! * SIN(Angle!) + D2! * COS(Angle!)
END SUB

SUB SinCos (Angled!, R!, X!, Y!)
    X! = R! * COS(Angled!)
    Y! = R! * SIN(Angled!)
END SUB

SUB OffScreen
    FOR K1%% = 0 TO 8
        DispTrans!(K1%%, 0) = -1000
        DispTrans!(K1%%, 2) = ZOffset%
    NEXT K1%%
    DoAnime%% = 0
END SUB

'Tracy Brothers Order
DATA 2,3,1,4,5
DATA 1,3,5,2,4

'Cloud Manipulation Data
DATA 252,118,354,170
DATA 330,166,426,214
DATA 30,34,184,104
DATA 186,26,390,118
DATA 394,22,584,110
DATA 76,110,216,156
DATA 426,110,594,204
DATA 14,156,144,206
DATA 20,308,186,370
DATA 188,294,344,362
DATA 14,388,134,442
DATA 166,378,336,440
DATA 384,206,586,274
DATA 0,0,42,8
'with A
DATA 366,288,564,364
DATA 40,70,80,76
'with B
DATA 346,356,620,448
DATA 114,0,154,8
'with C
DATA 62,156,390,290
DATA 190,0,292,14
DATA 268,10,328,58
DATA 0,0,82,50
'with D
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Fruit Machine Simulator (PE Edition) Magdha 1 256 12-11-2025, 02:25 AM
Last Post: Pete
  Coin Toss Graphics Program Magdha 0 227 11-23-2025, 11:14 AM
Last Post: Magdha

Forum Jump:


Users browsing this thread: 1 Guest(s)