2bpp sprites and general corrections

This commit is contained in:
sejo 2021-07-26 17:39:17 -05:00
parent e2f9c7debe
commit cbe891fe7b
3 changed files with 420 additions and 68 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1023 B

View File

@ -1,12 +1,10 @@
# uxn tutorial: day 2, the screen
(this section is a stub, it is being written)
this is the second section of the <(uxn tutorial)>!
here we start exploring the visual aspects of the uxn computer: we talk about the fundamentals of the screen device so that we can draw on it!
in this section we start exploring the visual aspects of the uxn computer: we talk about the fundamentals of the screen device so that we can start drawing on it!
we also discuss working with shorts (2-bytes) besides single bytes, and go over basic operations for manipulating the contents in the stack.
we also discuss working with shorts (2-bytes) besides single bytes.
if you haven't done it already, i recommend you read the previous section at <(uxn tutorial day 1)>
@ -20,9 +18,9 @@ even though uxn is a computer that works natively with 8-bits-sized words (bytes
when we use 8 bits, we can represent 256 different values (2 to the power of 8). at any given time, one byte will store only one of those possible values.
in the previous section we talked already about a case in uxn where this amount of possible values is not enough: the number of bytes that the main memory holds, 65536.
in the previous section, we talked about a case where this amount is not enough in uxn: the number of bytes that the main memory holds, 65536.
that amount of bytes is not arbitrary: that number corresponds to the values that can be represented using two bytes, or 16 bits, or a "short"; 2 to the power of 16. (that quantity is also known as 64KB, where 1KB corresponds to 1024 or 2 to the power of 10)
that number corresponds to the values that can be represented using two bytes, or 16 bits, or a "short": 2 to the power of 16. that quantity is also known as 64KB, where 1KB corresponds to 1024 or 2 to the power of 10.
besides expressing addresses in main memory, today we will see another case where 256 values is not always enough: the x and y coordinates for the pixels in our screen.
@ -32,7 +30,7 @@ how do we deal with them?
## the short mode
counting from right to left, the 6th bit of a byte that encodes an instruction for the uxn computer is a "flag" that corresponds to what is called the short mode.
counting from right to left, the 6th bit of a byte that encodes an instruction for the uxn computer is a binary "flag" that corresponds to what is called the short mode.
whenever this flag is set, i.e. when that bit is 1 instead of 0, the uxn cpu will perform the instruction given by the first 5 bits (the opcode) but using pairs of bytes instead of single bytes.
@ -88,7 +86,7 @@ what would be the state of the stack after executing this code?
#0004 #0008 ADD
```
answer: the stack will have the following values, because we are pushing 4 bytes down onto the stack, ADDing the two of them closest to the top, and pushing the result down onto the stack
that's right! the stack will have the following values, because we are pushing 4 bytes down onto the stack, ADDing the two of them closest to the top, and pushing the result down onto the stack
```
00 04 08 <- top
@ -132,7 +130,7 @@ DEO ( value address -- )
now that we are at it, let's mention its counterpart instruction: DEI (device in).
this instruction needs an i/o address (1 byte) in the stack, and it will push down onto the stack the value (1 byte) that corresponds to that input.
this instruction needs an i/o address (1 byte) in the stack, and it will push down onto the stack the value (1 byte) that corresponds to reading that input.
```
DEI ( address -- value )
@ -140,11 +138,13 @@ DEI ( address -- value )
what would DEO2 and DEI2 do?
in the case of the short mode of DEO and DEI the short aspect applies to the value to output or input, and not to the address.
in the case of the short mode of DEO and DEI, the short aspect applies to the value to output or input and not to the address.
remember that i/o addresses can be covered using one byte only already, so using one short for them would be redundant: the high byte would be always 00.
remember that the 256 i/o addresses are covered using one byte only already, so using one short for them would be redundant: the high byte would be always 00.
therefore, this is the behavior that we can expect: the DEO2 instruction needs a value (1 short) to output, and an i/o address (1 byte) in the stack, in order to output that value to that address.
considering this, the following are the behaviors that we can expect:
the DEO2 instruction needs a value (1 short) to output, and an i/o address (1 byte) in the stack, in order to output that value to that address.
on the other hand, the DEI2 instruction needs an i/o address (1 byte) in the stack, and it will push down onto the stack the value (1 short) that corresponds to that input.
@ -213,16 +213,16 @@ if you prefer to jump right into drawing to the screen, feel free to skip this s
if you tried using the F2 key while running your program before today, you would have found that apparently nothing happened.
that was because the on-screen debugger that the F2 key shows uses the screen device, and therefore needs the system colors to be set.
that was because the on-screen debugger uses the screen device, and therefore needs the system colors to be set.
now that you have some system colors, run your program and press the F2 key: you'll see several elements now!
now that you have some system colors set, run your program and press the F2 key: you'll see several elements now!
=> ./img/screenshot_uxn-debugger.png screenshot of the on-screen debugger using the assigned system colors
* there are some lines and a crosshair drawn with color 2
* there are four rows of eight hexadecimal representations of one byte each, drawn with color 1; these 32 bytes show the deeper contents of the stack, with the stack "top" highlighted using color 2.
* there is a single byte drawn with color 2: it corresponds to the address of the top of the return stack (we'll talk about it on day 5)
* there is another set of 32 bytes, drawn with color 3; these show the contents of the first section of the zero page in the main memory.
* there are some lines and a crosshair in the center, drawn with color 2
* at the top left, there are four rows of eight bytes each, represented in hexadecimal and drawn with color 1; these 32 bytes show the deeper contents of the stack, with the stack "top" highlighted using color 2.
* below, there is a single byte drawn with color 2: it corresponds to the address of the top of the return stack (we'll talk about it on day 5)
* finally, there is another set of 32 bytes, drawn with color 3; these show the contents of the first section of the zero page in the main memory.
remember: you can use the F1 key to switch between different zoom levels.
@ -238,11 +238,11 @@ what are these numbers?
we can think of the highlight in the leftmost 25, as an arrow pointing leftwards to the "top" of the stack. it current position implies that the stack is empty, as there are no more elements to its left.
tip: the stack memory is not erased when taking elements out of it, what changes is the value of the address that points to its top.
note that the stack memory is not erased when taking elements out of it, what changes is the value of the address that points to its top.
## stack debugging test
let's try appending to our program, after setting the system colors, the example code we discussed above:
let's try appending to our program the example code we discussed above, adding it after setting the system colors:
```
#0004 #0008 ADD2
@ -250,7 +250,7 @@ let's try appending to our program, after setting the system colors, the example
run it, open the debugger, and see the contents of the stack.
what does it mean?
what does it mean what you see?
if everything went alright, you'll see:
@ -258,7 +258,7 @@ if everything went alright, you'll see:
00 0c [00] 08
```
if we think of the highlight as an arrow pointing left towards the top of the stack, we'll see that its position corresponds to some extent with the result that we wrote before!
if we think of the highlight as an arrow pointing left towards the top of the stack, we'll see that its position corresponds with the result that we wrote before!
```
00 0c <- top
@ -282,13 +282,13 @@ let's discuss and start using the uxn screen device!
## inputs and outputs
you will be able to find the labels of the i/o memory address space of this device described in uxntal programs as follows:
in uxntal programs you will be able to find the labels corresponding to this device as follows:
```
|20 @Screen [ &vector $2 &width $2 &height $2 &pad $2 &x $2 &y $2 &addr $2 &color $1 ]
|20 @Screen [ &vector $2 &width $2 &height $2 &pad $2 &x $2 &y $2 &addr $2 &color $1 ]
```
the inputs that we can get from this device are:
the inputs that we can read from this device are:
* vector (2 bytes)
* width of the screen (2 bytes)
@ -307,7 +307,7 @@ the screen device has two overlayed layers of the same size, the foreground and
whatever is drawn over the foreground layer will cover anything that is drawn in the same position in the background layer.
in the foreground layer, color 0 is actually completely transparent: a process of alpha blending makes sure that we can see the background layer wherever color 0 is present in the foreground layer.
in the beginning the foreground layer is completey transparent: a process of alpha blending makes sure that we can see the background layer.
# drawing a pixel
@ -348,16 +348,27 @@ the high nibble of that byte will determine the layer in which we'll draw:
and the low nibble of the byte will determine its color.
therefore, the 8 possible combinations of the color byte that we have for drawing a pixel are:
the 8 possible combinations of the color byte that we have for drawing a pixel are:
* 00: draw pixel with color 0 in the background layer
* 01: draw pixel with color 1 in the background layer
* 02: draw pixel with color 2 in the background layer
* 03: draw pixel with color 3 in the background layer
* 10: draw pixel with color 0 in the foreground layer
* 11: draw pixel with color 1 in the foreground layer
* 12: draw pixel with color 2 in the foreground layer
* 13: draw pixel with color 3 in the foreground layer
+ <table>
+ <tr><th>color byte</th><th>layer</th><th>color</th></tr>
+ <tr><td>00</td><td>background</td><td>0</td></tr>
+ <tr><td>01</td><td>background</td><td>1</td></tr>
+ <tr><td>02</td><td>background</td><td>2</td></tr>
+ <tr><td>03</td><td>background</td><td>3</td></tr>
+ <tr><td>10</td><td>foreground</td><td>0</td></tr>
+ <tr><td>11</td><td>foreground</td><td>1</td></tr>
+ <tr><td>12</td><td>foreground</td><td>2</td></tr>
+ <tr><td>13</td><td>foreground</td><td>3</td></tr>
+ </table>
& * 00: draw pixel with color 0 in the background layer
& * 01: draw pixel with color 1 in the background layer
& * 02: draw pixel with color 2 in the background layer
& * 03: draw pixel with color 3 in the background layer
& * 10: draw pixel with color 0 in the foreground layer
& * 11: draw pixel with color 1 in the foreground layer
& * 12: draw pixel with color 2 in the foreground layer
& * 13: draw pixel with color 3 in the foreground layer
## hello pixel
@ -517,9 +528,9 @@ these tiles can be either in a 1bpp (1 bit per pixel) format, 8 bytes in size, o
a 1bpp tile consists in a set of 8 bytes that encode the state of its 8x8 pixels.
each byte corresponds to a row of the tile, and each bit in a row corresponds to the state of a pixel: it can be either "on" (1) or "off" (0).
each byte corresponds to a row of the tile, and each bit in a row corresponds to the state of a pixel from left to right: it can be either "on" (1) or "off" (0).
## encoding a sprite
## encoding a 1bpp sprite
for example, we could design a tile that corresponds to the outline of an 8x8 square, turning on or off its pixels accordingly.
@ -541,14 +552,14 @@ it's worth noting (or remembering) that groups of four bits correspond to a nibb
based on that, we could encode our square as follows:
``` the outline of a square marked with 1s, and its insides marked with 0s, and its equivalent in hexadecimal
11111111 ff
10000001 81
10000001 81
10000001 81
10000001 81
10000001 81
10000001 81
11111111 ff
11111111: ff
10000001: 81
10000001: 81
10000001: 81
10000001: 81
10000001: 81
10000001: 81
11111111: ff
```
## storing the sprite
@ -654,7 +665,7 @@ the low nibble of the byte color will determine the colors that are used to draw
note that 0 in the low nibble will clear the tile.
furthermore, 5, 'a' and 'f' in the low nibble will draw the pixels that are "on" but will leave the ones that are "off" as is: this will allow you to draw over something that has been drawn before.
additionally, 5, 'a' and 'f' in the low nibble will draw the pixels that are "on" but will leave the ones that are "off" as is: this will allow you to draw over something that has been drawn before, without erasing it completely.
## hello sprite
@ -706,7 +717,7 @@ the following code will draw our square sprite with all 16 combinations of color
( macros )
%INIT-X { #0008 .Screen/x DEO2 } ( -- )
%INIT-Y { #0008 .Screen/x DEO2 } ( -- )
%INIT-Y { #0008 .Screen/y DEO2 } ( -- )
%INC-X { .Screen/x DEI2 #0008 ADD2 .Screen/x DEO2 } ( -- )
%INC-Y { .Screen/y DEI2 #0008 ADD2 .Screen/y DEO2 } ( -- )
@ -766,40 +777,381 @@ here are the sprites of the boulder/rock and the character of {darena}:
i invite you to try using these sprites instead to explore how to draw them flipped in the different directions.
# designing sprites
TODO
=> https://wiki.xxiivv.com/site/nasu.html nasu
# responsiveness
TODO
# drawing 2bpp sprites
TODO
in 2bpp sprites, each pixel can have one of four possible states.
# practice
each one of these states can be encoded with a combination of two bits. these states can be assigned different combination of the four system colors, by using appropriate values in the screen color byte.
TODO
a single 2bpp tile of 8x8 pixels needs 16 bytes to be encoded. these bytes are ordered according to a format called chr.
## encoding a 2bpp sprite
to demonstrate this encoding, we are going to remix our 8x8 square, assigning one of four possible states (0, 1, 2, 3) to each of the pixels:
``` an 8x8 square built with the digits 0 and 1 in the border, and 2 and 3 in the inside
00000001
03333311
03333211
03332211
03322211
03222211
01111111
11111111
```
we can think of each these digits as a pair of bits: 0 is 00, 1 is 01, 2 is 10, and 3 is 11.
in this way, we could think of our sprite as follows:
``` an 8x8 square built with pair of bits between parenthesis, corresponding to the binary representation of each of the states
(00) (00) (00) (00) (00) (00) (00) (01)
(00) (11) (11) (11) (11) (11) (01) (01)
(00) (11) (11) (11) (11) (10) (01) (01)
(00) (11) (11) (11) (10) (10) (01) (01)
(00) (11) (11) (10) (10) (10) (01) (01)
(00) (11) (10) (10) (10) (10) (01) (01)
(00) (01) (01) (01) (01) (01) (01) (01)
(01) (01) (01) (01) (01) (01) (01) (01)
```
the chr encoding needs some interesting manipulation of those bits: we can think of each pair of bits as having a high bit in the left and a low bit in the right.
we separate our tile into two different squares, one for the high bits and the other for the low bits:
``` two 8x8 squares corresponding to dividing the previous square in its high and low bits
00000000 00000001
01111100 01111111
01111100 01111011
01111100 01110011
01111100 01100011
01111100 01000011
00000000 01111111
00000000 11111111
```
now we can take each of these squares as 1bpp sprites, and encode them in hexadecimal as he did before:
``` the two previous 8x8 squares with their corresponding hexadecimal encoding
00000000: 00 00000001: 01
01111100: 7c 01111111: 7f
01111100: 7c 01111011: 7b
01111100: 7c 01110011: 73
01111100: 7c 01100011: 63
01111100: 7c 01000011: 43
00000000: 00 01111111: 7f
00000000: 00 11111111: ff
```
## storing the sprite
in order to write this sprite into memory, we first store the square corresponding to the low bits, and then the square corresponding to the high bits. each of them, from top to bottom:
```
@new-square 017f 7b73 6343 7fff 007c 7c7c 7c7c 0000
```
we can set this address in the screen device the same as before:
```
;new-square .Screen/addr DEO2
```
the screen device will use treat this address as a 2bpp sprite when we use the appropriate color byte.
## setting the color
let's see how to use the color byte in order to draw 2bpp tiles!
### color high nibble for 2bpp
the high nibble for 2bpp sprites will allow us to choose the layer we want it to be drawn, and the flip direction, if any:
+ <table>
+ <tr><th>high nibble</th><th>layer</th><th>flip-x</th><th>flip-y</th></tr>
+ <tr><td>4</td><td>background</td><td>no</td><td>no</td></tr>
+ <tr><td>5</td><td>foreground</td><td>no</td><td>no</td></tr>
+ <tr><td>8</td><td>background</td><td>yes</td><td>no</td></tr>
+ <tr><td>9</td><td>foreground</td><td>yes</td><td>no</td></tr>
+ <tr><td>c</td><td>background</td><td>yes</td><td>yes</td></tr>
+ <tr><td>d</td><td>foreground</td><td>yes</td><td>yes</td></tr>
+ </table>
& * 4: draw a 2bpp sprite in the background, original orientation
& * 5: draw a 2bpp sprite in the foreground, original orientation
& * 8: draw a 2bpp sprite in the background, flipped horizontally
& * 9: draw a 2bpp sprite in the foreground, flipped horizontally
& * c: draw a 2bpp sprite in the background, flipped horizontally and vertically
& * d: draw a 2bpp sprite in the foreground, flipped horizontally and vertically
### color low nibble for 2bpp
the low nibble will allow us to choose between many combinations of colors assigned to each different states of the pixels.
+ <table>
+ <tr><th>low nibble</th><th>color for state 0</th><th>color for state 1</th><th>color for state 2</th><th>color for state 3</th></tr>
+ <tr><td>0</td><td>clear</td><td>clear</td><td>clear</td><td>clear</td></tr>
+ <tr><td>1</td><td>0</td><td>1</td><td>2</td><td>3</td></tr>
+ <tr><td>2</td><td>0</td><td>2</td><td>0</td><td>2</td></tr>
+ <tr><td>3</td><td>0</td><td>2</td><td>0</td><td>2</td></tr>
+ <tr><td>4</td><td>1</td><td>1</td><td>1</td><td>1</td></tr>
+ <tr><td>5</td><td>1</td><td>2</td><td>3</td><td>0</td></tr>
+ <tr><td>6</td><td>1</td><td>3</td><td>1</td><td>3</td></tr>
+ <tr><td>7</td><td>1</td><td>0</td><td>3</td><td>2</td></tr>
+ <tr><td>8</td><td>2</td><td>2</td><td>2</td><td>2</td></tr>
+ <tr><td>9</td><td>2</td><td>3</td><td>0</td><td>1</td></tr>
+ <tr><td>a</td><td>2</td><td>0</td><td>2</td><td>0</td></tr>
+ <tr><td>b</td><td>2</td><td>1</td><td>0</td><td>3</td></tr>
+ <tr><td>c</td><td>3</td><td>3</td><td>3</td><td>3</td></tr>
+ <tr><td>d</td><td>3</td><td>0</td><td>1</td><td>2</td></tr>
+ <tr><td>e</td><td>3</td><td>1</td><td>3</td><td>1</td></tr>
+ <tr><td>f</td><td>3</td><td>2</td><td>1</td><td>0</td></tr>
+ </table>
& * 0: clear
& * 1: colors 0, 1, 2, 3
& * 2: colors 0, 2, 0, 2
& * 3: colors 0, 3, 2, 1
& * 4: colors 1, 1, 1, 1
& * 5: colors 1, 2, 3, 0
& * 6: colors 1, 3, 1, 3
& * 7: colors 1, 0, 3, 2
& * 8: colors 2, 2, 2, 2
& * 9: colors 2, 3, 0, 1
& * a: colors 2, 0, 2, 0
& * b: colors 2, 1, 0, 3
& * c: colors 3, 3, 3, 3
& * d: colors 3, 0, 1, 2
& * e: colors 3, 1, 3, 1
& * f: colors 3, 2, 1, 0
## hello new sprites!
=> ./img/screenshot_uxn-tiles-2bpp.png screenshot of the output of the program, showing 16 squares colored with different combinations of outline and fill.
the following code will show our sprite in the 16 different combinations of color. there's some margin in between the tiles in order to appreciate them better:
```
( hello-2bpp-sprite.tal )
( devices )
|00 @System [ &vector $2 &pad $6 &r $2 &g $2 &b $2 ]
|20 @Screen [ &vector $2 &width $2 &height $2 &pad $2 &x $2 &y $2 &addr $2 &color $1 ]
( macros )
%INIT-X { #0008 .Screen/x DEO2 } ( -- )
%INIT-Y { #0008 .Screen/y DEO2 } ( -- )
%INC-X { .Screen/x DEI2 #000c ADD2 .Screen/x DEO2 } ( -- )
%INC-Y { .Screen/y DEI2 #000c ADD2 .Screen/y DEO2 } ( -- )
( main program )
|0100
( set system colors )
#2ce9 .System/r DEO2
#01c0 .System/g DEO2
#2ce5 .System/b DEO2
( set initial x,y coordinates )
INIT-X INIT-Y
( set sprite address )
;new-square .Screen/addr DEO2
#40 .Screen/color DEO INC-X
#41 .Screen/color DEO INC-X
#42 .Screen/color DEO INC-X
#43 .Screen/color DEO INC-Y
INIT-X
#44 .Screen/color DEO INC-X
#45 .Screen/color DEO INC-X
#46 .Screen/color DEO INC-X
#47 .Screen/color DEO INC-Y
INIT-X
#48 .Screen/color DEO INC-X
#49 .Screen/color DEO INC-X
#4a .Screen/color DEO INC-X
#4b .Screen/color DEO INC-Y
INIT-X
#4c .Screen/color DEO INC-X
#4d .Screen/color DEO INC-X
#4e .Screen/color DEO INC-X
#4f .Screen/color DEO
BRK
@new-square 017f 7b73 6343 7fff 007c 7c7c 7c7c 0000
```
try flipping the tiles!
## screen.tal and the combinations of the color byte
the screen.tal example in the uxn repo consists of a table showing all possible (256!) combinations of high and low nibbles in the color byte.
=> ./img/screenshot_uxn-screen.png screenshot of the screen.tal example, that shows a sprite colored and flipped in different ways.
=> https://git.sr.ht/~rabbits/uxn/tree/master/item/projects/examples/devices/screen.tal screen.tal code
compare them with everything we have said before about the color byte!
## designing sprites
nasu is a tool by 100R, written in uxntal, that makes it easier to design and export 2bpp sprites.
=> https://100r.co/site/nasu.html 100R - nasu
besides using it to draw with colors 1, 2, 3 (and erasing to get color 0), you can use it to find your system colors, to see how your sprites will look with the different color modes (aka blending modes), and to assemble assets made of multiple sprites.
you can export and import chr files, that you can include in your code using a tool like hexdump.
i recommend you give it a try!
# screen size and responsiveness
the last thing we'll cover today has to do with the assumptions uxn makes about the screen size, and some code strategies we can use to deal with them.
in short, there's not a standard screen size!
by default, the screen of the uxnemu emulator is 512x320 pixels (or 64x40 tiles).
however, and for example, uxn also runs in the nintendo ds, with a resolution of 256x192 pixels (32x24 tiles), and in the teletype with a resolution of 128x64 pixels (16x8 tiles)
as programmers, we are expected to decide what to do with these: our programs can adapt to the different screen sizes, they might have different modes depending on the screen size, and so on.
## changing the screen size
as of today, the way of changing the screen size in uxnemu is by editing its source code.
in the uxn repo we downloaded, inside the src/ directory, there's uxnemu.c, with a line that looks like that the following:
```
if(!initppu(&ppu, 64, 40))
```
those two numbers, 64 and 40, are the default screen size in tiles, as we mentioned above.
you can change those, save the file, and then re-run the build.sh script to have uxnemu working with this new resolution.
## reading and adapting to the screen size (the basics)
as you may recall from the device addresses mentioned above, the screen allows us to read its width and height, as shorts.
if we wanted to, for example, draw a pixel in the middle of the screen regardless of the screen size, we can translate to uxntal an expression like the following:
```
x = screenwidth/2
y = screenheight/2
```
### uxntal division
for this, let's introduce the MUL and DIV instructions: they work like ADD and SUB, but for multiplication and division:
* MUL: take the top two elements from the stack, multiply them, and push down the result ( a b -- a*b )
* DIV: take the top two elements from the stack, divide them, and push down the result ( a b -- a/b )
using DIV, our translated expression for the case of the x coordinate, could look like:
```
.Screen/width DEI2 ( get screen width into the stack )
#0002 DIV2 ( divide over 2 )
.Screen/x DEO2 ( take the result from the stack and output it to Screen/x )
```
### bitwise shifting
if what we want is to divide over or multiply by powers of two (like in this case), we can also use the SFT instruction.
this instruction takes a number and a "shift value" that indicates the amount of bits to shift to the right, and/or to the left.
the low nibble of the shift value tells uxn how many bits to shift to the right, and the high nibble expresses how many bits to shift to the left.
in order to divide a number over 2, we'd need to shift its bits one space to the right.
for example, dividing 10 (in decimal) over 2 could be expressed as follows:
```
#0a #01 SFT ( result: 05 )
```
0a is 0000 1010 in binary, and 05 is 0000 0101 in binary.
to multiply times 2, we shift one space to the left:
```
#0a #10 SFT ( result: 14 in hexadecimal )
```
14 in hexadecimal (20 in decimal), is 0001 0100 in binary.
in short mode, the number to shift is a short, but the shift value is still a byte.
for example, the following will divide the screen width over two, by using bitwise shifting:
```
.Screen/width DEI2
#01 SFT2
```
### HALF macros
in order to keep illustrating the use of macros, we could define a HALF and HALF2 macros, either using DIV or SFT.
using DIV:
```
%HALF { #02 DIV } ( number -- number/2 )
%HALF2 { #0002 DIV2 } ( number -- number/2 )
```
using SFT:
```
%HALF { #01 SFT } ( number -- number/2 )
%HALF2 { #01 SFT2 } ( number -- number/2 )
```
and use any of them to calculate the center:
```
.Screen/width DEI2 HALF .Screen/x DEO2
.Screen/height DEI2 HALF .Scren/y DEO2
```
not that the HALF2 macro using SFT2 would require one byte less than the one using DIV2. this may or may not be important depending on your priorities :)
## drawing sprites in specific positions
as an exercise for you, i invite you to write the code in order to do some or all of the following:
* draw an 8x8 tile completely centered in the screen
* draw an 8x8 tile in each of the corners of the screen
* draw an 8x8 tile touching each of the screen borders, centered in each of them
do the same, but using an image composed of multiple tiles (e.g. 2x2 tiles, 1x2 tiles, etc).
# instructions of day 2
today we covered the short mode, that indicates the cpu that it should operate with words that are 2 bytes long.
these are the instructions we covered today:
new instructions: DEI, BRK, MUL, DIV, SWP, OVR, ROT, DUP, POP
besides covering the basics of the screen device today, we discussed these new instructions:
* DEI: read a value into the stack, from the device address given in the stack ( address -- value )
* BRK: break the flow of the program, in order to close subroutines
* MUL: take the top two elements from the stack, multiply them, and push down the result ( a b -- a*b )
* DIV: take the top two elements from the stack, divide them, and push down the result ( a b -- a/b )
* SFT: take a shift value and a number to shift with that value, and shift it. the low nibble of the shift value indicates the shift to the right, and the high nibble the shift to the left ( number shift -- shiftednumber )
# day 3
we also covered the short mode, that indicates the cpu that it should operate with words that are 2 bytes long.
stay tuned for the next sections of the <(uxn tutorial)>!
# coming soon: day 3
in the next section of the <(uxn tutorial)> we'll start working with interactivity in the screen!
meanwhile, i invite you to take a break, and keep exploring drawing in the uxn screen via code!
stay tuned!
# support
if you found this tutorial to be helpful, consider sharing it and giving it your <(support)> :)