we also talk about using the program memory as a space for data via "variables", in order to have some persistency of data during the runtime of our programs, and/or in order to save us from complex stack wrangling :)
now that we have covered devices vectors on day 3, let's jump right in into how to use the one in the screen!
the following line of uxntal would assign the absolute address of the label on-frame to the screen vector:
```
;on-frame .Screen/vector DEO2
```
uxn will jump to that 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.
## a line that grows
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 Screen/x:
note that the code is very similar to the one we wrote on day 2 for drawing a line. in that one, we manually incremented the value of Screen/x in order to draw 6 pixels.
here, the same code for incrementing Screen/x is called instead inside the on-frame subroutine, having it occurring 60 times per second.
some change for you to try and practice:
* how would you make the line grow vertically? and diagonally?
* how would you make the line grow in the opposite direction?
* how would you make it a dotted line?
* how would you make the line stop growing at a certain position? (remember conditional jumps!)
* how would you draw using a sprite instead of a pixel?
# variables
the varvara screen vector opens up a whole world of possibilities! it's worth noting that many of these possibilities require ways of storing and retrieving data between frames.
in the previous example, we are using the screen ports for the x and y coordinates as a way of storing the coordinates for the pixel.
but what happens when we want to draw different objects, each with its own set of coordinates and other characteristics that can change over time?
we can use labels in program memory in order to achieve that!
## variables with absolute addresses
in a way, when storing our sprite data we have been doing something like that already.
we have labelled a section of memory with contents that are not instructions for uxn, but data; e.g.:
```
@square ff81 8181 8181 81ff
```
however, we have not used the data directly; we have sent its address to the corresponding screen device port.
### labels
we could use a similar system for storing e.g. x and y coordinates instead of sprite data:
```
@pixel-x 0008
@pixel-y 0008
```
or if we didn't want to initialize them here, we could define them as follows:
```
@pixel-x $2
@pixel-y $2
```
remember that $2 creates a relative pad of two byes, such that pixel-y is a label for an address in memory two bytes after pixel-x.
we could also use labels and sublabels, in a manner that would be very similar to how we define devices and their ports:
```
@pixel [ &x $2 &y $2 ]
```
### instructions: LDA and STA
how could we read (load) and write (store) the contents of the memory at those labels?
here are the two instructions that would help us with that:
* LDA: load and push down into the stack the value at the given absolute address ( address -- value )
* STA: store into the given absolute address the value at the top of the stack ( value address -- )
as we have discussed already, an absolute address will always be two bytes long.
in the short mode, LDA2 will load a short from the given address, and STA2 will store a short into the given address.
### examples
as an example, the following code would read the two bytes from pixel/x, increment them by one, and store them back into pixel/x:
here we can see how a DUP2 can make that operation easier, as long as we keep a mental (or tangible!) model of what is happening on the stack.
## variables in the zero-page
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. a program starts at address 0100, that is the next address after the zero page.
we can refer to any of the 256 addresses of the zero page using one byte only, instead of the two bytes that are needed for absolute addresses.
the only caveat to keep in mind is that in order to initialize these variables we need to do it during runtime.
### labels
labels for the zero page would work the same as before; we only need to specify that they are in the zero page with an absolute pad:
```
|0000 ( zero page )
@pixel [ &x $2 &y $2 ]
```
in order to refer to them, we would use the dot (.) rune for literal zero page addresses, instead of the colon (;) rune for literal absolute addresses.
### instructions: LDZ, STZ
the instructions for loading (reading) and storing (writing) from and to the zero page are:
* LDZ: load and push down into the stack the value at the given zero page address ( address -- value )
* STZ: store into the given zero page address the value at the top of the stack ( value address -- )
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:
another possibility that we have in uxn that might be more appropriate for "local variables", consists in using relative addresses.
similar to variables in the zero page, in order to address these variables we only need one byte.
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.
### instructions: LDR, STR
the instructions for working in this way are:
* LDR: load and push down into the stack the value at the given relative address ( address -- value )
* STR: store into the given relative address the value at the top of the stack ( value address -- )
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 )
note that in this case, the comma (,) rune is accompanied by the sublabel (&) rune.
the use of this kind of variables will make more sense in day 5 of the tutorial :)
# sprite change of position
the use of "variables" will help us now in discussing three different ways of animating a sprite:
* autonomous change of position
* interactive change of position (with keyboard)
* autonomous change of drawn tile
we will review them separately in order to keep the examples simple and readable. it will be up to you to combine and/or improve upon them :)
## autonomous change of position
we discussed already how to have uxn change the position of a pixel in the screen, leaving a trail.
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 mode byte, 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.
how can we avoid leaving that trail?
a possible way of achieving it would be by following this order of operations inside the on-frame subroutine:
* clear sprite
* change position
* draw sprite
this allows us to clear the sprite from its position in the previous frame, update its coordinates to a new position, and then draw it there.
### example code
the following program illustrates the previous points, having our square from day 2 travel from left to right in the middle of our screen.
it combines several things that we have covered in the past few days!
( load x coordinate from zero page and send to screen )
.sprite/pos-x LDZ2 .Screen/x DEO2
( draw sprite in fg with color 2 and transparency )
color-2 .Screen/sprite DEO
BRK
( sprite data )
@square ff81 8181 8181 81ff
```
note that on one hand there are some things that could be optimized in order to make our program smaller, and that on the other there are some things that could be useful but that were left out, like the initial value of the x coordinate, or the use of the y coordinate.
regarding optimization, and as an example, section 2 and the first part of section 3 of on-frame could have been written as follows:
.sprite/pos-x STZ2 ( store the first copy of the result )
( 3 : draw sprite )
( use x coordinate from the stack and send to screen )
.Screen/x DEO2
```
as always, it is up to us how we want to navigate between efficient code and readability :)
here are some questions for you to ponder and try:
* how would you make the sprite move faster?
* and how would you make it move slower?
## interactive change of position
when we use the controller vector, we are acting upon a change in the button(s) or key(s) that were pressed or released. this can be very useful for some applications.
but, how can we deal with doing a continuous action when a key is kept pressed?
in some operating systems, if we keep a key pressed, it fires the controller vector several times.
however, this repetition might not allow for a smooth movement like what we can get if we check for the state of the controller inside the on-frame subroutine!
the following program allows us to control the horizontal position of our square using the arrow keys.
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:
another strategy for animation would consist in changing the sprite that is drawn at a specific position.
you could have a sequence of sprites/frames and animate them by running them in sequence!
## the frames
for practical purposes i would recommend you to have a number of frames corresponding to a power of two, like 2, 4, 8, 16, 32, etc.
for example, the following is a sequence of eight 1bpp sprites corresponding to a diagonal line moving from the bottom right to the top left:
```
@animation
&frame0 00 00 00 00 00 00 01 03
&frame1 00 00 00 00 01 03 06 0c
&frame2 00 00 01 03 06 0c 18 30
&frame3 01 03 06 0c 18 30 60 c0
&frame4 03 06 0c 18 30 60 c0 80
&frame5 0c 18 30 60 c0 80 00 00
&frame6 30 60 c0 80 00 00 00 00
&frame7 c0 80 00 00 00 00 00 00
```
note that each frame consists in 8 bytes; that implies that there's an offset of 8 bytes between the addresses corresponding to each sublabel.
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.
we know already how to do the first part!
in the zero page we declare the label for our framecount:
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.
for example, if we have 8 frames numbered from 0 to 7, we can notice that those numbers only require three bits to be represented.
to build our AND mask, we set as 1 those three bits, and 0 the others:
```
0000 0111: 07
```
this AND mask will "let pass" the three least significant bits of another byte, and turn off the others.
in uxntal this process would look as follows:
```
.framecount LDZ ( load framecount )
#07 AND ( apply AND mask, corresponding to modulo 8 )
```
the result of the operation will be a count going repeatedly from 0 to 7.
we could define this fast modulo operation as a macro to make the code more readable:
```
%8MOD { #07 AND } ( byte -- byte%8 )
```
## pointer arithmetic
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.
however, absolute addresses are actually shorts!
we need to convert our result to a short so that we can add it to the address of the animation data.
one way of doing it is with this macro that adds a 00 before the top element in the stack:
```
%TO-SHORT { #00 SWP } ( byte -- short )
```
our code would look as follows:
```
.framecount LDZ ( load framecount )
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 )
```
another way, less clear but kind of fun (and slightly shorter in program memory), would consist in pushing the 00 before anything else happens:
```
#00 ( push high byte of the offset )
.framecount LDZ ( load framecount )
8MOD ( apply modulo 8 to obtain sequence between 0 and 7 )
#08 MUL ( multiply times 8 to get the offset )
```
### adding the offset
adding this offset to the address of our animation is simple:
```
.framecount LDZ ( load framecount )
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 :)
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 )
.Screen/addr DEO2 ( set computed address )
( draw sprite in fg with color 2 and 3 )
color-2-3 .Screen/sprite DEO
BRK
( sprite data )
@animation
&frame0 00 00 00 00 00 00 01 03
&frame1 00 00 00 00 01 03 06 0c
&frame2 00 00 01 03 06 0c 18 30
&frame3 01 03 06 0c 18 30 60 c0
&frame4 03 06 0c 18 30 60 c0 80
&frame5 0c 18 30 60 c0 80 00 00
&frame6 30 60 c0 80 00 00 00 00
&frame7 c0 80 00 00 00 00 00 00
```
i invite you to draw the tile multiple times with different flipping modes, in order to create more interesting animations!
or, better yet, design and use your own sprites!
## slow down!
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.
you'd have to adapt the program to work with that size of framecount - nice exercise, i feel-think!
# instructions of day 4
these are all the uxntal instructions that we discussed today!
* LDA: load and push down into the stack the value at the given absolute address ( address -- value )
* STA: store into the given absolute address the value at the top of the stack ( value address -- )
* LDZ: load and push down into the stack the value at the given zero page address ( address -- value )
* STZ: store into the given zero page address the value at the top of the stack ( value address -- )
* LDR: load and push down into the stack the value at the given relative address ( address -- value )
* STR: store into the given relative address the value at the top of the stack ( value address -- )
the addresses for LDA and STA are always shorts, while the addresses for the other instructions are always one byte.
in short mode, these instructions load or store shorts from or into memory.
in {uxn tutorial day 5} here 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.