we also talk about using the program memory as a space for data using "variables". this allows us to save and retrieve data during the runtime of our programs, and can save us from complex stack wrangling :)
uxn will jump to the location of at label at a rate of 60 times per second: we can use the subroutine under on-frame to change the contents of the screen, generating animation, and/or we can also use it for other timing-related purposes.
the following program demonstrates a basic but powerful use of the screen vector: on each frame, it draws a pixel at the given screen x,y coordinates, and it adds 1 to the value of the x coordinate:
remember that $2 creates a relative pad of two byes: this makes pixel-y a label for an address in memory two bytes after pixel-x. and whatever code afterwards will happen two bytes after pixel-y.
variables with absolute address work well for cases where we want to be able to access their contents from any part of our program (i.e. "global variables").
however, uxn has a better mechanism for those cases: the zero page!
as you may recall, the zero page consists of the first 256 addresses of program memory. normally, a program starts at address 0100, that is the next address after the zero page.
this means that a caveat of using variables there, is that in order to initialize them we need to do it during runtime, by storing values from the stack into them.
in order to refer to them, we would use the dot (.) rune for literal zero page addresses, instead of the semicolon (;) rune for literal absolute addresses.
in these instructions, the address will always be one byte long.
in the short mode, LDZ2 will load a short from the given address, and STZ2 will store a short into the given address.
### examples
the following example consists in the same line that grows, but now using the zero page to store the x and y coordinates of the pixel instead of the screen x and y ports.
in this case the program is longer, but it could be seen as a nice template for having other lines behaving in different ways:
also, note that in the case of .pixel the address is referring to the zero page, accessed with LDZ/STZ, and in the case of .Screen the address is referring to the i/o address space, accessed with DEI/DEO.
however, as these addresses are given as relative and signed offsets, they can only be reached if they are within the 256 bytes surrounding the instruction that loads or stores them.
similar to LDZ and STZ, in these instructions the address will always be one byte long.
in the short mode, LDR2 will load a short from the given address, and STR2 will store a short into the given address.
### examples
the following is the on-frame subroutine that draws the growing line, but storing the pixel coordinates in a "local" variable accessed via LDR and STR.
```
@on-frame ( -> )
( load x,y coordinates from zero page and send to screen )
note the use of the comma (,) rune to indicate that it's a relative address; uxnasm calculates the required offset assuming it will be used in the next instruction.
in this case we can't really duplicate that offset as we did previously with the zero-page address, because it is specific to the position in the code it was written.
if we declared these variables as sublabels of on-frame, the code would look as follows:
```
@on-frame ( -> )
( load x,y coordinates from zero page and send to screen )
changing that program in order to draw an 8x8 sprite instead would be relatively straightforward, and you may have tried it already: we would need to use Screen/sprite instead of Screen/pixel, with an appropriate byte to define its color and orientation, and we would need to set the address of our sprite data in Screen/addr.
that would result in a sprite that moves and that also leaves a trail: i invite you to try it first!
as this is just an example to illustrate a point, there are some things that could be optimized in order to make our program smaller, and there are some things that could be useful but were left out. for example, there's not an initial value for the x coordinate, or the y coordinate is not used.
when we use the controller vector, we are acting based on a change in the button(s) or key(s) that were pressed or released. this can be very useful for some applications.
in some operating systems, if we keep a key pressed, it fires the controller vector several times, but not necessarily at the same rate as the screen vector!
another possibility could be applying a modulo operation to our changed coordinates so that they always stay within the limits, returning to the left when crossing over the right, and viceversa.
a possible set of modulo macros could be:
```
%MOD { DUP2 DIV MUL SUB } ( a b -- a%b )
%MOD2 { OVR2 OVR2 DIV2 MUL2 SUB2 } ( a b -- a%b )
```
(there's a more optimized set but we'll discuss it later :)
we can apply those macros after incrementing or decrementing. for example:
for example, the address of &frame1 would be 8 bytes more than the address of &frame0.
the frames you use could also be composed of 2bpp sprites. in that case, the offset between frames would be of 16 in decimal (10 in hexadecimal) bytes.
## frame count
in order to have an animation consisting of those frames we need to change the address of Screen/addr at specific intervals so that it points to a different sprite each time.
how can we know the sprite address that we should be using at each frame?
one way of achieving it is having a "global variable" in the zero page that counts the frames of the program. also, we would need to have that count constrained in a range corresponding to the amount of frames in our animation.
note that we are using a single byte to count, so it will go from 0 to 255 in a little bit more than 4 seconds, and then restart when overflowing its count.
for some applications it might be better to have a framecount in a short, that would count from 0 to 65535 and overflow in a little bit more than 18 minutes.
### fast modulo
in order to have that framecount constrained to a range corresponding to our number of frames, we can use a modulo operation.
when we have a number of frames corresponding to a power of two, as recommended above, we can use an "AND mask" to perform this modulo operation faster than if we were using the MOD macros suggested previously.
how can we use that count to select the sprite for the animation frame that we want to show?
we could use several conditional jumps, or we could use a more fun way that can be called pointer arithmetic :)
observe that the sublabel for the first frame (frame0) of our animation has the same address as the label for the whole animation. and, as we mentioned already, the next frame (frame1) starts 8 bytes afterwards.
the sublabel for each next frame is 8 bytes after the previous one.
or, another way to look at it:
* frame0 is 0 bytes after the animation label
* frame1 is 8 bytes after the animation label
* frame2 is 16 bytes after the animation label
* frame3 is 24 bytes after the animation label
* and so on
generalizing, frameN is (N times 8) bytes after the animation label!
this means that if we get the absolute address for the animation label, and we add (N times 8) bytes to it, we'll get the absolute address for frameN :)
this amount of bytes that separates each sublabel is called an offset.
### computing the offset
after applying the modulo 8 to our framecount, we can multiply it times 8 to get the offset with respect to the animation label:
```
.framecount LDZ ( load framecount )
8MOD ( apply modulo 8 to obtain sequence between 0 and 7 )
#08 MUL ( multiply times 8 to get the offset )
```
### from byte to short
note that so far we have been working with bytes, and everything has been fine.
8MOD ( apply modulo 8 to obtain sequence between 0 and 7 )
#08 MUL ( multiply times 8 to get the offset )
TO-SHORT ( convert to short )
;animation ( get animation address )
ADD2 ( add offset to address )
```
and then we could just send that to the Screen/addr port:
```
.Screen/addr DEO2 ( set computed address )
```
## the complete program
the program that does all this would look as follows.
note that it uses a sequence similar to the previous programs:
* increment framecount
* clear sprite
* calculate sprite address
* draw sprite
the clear sprite section is not actually needed in this case because of the colors that are used, but it would be when using colors with transparency in them :)
it wasn't as complicated, was it? :) this example includes many concepts that are worth studying, so i invite you to read it carefully!
for some fun possibilities, i invite you to draw the tile multiple times in different places and possibly with different flipping modes! that may generate more interesting animations!
until now, everything we have been doing has happened at 60 frames per second, that may be too fast for some applications!
fortunately, we can use some simple arithmetic with our framecount in order to slow down its effects.
for example, if we want to update our frames at half that speed (30 frames per second), we can divide over two the value of framecount before applying the modulo.
as you may remember this division can be done with SFT in the case of powers of two, or with DIV for any other case.
```
%HALF { #01 SFT } ( byte -- byte/2 )
%QUARTER { #02 SFT } ( byte -- byte/4 )
%EIGHTH { #03 SFT } ( byte -- byte/8 )
```
we can use these macros to divide the frequency in our code:
```
( 2: update sprite address )
.framecount LDZ ( load framecount )
QUARTER ( divide over 4 the frequency )
8MOD ( apply modulo 8 to obtain sequence between 0 and 7 )
=> ./img/screencap_uxn-animation-quarterspeed.gif animation of a diagonal stripe inside a pixelated square. the diagonal moves from bottom right to top left. it moves slower than the previous one.
note that if you want to divide the frequency to numbers that are not powers of 2, you might start to see some glitches approximately every 4 seconds: this is due to framecount overflowing and not giving a nice sequence of results for those divisors.
this might also happen if you have an animation consisting of a number of frames that is not a power of 2, and you use a normal MOD operation to calculate the offset to the corresponding frame.
the easiest workaround for these issues would be to use a short-sized framecount that would only cause those overflow glitches at approximately every 18 minutes.
in {uxn tutorial day 5} we introduce the varvara mouse device to explore more possible interactions, and we cover the remaining elements of uxntal and uxn: the return stack, the return mode and the keep mode.