Video Mode 11

From Uzebox Wiki
Jump to navigation Jump to 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 Flash needed for tiles
  • Half of 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 mode

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.

136 color 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 colors.

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.


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

TODO!