Four pages of tiles, in bits that were already there
A tile number is a byte and a byte reaches 256, which is not many once a font has taken 135 of them and a game wants a character, a background and a wall. Bits 4 and 5 of the attribute now say which page of 256 the number is in - bits already written on every cell and every sprite, and reserved for this since the attribute was defined. Four pages of 16K is 64K, which is the whole atlas, so THE FOURTH PAGE IS THE MEMORY THE SPRITE TABLE AND THE PALETTE ARE IN. That is not a hole in the design; it is the answer shared video memory has always given, and it is checked rather than forbidden. The atlas is 1024 tiles, and what a program spends on sprites and colours comes out of them: no sprites means page 3 is art, and sprites means 768 tiles and a reason. The page is a property of the CELL and not a mode, so one screen shows tiles from all four at once and nothing has to decide which page it is in. Both places a tile is drawn from now ask one function where the art is. They would otherwise drift: the sprite pass was written days after the map pass and neither is where the other is looked at. Nothing in CosmOS changes. The shell draws from page 0, which the screen save covers; a tile left in another page is invisible unless a map cell names that page, and the map is given back or cleared. Both breaks were tried and both failed the checks - and the second had to be tried twice, because the constant it needed lives in video.h and the harness was only editing video.c. That is the same silent no-op as yesterday's uncompiled break, in a different disguise. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW
This commit is contained in:
co-authored by
Claude Opus 5
parent
a916103a7f
commit
9eed23120f
@@ -1205,6 +1205,11 @@ before quietly answers to nothing.
|
|||||||
| 5 | The screen's map, for the same. |
|
| 5 | The screen's map, for the same. |
|
||||||
| 6 and up | Free for a program to use. |
|
| 6 and up | Free for a program to use. |
|
||||||
|
|
||||||
|
**Tile pages 1 to 3 are not saved either**, and need not be: the shell's own text is drawn
|
||||||
|
from page 0, which is, and a tile left in another page is invisible unless a map cell names
|
||||||
|
that page - and the map is given back or cleared. What a program puts in page 1 is its own
|
||||||
|
and nobody is looking at it afterwards.
|
||||||
|
|
||||||
**The sprite table is cleared at exit, not saved and restored.** It lives in the atlas at
|
**The sprite table is cleared at exit, not saved and restored.** It lives in the atlas at
|
||||||
0xC000, and the pages the screen save walks run to the end of the map and pick up again at the
|
0xC000, and the pages the screen save walks run to the end of the map and pick up again at the
|
||||||
palette, with the sprites in the gap between. That is deliberate: nothing the shell draws is a
|
palette, with the sprites in the gap between. That is deliberate: nothing the shell draws is a
|
||||||
|
|||||||
+17
-4
@@ -29,6 +29,18 @@ static uint8_t videoScreen[VIDEO_SCREEN_COUNT][VIDEO_MEMORY_BYTES];
|
|||||||
// frame, exactly like the pixel buffer beside it.
|
// frame, exactly like the pixel buffer beside it.
|
||||||
static uint8_t backgroundEmpty[VIDEO_MAX_WIDTH * VIDEO_MAX_HEIGHT];
|
static uint8_t backgroundEmpty[VIDEO_MAX_WIDTH * VIDEO_MAX_HEIGHT];
|
||||||
|
|
||||||
|
// ---- Where a tile's art is ----
|
||||||
|
//
|
||||||
|
// The scheme nibble and the page bits live in the same byte and are asked of it in the same
|
||||||
|
// breath, in the two places a tile is drawn from: a map cell and a sprite. One function, so
|
||||||
|
// that the two cannot drift apart - which they would, because the sprite pass was written
|
||||||
|
// three days after the map pass and neither is where the other is looked at.
|
||||||
|
static const uint8_t *tileArt(uint8_t attribute, uint8_t tile) {
|
||||||
|
const int page = (attribute & VIDEO_ATTRIBUTE_PAGE) >> VIDEO_ATTRIBUTE_SHIFT;
|
||||||
|
return videoAtlas + VIDEO_TILE_BASE + page * VIDEO_TILE_PAGE_BYTES
|
||||||
|
+ tile * VIDEO_TILE_BYTES;
|
||||||
|
}
|
||||||
|
|
||||||
// Which screen is being shown. The console draws into THIS one rather than into a screen of
|
// Which screen is being shown. The console draws into THIS one rather than into a screen of
|
||||||
// its own, so text goes where whoever is looking is looking - which matters most when the
|
// its own, so text goes where whoever is looking is looking - which matters most when the
|
||||||
// text is a fault message printed over a game that had flipped.
|
// text is a fault message printed over a game that had flipped.
|
||||||
@@ -377,7 +389,8 @@ static void drawSprites(uint8_t *pixels, int width, int height) {
|
|||||||
| (entry[VIDEO_SPRITE_X + 1] << 8));
|
| (entry[VIDEO_SPRITE_X + 1] << 8));
|
||||||
const int top = (int16_t)(uint16_t)(entry[VIDEO_SPRITE_Y]
|
const int top = (int16_t)(uint16_t)(entry[VIDEO_SPRITE_Y]
|
||||||
| (entry[VIDEO_SPRITE_Y + 1] << 8));
|
| (entry[VIDEO_SPRITE_Y + 1] << 8));
|
||||||
const uint8_t bank = (uint8_t)((entry[VIDEO_SPRITE_ATTRIBUTE] & 0x0F) << 4);
|
const uint8_t bank =
|
||||||
|
(uint8_t)((entry[VIDEO_SPRITE_ATTRIBUTE] & VIDEO_ATTRIBUTE_SCHEME) << 4);
|
||||||
const uint8_t flags = entry[VIDEO_SPRITE_FLAGS];
|
const uint8_t flags = entry[VIDEO_SPRITE_FLAGS];
|
||||||
const int mirrored = (flags & VIDEO_SPRITE_HFLIP) != 0;
|
const int mirrored = (flags & VIDEO_SPRITE_HFLIP) != 0;
|
||||||
const int inverted = (flags & VIDEO_SPRITE_VFLIP) != 0;
|
const int inverted = (flags & VIDEO_SPRITE_VFLIP) != 0;
|
||||||
@@ -396,7 +409,7 @@ static void drawSprites(uint8_t *pixels, int width, int height) {
|
|||||||
// is a byte and the tile number is one.
|
// is a byte and the tile number is one.
|
||||||
const uint8_t tile = (uint8_t)(entry[VIDEO_SPRITE_TILE]
|
const uint8_t tile = (uint8_t)(entry[VIDEO_SPRITE_TILE]
|
||||||
+ readDown * wide + readAcross);
|
+ readDown * wide + readAcross);
|
||||||
const uint8_t *art = videoAtlas + VIDEO_TILE_BASE + tile * VIDEO_TILE_BYTES;
|
const uint8_t *art = tileArt(entry[VIDEO_SPRITE_ATTRIBUTE], tile);
|
||||||
|
|
||||||
for (int y = 0; y < VIDEO_CELL_PIXELS; y++) {
|
for (int y = 0; y < VIDEO_CELL_PIXELS; y++) {
|
||||||
const int atY = top + downTile * VIDEO_CELL_PIXELS + y;
|
const int atY = top + downTile * VIDEO_CELL_PIXELS + y;
|
||||||
@@ -502,8 +515,8 @@ void videoRender(void) {
|
|||||||
// of sixteen colour schemes without a second copy of it in tile memory, and a
|
// of sixteen colour schemes without a second copy of it in tile memory, and a
|
||||||
// tile that wants all 256 colours simply leaves the nibble at zero and gets
|
// tile that wants all 256 colours simply leaves the nibble at zero and gets
|
||||||
// them. One adder in hardware, and neither use costs the other anything.
|
// them. One adder in hardware, and neither use costs the other anything.
|
||||||
const uint8_t bank = (uint8_t)((attribute & 0x0F) << 4);
|
const uint8_t bank = (uint8_t)((attribute & VIDEO_ATTRIBUTE_SCHEME) << 4);
|
||||||
const uint8_t *art = videoAtlas + VIDEO_TILE_BASE + tile * VIDEO_TILE_BYTES;
|
const uint8_t *art = tileArt(attribute, tile);
|
||||||
for (int y = 0; y < VIDEO_CELL_PIXELS; y++) {
|
for (int y = 0; y < VIDEO_CELL_PIXELS; y++) {
|
||||||
// Where this row of the cell lands once the view has been slid up by the
|
// Where this row of the cell lands once the view has been slid up by the
|
||||||
// fine offset. Negative means it is the part of the top cell that is off
|
// fine offset. Negative means it is the part of the top cell that is off
|
||||||
|
|||||||
+30
-2
@@ -42,12 +42,30 @@
|
|||||||
|
|
||||||
// ---- In the ATLAS bank ----
|
// ---- In the ATLAS bank ----
|
||||||
//
|
//
|
||||||
// Tile memory: 256 tiles of 8x8, one byte a pixel. Everything above it is free, and is
|
// Tile memory: 256 tiles of 8x8, one byte a pixel.
|
||||||
// where more tiles and the sprite table are going.
|
|
||||||
#define VIDEO_TILE_BASE 0x0000
|
#define VIDEO_TILE_BASE 0x0000
|
||||||
#define VIDEO_TILE_BYTES 64
|
#define VIDEO_TILE_BYTES 64
|
||||||
#define VIDEO_TILE_COUNT 256
|
#define VIDEO_TILE_COUNT 256
|
||||||
|
|
||||||
|
// ---- Four pages of them ----
|
||||||
|
//
|
||||||
|
// A tile number is a byte and a byte reaches 256, which is not many once a font has taken
|
||||||
|
// 135 of them and a game wants a character, a background and a wall. So two bits of the
|
||||||
|
// ATTRIBUTE say which page of 256 the number is in - bits that were already there, already
|
||||||
|
// written on every cell and every sprite, and reserved from the day the attribute was
|
||||||
|
// defined for exactly this.
|
||||||
|
//
|
||||||
|
// Four pages of 16K is 64K, which is the whole atlas, so THE FOURTH PAGE IS THE MEMORY THE
|
||||||
|
// SPRITE TABLE AND THE PALETTE ARE IN. That is not a hole in the design, it is the same
|
||||||
|
// answer shared video memory has always given: the atlas is 1024 tiles, and what a program
|
||||||
|
// spends on sprites and colours comes out of them. A program that wants no sprites may have
|
||||||
|
// page three for art, and one that wants sprites has 768 tiles and knows why.
|
||||||
|
//
|
||||||
|
// The page is per CELL and per SPRITE rather than a mode, so a screen can show tiles from
|
||||||
|
// all four at once and a program never has to decide which page it is "in".
|
||||||
|
#define VIDEO_TILE_PAGE_BYTES (VIDEO_TILE_COUNT * VIDEO_TILE_BYTES)
|
||||||
|
#define VIDEO_TILE_PAGES 4
|
||||||
|
|
||||||
// ---- The map, one page a row ----
|
// ---- The map, one page a row ----
|
||||||
//
|
//
|
||||||
// A row is padded to exactly 256 bytes whether the mode uses all of it or not, and that is
|
// A row is padded to exactly 256 bytes whether the mode uses all of it or not, and that is
|
||||||
@@ -71,6 +89,16 @@
|
|||||||
// Two bytes to a cell: which tile, and how to colour it.
|
// Two bytes to a cell: which tile, and how to colour it.
|
||||||
#define VIDEO_CELL_BYTES 2
|
#define VIDEO_CELL_BYTES 2
|
||||||
|
|
||||||
|
// ---- What the attribute byte means, in both places it appears ----
|
||||||
|
//
|
||||||
|
// A map cell's second byte and a sprite's byte 1 are the same thing and are read the same
|
||||||
|
// way, which is what lets the same art be a background in one place and a moving thing in
|
||||||
|
// another with nothing rewritten.
|
||||||
|
#define VIDEO_ATTRIBUTE_SCHEME 0x0F
|
||||||
|
#define VIDEO_ATTRIBUTE_PAGE 0x30
|
||||||
|
#define VIDEO_ATTRIBUTE_SHIFT 4
|
||||||
|
// Bits 6 and 7 are still reserved and should be left at nought.
|
||||||
|
|
||||||
// ---- A bitmap, over the top of the tiles and the map ----
|
// ---- A bitmap, over the top of the tiles and the map ----
|
||||||
//
|
//
|
||||||
// THE SAME MEMORY MEANING DIFFERENT THINGS IN DIFFERENT MODES, which is what shared video
|
// THE SAME MEMORY MEANING DIFFERENT THINGS IN DIFFERENT MODES, which is what shared video
|
||||||
|
|||||||
@@ -621,11 +621,12 @@ Two rather than one because the two halves of a screen are written at completely
|
|||||||
|
|
||||||
| Bank | Address | Holds |
|
| Bank | Address | Holds |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| Atlas | 0x0000 - 0x3FFF | Tile memory. 256 tiles of 8 by 8, one byte a pixel, so tile n begins at n times 64. |
|
| Atlas | 0x0000 - 0x3FFF | Tile page 0. 256 tiles of 8 by 8, one byte a pixel, so tile n begins at n times 64. |
|
||||||
| Atlas | 0x4000 - 0xBFFF | Free. Two more 16K pages of tiles would fit here. |
|
| Atlas | 0x4000 - 0x7FFF | Tile page 1. |
|
||||||
| Atlas | 0xC000 - 0xC7FF | The sprite table. 256 entries of eight bytes. |
|
| Atlas | 0x8000 - 0xBFFF | Tile page 2. |
|
||||||
| Atlas | 0xC800 - 0xFBFF | Free. |
|
| Atlas | 0xC000 - 0xC7FF | The sprite table. 256 entries of eight bytes - and tiles 0 to 31 of page 3. |
|
||||||
| Atlas | 0xFC00 - 0xFFFF | The palette. 256 entries of four bytes: red, green, blue, and one unused. |
|
| Atlas | 0xC800 - 0xFBFF | Free - and tiles 32 to 239 of page 3. |
|
||||||
|
| Atlas | 0xFC00 - 0xFFFF | The palette. 256 entries of four bytes: red, green, blue, and one unused - and tiles 240 to 255 of page 3. |
|
||||||
| Screen | 0x0000 - 0x3FFF | Free in a tile mode. |
|
| Screen | 0x0000 - 0x3FFF | Free in a tile mode. |
|
||||||
| Screen | 0x4000 - 0xBFFF | The map. 128 rows of 256 bytes. |
|
| Screen | 0x4000 - 0xBFFF | The map. 128 rows of 256 bytes. |
|
||||||
| Screen | 0x0000 - 0xF9FF | In bitmap mode, the picture instead: 64,000 bytes, one to a pixel. |
|
| Screen | 0x0000 - 0xF9FF | In bitmap mode, the picture instead: 64,000 bytes, one to a pixel. |
|
||||||
@@ -678,14 +679,16 @@ A palette entry is four bytes for the same reason. Entry n begins at n times fou
|
|||||||
|
|
||||||
Things that move without the map moving. A cell is where it is; something between two cells meant rewriting both of them, and something moving a pixel at a time meant rewriting them sixty times a second - which is affordable for one thing and not for twenty. A sprite is put at a **pixel**, and the device draws it over whatever is behind.
|
Things that move without the map moving. A cell is where it is; something between two cells meant rewriting both of them, and something moving a pixel at a time meant rewriting them sixty times a second - which is affordable for one thing and not for twenty. A sprite is put at a **pixel**, and the device draws it over whatever is behind.
|
||||||
|
|
||||||
|
A sprite's attribute is a cell's attribute, read the same way and by the same code - which is what lets one piece of art be a wall in one place and a moving thing in another with nothing rewritten.
|
||||||
|
|
||||||
**A sprite is m by n tiles**, taken in reading order from one index. That is the decision the rest follows from: it needs no pixel format of its own, no second kind of memory, and nothing its art can be that the map could not also show. A 16 by 16 character is four tiles, and a program that wants the same picture in the background just names the same four.
|
**A sprite is m by n tiles**, taken in reading order from one index. That is the decision the rest follows from: it needs no pixel format of its own, no second kind of memory, and nothing its art can be that the map could not also show. A 16 by 16 character is four tiles, and a program that wants the same picture in the background just names the same four.
|
||||||
|
|
||||||
The table is 256 entries of 8 bytes at **0xC000 in the atlas**. Eight so that entry n begins at n times eight, which is a shift - the same reason a palette entry is four bytes.
|
The table is 256 entries of 8 bytes at **0xC000 in the atlas**. Eight so that entry n begins at n times eight, which is a shift - the same reason a palette entry is four bytes.
|
||||||
|
|
||||||
| Byte | Holds |
|
| Byte | Holds |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| 0 | The top left tile. The rest follow it in reading order, wrapping at 255. |
|
| 0 | The top left tile, in the page its attribute names. The rest follow it in reading order, wrapping at 255 inside that page. |
|
||||||
| 1 | Attribute. Its low nibble times sixteen is added to every index in the art, exactly as a cell's is. |
|
| 1 | Attribute, which means exactly what a cell's does: low nibble the colour scheme, bits 4 and 5 the tile page. |
|
||||||
| 2, 3 | X, low byte first, **signed**. |
|
| 2, 3 | X, low byte first, **signed**. |
|
||||||
| 4, 5 | Y, the same. |
|
| 4, 5 | Y, the same. |
|
||||||
| 6 | Size: tiles across in the high nibble, tiles down in the low. |
|
| 6 | Size: tiles across in the high nibble, tiles down in the low. |
|
||||||
@@ -711,7 +714,13 @@ Two bytes. The first says which tile, the second how to colour it.
|
|||||||
|
|
||||||
The low nibble of the second byte is **added to every palette index in the tile, sixteen at a time**. A tile drawn in indices 0 to 15 therefore appears in any of sixteen colour schemes without a second copy of it in tile memory. A tile that wants all 256 colours leaves the nibble at zero and gets them. The addition wraps, because a byte plus a byte is a byte.
|
The low nibble of the second byte is **added to every palette index in the tile, sixteen at a time**. A tile drawn in indices 0 to 15 therefore appears in any of sixteen colour schemes without a second copy of it in tile memory. A tile that wants all 256 colours leaves the nibble at zero and gets them. The addition wraps, because a byte plus a byte is a byte.
|
||||||
|
|
||||||
The high nibble is reserved and should be left at zero, so that a meaning can be given to it later without changing what already-written programs mean. The meaning waiting for it is a tile page: there is room in the atlas for two more pages of 256, and one bit of that nibble would reach them.
|
**Bits 4 and 5 say which page of tiles the number is in.** A tile number is a byte and a byte reaches 256, which is not many once a font has taken 135 of them and a game wants a character, a background and a wall. Two bits that were already being written on every cell reach 1024.
|
||||||
|
|
||||||
|
Four pages of 16K is 64K, which is the whole atlas, so **the fourth page is the memory the sprite table and the palette are in.** That is not a hole in the design; it is the same answer shared video memory has always given. The atlas is 1024 tiles, and what a program spends on sprites and colours comes out of them. A program that wants no sprites may use page 3 for art, and one that wants sprites has 768 tiles and knows why.
|
||||||
|
|
||||||
|
The page is a property of the **cell**, not a mode, so one screen can show tiles from all four pages at once and a program never has to decide which page it is "in".
|
||||||
|
|
||||||
|
Bits 6 and 7 are still reserved and should be left at zero.
|
||||||
|
|
||||||
### Registers:
|
### Registers:
|
||||||
|
|
||||||
|
|||||||
@@ -158,6 +158,13 @@ solidTile() {
|
|||||||
pokeAtlasRun "$(( $1 * 64 ))" "$2" 64
|
pokeAtlasRun "$(( $1 * 64 ))" "$2" 64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# The same, in one of the four pages. Page p begins at p times 16K, so a tile number means a
|
||||||
|
# different 64 bytes in each of them.
|
||||||
|
pageTile() {
|
||||||
|
# pageTile <page> <tile> <index>
|
||||||
|
pokeAtlasRun "$(( $1 * 0x4000 + $2 * 64 ))" "$3" 64
|
||||||
|
}
|
||||||
|
|
||||||
# The top half one index and the bottom half another, which is how a tile gets a hole in it:
|
# The top half one index and the bottom half another, which is how a tile gets a hole in it:
|
||||||
# index nought is what a sprite does not draw.
|
# index nought is what a sprite does not draw.
|
||||||
halfTile() {
|
halfTile() {
|
||||||
@@ -399,6 +406,48 @@ echo "Checking what the video device draws."
|
|||||||
&& result ok "the map is a ring" "row 0 follows row 127" \
|
&& result ok "the map is a ring" "row 0 follows row 127" \
|
||||||
|| result no "the map is a ring" "got $(pixel ring 0 8)"
|
|| result no "the map is a ring" "got $(pixel ring 0 8)"
|
||||||
|
|
||||||
|
# ---- Four pages of tiles ----
|
||||||
|
#
|
||||||
|
# ONE TILE NUMBER, four different pictures. Every cell below names tile 1 and they differ only
|
||||||
|
# in the attribute's page bits, which is the whole of what this adds: a byte reaches 256 tiles
|
||||||
|
# and two bits that were already being written on every cell reach 1024.
|
||||||
|
#
|
||||||
|
# The fourth page is the memory the sprite table and the palette are in, and that is checked
|
||||||
|
# here rather than forbidden - it is the same answer shared video memory has always given.
|
||||||
|
# Page 3 tile 8 lands at 0xC200, which is sprite entries 64 to 71, and 64 bytes of index four
|
||||||
|
# read as a size byte of 0x04: no width, so no sprite. The art works and nothing is drawn.
|
||||||
|
{ prologue
|
||||||
|
spriteColours
|
||||||
|
solidTile 1 0x01
|
||||||
|
pageTile 1 1 0x02
|
||||||
|
pageTile 2 1 0x03
|
||||||
|
pageTile 3 8 0x04
|
||||||
|
pokeScreen 0x4304 0x01; pokeScreen 0x4305 0x00
|
||||||
|
pokeScreen 0x4306 0x01; pokeScreen 0x4307 0x10
|
||||||
|
pokeScreen 0x4308 0x01; pokeScreen 0x4309 0x20
|
||||||
|
pokeScreen 0x430A 0x08; pokeScreen 0x430B 0x30
|
||||||
|
epilogue
|
||||||
|
} | run pages || exit 1
|
||||||
|
[ "$(pixel pages 16 24)" = "255,0,0" ] && [ "$(pixel pages 24 24)" = "0,255,0" ] \
|
||||||
|
&& [ "$(pixel pages 32 24)" = "0,0,255" ] \
|
||||||
|
&& result ok "the attribute says which page" "the same tile number, three pictures" \
|
||||||
|
|| result no "the attribute says which page" "$(pixel pages 16 24) $(pixel pages 24 24) $(pixel pages 32 24)"
|
||||||
|
[ "$(pixel pages 40 24)" = "255,255,0" ] \
|
||||||
|
&& result ok "and the fourth page is the sprite table" "art read out of the memory sprites are in" \
|
||||||
|
|| result no "and the fourth page is the sprite table" "got $(pixel pages 40 24)"
|
||||||
|
|
||||||
|
# The page bits and the scheme nibble are in one byte and must not disturb each other. Tile 2
|
||||||
|
# of page 1 is index one everywhere; scheme one adds sixteen, and entry 17 is cyan.
|
||||||
|
{ prologue
|
||||||
|
spriteColours
|
||||||
|
pageTile 1 2 0x01
|
||||||
|
pokeScreen 0x4304 0x02; pokeScreen 0x4305 0x11
|
||||||
|
epilogue
|
||||||
|
} | run pagescheme || exit 1
|
||||||
|
[ "$(pixel pagescheme 16 24)" = "0,255,255" ] \
|
||||||
|
&& result ok "a page and a scheme in one byte" "page one, scheme one, and both applied" \
|
||||||
|
|| result no "a page and a scheme in one byte" "got $(pixel pagescheme 16 24)"
|
||||||
|
|
||||||
# ---- Sprites ----
|
# ---- Sprites ----
|
||||||
#
|
#
|
||||||
# A thing put at a PIXEL rather than in a cell. Tile 1 is solid index one, which the palette
|
# A thing put at a PIXEL rather than in a cell. Tile 1 is solid index one, which the palette
|
||||||
@@ -538,6 +587,20 @@ echo "Checking what the video device draws."
|
|||||||
&& result ok "no width or no height draws nothing" "and the one beside them still does" \
|
&& result ok "no width or no height draws nothing" "and the one beside them still does" \
|
||||||
|| result no "no width or no height draws nothing" "$(pixel spritenone 16 24) $(pixel spritenone 40 24) $(pixel spritenone 64 24)"
|
|| result no "no width or no height draws nothing" "$(pixel spritenone 16 24) $(pixel spritenone 40 24) $(pixel spritenone 64 24)"
|
||||||
|
|
||||||
|
# A sprite reads its page from the same bits, because a sprite's attribute IS a cell's
|
||||||
|
# attribute - which is what lets the same art be a wall in one place and a moving thing in
|
||||||
|
# another with nothing rewritten.
|
||||||
|
{ prologue
|
||||||
|
spriteColours
|
||||||
|
solidTile 1 0x01
|
||||||
|
pageTile 1 1 0x02
|
||||||
|
spriteAt 0 1 0x10 16 24 0x11 0x00
|
||||||
|
epilogue
|
||||||
|
} | run spritepage || exit 1
|
||||||
|
[ "$(pixel spritepage 16 24)" = "0,255,0" ] \
|
||||||
|
&& result ok "a sprite has pages too" "tile one of page one, not of page nought" \
|
||||||
|
|| result no "a sprite has pages too" "got $(pixel spritepage 16 24)"
|
||||||
|
|
||||||
# ---- Two screens, and the flip between them ----
|
# ---- Two screens, and the flip between them ----
|
||||||
#
|
#
|
||||||
# One red cell in each screen, in different rows: row one of the screen being shown, and the
|
# One red cell in each screen, in different rows: row one of the screen being shown, and the
|
||||||
|
|||||||
Reference in New Issue
Block a user