506 lines
17 KiB
C++
506 lines
17 KiB
C++
|
|
// ****************************************************************************
|
|
//
|
|
// VGA layers
|
|
//
|
|
// ****************************************************************************
|
|
|
|
#include "include.h"
|
|
|
|
// layer program descriptors
|
|
const sLayerProg LayerProg[LAYERPROG_NUM] = {
|
|
|
|
// LAYERPROG_BASE base layer
|
|
{
|
|
.ins=vga_program_instructions, // pointer to program instructions
|
|
.prg=&vga_program, // pointer to program descriptor
|
|
.length=vga_program.length, // program length (number of instructions)
|
|
.wrap_target=vga_wrap_target, // offset of wrap target
|
|
.wrap=vga_wrap, // offset of wrap end
|
|
.idle=vga_offset_entry, // offset of idle
|
|
.entry=vga_offset_entry, // offset of entry
|
|
.maxidle=2, // max. offset of idle to detect end of job
|
|
.extranum=2, // number of extra offsets
|
|
.extra={ // extra offsets, pairs: offset, CPP-correction
|
|
vga_offset_extra1, 2,
|
|
vga_offset_extra2, 2,
|
|
},
|
|
},
|
|
|
|
// LAYERPROG_KEY layer with key color
|
|
{
|
|
.ins=keylayer_program_instructions, // pointer to program instructions
|
|
.prg=&keylayer_program, // pointer to program descriptor
|
|
.length=keylayer_program.length, // program length (number of instructions)
|
|
.wrap_target=keylayer_wrap_target, // offset of wrap target
|
|
.wrap=keylayer_wrap, // offset of wrap end
|
|
.idle=keylayer_offset_idle, // offset of idle
|
|
.entry=keylayer_offset_entry, // offset of entry
|
|
.maxidle=2, // max. offset of idle to detect end of job
|
|
.extranum=1, // number of extra offsets
|
|
.extra={ // extra offsets, pairs: offset, CPP-correction
|
|
keylayer_offset_extra1, 6,
|
|
},
|
|
},
|
|
|
|
// LAYERPROG_BLACK layer with black key color
|
|
{
|
|
.ins=blacklayer_program_instructions, // pointer to program instructions
|
|
.prg=&blacklayer_program, // pointer to program descriptor
|
|
.length=blacklayer_program.length, // program length (number of instructions)
|
|
.wrap_target=blacklayer_wrap_target, // offset of wrap target
|
|
.wrap=blacklayer_wrap, // offset of wrap end
|
|
.idle=blacklayer_offset_idle, // offset of idle
|
|
.entry=blacklayer_offset_entry, // offset of entry
|
|
.maxidle=2, // max. offset of idle to detect end of job
|
|
.extranum=2, // number of extra offsets
|
|
.extra={ // extra offsets, pairs: offset, CPP-correction
|
|
blacklayer_offset_extra1, 4,
|
|
blacklayer_offset_extra2, 3,
|
|
},
|
|
},
|
|
|
|
// LAYERPROG_WHITE layer with white key color
|
|
{
|
|
.ins=whitelayer_program_instructions, // pointer to program instructions
|
|
.prg=&whitelayer_program, // pointer to program descriptor
|
|
.length=whitelayer_program.length, // program length (number of instructions)
|
|
.wrap_target=whitelayer_wrap_target, // offset of wrap target
|
|
.wrap=whitelayer_wrap, // offset of wrap end
|
|
.idle=whitelayer_offset_idle, // offset of idle
|
|
.entry=whitelayer_offset_entry, // offset of entry
|
|
.maxidle=2, // max. offset of idle to detect end of job
|
|
.extranum=1, // number of extra offsets
|
|
.extra={ // extra offsets, pairs: offset, CPP-correction
|
|
whitelayer_offset_extra1, 4,
|
|
},
|
|
},
|
|
|
|
// LAYERPROG_MONO layer with mono pattern or simple color
|
|
{
|
|
.ins=monolayer_program_instructions, // pointer to program instructions
|
|
.prg=&monolayer_program, // pointer to program descriptor
|
|
.length=monolayer_program.length, // program length (number of instructions)
|
|
.wrap_target=monolayer_wrap_target, // offset of wrap target
|
|
.wrap=monolayer_wrap, // offset of wrap end
|
|
.idle=monolayer_offset_idle, // offset of idle
|
|
.entry=monolayer_offset_entry, // offset of entry
|
|
.maxidle=2, // max. offset of idle to detect end of job
|
|
.extranum=2, // number of extra offsets
|
|
.extra={ // extra offsets, pairs: offset, CPP-correction
|
|
monolayer_offset_extra1, 4,
|
|
monolayer_offset_extra2, 2,
|
|
},
|
|
},
|
|
|
|
// LAYERPROG_RLE layer with RLE compression
|
|
{
|
|
.ins=rlelayer_program_instructions, // pointer to program instructions
|
|
.prg=&rlelayer_program, // pointer to program descriptor
|
|
.length=rlelayer_program.length, // program length (number of instructions)
|
|
.wrap_target=rlelayer_wrap_target, // offset of wrap target
|
|
.wrap=rlelayer_wrap, // offset of wrap end
|
|
.idle=rlelayer_offset_idle, // offset of idle
|
|
.entry=rlelayer_offset_entry, // offset of entry
|
|
.maxidle=2, // max. offset of idle to detect end of job
|
|
.extranum=7, // number of extra offsets
|
|
.extra={ // extra offsets, pairs: offset, CPP-correction
|
|
rlelayer_offset_extra1, 1,
|
|
rlelayer_offset_extra2, 3,
|
|
rlelayer_offset_extra3, 2,
|
|
rlelayer_offset_extra4, 2,
|
|
rlelayer_offset_extra5, 3,
|
|
rlelayer_offset_extra6, 2,
|
|
rlelayer_offset_extra7, 3,
|
|
},
|
|
},
|
|
|
|
};
|
|
|
|
// current layer program of overlapped layers
|
|
u8 LayerProgInx; // index of current layer program (LAYERPROG_*)
|
|
sLayerProg CurLayerProg; // copy of current layer program
|
|
|
|
// layer mode descriptors
|
|
const sLayerMode LayerMode[LAYERMODE_NUM] = {
|
|
|
|
// LAYERMODE_BASE base layer
|
|
{
|
|
.prog=LAYERPROG_BASE, // layer program (LAYERPROG_*)
|
|
.mincpp=2, // minimal clock cycles per pixel
|
|
.maxcpp=17, // maximal clock cycles per pixel
|
|
},
|
|
|
|
// LAYERMODE_KEY layers with key color
|
|
{
|
|
.prog=LAYERPROG_KEY, // layer program (LAYERPROG_*)
|
|
.mincpp=6, // minimal clock cycles per pixel
|
|
.maxcpp=37, // maximal clock cycles per pixel
|
|
},
|
|
|
|
// LAYERMODE_BLACK layers with black key color
|
|
{
|
|
.prog=LAYERPROG_BLACK, // layer program (LAYERPROG_*)
|
|
.mincpp=4, // minimal clock cycles per pixel
|
|
.maxcpp=34, // maximal clock cycles per pixel
|
|
},
|
|
|
|
// LAYERMODE_WHITE layers with white key color
|
|
{
|
|
.prog=LAYERPROG_WHITE, // layer program (LAYERPROG_*)
|
|
.mincpp=4, // minimal clock cycles per pixel
|
|
.maxcpp=35, // maximal clock cycles per pixel
|
|
},
|
|
|
|
// LAYERMODE_MONO layers with mono pattern
|
|
{
|
|
.prog=LAYERPROG_MONO, // layer program (LAYERPROG_*)
|
|
.mincpp=4, // minimal clock cycles per pixel
|
|
.maxcpp=35, // maximal clock cycles per pixel
|
|
},
|
|
|
|
// LAYERMODE_COLOR layers with simple color
|
|
{
|
|
.prog=LAYERPROG_MONO, // layer program (LAYERPROG_*)
|
|
.mincpp=2, // minimal clock cycles per pixel
|
|
.maxcpp=33, // maximal clock cycles per pixel
|
|
},
|
|
|
|
// LAYERMODE_RLE layers with RLE compression
|
|
{
|
|
.prog=LAYERPROG_RLE, // layer program (LAYERPROG_*)
|
|
.mincpp=3, // minimal clock cycles per pixel
|
|
.maxcpp=32, // maximal clock cycles per pixel
|
|
},
|
|
|
|
// LAYERMODE_SPRITEKEY layers with sprites with key color
|
|
{
|
|
.prog=LAYERPROG_KEY, // layer program (LAYERPROG_*)
|
|
.mincpp=6, // minimal clock cycles per pixel
|
|
.maxcpp=37, // maximal clock cycles per pixel
|
|
},
|
|
|
|
// LAYERMODE_SPRITEBLACK layers with sprites with black key color
|
|
{
|
|
.prog=LAYERPROG_BLACK, // layer program (LAYERPROG_*)
|
|
.mincpp=4, // minimal clock cycles per pixel
|
|
.maxcpp=34, // maximal clock cycles per pixel
|
|
},
|
|
|
|
// LAYERMODE_SPRITEWHITE layers with sprites with white key color
|
|
{
|
|
.prog=LAYERPROG_WHITE, // layer program (LAYERPROG_*)
|
|
.mincpp=4, // minimal clock cycles per pixel
|
|
.maxcpp=35, // maximal clock cycles per pixel
|
|
},
|
|
|
|
// LAYERMODE_FASTSPRITEKEY layers with fast sprites with key color
|
|
{
|
|
.prog=LAYERPROG_KEY, // layer program (LAYERPROG_*)
|
|
.mincpp=6, // minimal clock cycles per pixel
|
|
.maxcpp=37, // maximal clock cycles per pixel
|
|
},
|
|
|
|
// LAYERMODE_FASTSPRITEBLACK layers with fast sprites with black key color
|
|
{
|
|
.prog=LAYERPROG_BLACK, // layer program (LAYERPROG_*)
|
|
.mincpp=4, // minimal clock cycles per pixel
|
|
.maxcpp=34, // maximal clock cycles per pixel
|
|
},
|
|
|
|
// LAYERMODE_FASTSPRITEWHITE layers with fast sprites with white key color
|
|
{
|
|
.prog=LAYERPROG_WHITE, // layer program (LAYERPROG_*)
|
|
.mincpp=4, // minimal clock cycles per pixel
|
|
.maxcpp=35, // maximal clock cycles per pixel
|
|
},
|
|
|
|
// LAYERMODE_PERSPKEY layer with key color and image with transformation matrix
|
|
{
|
|
.prog=LAYERPROG_KEY, // layer program (LAYERPROG_*)
|
|
.mincpp=6, // minimal clock cycles per pixel
|
|
.maxcpp=37, // maximal clock cycles per pixel
|
|
},
|
|
|
|
// LAYERMODE_PERSPBLACK layer with black key color and image with transformation matrix
|
|
{
|
|
.prog=LAYERPROG_BLACK, // layer program (LAYERPROG_*)
|
|
.mincpp=4, // minimal clock cycles per pixel
|
|
.maxcpp=34, // maximal clock cycles per pixel
|
|
},
|
|
|
|
// LAYERMODE_PERSPWHITE layer with white key color and image with transformation matrix
|
|
{
|
|
.prog=LAYERPROG_WHITE, // layer program (LAYERPROG_*)
|
|
.mincpp=4, // minimal clock cycles per pixel
|
|
.maxcpp=35, // maximal clock cycles per pixel
|
|
},
|
|
|
|
// LAYERMODE_PERSP2KEY layer with key color and double pixel image with transformation matrix
|
|
{
|
|
.prog=LAYERPROG_KEY, // layer program (LAYERPROG_*)
|
|
.mincpp=6, // minimal clock cycles per pixel
|
|
.maxcpp=37, // maximal clock cycles per pixel
|
|
},
|
|
|
|
// LAYERMODE_PERSP2BLACK layer with black key color and double pixel image with transformation matrix
|
|
{
|
|
.prog=LAYERPROG_BLACK, // layer program (LAYERPROG_*)
|
|
.mincpp=4, // minimal clock cycles per pixel
|
|
.maxcpp=34, // maximal clock cycles per pixel
|
|
},
|
|
|
|
// LAYERMODE_PERSP2WHITE layer with white key color and double pixel image with transformation matrix
|
|
{
|
|
.prog=LAYERPROG_WHITE, // layer program (LAYERPROG_*)
|
|
.mincpp=4, // minimal clock cycles per pixel
|
|
.maxcpp=35, // maximal clock cycles per pixel
|
|
},
|
|
};
|
|
|
|
// current layer mode of layers
|
|
u8 LayerModeInx[LAYERS]; // index of current layer mode (LAYERMODE_*)
|
|
sLayerMode CurLayerMode[LAYERS]; // copy of current layer mode
|
|
|
|
// current layer screens
|
|
sLayer LayerScreen[LAYERS]; // layer screens
|
|
|
|
u8 LayerMask; // mask of active layers
|
|
|
|
// index of first pin of layer (base layer should stay VGA_GPIO_FIRST)
|
|
u8 LayerFirstPin[LAYERS_MAX] = { VGA_GPIO_FIRST, VGA_GPIO_FIRST, VGA_GPIO_FIRST, VGA_GPIO_FIRST};
|
|
|
|
// number of pins of overlapped layer (base layer should stay VGA_GPIO_OUTNUM)
|
|
u8 LayerNumPin[LAYERS_MAX] = { VGA_GPIO_OUTNUM, VGA_GPIO_OUTNUM, VGA_GPIO_OUTNUM, VGA_GPIO_OUTNUM};
|
|
|
|
// set overlapped layer 1..3 ON
|
|
void LayerOn(u8 inx)
|
|
{
|
|
__dmb();
|
|
LayerScreen[inx].on = True;
|
|
__dmb();
|
|
}
|
|
|
|
// set overlapped layer 1..3 OFF
|
|
void LayerOff(u8 inx)
|
|
{
|
|
__dmb();
|
|
LayerScreen[inx].on = False;
|
|
__dmb();
|
|
}
|
|
|
|
// set coordinate X of overlapped layer
|
|
void LayerSetX(u8 inx, s16 x)
|
|
{
|
|
sLayer* lay = &LayerScreen[inx];
|
|
s32 cppx = lay->cpp*x; // initial delay
|
|
if (cppx < 0) cppx = 0;
|
|
u32 w = lay->w; // image width
|
|
u32 init = 0; // init word
|
|
|
|
// prepare init word
|
|
switch (lay->mode)
|
|
{
|
|
case LAYERMODE_PERSP2KEY: // layer with key color and double pixel image with transformation matrix
|
|
case LAYERMODE_PERSPKEY: // layer with key color and image with transformation matrix
|
|
case LAYERMODE_FASTSPRITEKEY: // layer with fast sprites with key color
|
|
case LAYERMODE_SPRITEKEY: // layer with sprites with key color
|
|
case LAYERMODE_KEY: // layer with key color
|
|
init = VGAKEY(cppx, w, (lay->keycol & 0xff));
|
|
break;
|
|
|
|
case LAYERMODE_PERSP2BLACK: // layer with black key color and double pixel image with transformation matrix
|
|
case LAYERMODE_PERSPBLACK: // layer with black key color and image with transformation matrix
|
|
case LAYERMODE_FASTSPRITEBLACK: // layer with fast sprites with black key color
|
|
case LAYERMODE_SPRITEBLACK: // layer with sprites with black key color
|
|
case LAYERMODE_BLACK: // layer with black key color
|
|
init = VGABLACK(cppx, w);
|
|
break;
|
|
|
|
case LAYERMODE_PERSP2WHITE: // layer with white key color and double pixel image with transformation matrix
|
|
case LAYERMODE_PERSPWHITE: // layer with white key color and image with transformation matrix
|
|
case LAYERMODE_FASTSPRITEWHITE: // layer with fast sprites with white key color
|
|
case LAYERMODE_SPRITEWHITE: // layer with sprites with white key color
|
|
case LAYERMODE_WHITE: // layer with white key color
|
|
init = VGAWHITE(cppx, w);
|
|
break;
|
|
|
|
case LAYERMODE_MONO: // layer with mono pattern
|
|
init = VGAMONO(cppx, w, (lay->keycol & 0xff));
|
|
break;
|
|
|
|
case LAYERMODE_COLOR: // layer with simple color
|
|
init = VGACOLOR(cppx, w);
|
|
break;
|
|
|
|
case LAYERMODE_RLE: // layer with RLE compression
|
|
init = VGARLE(cppx);
|
|
break;
|
|
}
|
|
lay->init = init; // init word
|
|
lay->x = x; // start X coordinate
|
|
}
|
|
|
|
// set coordinate Y of overlapped layer
|
|
void LayerSetY(u8 inx, s16 y)
|
|
{
|
|
sLayer* lay = &LayerScreen[inx];
|
|
lay->y = y;
|
|
}
|
|
|
|
// set width of image of overlapped layer
|
|
// Uses auto pitch wb (full line). Set custom wb after calling this function.
|
|
void LayerSetW(u8 inx, u16 w)
|
|
{
|
|
sLayer* lay = &LayerScreen[inx];
|
|
lay->w = w; // image width
|
|
Bool mono = (lay->mode == LAYERMODE_MONO);
|
|
lay->trans = mono ? (((w/8)+3)/4) : (w/4); // transfer count
|
|
lay->wb = mono ? (w/8) : w; // width bytes
|
|
LayerSetX(inx, lay->x); // update init word
|
|
}
|
|
|
|
// set height of image of overlapped layer
|
|
void LayerSetH(u8 inx, u16 h)
|
|
{
|
|
sLayer* lay = &LayerScreen[inx];
|
|
lay->h = h;
|
|
}
|
|
|
|
// setup overlapped layer 1..3 (not for sprites and not for perspective mode)
|
|
// inx ... layer index 1..3
|
|
// img ... pointer to image data
|
|
// vmode ... pointer to initialized video configuration
|
|
// w ... image width in pixels (must be multiple of 4)
|
|
// h ... image height
|
|
// col ... key color (needed for LAYERMODE_KEY and LAYERMODE_MONO layer mode)
|
|
// par ... additional data (RLE index table, integer transformation matrix)
|
|
// Use these functions after layer setup: LayerSetX, LayerSetY, LayerOn
|
|
void LayerSetup(u8 inx, const u8* img, const sVmode* vmode, u16 w, u16 h, u8 col /* = 0 */, const void* par /* = NULL */)
|
|
{
|
|
LayerOff(inx); // set layer OFF
|
|
sLayer* lay = &LayerScreen[inx]; // get pointer to layer
|
|
lay->img = img; // pointer to image data
|
|
lay->par = par; // additional parameter
|
|
lay->keycol = col | ((u16)col << 8) | ((u32)col << 16) | ((u32)col << 24); // key color
|
|
lay->x = 0; // X coordinate
|
|
lay->y = 0; // Y coordinate
|
|
lay->h = h; // height of image
|
|
lay->spritenum = 0; // number of sprites
|
|
lay->cpp = vmode->cpp; // save clocks per pixel
|
|
lay->mode = vmode->mode[inx]; // layer mode
|
|
LayerSetW(inx, w); // set width of image, update parameters init, trans and wb
|
|
}
|
|
|
|
// setup overlapped layer 1..3 for LAYERMODE_PERSP* modes
|
|
// inx ... layer index 1..3
|
|
// img ... pointer to source image data (image width and height must be power of 2)
|
|
// vmode ... pointer to initialized video configuration
|
|
// w ... destination image width in pixels (must be multiple of 4)
|
|
// h ... destination image height
|
|
// xbits ... number of bits of width of source image
|
|
// ybits ... number of bits of height of source image
|
|
// horiz ... horizon of perspective projection/4 (0=no perspecitve, <0 ceilling)
|
|
// mat ... integer transformation matrix
|
|
// col ... key color (needed for LAYERMODE_PERSPKEY layer mode)
|
|
// Use these functions after layer setup: LayerSetX, LayerSetY, LayerOn
|
|
void LayerPerspSetup(u8 inx, const u8* img, const sVmode* vmode, u16 w, u16 h, u8 xbits, u8 ybits,
|
|
s8 horiz, const int* mat, u8 col /* = 0 */)
|
|
{
|
|
LayerSetup(inx, img, vmode, w, h, col, mat);
|
|
sLayer* lay = &LayerScreen[inx]; // get pointer to layer
|
|
lay->xbits = xbits;
|
|
lay->ybits = ybits;
|
|
lay->horiz = horiz;
|
|
}
|
|
|
|
// setup overlapped layer 1..3 for LAYERMODE_SPRITE* and LAYERMODE_FASTSPRITE* modes
|
|
// inx ... layer index 1..3
|
|
// sprite ... pointer to list of sprites (array of pointers to sprites; sorted by X on LAYERMODE_FASTSPRITE* modes)
|
|
// spritenum ... number of sprites in the list (to turn sprite off, you can set its coordinate Y out of the screen)
|
|
// vmode ... pointer to initialized video configuration
|
|
// x ... start coordinate X of area with sprites
|
|
// y ... start coordinate Y of area with sprites
|
|
// w ... width of area with sprites (must be multiple of 4)
|
|
// h ... height of area with sprites
|
|
// col ... key color (needed for LAYERMODE_SPRITEKEY and LAYERMODE_FASTSPRITEKEY layer mode)
|
|
// Use functions LayerOn after layer setup.
|
|
void LayerSpriteSetup(u8 inx, sSprite** sprite, u16 spritenum, const sVmode* vmode,
|
|
s16 x, s16 y, u16 w, u16 h, u8 col /* = 0 */)
|
|
{
|
|
LayerSetup(inx, (const u8*)sprite, vmode, w, h, col);
|
|
LayerSetX(inx, x);
|
|
LayerSetY(inx, y);
|
|
sLayer* lay = &LayerScreen[inx]; // get pointer to layer
|
|
lay->spritenum = spritenum;
|
|
}
|
|
|
|
// prepare array of start and length of lines (detects transparent pixels)
|
|
// img ... image
|
|
// x0 ... array of start of lines
|
|
// w0 ... array of length of lines
|
|
// w ... sprite width (slow sprite: max. width 255)
|
|
// h ... sprite height
|
|
// wb ... sprite pitch (bytes between lines)
|
|
// col ... key color
|
|
// fast ... fast sprite, divide start and length of line by 4
|
|
void SpritePrepLines(const u8* img, u8* x0, u8* w0, u16 w, u16 h, u16 wb, u8 col, Bool fast)
|
|
{
|
|
int x1, x2, w2, y;
|
|
const u8* d;
|
|
|
|
// loop through lines
|
|
for (y = 0; y < h; y++)
|
|
{
|
|
// find start of line
|
|
d = &img[y*wb];
|
|
for (x1 = 0; x1 < w; x1++)
|
|
{
|
|
if (*d != col) break;
|
|
d++;
|
|
}
|
|
|
|
// find end of line
|
|
d = &img[y*wb + w - 1];
|
|
for (x2 = w; x2 > x1; x2--)
|
|
{
|
|
if (*d != col) break;
|
|
d--;
|
|
}
|
|
|
|
// prepare start and length
|
|
w2 = x2 - x1;
|
|
if (fast)
|
|
{
|
|
w2 += ((x2 + 3) & ~3) - x2;
|
|
x1 /= 4;
|
|
w2 = (w2 + 3)/4;
|
|
}
|
|
if (x1 > 255) x1 = 255;
|
|
if (w2 > 255) w2 = 255;
|
|
|
|
// store start and length
|
|
*x0++ = x1;
|
|
*w0++ = w2;
|
|
}
|
|
}
|
|
|
|
// sort fast sprite list by X coordinate
|
|
void SortSprite(sSprite** list, int num)
|
|
{
|
|
int i;
|
|
sSprite* s;
|
|
sSprite* s2;
|
|
for (i = 0; i < num-1; i++)
|
|
{
|
|
s = list[i];
|
|
s2 = list[i+1];
|
|
if (s->x > s2->x)
|
|
{
|
|
list[i] = s2;
|
|
list[i+1] = s;
|
|
if (i > 0) i -= 2;
|
|
}
|
|
}
|
|
}
|