// Commander X16 VERA (Versatile Embedded Retro Adapter) Video and Audio Processor
// https://github.com/commanderx16/x16-docs/blob/master/VERA%20Programmer's%20Reference.md

// Author: Sven Van de Velde

#include <cx16.h>
#include <cx16-veralib.h>

// --- VERA function encapsulation ---

// --- VERA layer management ---


// --- VERA addressing ---

inline void vera_vram_bank_offset(byte bank, word offset, byte incr) {
    // Select DATA0
    *VERA_CTRL &= ~VERA_ADDRSEL;
    // Set address
    *VERA_ADDRX_L = BYTE0(offset);
    *VERA_ADDRX_M = BYTE1(offset);
    *VERA_ADDRX_H = bank | incr;
}

inline void vera_vram_address0(dword bankaddr, byte incr) {
    // Select DATA0
    *VERA_CTRL &= ~VERA_ADDRSEL;
    // Set address
    *VERA_ADDRX_L = BYTE0(bankaddr);
    *VERA_ADDRX_M = BYTE1(bankaddr);
    *VERA_ADDRX_H = BYTE2(bankaddr) | incr;
}

inline void vera_vram_address1(dword bankaddr, byte incr) {
    // Select DATA1
    *VERA_CTRL |= VERA_ADDRSEL;
    // Set address
    *VERA_ADDRX_L = BYTE0(bankaddr);
    *VERA_ADDRX_M = BYTE1(bankaddr);
    *VERA_ADDRX_H = BYTE2(bankaddr) | incr;
}

// --- VERA active display management ---

inline void vera_display_set_scale_none() {
    *VERA_DC_HSCALE = 128;
    *VERA_DC_VSCALE = 128;
}

inline void vera_display_set_scale_double() {
    *VERA_DC_HSCALE = 64;
    *VERA_DC_VSCALE = 64;
}

inline void vera_display_set_scale_triple() {
    *VERA_DC_HSCALE = 32;
    *VERA_DC_VSCALE = 32;
}

byte vera_display_get_hscale() {
    byte hscale[4] = {0,128,64,32};
    byte scale = 0;
    for(byte s:1..3) {
        if(*VERA_DC_HSCALE==hscale[s]) {
            scale = s;
            break;
        }
    }
    return scale;
}

byte vera_display_get_vscale() {
    byte vscale[4] = {0,128,64,32};
    byte scale = 0;
    for(byte s:1..3) {
        if(*VERA_DC_VSCALE==vscale[s]) {
            scale = s;
            break;
        }
    }
    return scale;
}

word vera_display_get_height() {
    byte scale = vera_display_get_vscale();
    *VERA_CTRL = *VERA_CTRL | VERA_DCSEL;
    word height = (word)(*VERA_DC_VSTOP - *VERA_DC_VSTART);
    switch( scale ) {
        case 2:
            height = height >> 1;
            break;
        case 3:
            height = height >> 2;
            break;
    }
    *VERA_CTRL = *VERA_CTRL & ~VERA_DCSEL;
    return height<<1;
}

word vera_display_get_width() {
    byte scale = vera_display_get_hscale();
    *VERA_CTRL = *VERA_CTRL | VERA_DCSEL;
    word width = (word)(*VERA_DC_HSTOP - *VERA_DC_HSTART);
    switch( scale ) {
        case 2:
            width = width >> 1;
            break;
        case 3:
            width = width >> 2;
            break;
    }
    *VERA_CTRL = *VERA_CTRL & ~VERA_DCSEL;
    return width<<1;
}

// --- VERA layer management ---

// Set the configuration of the layer.
// - layer: Value of 0 or 1.
// - config: Specifies the modes which are specified using T256C / 'Bitmap Mode' / 'Color Depth'.
void vera_layer_set_config(byte layer, byte config) {
    byte* addr = vera_layer_config[layer];
    *addr = config;
}

// Get the configuration of the layer.
// - layer: Value of 0 or 1.
// - return: Specifies the modes which are specified using T256C / 'Bitmap Mode' / 'Color Depth'.
byte vera_layer_get_config(byte layer) {
    byte* config = vera_layer_config[layer];
    return *config;
}
// Set the configuration of the layer text color mode.
// - layer: Value of 0 or 1.
// - color_mode: Specifies the color mode to be VERA_LAYER_CONFIG_16 or VERA_LAYER_CONFIG_256 for text mode.
void vera_layer_set_text_color_mode( byte layer, byte color_mode ) {
    byte* addr = vera_layer_config[layer];
    *addr &= ~VERA_LAYER_CONFIG_256C;
    *addr |= color_mode;
}

// Set the configuration of the layer to bitmap mode.
// - layer: Value of 0 or 1.
void vera_layer_set_bitmap_mode( byte layer ) {
    byte* addr = vera_layer_config[layer];
    *addr &= ~VERA_LAYER_CONFIG_MODE_BITMAP;
    *addr |= VERA_LAYER_CONFIG_MODE_BITMAP;
}

// Set the configuration of the layer to tilemap mode.
// - layer: Value of 0 or 1.
void vera_layer_set_tilemap_mode( byte layer ) {
    byte* addr = vera_layer_config[layer];
    *addr &= ~VERA_LAYER_CONFIG_MODE_BITMAP;
    *addr |= VERA_LAYER_CONFIG_MODE_TILE;
}

// Set the map width or height of the layer.
// - layer: Value of 0 or 1.
inline void vera_layer_set_width_32(byte layer) {
    byte* addr = vera_layer_config[layer];
    *addr &= ~VERA_LAYER_WIDTH_MASK;
    *addr |= VERA_LAYER_WIDTH_32;
}
inline void vera_layer_set_width_64(byte layer) {
    byte* addr = vera_layer_config[layer];
    //*addr &= (~VERA_CONFIG_WIDTH_MASK) | VERA_CONFIG_WIDTH_64;
    *addr &= ~VERA_LAYER_WIDTH_MASK;
    *addr |= VERA_LAYER_WIDTH_64;
}
inline void vera_layer_set_width_128(byte layer) {
    byte* addr = vera_layer_config[layer];
    *addr &= ~VERA_LAYER_WIDTH_MASK;
    *addr |= VERA_LAYER_WIDTH_128;
}
inline void vera_layer_set_width_256(byte layer) {
    byte* addr = vera_layer_config[layer];
    *addr &= ~VERA_LAYER_WIDTH_MASK;
    *addr |= VERA_LAYER_WIDTH_256;
}
inline void vera_layer_set_height_32(byte layer) {
    byte* addr = vera_layer_config[layer];
    *addr &= ~VERA_LAYER_HEIGHT_MASK;
    *addr |= VERA_LAYER_HEIGHT_32;
}
inline void vera_layer_set_height_64(byte layer) {
    byte* addr = vera_layer_config[layer];
    *addr &= ~VERA_LAYER_HEIGHT_MASK;
    *addr |= VERA_LAYER_HEIGHT_64;
}
inline void vera_layer_set_height_128(byte layer) {
    byte* addr = vera_layer_config[layer];
    *addr &= ~VERA_LAYER_HEIGHT_MASK;
    *addr |= VERA_LAYER_HEIGHT_128;
}
inline void vera_layer_set_height_256(byte layer) {
    byte* addr = vera_layer_config[layer];
    *addr &= ~VERA_LAYER_HEIGHT_MASK;
    *addr |= VERA_LAYER_HEIGHT_256;
}

// Get the map width of the layer.
// - layer: Value of 0 or 1.
inline word vera_layer_get_width(byte layer) {
    byte* config = vera_layer_config[layer];
    return VERA_LAYER_WIDTH[ (*config & VERA_LAYER_WIDTH_MASK) >> 4];
}

// Get the map height of the layer.
// - layer: Value of 0 or 1.
inline word vera_layer_get_height(byte layer) {
    byte* config = vera_layer_config[layer];
    return VERA_LAYER_HEIGHT[ (*config & VERA_LAYER_HEIGHT_MASK) >> 6];
}

// Set the color depth of the layer in bit per pixel (BPP) to 1.
// - layer: Value of 0 or 1.
inline void vera_layer_set_color_depth_1BPP(byte layer) {
    byte* addr = vera_layer_config[layer];
    *addr &= ~VERA_LAYER_COLOR_DEPTH_MASK;
    *addr |= VERA_LAYER_COLOR_DEPTH_1BPP;
}

// Set the color depth of the layer in bit per pixel (BPP) to 1.
// - layer: Value of 0 or 1.
inline void vera_layer_set_color_depth_2BPP(byte layer) {
    byte* addr = vera_layer_config[layer];
    *addr &= ~VERA_LAYER_COLOR_DEPTH_MASK;
    *addr |= VERA_LAYER_COLOR_DEPTH_2BPP;
}

// Set the color depth of the layer in bit per pixel (BPP) to 1.
// - layer: Value of 0 or 1.
inline void vera_layer_set_color_depth_4BPP(byte layer) {
    byte* addr = vera_layer_config[layer];
    *addr &= ~VERA_LAYER_COLOR_DEPTH_MASK;
    *addr |= VERA_LAYER_COLOR_DEPTH_4BPP;
}

// Set the color depth of the layer in bit per pixel (BPP) to 1.
// - layer: Value of 0 or 1.
inline void vera_layer_set_color_depth_8BPP(byte layer) {
    byte* addr = vera_layer_config[layer];
    *addr &= ~VERA_LAYER_COLOR_DEPTH_MASK;
    *addr |= VERA_LAYER_COLOR_DEPTH_8BPP;
}

// Get the color depth of the layer.
// - layer: Value of 0 or 1.
// - return: 0 = 1 color, 1 = 2 colors, 2 = 4 colors or 3 = 8 colors.
inline byte vera_layer_get_color_depth(byte layer) {
    byte* config = vera_layer_config[layer];
    return (*config & VERA_LAYER_COLOR_DEPTH_MASK);
}

// Enable the layer to be displayed on the screen.
// - layer: 0 or 1.
inline void vera_layer_show(byte layer) {
    *VERA_DC_VIDEO |= vera_layer_enable[layer];
}


// Disable the layer to be displayed on the screen.
// - layer: 0 or 1.
inline void vera_layer_hide(byte layer) {
    *VERA_DC_VIDEO &= ~vera_layer_enable[layer];
}

// Is the layer shown on the screen?
// - returns: 1 if layer is displayed on the screen, 0 if not.
inline byte vera_layer_is_visible(byte layer) {
    return *VERA_DC_VIDEO & vera_layer_enable[layer];
}

// Set the base of the map layer with which the conio will interact.
// - layer: Value of 0 or 1.
// - mapbase: Specifies the base address of the tile map.
//   Note that the register only specifies bits 16:9 of the address,
//   so the resulting address in the VERA VRAM is always aligned to a multiple of 512 bytes.
void vera_layer_set_mapbase(byte layer, byte mapbase) {
    byte* addr = vera_layer_mapbase[layer];
    *addr = mapbase;
}

// Set the base of the map layer with which the conio will interact.
// - layer: Value of 0 or 1.
// - mapbase_address: a dword typed address (4 bytes), that specifies the full address of the map base.
//   The function does the translation from the dword that contains the 17 bit address,
//   to the respective mapbase vera register.
//   Note that the register only specifies bits 16:9 of the address,
//   so the resulting address in the VERA VRAM is always aligned to a multiple of 512 bytes.
void vera_layer_set_mapbase_address(byte layer, dword mapbase_address) {

    mapbase_address = mapbase_address & 0x1FF00; // Aligned to 2048 bit zones.
    byte bank_mapbase = BYTE2(mapbase_address);
    word offset_mapbase = WORD0(mapbase_address);

    vera_mapbase_address[layer] = mapbase_address;
    vera_mapbase_offset[layer] = offset_mapbase;
    vera_mapbase_bank[layer] = bank_mapbase;

    byte mapbase = BYTE1(mapbase_address>>1);
    vera_layer_set_mapbase(layer,mapbase);
}

// Get the map base address of the tiles for the layer.
// - layer: Value of 0 or 1.
// - return: Specifies the map base address of the layer, which is returned as a dword.
//   Note that the register only specifies bits 16:9 of the 17 bit address,
//   so the resulting address in the VERA VRAM is always aligned to a multiple of 512 bytes!
dword vera_layer_get_mapbase_address(byte layer) {
    return vera_mapbase_address[layer];
}

// Get the map base bank of the tiles for the layer.
// - layer: Value of 0 or 1.
// - return: Bank in vera vram.
byte vera_layer_get_mapbase_bank(byte layer) {
    return vera_mapbase_bank[layer];
}

// Get the map base lower 16-bit address (offset) of the tiles for the layer.
// - layer: Value of 0 or 1.
// - return: Offset in vera vram of the specified bank.
word vera_layer_get_mapbase_offset(byte layer) {
    return vera_mapbase_offset[layer];
}

// Get the base of the map layer with which the conio will interact.
// - layer: Value of 0 or 1.
// - return: Returns the base address of the tile map.
//   Note that the register is a byte, specifying only bits 16:9 of the address,
//   so the resulting address in the VERA VRAM is always aligned to a multiple of 512 bytes.
byte vera_layer_get_mapbase(byte layer) {
    byte* mapbase = vera_layer_mapbase[layer];
    return *mapbase;
}

// Set the base of the tiles for the layer with which the conio will interact.
// - layer: Value of 0 or 1.
// - tilebase: Specifies the base address of the tile map.
//   Note that the register only specifies bits 16:11 of the address,
//   so the resulting address in the VERA VRAM is always aligned to a multiple of 2048 bytes!
void vera_layer_set_tilebase(byte layer, byte tilebase) {
    byte* addr = vera_layer_tilebase[layer];
    *addr = tilebase;
}

// Get the base of the tiles for the layer with which the conio will interact.
// - layer: Value of 0 or 1.
// - return: Specifies the base address of the tile map.
//   Note that the register only specifies bits 16:11 of the address,
//   so the resulting address in the VERA VRAM is always aligned to a multiple of 2048 bytes!
byte vera_layer_get_tilebase(byte layer) {
    byte* tilebase = vera_layer_tilebase[layer];
    return *tilebase;
}

// Set the base address of the tiles for the layer with which the conio will interact.
// - layer: Value of 0 or 1.
// - tilebase_address: a dword typed address (4 bytes), that specifies the base address of the tile map.
//   The function does the translation from the dword that contains the 17 bit address,
//   to the respective tilebase vera register.
//   Note that the resulting vera register holds only specifies bits 16:11 of the address,
//   so the resulting address in the VERA VRAM is always aligned to a multiple of 2048 bytes!
void vera_layer_set_tilebase_address(byte layer, dword tilebase_address) {

    tilebase_address = tilebase_address & 0x1FC00; // Aligned to 2048 bit zones.
    byte bank_tilebase = BYTE2(tilebase_address);
    word word_tilebase = WORD0(tilebase_address);

    vera_tilebase_address[layer] = tilebase_address;
    vera_tilebase_offset[layer] = word_tilebase;
    vera_tilebase_bank[layer] = bank_tilebase;

    byte* vera_tilebase = vera_layer_tilebase[layer];
    byte tilebase = BYTE1(tilebase_address>>1);
    tilebase &= VERA_LAYER_TILEBASE_MASK; // Ensure that only tilebase is blanked, but keep the rest!
    //printf("tilebase = %x\n",tilebase);
    //while(!kbhit());
    tilebase = tilebase | ( *vera_tilebase & ~VERA_LAYER_TILEBASE_MASK );

    vera_layer_set_tilebase(layer,tilebase);
}

// Get the tile base address of the tiles for the layer.
// - layer: Value of 0 or 1.
// - return: Specifies the base address of the tile map, which is calculated as an unsigned long int.
//   Note that the register only specifies bits 16:11 of the address,
//   so the resulting address in the VERA VRAM is always aligned to a multiple of 2048 bytes!
dword vera_layer_get_tilebase_address(byte layer) {
    byte tilebase = *vera_layer_tilebase[layer];
    dword address = tilebase;
    address &= $FC;
    address <<= 8;
    address <<= 1;
    return address;
}

// --- VERA color management ---

// Set the front color for text output. The old front text color setting is returned.
// - layer: Value of 0 or 1.
// - color: a 4 bit value ( decimal between 0 and 15) when the VERA works in 16x16 color text mode.
//   An 8 bit value (decimal between 0 and 255) when the VERA works in 256 text mode.
//   Note that on the VERA, the transparent color has value 0.
byte vera_layer_set_textcolor(byte layer, byte color) {
    byte old = vera_layer_textcolor[layer];
    vera_layer_textcolor[layer] = color;
    return old;
}

// Get the front color for text output. The old front text color setting is returned.
// - layer: Value of 0 or 1.
// - return: a 4 bit value ( decimal between 0 and 15).
//   This will only work when the VERA is in 16 color mode!
//   Note that on the VERA, the transparent color has value 0.
byte vera_layer_get_textcolor(byte layer) {
    return vera_layer_textcolor[layer];
}

// Set the back color for text output. The old back text color setting is returned.
// - layer: Value of 0 or 1.
// - color: a 4 bit value ( decimal between 0 and 15).
//   This will only work when the VERA is in 16 color mode!
//   Note that on the VERA, the transparent color has value 0.
byte vera_layer_set_backcolor(byte layer, byte color) {
    byte old = vera_layer_backcolor[layer];
    vera_layer_backcolor[layer] = color;
    return old;
}

// Get the back color for text output. The old back text color setting is returned.
// - layer: Value of 0 or 1.
// - return: a 4 bit value ( decimal between 0 and 15).
//   This will only work when the VERA is in 16 color mode!
//   Note that on the VERA, the transparent color has value 0.
byte vera_layer_get_backcolor(byte layer) {
    return vera_layer_backcolor[layer];
}

// Get the text and back color for text output in 16 color mode.
// - layer: Value of 0 or 1.
// - return: an 8 bit value with bit 7:4 containing the back color and bit 3:0 containing the front color.
//   This will only work when the VERA is in 16 color mode!
//   Note that on the VERA, the transparent color has value 0.
byte vera_layer_get_color(byte layer) {
    byte* addr = vera_layer_config[layer];
    if( *addr & VERA_LAYER_CONFIG_256C )
        return (vera_layer_textcolor[layer]);
    else
        return ((vera_layer_backcolor[layer] << 4) | vera_layer_textcolor[layer]);
}


// Scroll the horizontal (X) axis of the layer visible area over the layer tile map area.
// - layer: Value of 0 or 1.
// - scroll: A value between 0 and 4096.
inline void vera_layer_set_horizontal_scroll(byte layer, word scroll) {
    *vera_layer_hscroll_l[layer] = BYTE0(scroll);
    *vera_layer_hscroll_h[layer] = BYTE1(scroll);
}

// Scroll the vertical (Y) axis of the layer visible area over the layer tile map area.
// - layer: Value of 0 or 1.
// - scroll: A value between 0 and 4096.
inline void vera_layer_set_vertical_scroll(byte layer, word scroll) {
    *vera_layer_vscroll_l[layer] = BYTE0(scroll);
    *vera_layer_vscroll_h[layer] = BYTE1(scroll);
}

// Get the bit shift value required to skip a whole line fast.
// - layer: Value of 0 or 1.
// - return: Rowshift value to calculate fast from a y value to line offset in tile mode.
byte vera_layer_get_rowshift(byte layer) {
    return vera_layer_rowshift[layer];
}

// Get the value required to skip a whole line fast.
// - layer: Value of 0 or 1.
// - return: Skip value to calculate fast from a y value to line offset in tile mode.
word vera_layer_get_rowskip(byte layer) {
    return vera_layer_rowskip[layer];
}



// Set a vera layer in tile mode and configure the:
// - layer: Value of 0 or 1.
// - mapbase_address: A dword typed address (4 bytes), that specifies the full address of the map base.
//   The function does the translation from the dword that contains the 17 bit address,
//   to the respective mapbase vera register.
//   Note that the register only specifies bits 16:9 of the address,
//   so the resulting address in the VERA VRAM is always aligned to a multiple of 512 bytes.
// - tilebase_address: A dword typed address (4 bytes), that specifies the base address of the tile map.
//   The function does the translation from the dword that contains the 17 bit address,
//   to the respective tilebase vera register.
//   Note that the resulting vera register holds only specifies bits 16:11 of the address,
//   so the resulting address in the VERA VRAM is always aligned to a multiple of 2048 bytes!
// - mapwidth: The width of the map in number of tiles.
// - mapheight: The height of the map in number of tiles.
// - tilewidth: The width of a tile, which can be 8 or 16 pixels.
// - tileheight: The height of a tile, which can be 8 or 16 pixels.
// - color_depth: The color depth in bits per pixel (BPP), which can be 1, 2, 4 or 8.
void vera_layer_mode_tile(byte layer, dword mapbase_address, dword tilebase_address, word mapwidth, word mapheight, byte tilewidth, byte tileheight, byte color_depth ) {
    // config
    byte config = 0x00;
    switch(color_depth) {
        case 1:
            config |= VERA_LAYER_COLOR_DEPTH_1BPP;
            break;
        case 2:
            config |= VERA_LAYER_COLOR_DEPTH_2BPP;
            break;
        case 4:
            config |= VERA_LAYER_COLOR_DEPTH_4BPP;
            break;
        case 8:
            config |= VERA_LAYER_COLOR_DEPTH_8BPP;
            break;
    }

    switch(mapwidth) {
        case 32:
            config |= VERA_LAYER_WIDTH_32;
            vera_layer_rowshift[layer] = 6;
            vera_layer_rowskip[layer] = 64;
            break;
        case 64:
            config |= VERA_LAYER_WIDTH_64;
            vera_layer_rowshift[layer] = 7;
            vera_layer_rowskip[layer] = 128;
            break;
        case 128:
            config |= VERA_LAYER_WIDTH_128;
            vera_layer_rowshift[layer] = 8;
            vera_layer_rowskip[layer] = 256;
            break;
        case 256:
            config |= VERA_LAYER_WIDTH_256;
            vera_layer_rowshift[layer] = 9;
            vera_layer_rowskip[layer] = 512;
            break;
    }
    switch(mapheight) {
        case 32:
            config |= VERA_LAYER_HEIGHT_32;
            break;
        case 64:
            config |= VERA_LAYER_HEIGHT_64;
            break;
        case 128:
            config |= VERA_LAYER_HEIGHT_128;
            break;
        case 256:
            config |= VERA_LAYER_HEIGHT_256;
            break;
    }
    vera_layer_set_config(layer, config);

    // mapbase
    vera_mapbase_offset[layer] = WORD0(mapbase_address);
    vera_mapbase_bank[layer] = BYTE2(mapbase_address);
    vera_mapbase_address[layer] = mapbase_address;

    mapbase_address = mapbase_address >> 1;
    byte mapbase = BYTE1(mapbase_address);
    vera_layer_set_mapbase(layer,mapbase);

    // tilebase
    vera_tilebase_offset[layer] = WORD0(tilebase_address);
    vera_tilebase_bank[layer] = BYTE2(tilebase_address);
    vera_tilebase_address[layer] = tilebase_address;

    tilebase_address = tilebase_address >> 1;
    byte tilebase = BYTE1(tilebase_address);
    tilebase &= VERA_LAYER_TILEBASE_MASK;
    switch(tilewidth) {
        case 8:
            tilebase |= VERA_TILEBASE_WIDTH_8;
            break;
        case 16:
            tilebase |= VERA_TILEBASE_WIDTH_16;
            break;
    }
    switch(tileheight) {
        case 8:
            tilebase |= VERA_TILEBASE_HEIGHT_8;
            break;
        case 16:
            tilebase |= VERA_TILEBASE_HEIGHT_16;
            break;
    }
    vera_layer_set_tilebase(layer,tilebase);
}


// Set a vera layer in text mode and configure the:
// - layer: Value of 0 or 1.
// - mapbase_address: A dword typed address (4 bytes), that specifies the full address of the map base.
//   The function does the translation from the dword that contains the 17 bit address,
//   to the respective mapbase vera register.
//   Note that the register only specifies bits 16:9 of the address,
//   so the resulting address in the VERA VRAM is always aligned to a multiple of 512 bytes.
// - tilebase_address: A dword typed address (4 bytes), that specifies the base address of the tile map.
//   The function does the translation from the dword that contains the 17 bit address,
//   to the respective tilebase vera register.
//   Note that the resulting vera register holds only specifies bits 16:11 of the address,
//   so the resulting address in the VERA VRAM is always aligned to a multiple of 2048 bytes!
// - mapwidth: The width of the map in number of tiles.
// - mapheight: The height of the map in number of tiles.
// - tilewidth: The width of a tile, which can be 8 or 16 pixels.
// - tileheight: The height of a tile, which can be 8 or 16 pixels.
// - color_mode: The color mode, which can be 16 or 256.
void vera_layer_mode_text(byte layer, dword mapbase_address, dword tilebase_address, word mapwidth, word mapheight, byte tilewidth, byte tileheight, word color_mode ) {
    vera_layer_mode_tile( layer, mapbase_address, tilebase_address, mapwidth, mapheight, tilewidth, tileheight, 1 );
    switch(color_mode) {
        case 16:
            vera_layer_set_text_color_mode( layer, VERA_LAYER_CONFIG_16C );
            break;
        case 256:
            vera_layer_set_text_color_mode( layer, VERA_LAYER_CONFIG_256C );
            break;
    }
}

// Set a vera layer in bitmap mode and configure the:
// - layer: Value of 0 or 1.
// - mapbase_address: A dword typed address (4 bytes), that specifies the full address of the map base.
//   The function does the translation from the dword that contains the 17 bit address,
//   to the respective mapbase vera register.
//   Note that the register only specifies bits 16:9 of the address,
//   so the resulting address in the VERA VRAM is always aligned to a multiple of 512 bytes.
// - tilebase_address: A dword typed address (4 bytes), that specifies the base address of the tile map.
//   The function does the translation from the dword that contains the 17 bit address,
//   to the respective tilebase vera register.
//   Note that the resulting vera register holds only specifies bits 16:11 of the address,
//   so the resulting address in the VERA VRAM is always aligned to a multiple of 2048 bytes!
// - mapwidth: The width of the map in number of tiles.
// - mapheight: The height of the map in number of tiles.
// - tilewidth: The width of a tile, which can be 8 or 16 pixels.
// - tileheight: The height of a tile, which can be 8 or 16 pixels.
// - color_mode: The color mode, which can be 16 or 256.
void vera_layer_mode_bitmap(byte layer, dword bitmap_address, word mapwidth, word color_depth ) {


    // config
    byte config = 0x00;
    switch(color_depth) {
        case 1:
            config |= VERA_LAYER_COLOR_DEPTH_1BPP;
            break;
        case 2:
            config |= VERA_LAYER_COLOR_DEPTH_2BPP;
            break;
        case 4:
            config |= VERA_LAYER_COLOR_DEPTH_4BPP;
            break;
        case 8:
            config |= VERA_LAYER_COLOR_DEPTH_8BPP;
            break;
    }
    config = config | VERA_LAYER_CONFIG_MODE_BITMAP;

    // tilebase
    vera_tilebase_offset[layer] = WORD0(bitmap_address);
    vera_tilebase_bank[layer] = BYTE2(bitmap_address);
    vera_tilebase_address[layer] = bitmap_address;

    bitmap_address = bitmap_address >> 1;
    byte tilebase = BYTE1(bitmap_address);
    tilebase &= VERA_LAYER_TILEBASE_MASK;

    // mapwidth
    switch(mapwidth) {
        case 320:
            vera_display_set_scale_double();
            tilebase |= VERA_TILEBASE_WIDTH_8;
            break;
        case 640:
            vera_display_set_scale_none();
            tilebase |= VERA_TILEBASE_WIDTH_16;
            break;
    }

    vera_layer_set_config(layer, config);
    vera_layer_set_tilebase(layer,tilebase);
}

// --- TILE FUNCTIONS ---

void vera_tile_area(byte layer, word tileindex, byte x, byte y, byte w, byte h, byte hflip, byte vflip, byte offset) {

    dword mapbase = vera_mapbase_address[layer];
    byte shift = vera_layer_rowshift[layer];
    word rowskip = (word)1 << shift;
    hflip = vera_layer_hflip[hflip];
    vflip = vera_layer_vflip[vflip];
    offset = offset << 4;
    byte index_l = BYTE0(tileindex);
    byte index_h = BYTE1(tileindex);
    index_h |= hflip;
    index_h |= vflip;
    index_h |= offset;
    mapbase += ((word)y << shift);
    mapbase += (x << 1);
    for(byte r=0; r<h; r++) {
        vera_vram_address0(mapbase,VERA_INC_1);
        for(byte c=0; c<w; c++) {
            *VERA_DATA0 = index_l;
            *VERA_DATA0 = index_h;
        }
        mapbase += rowskip;
    }

}

