8: What's in that last QWord?
The harness uses the very last word of data memory to give us a helping hand.  The four fields each contain a little bonus present to help us out with some things that the VU simply can't do by itself.

The last QWord, numbered 1023, is updated every frame with the following information in each field:

x - The address of the on-screen 640x224 framebuffer
y - The address of the off-screen 640x224 framebuffer (The harness uses double buffering by default)
z - A random number
w - Information on what buttons are being pressed on the controllers

The first 2 fields aren't that interesting for now, but we can do some pretty effects with them later  However, they can be quite complicated, so I'm leaving them for a future lesson.

The last two are very interesting though, and we'll talk about them in this lesson.

Why use the random number here?
First, a digression into random numbers.  Computers can't actually generate random numbers, they generate pseudo-random numbers.  What this means is that although the numbers look random to us, they actually fit a predefined sequence.  Thus, if you set the random number generator off twice using the same seed both times, you will get the same 'random' sequence of numbers!  For this reason, the two ways of generating random numbers available to us in writing VU demos have different uses.

To use a random number generated for us by the harness, we only need use one single instruction:

ilw.z iRandom, 1023(vi00)

There we are, the iRandom register now contains a random number.  The key point here is that this random number is unpredictable.  We don't know what seed was used to generate the random number sequence, and we don't know how long the sequence has gone on for, because other people's demos might already have been executed by the harness.

We can generate random numbers ourselves, but we'd have to seed the generator ourselves and use those RINIT, RGET, and RNEXT instructions.  The catch here is that the generator is predictable, if we use the same seed each time for our random numbers, we'll get the same sequence, and our demo will run exactly the same way every time.  This may be what you want, or it may not.  (Of course, there's nothing stopping you using the random number from the harness to seed your own generator... :)

What about the pad info?
If you want to follow the path that others have tried, and make a game out of your VU demo, you're certainly going to have to read the controllers to see if your player is pressing any of the buttons.  Have a quick look at bjt's Plasmaroids demo, the VU Tunnel demo, and Space inVUders to see what you're up against, then get back here to learn how they work.  (Note: I'm not trying to put you off writing a game, in fact I've spent far too long playing Plasmaroids myself!  However, notice that none of the competition winners have been games, no matter how fun they are to play.)

Put this at the start of your VCL file:

kSquare .assign H'7FFF
kCross .assign H'4000
kTriangle .assign H'1000
kCircle .assign H'2000
kR1 .assign H'0800
kR2 .assign H'0200
kStart .assign H'0008
kLeft .assign H'0080
kDown .assign H'0040
kUp .assign H'0010
kRight .assign H'0020

Note: When using VCL with gasp, some versions (including the one on the kit) don't handle the hex notation 0x123 properly.  They do however handle the notation H'123 properly.  That's why I've used the H' prefix above to denote hex values.  For future reference, GASP also doesn't like numebrs like 0.005235, it prefers 5.235e-2.  Just so you know.

These constants have come straight out of the harness source, putting this at the start of your code will make things easier to read.  Notice that I haven't given any numbers for L1, L2 or Select, as these are used by the harness to switch demos or display help text, so we can't use them in our demos.  Also note that the Left, Down Up and Right refer to the D-pad, or the left analogue stick when the analogue button is pressed.  The right analogue stick is not available, nor are the L3 and R3 buttons.

Now, how do we check whether a key is pressed?  It goes a little something like this - First we load the pad info into a register.

ilw.w iPad, 1023(vi00)

Then we load the value we're checking for (Cross for example) into another register

iaddiu iMask, vi00, kCross

Then we logically AND them together:

iand iCheck, iPad, iMask

And check the result.  iCheck will be zero if the button is pressed, and 1 if it is not pressed.  That sound's a little backwards to me, but we have to live with it :)

Note: I confused at least one person with the above statement.  The IAND instruction behaves exactly like you would expect - a bit in iCheck is 1 if both the coressponding bits in iPad and iMask are 1.  It's the *data* provided by the harness in the iPad register that is backwards - i.e. 0 if the button is pressed, and 1 if the button is *not* pressed.

Putting it all together results in a code block like this:

    ilw.w iPad, 1023(vi00)
    iaddiu iMask, vi00, kCross
    iand iCheck, iPad, iMask
    ibeq iCheck, vi00, CROSS_IS_PRESSED:
    b CROSS_IS_NOT_PRESSED:
CROSS_IS_PRESSED:
    ;This code is only executed if Cross is pressed
    b ONWARDS:
CROSS_IS_NOT_PRESSED:
    ;This code is only executed if Cross is not pressed
ONWARDS:
    ;This code is executed regardless of whether Cross is pressed.

The code could be even more readable if we put a kLastQWord .assign 1023, and used that name rather than its value in the first line.

There is one gotcha.  The mask for checking whether Square is pressed or not should be 0x8000.  Why have I lied to you and told you it's 0x7FFF then?  The answer is that 0x8000 is a 16-bit number, and the iaddiu instruction only has enough room to add a 15-bit number.  So, what we have to do is load 0x7FFF into the iMask register, and then add 1 to it to make it 0x8000.  So, to change the above code to check for Square instead of cross, you need to change

    iaddiu iMask, vi00, kCross

into

    iaddiu iMask, vi00, kSquare
    iaddiu iMask, iMask, 1 ; This instruction only needed for Square.

Homework
OK, let's get some code up and running using these extra bits of info...

1)  Go right back to the code in 4: Making your code file, where we moved one vertex of the triangle horizontally.  Make it so that the vertex stays still unless you press any of the D-pad buttons.  Move the vertex in the direction corresponding to the keys being pressed.  (So, check for up being pressed, and if it is, decrement the Y co-ordinate)
2)  Expand on Q2 to move the entire triangle instead of a single vertex if Square is being held down.  (Hint, check to see whether Square is pressed first, then decide what to move)
3)  Read in a random number, and if it's bigger than a limit you set, move the vertex left, if not, don't move it all.  You should get some jagged movement of the vertex.
4)  Expand Q3 to read in two random numbers, and code them somehow into a direction and a value for a counter, which you will decrement each frame.  Move the vertex in the random direction selected, until the counter reaches zero.  Then pick a new direction and counter.  For instance, the vertex could move right for 10 frames, then up for 5 frames, then diagonally down-left for 16 frames... all based on random numbers.
5)  How about using VU code to generate a GIFpacket of 100 random points of random colours scattered all over the screen?

Prev - 7: Some Maths Next - 9: Uploading Image data