Compare commits

...

3 Commits

3 changed files with 111 additions and 96 deletions

View File

@ -7,16 +7,21 @@ we have a twitch channel that we're using to stream our maintenance practice, fo
# upcoming stream(s)
* 12024-03-16, saturday, 19:00-21:00 UTC+1
* 12024-03-28, thursday, 19:00-21:00 UTC+1
# stream log
in reverse chronological order:
## 12024-03-16: uxn tutorial day 2 (part 2.1)
in this stream, we updated the example sprite for the 1bpp mode; it's now an arrow pointing downwards and to the left so that the flipping is more evident. we updated the corresponding code.
we also updated the colors table (sprite byte low nibble for 1bpp) and did some other minor formatting corrections.
## 12024-03-14: uxn tutorial day 2 (part 1)
in this stream, we went through the first part of {uxn tutorial day 2} and decided to split it into two parts: morning and evening. this change will be implemented in the next stream.
in this stream, we went through the first part of {uxn tutorial day 2} and decided to split it into two parts: morning and evening.
we updated the colors in all the examples (to do: update the screenshots) to have them further differentiated.

View File

@ -29,24 +29,28 @@ implement the following concepts as {coloring computers}:
## tutorial
### day 2 and onwards
* remove square brackets in devices?
* divide into morning and evening
* update images if needed
* check blend mode 0
* remove square brackets in devices
* update images (to do: emulator needs a patch)
* check blend mode 0 (in progress)
=> https://lists.sr.ht/~rabbits/uxn/%3C692CA0D5-0200-408D-9357-BF0D8887D2BF%40noyu.me%3E Blend mode 0
=> https://lists.sr.ht/~rabbits/uxn/%3CCAE2DaSQuj%3DC8e7ofV3+4H6MaTOhtD_wrFWihhYtCuYiEVtV6WQ%40mail.gmail.com%3E Massive tiny change coming to Varvara's Screen device
> the #00 blending will, from now on, only clear the pixels that are present in the sprite data at Screen/addr*.
* auto sprite flipping
* {uxn tutorial day 6} auto sprite flipping
=> https://lists.sr.ht/~rabbits/uxn/%3CCAE2DaSQQMb8XVfsn2NSsXQO+-0m2t4U2GD7nYD3GBUO4GPeTxQ%40mail.gmail.com%3E Whole auto sprite flipping
* make a folder of examples
* whenever we mention the theme loading, link to the suggested palette.
* replace intro to colors with a table.
* replace {uxn tutorial day 2} intro to colors with a table.
* format and update {uxn running}
### further changes
* {uxn tutorial day 2}: divide into morning and evening
* {uxn tutorial day 2}: check sprite nibbles tables. include colors when colors are mentioned.
* new day: lambdas and more complex stuff (jumps, callings, etc)
* include uxn5 in the web tutorial so that code can be run from there
=> https://git.sr.ht/~rabbits/uxn5 uxn5
* format and update {uxn running}
## traducción:

View File

@ -131,7 +131,7 @@ the DEO instruction needs a value (1 byte) to output, and an i/o address (1 byte
DEO ( value address -- )
```
this instuction has a counterpart: DEI (device in).
this instruction has a counterpart: DEI (device in).
the DEI instruction takes an i/o address (1 byte) from the stack, and it will push down onto the stack the value (1 byte) that corresponds to reading that input.
@ -488,39 +488,41 @@ nice, isn't it? the operations now look clearer! and if we wanted to have this l
try writing the macro and using it in different positions of the screen!
afterwards, i recommend you to take a break, as we have covered a lot of ground already!
# drawing sprites
now, we'll see how to leverage the built-in support for "sprites" in the varvara screen device in order to draw many pixels at once!
drawing one pixel at a time can be fun, but the varvara screen device has a built-in support for "sprites". we'll see how to leverage that capability in order to draw many pixels at once!
the varvara screen device allows us to use and draw tiles of 8x8 pixels, also called sprites.
there are two posible modes: 1bpp (1 bit per pixel), and 2bpp (2 bits per pixel).
1bpp tiles use two colors, and they are encoded using 8 bytes; using one bit per pixel means that we can only encode if that pixel is using one color, or the other.
1bpp tiles use two colors and they are encoded using 8 bytes. using one bit per pixel means that we can only encode if that pixel is using one color or the other.
2bpp tiles use four colors and they are encoded using 16 bytes; using two bits per pixel means we can encode which one of the four available colors the pixel has.
2bpp tiles use four colors and they are encoded using 16 bytes. using two bits per pixel means we can encode which one of the four available colors the pixel has.
we will be storing and accessing these tiles from the main memory.
# drawing 1bpp sprites
a 1bpp tile consists in a set of 8 bytes that encode the state of its 8x8 pixels.
a 1bpp tile consists of a set of 8 bytes that encodes 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 from left to right: it can be either "on" (1) or "off" (0).
each byte corresponds to a row of the tile. each bit in a row, going from left to right, corresponds to the state of a pixel: it can be either "on" (1) or "off" (0).
## 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.
for example, we could design a tile that corresponds to an arrow pointing downwards and to the left, within an 8x8 square, turning on or off its pixels accordingly. (if it doesn't look like an arrow yet, trust me for a little bit and you'll see)
``` the outline of a square marked with 1s, and its insides marked with 0s
11111111
10000001
10000001
10000001
10000001
10000001
10000001
11111111
``` an arrow pointing downwards and left, made with 1s, the negative space marked with 0s
00000001
00000010
00000100
10001000
11010000
11100000
11110000
11111000
```
as each of the rows is a byte, we can encode them as hexadecimal numbers instead of binary.
@ -529,28 +531,31 @@ 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
``` the same arrow as above, and its equivalent in hexadecimal
00000001: 01
00000010: 02
00000100: 04
10001000: 88
11010000: d0
11100000: e0
11110000: f0
11111000: f8
```
this process is illustrated by Rostiger's notes here, but using a square:
=> https://nchrs.xyz/uxn_notes.html nchrs: uxn notes
## storing the sprite
in uxntal, we need to label and write into main memory the data corresponding to the sprite. we write the bytes going from top to bottom of the sprite:
in uxntal, we need to label and write into main memory the data corresponding to the sprite. we write the bytes in order, from left to right, starting from the top and towards the bottom of the sprite:
```
@square ff81 8181 8181 81ff
@arrow [ 0102 0488 d0e0 f0f8 ]
```
note that we are not using the literal hex (#) rune here: we want to use the raw bytes in memory, and we don't need to push them down onto the stack.
note that we are not using the literal hex (#) rune here: we want to use the raw bytes in memory, and we don't need to push them down onto the stack. the square brackets are only used for visually grouping the code and are ignored by the assemblers.
to make sure that these bytes are not read as instructions by the uxn cpu, it's a good practice to precede them with the BRK instruction: this will interrupt the execution of the program before arriving here, leaving uxn in a state where it's waiting for inputs.
to make sure that these bytes are not read as instructions by the uxn cpu, it's a good practice to precede them with the BRK instruction. this is a new instruction for us! this instruction will interrupt the execution of the program before arriving to the data, leaving uxn in a state where it's waiting for inputs.
we'll see in a moment where to write this code.
@ -561,24 +566,26 @@ in order to draw the sprite, we need to send its address in memory to the screen
to achieve the former, we write the following:
```
;square .Screen/addr DEO2
;arrow .Screen/addr DEO2
```
a new rune is here! the literal absolute address rune (;) lets us push down onto the stack the absolute address of the given label in main memory.
an absolute address would be 2-bytes long, and is pushed down onto the stack with LIT2, included by the assembler when using this rune.
an absolute address is an address pointing to a location within the whole main memory space of 65536 bytes (from 0000 to ffff in hexadecimal). therefore, an absolute address is one short, i.e. it is 2-bytes long.
because the address is 2-bytes long, we output it using DEO2.
when using the literal absolute address rune (;), the assembler precedes the address with a LIT2 instruction. in this way, the address is pushed down onto the stack.
because the address is 2-bytes long, we send it to the screen device it using DEO2.
## setting the color
similar to what we saw already with the pixel, sending a byte to .Screen/sprite will perform the drawing in the screen.
similar to what we saw above when drawing a pixel, sending a byte to .Screen/sprite will perform the drawing of the sprite in the screen.
### sprite high nibble for 1bpp
the high nibble of the 'sprite' byte will determine the layer in which we'll draw, just like when we were drawing using the 'pixel' byte.
however, in this case we'll have other possibilities: we can flip the sprite in the horizontal (x) and/or the vertical (y) axis.
however, in this case we'll have other possibilities: we can flip the sprite in the vertical (y) and/or the horizontal (x) axis.
the eight possible values of the sprite high nibble, used for drawing a 1bpp sprite, are:
@ -627,63 +634,61 @@ a high nible of 1, i.e. 0001 in binary, has the last flag on, so that's why it's
### sprite low nibble for 1bpp
the low nibble of the 'sprite' byte will determine the colors that are used to draw the "on" (1) and "off"(0) pixels of the tiles.
the low nibble of the 'sprite' byte will determine the colors that are used to draw the "on" (1) and "off" (0) pixels of the tiles.
+ <table>
+ <tr><th></th><th colspan="4">colors for:</th></tr>
+ <tr><th>sprite low</th><th>1</th><th>0</th></tr>
+ <tr><td class="num">0</td><td>clear</td><td>clear</td></tr>
+ <tr><td class="num">1</td><td>1</td><td>0</td></tr>
+ <tr><td class="num">2</td><td>2</td><td>0</td></tr>
+ <tr><td class="num">3</td><td>3</td><td>0</td></tr>
+ <tr><td class="num">4</td><td>0</td><td>1</td></tr>
+ <tr><td class="num">5</td><td>1</td><td>none</td></tr>
+ <tr><td class="num">6</td><td>2</td><td>1</td></tr>
+ <tr><td class="num">7</td><td>3</td><td>1</td></tr>
+ <tr><td class="num">8</td><td>0</td><td>2</td></tr>
+ <tr><td class="num">9</td><td>1</td><td>2</td></tr>
+ <tr><td class="num">a</td><td>2</td><td>none</td></tr>
+ <tr><td class="num">b</td><td>3</td><td>2</td></tr>
+ <tr><td class="num">c</td><td>0</td><td>3</td></tr>
+ <tr><td class="num">d</td><td>1</td><td>3</td></tr>
+ <tr><td class="num">e</td><td>2</td><td>3</td></tr>
+ <tr><td class="num">f</td><td>3</td><td>none</td></tr>
+ <tr><td class="num">0</td><td>clear</td><td>none</td></tr>
+ <tr><td class="num">1</td><td>color1</td><td>color0</td></tr>
+ <tr><td class="num">2</td><td>color2</td><td>color0</td></tr>
+ <tr><td class="num">3</td><td>color3</td><td>color0</td></tr>
+ <tr><td class="num">4</td><td>color0</td><td>color1</td></tr>
+ <tr><td class="num">5</td><td>color1</td><td>none</td></tr>
+ <tr><td class="num">6</td><td>color2</td><td>color1</td></tr>
+ <tr><td class="num">7</td><td>color3</td><td>color1</td></tr>
+ <tr><td class="num">8</td><td>color0</td><td>color2</td></tr>
+ <tr><td class="num">9</td><td>color1</td><td>color2</td></tr>
+ <tr><td class="num">a</td><td>color2</td><td>none</td></tr>
+ <tr><td class="num">b</td><td>color3</td><td>color2</td></tr>
+ <tr><td class="num">c</td><td>color0</td><td>color3</td></tr>
+ <tr><td class="num">d</td><td>color1</td><td>color3</td></tr>
+ <tr><td class="num">e</td><td>color2</td><td>color3</td></tr>
+ <tr><td class="num">f</td><td>color3</td><td>none</td></tr>
+ </table>
& * 0: clear tile
& * 1: "on" with color 1, "off" with color 0
& * 2: "on" with color 2, "off" with color 0
& * 3: "on" with color 3, "off" with color 0
& * 4: "on" with color 0, "off" with color 1
& * 5: "on" with color 1, "off" with no color
& * 6: "on" with color 2, "off" with color 1
& * 7: "on" with color 3, "off" with color 1
& * 8: "on" with color 0, "off" with color 2
& * 9: "on" with color 1, "off" with color 2
& * a: "on" with color 2, "off" with no color
& * b: "on" with color 3, "off" with color 2
& * c: "on" with color 0, "off" with color 3
& * d: "on" with color 1, "off" with color 3
& * e: "on" with color 2, "off" with color 3
& * f: "on" with color 3, "off" with no color
& * 0: "on" will be cleared, "off" will be left as is
& * 1: "on" with color1, "off" with color0
& * 2: "on" with color2, "off" with color0
& * 3: "on" with color3, "off" with color0
& * 4: "on" with color0, "off" with color1
& * 5: "on" with color1, "off" will be left as is
& * 6: "on" with color2, "off" with color1
& * 7: "on" with color3, "off" with color1
& * 8: "on" with color0, "off" with color2
& * 9: "on" with color1, "off" with color2
& * a: "on" with color2, "off" will be left as is
& * b: "on" with color3, "off" with color2
& * c: "on" with color0, "off" with color3
& * d: "on" with color1, "off" with color3
& * e: "on" with color2, "off" with color3
& * f: "on" with color3, "off" will be left as is
as an example, this means that setting the sprite low nibble to 6 will draw the sprite with color 2 in the "on" pixels, and color 1 in the "off" pixels.
as an example, this means that setting the sprite low nibble to 6 will draw the sprite with color2 in the "on" pixels, and color1 in the "off" pixels.
note that 0 in the low nibble will clear the tile.
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.
note that 0 in the low nibble will clear the "on" pixels of the tile, leaving the remaining ones as is. additionally, 5, 'a' and 'f' in the low nibble will draw the pixels that are "on" and will also 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.
don't worry if this is not making a lot of sense: let's see an example!
## hello sprite
the following program will draw our sprite once:
the following program will draw our sprite once using color1 over a background of color0:
```
( hello-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 &pixel $1 &sprite $1 ]
|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 &pixel $1 &sprite $1
( main program )
|0100
@ -697,17 +702,19 @@ the following program will draw our sprite once:
#0008 .Screen/y DEO2
( set sprite address )
;square .Screen/addr DEO2
;arrow .Screen/addr DEO2
( draw sprite in the background )
( using color 1 for the outline )
( draw 1bpp sprite in the background )
( using color1 for the outline )
#01 .Screen/sprite DEO
BRK
@square ff81 8181 8181 81ff
@arrow [ 0102 0488 d0e0 f0f8 ]
```
nice, there's our arrow!
## hello sprites
=> ./img/screenshot_uxn-tiles.png screenshot of the output of the program, showing 16 squares colored with different combinations of outline and fill.
@ -718,8 +725,8 @@ the following code will draw our square sprite with all 16 combinations of color
( hello-sprites.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 &pixel $1 &sprite $1 ]
|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 &pixel $1 &sprite $1
( macros )
%INIT-X { #0008 .Screen/x DEO2 } ( -- )
@ -738,7 +745,7 @@ the following code will draw our square sprite with all 16 combinations of color
INIT-X INIT-Y
( set sprite address )
;square .Screen/addr DEO2
;arrow .Screen/addr DEO2
#00 .Screen/sprite DEO 8ADD-X
#01 .Screen/sprite DEO 8ADD-X
@ -765,23 +772,22 @@ the following code will draw our square sprite with all 16 combinations of color
BRK
@square ff81 8181 8181 81ff
@arrow [ 0102 0488 d0e0 f0f8 ]
```
note that in this case, we have a couple of 8ADD-X and 8ADD-Y macros to increment each coordinate by 0008: that's the size of the tile.
## flipping experiments
because the square sprite is symmetric, we can't really see the effect of flipping it.
i invite you to try changing the sprite byte high nibble to explore the effects of flipping the sprites.
here are the sprites of the boulder/rock and the character of {darena}:
additionally, here are more sprites that you can use to test. they are the boulder/rock and the character of {darena}:
```
@rock 3c4e 9ffd f962 3c00
@character 3c7e 5a7f 1b3c 5a18
@rock [ 3c4e 9ffd f962 3c00 ]
@character [ 3c7e 5a7f 1b3c 5a18 ]
```
i invite you to try using these sprites instead to explore how to draw them flipped in the different directions.
# drawing 2bpp sprites