Video Mode 11

From Uzebox Wiki
Jump to: navigation, search

NOTE: This mode is a current work-in-progress.

Video Mode 11 is a derivative of video mode 3, which has some interesting additional features:

  • "smooth" 4-pixel vertical moving of background tiles due to 16x4 pixel tileset
  • Palette support
  • Half of mode 3 Flash needed for tiles
  • Half of mode 3 RAM needed for RAM tiles/Sprites

Motivation

During the development of Würgertime Janka found out he needs to have a half-tile (4 pixel) vertical moving for the burger components. Because of the number of burger tiles involved at the same time (up to 100), it is not possible to achieve this with sprites.

With any existing video mode, this feature of the game leads to having a lot of tile combinations where real background tiles like air, floors and other burger components have to be mixed with the falling burger components within one tile. That means any burger component is present a lot of times in the tileset combined with other tiles, and that way, wasting flash.

Both the smoother moving and flash saving would be interesting for platformer games. Floors may be at 4-pixel boundaries instead of 8 pixels, making ramps more smooth. Moving of elevators and escalators could be made smooth the same way. These items and ladders on the other side can be placed at 16-pixel horizontal boundaries without making a difference.

See the original forum thread.


Palettes

During the discussion Janka found out it's possible to have a palette with a 16x4 "mode 3", because calculation of next tile address does not scale with tile width. It's always 16 cycles.

Video mode 3:
   cycles | code
   =======+======================================================================
   3      | lpm r16,Z+    ; load pixel 1 direct video
   1      | out vport,r16 ; output pixel 1 data
   2      | Used for calculation of next tile address from index (step 1)
   -------+----------------------------------------------------------------------
   3      | lpm r16,Z+    ; load pixel 2 direct video
   1      | out vport,r16 ; output pixel 2 data
   2      | Used for calculation of next tile address from index (step 2)
   ==============================================================================
   12 cycles for 2 pixels, 8 calculation steps per 8-pixel tile.
Video mode 11, palette submode:
   cycles | code
   =======+======================================================================
   3      | lpm r28,Z+    ; load pixel 1+2 palette indices from tile. (r28 is yl)
   2      | ld r16,Y      ; palette lookup
   1      | out vport,r16 ; output pixel 1 data
   -------+----------------------------------------------------------------------
   1      | swap r28      ; other pixel palette index (r28 is yl)
   2      | ld r16,Y      ; palette lookup
   2      | Used for calculation of next tile address from index (step 1)
   1      | out vport,r16 ; output pixel 2 data
   ==============================================================================
   12 cycles for 2 pixels, still 8 calculation steps per 16-pixel tile.

This saves us half the flash needed for tiles, because there is only one byte in flash needed for two pixels. As a pitfall, the palette has to reside in RAM because of the tight timing. It's up to 256 bytes, which are taken from the really tight pool of 4KB overall RAM - ~1KB video RAM - ~2KB for RAM tiles.

Beginning at those musings, the development of video mode 11 has started.

Implementation details

As video mode 11 is a work in progress, some of the following information may change.

Tile submodes

While in mode 3, the video ram is an array of up to 32x32 bytes, things are a little more complicated in mode 11: Because for displaying scores and and other textual information a tile size of 16x4 is not suitable, there has to be a possibility to switch to 8x8 pixel tiles.

In mode 11, video RAM is organized in up to 32 "eight-scanlines" of up to 32 bytes. Each byte is used as a tile index, like in mode 3. Now comes the difference: each "eight-scanlines" may consist of one line of up to 32 8x8 pixel tiles or two lines of up to 16 16x4 pixel tiles. Which format to use is selectable for each "eight-scanlines".

    x=0 x=1 x=2...
y=0 000 001 002 003 004 005 006 007 008 009 00a 00b 00c 00d 00e 00f 010 011 012 013 014 015 016 017 018 019 01a 01b 01c 01d 01e 01f
y=1 ->Don't care
y=2   020     021     022     023     024     025     026     027     028     029     02a     02b     02c     02d     02e     02f
y=3   030     031     032     033     034     035     036     037     038     039     03a     03b     03c     03d     03e     03f
      x=0     x=2     x=4     x=6     x=8...

The numbers in the table are VRAM addresses. Odd y coordinates don't care for 8x8 pixel "eight-scanlines" while odd x coordinates don't care for 16x4 pixel "eight-scanlines".

Because we need a different tileset for 8x8 pixel tiles and 16x4 pixel tiles, this is automatically selected for each "eight-scanlines". Same for 16x4 direct video and 16x4 palette video submodes. And because we have this function and switch anyway, there's another switch per "eight-scanlines" which allows to select one of two tilesets per "eight-scanlines" mode, making it possible to have 1024 different tiles on screen.

By the way, that means any tile on screen may be different from any other -> full bitmap support at 240x224 and 136 colors. Such a bitmap would eat up ~24KB though.

Color submodes

Like with the tile submodes, mode 11 allows to select a color submode for each "eight-scanlines". These are:

Direct video

This is the same color submode as mode 3 uses. Each byte in a tile directly encodes a color on screen. This submode is the only one valid for 8x8 pixel tile "eight-scanlines", as 8x8 pixel tiles don't allow a palette because of the tight timing. You may select it for 16x4 tile "eight-scanlines", too, however. That way you don't need a palette, don't waste additional RAM, though you gain no additional free flash. The only advantages are smoother moving of background tile in the vertical direction and saving some flash by not needing combination tiles.

Palette video

This mode is selectable only for 16x4 tile "eight-scanlines" as 8x8 pixel tiles don't allow a palette because of the tight timing. In palette mode, each two even/odd pixels in a line are a "pair" and they can't be colored independently. This is because of the tight timing doesn't allow us independent palette indices for each pixel. Instead, we have one load for a palette index from flash for two pixels and two palette lookups based on the loaded index (first pixel) and nibble-swapped index (second pixel).

As the palette entries are in RAM, you may change them anytime to generate special effects, like changing background colors (e.g. for having a light switch), let some components of your game screen vanish in the background (open bridges) or even effects like discussed on the Sprite_Techniques#Sprite_Curtains page (without using sprites!).


Palette mode has two flavours, which aren't selected by a "eight-scanlines" switch, but how the palette is populated:

16 color palette video

This is a very straightforward palette mode. You may pick 16 of the possible 256 colors and put it into the palette. When you have read above the two pixels of a pair cannot be colored independently, you can circumvent this limitation by limiting yourself to 16 colors. That way, any combination of 16 colors by 16 colors is within the maximum palette index of 256. To achieve this independent coloring, fill the palette with 16 blocks of 16 identical colors. That's it.

The pitfall of this we need a 256 byte palette for only 16 colors. You may see that's too much for your game, but there is a trick: The palette is an array of 256 bytes, but it may be sparsely populated. E.g. if you only need 8 of 256 colors, it comes clear that any palette entry with an index 0x80 or higher is never used, same with any index 0x08, 0x09, 0x0a, ... 0x18, 0x19 ... etc For 8 colors, only 64 palette entries are used, the remaining 192 are useable as variables. You may pick any number of colors <=16 and need color^2 palette entries.

This submode flavour may be combined either with direct video sprites or with palette sprites, both with no further restrictions. With palette sprites, the amount of RAM needed for RAM tiles is halved, so the 256 byte palette is bearable.

136 color pairs palette video

To understand this flavour of palette mode, forget everything you read about 16 color palette video and go back to the origins of palette mode. There are two important things to learn from this code snippet (copied from above):

  lpm r28,Z+    ; load pixel 1+2 palette indices from tile. (r28 is yl)
  ld r16,Y      ; palette lookup
  out vport,r16 ; output pixel 1 data
  swap r28      ; other pixel palette index (r28 is yl)
  ld r16,Y      ; palette lookup
  *** calculation of next tile address from index (step 1)
  out vport,r16 ; output pixel 2 data

First, one palette index is loaded from flash for two pixels. This means, if there is e.g. a 0x52 stored in flash at the current location, the first palette lookup (next statement) will load the resulting color from palette entry 0x52. This should be red in our example, which is OUTed the next statement. Then the interesting part happens. Instead of loading another palette index from flash (not possible due to tight timing), the current palette index is SWAPped, meaning there's now 0x25 in r28/YL. This is the palette index where the color for the second pixel is loaded from, it should be green in our example. If we'd started with 0x25 instead, we had the first pixel green and the second pixel red.

Second, this means not only the even/odd pixels are a pair, but the palette indices, too. 0x52 is paired with 0x25, 0xe3 is paired with 0x3e and 0x77 is paired with itself, 0x77. There are 256 palette indices, 16 of them are of the latter form (0x00, 0x11, 0x22 ...), which can be used for red-red, green-green, magenta-magenta... pixel pairs only and 240 indices of the other form, which can be any color combination. Because red-green and green-red need two palette entries, there are only 120 independent colors for such pairs. Plus 16 for the same-color pairs gives 136 color pairs.

You may find it very complicated to create a palette and tiles for such a mode, but Janka has created a tool for it (see the forum thread above). However, it's recommended to start with a small number of distinct colors (e.g. 30..40) as the tool can only assist you to reduce colors or move pixels to other positions when their combinations don't fit into the palette.

This submode flavour may be combined either with direct video sprites (no restrictions) or with palette sprites and the restriction to have sprites only at even horizontal coordinates, and masking is also done on a horizontal two-pixel granularity. With palette sprites, the amount of RAM needed for RAM tiles is halved, so the 256 byte palette is bearable.


Please note 136 colors is the ultimate of mode 11 palette mode. Once you decided the tile's pixel palette index 0x52 should mean red-green (with 0x52 holding red and 0x25 holding green) there is no way to get around the gift 0x25 now means green-red.

Sprites and RAM tiles

Sprites can come in four different submodes in video mode 11:

  • 8x8 direct video
  • 8x8 palette video
  • 16x4 direct video
  • 16x4 palette video

As a general rule, 8x8 sprites can only appear in 8x8 tile "eight-scanlines", while 16x4 sprites can only appear in 16x4 tile "eight-scanlines". The second limitation is, every "eight-scanlines" has a "RAM color submode", which may be direct video or palette video. That means any sprites in the same "eight-scanlines" have to share the RAM color submode. (It may be possible to implement mixing but it's at any chance extremly complicated and brings not much additional fun.) Besides those limitations, each sprite can have its own submode, so full-featured split-screens are possible.

There are five possible combinations of sprite and background.

Direct video sprite on direct video background

This is completly the same as in mode 3, just for the difference the tile ratio may be 16x4 instead of 8x8.

The RAM color submode for the "eight-scanlines" has to be direct video.

Palette video sprite on direct video background

This sprite mode saves half of flash for sprite tiles on the expense of using some extra cycles for palette lookup. Before the sprite data is put on top of the overlapping background in the RAM tile, the palette is consulted. If the color stored in a palette entry is 0xfe, that means "transparent pixel" for the sprite.

The RAM color submode for the "eight-scanlines" has to be direct video. This combination works for 16x4 and 8x8 tile "eight-scanlines". It makes no difference whether the palette is 16 color or 136 color flavour for this combination.

Direct video sprite on palette video background

Again very straightforward. The overlapping background is copied into RAM tiles, but now respecting the palette. The direct video sprite data is put on top of it.

The RAM color submode for the "eight-scanlines" has to be direct video! This combination is only valid for 16x4 tile palette video "eight-scanlines". It makes no difference whether the palette is 16 color or 136 color flavour for this combination.

Palette video sprite on palette video background, result is palette video

This mode saves a half of RAM tile RAM because the RAM tiles are in palette mode, too. It means, two pixels are encoded into one byte in RAM, in addition, flash memory needed for background and sprite tiles is also halved.

This combination is only valid for 16x4 tile palette video "eight-scanlines". The RAM color submode for the "eight-scanlines" has to be palette video, too.

There are two different flavours of this submode combination, which have to be selected by a global switch:

In the 16-color mode, a 16 (or less) color palette has had to be loaded. The sprite to RAM tile logic treats upper and lower nibble of the palette index read from sprite and background as independent, so the sprite may have any horizontal position and masking is at pixel-granularity. Palette index 0x0 means "transparent pixel", so the color at that palette position cannot be used for sprites. Preferably use this index for the background color so it makes no big difference.

In the 136-color pairs mode, a 256 (or less) color palette has had to be loaded. The sprite to RAM logic treats any byte as a palette index so the sprite may be only at even horizontal positions and horizontal masking is done on a two-pixel granularity. Note palette index 0x00 (not 0xfe!) means "transparent pixel", so the color at that palette position cannot be used for sprites. Preferably use this index for the background color so it makes no big difference.

Palette video sprite on palette video background, result is direct video

This mode saves half of flash for both background and sprite tiles, like the same mode with palette video output does. However, it doesn't save any RAM (actually needs up to 256 additional bytes) because the RAM tiles are direct video. Both the data from background tile memory and sprite are seen as palette indices. There are two flavours again:

In the 16-color mode, there would be no gain of having direct video as output as there are no sprite restrictions with the palette video output, too. Therefore, this combination isn't implemented.

In the 136-color pairs mode, direct video output gives us freedom to combine any two colors in a pair, so all horizontal positions are possible for the sprite, likewise masking is done at pixel granularity. In difference to palette video output, masking isn't done on the base of palette index, but on the actual color (0xfe) stored at the palette position given by the palette index stored in the sprite tile.

The RAM color submode for the "eight-scanlines" has to be direct video. This combination works for 16x4 "eight-scanlines" only. It would be possible to implement it for 8x8 tile lines because the output is direct video, but then the whole "eight-scanlines" would have to consist of RAM tiles because Flash background tiles are palette video, which is not feasible with 8x8 tiles due to tight timing. Because of this, 8x8 tile support is not implemented