kolibrios-fun/programs/emulator/dgen-sdl-1.33/ras.cpp
turbocat ea1a60faa3 Upload DGEN port source
git-svn-id: svn://kolibrios.org@9837 a494cfbc-eb01-0410-851d-a64ba20cac60
2022-06-15 18:25:17 +00:00

1266 lines
39 KiB
C++

// DGen/SDL v1.16+
// New raster effects engine
// I'd like to thank the Mac folks for giving me a good template to work from.
// This is just a cheap rehash of their code, except friendlier to other bit
// depths. :) I also put in a few little optimizations, like blank checking
// and especially the sprites.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <assert.h>
#include "system.h"
#include "md.h"
#include "pd.h"
#include "rc-vars.h"
// This is marked each time the palette is updated. Handy for the 8bpp
// implementation, so we don't waste time changing the palette unnecessarily.
int pal_dirty;
// Macros, to route draw_tile and draw_tile_solid to the right handler
#define draw_tile(which, line, where) \
switch(Bpp)\
{\
case 1:\
draw_tile1((which),(line),(where)); break;\
case 2:\
draw_tile2((which),(line),(where)); break;\
case 3:\
draw_tile3((which),(line),(where)); break;\
case 4:\
draw_tile4((which),(line),(where)); break;\
}
#define draw_tile_solid(which, line, where) \
switch(Bpp)\
{\
case 1:\
draw_tile1_solid((which),(line),(where)); break;\
case 2:\
draw_tile2_solid((which),(line),(where)); break;\
case 3:\
draw_tile3_solid((which),(line),(where)); break;\
case 4:\
draw_tile4_solid((which),(line),(where)); break;\
}
// Silly utility function, get a big-endian word
#ifdef WORDS_BIGENDIAN
static inline int get_word(unsigned char *where)
{ return (int)(*(unsigned short*)where); }
#else
static inline int get_word(unsigned char *where)
{ return (where[0] << 8) | where[1]; }
#endif
// Tile pixel masks
#ifdef WORDS_BIGENDIAN
# define PIXEL0 (0xf0000000)
# define PIXEL1 (0x0f000000)
# define PIXEL2 (0x00f00000)
# define PIXEL3 (0x000f0000)
# define PIXEL4 (0x0000f000)
# define PIXEL5 (0x00000f00)
# define PIXEL6 (0x000000f0)
# define PIXEL7 (0x0000000f)
# define SHIFT0 (28)
# define SHIFT1 (24)
# define SHIFT2 (20)
# define SHIFT3 (16)
# define SHIFT4 (12)
# define SHIFT5 ( 8)
# define SHIFT6 ( 4)
# define SHIFT7 ( 0)
#else // WORDS_BIGENDIAN
# define PIXEL0 (0x000000f0)
# define PIXEL1 (0x0000000f)
# define PIXEL2 (0x0000f000)
# define PIXEL3 (0x00000f00)
# define PIXEL4 (0x00f00000)
# define PIXEL5 (0x000f0000)
# define PIXEL6 (0xf0000000)
# define PIXEL7 (0x0f000000)
# define SHIFT0 ( 4)
# define SHIFT1 ( 0)
# define SHIFT2 (12)
# define SHIFT3 ( 8)
# define SHIFT4 (20)
# define SHIFT5 (16)
# define SHIFT6 (28)
# define SHIFT7 (24)
#endif // WORDS_BIGENDIAN
#ifdef WITH_X86_TILES
extern "C" {
void asm_tiles_init(unsigned char *vram,
unsigned char *reg,
unsigned *highpal);
void drawtile1(int which, int line, unsigned char *where);
void drawtile1_solid(int which, int line, unsigned char *where);
void drawtile2(int which, int line, unsigned char *where);
void drawtile2_solid(int which, int line, unsigned char *where);
void drawtile3(int which, int line, unsigned char *where);
void drawtile3_solid(int which, int line, unsigned char *where);
void drawtile4(int which, int line, unsigned char *where);
void drawtile4_solid(int which, int line, unsigned char *where);
}
// Pass off these calls to assembler counterparts
inline void md_vdp::draw_tile1_solid(int which, int line, unsigned char *where)
{ drawtile1_solid(which, line, where); }
inline void md_vdp::draw_tile1(int which, int line, unsigned char *where)
{ drawtile1(which, line, where); }
inline void md_vdp::draw_tile2_solid(int which, int line, unsigned char *where)
{ drawtile2_solid(which, line, where); }
inline void md_vdp::draw_tile2(int which, int line, unsigned char *where)
{ drawtile2(which, line, where); }
inline void md_vdp::draw_tile3_solid(int which, int line, unsigned char *where)
{ drawtile3_solid(which, line, where); }
inline void md_vdp::draw_tile3(int which, int line, unsigned char *where)
{ drawtile3(which, line, where); }
inline void md_vdp::draw_tile4_solid(int which, int line, unsigned char *where)
{ drawtile4_solid(which, line, where); }
inline void md_vdp::draw_tile4(int which, int line, unsigned char *where)
{ drawtile4(which, line, where); }
#else // WITH_X86_TILES
static bool has_zero_nibbles(uint32_t u32)
{
return ((u32 - 0x11111111) & ~u32 & 0x88888888);
}
// Blit tile solidly, for 1 byte-per-pixel
inline void md_vdp::draw_tile1_solid(int which, int line, unsigned char *where)
{
unsigned tile, pal;
pal = (which >> 9 & 0x30); // Determine which 16-color palette
if(which & 0x1000) // y flipped
line ^= 7; // take from the bottom, instead of the top
if(reg[12] & 2) // interlace
tile = *(unsigned*)(vram + ((which&0x7ff) << 6) + (line << 3));
else
tile = *(unsigned*)(vram + ((which&0x7ff) << 5) + (line << 2));
// Blit the tile!
if(which & 0x800) // x flipped
{
*(where ) = ((tile & PIXEL7)>>SHIFT7) | pal;
*(where+1) = ((tile & PIXEL6)>>SHIFT6) | pal;
*(where+2) = ((tile & PIXEL5)>>SHIFT5) | pal;
*(where+3) = ((tile & PIXEL4)>>SHIFT4) | pal;
*(where+4) = ((tile & PIXEL3)>>SHIFT3) | pal;
*(where+5) = ((tile & PIXEL2)>>SHIFT2) | pal;
*(where+6) = ((tile & PIXEL1)>>SHIFT1) | pal;
*(where+7) = ((tile & PIXEL0)>>SHIFT0) | pal;
} else {
*(where ) = ((tile & PIXEL0)>>SHIFT0) | pal;
*(where+1) = ((tile & PIXEL1)>>SHIFT1) | pal;
*(where+2) = ((tile & PIXEL2)>>SHIFT2) | pal;
*(where+3) = ((tile & PIXEL3)>>SHIFT3) | pal;
*(where+4) = ((tile & PIXEL4)>>SHIFT4) | pal;
*(where+5) = ((tile & PIXEL5)>>SHIFT5) | pal;
*(where+6) = ((tile & PIXEL6)>>SHIFT6) | pal;
*(where+7) = ((tile & PIXEL7)>>SHIFT7) | pal;
}
}
// Blit tile, leaving color zero transparent, for 1 byte per pixel
inline void md_vdp::draw_tile1(int which, int line, unsigned char *where)
{
unsigned tile, pal;
pal = (which >> 9 & 0x30); // Determine which 16-color palette
if(which & 0x1000) // y flipped
line ^= 7; // take from the bottom, instead of the top
if(reg[12] & 2) // interlace
tile = *(unsigned*)(vram + ((which&0x7ff) << 6) + (line << 3));
else
tile = *(unsigned*)(vram + ((which&0x7ff) << 5) + (line << 2));
// If the tile is all 0's, why waste the time?
if(!tile) return;
// If the tile doesn't have any transparent pixels, draw it solidly.
if (!has_zero_nibbles(tile)) {
if (which & 0x800) {
// x flipped
*(where ) = ((tile & PIXEL7)>>SHIFT7) | pal;
*(where+1) = ((tile & PIXEL6)>>SHIFT6) | pal;
*(where+2) = ((tile & PIXEL5)>>SHIFT5) | pal;
*(where+3) = ((tile & PIXEL4)>>SHIFT4) | pal;
*(where+4) = ((tile & PIXEL3)>>SHIFT3) | pal;
*(where+5) = ((tile & PIXEL2)>>SHIFT2) | pal;
*(where+6) = ((tile & PIXEL1)>>SHIFT1) | pal;
*(where+7) = ((tile & PIXEL0)>>SHIFT0) | pal;
}
else {
*(where ) = ((tile & PIXEL0)>>SHIFT0) | pal;
*(where+1) = ((tile & PIXEL1)>>SHIFT1) | pal;
*(where+2) = ((tile & PIXEL2)>>SHIFT2) | pal;
*(where+3) = ((tile & PIXEL3)>>SHIFT3) | pal;
*(where+4) = ((tile & PIXEL4)>>SHIFT4) | pal;
*(where+5) = ((tile & PIXEL5)>>SHIFT5) | pal;
*(where+6) = ((tile & PIXEL6)>>SHIFT6) | pal;
*(where+7) = ((tile & PIXEL7)>>SHIFT7) | pal;
}
return;
}
// Blit the tile!
if(which & 0x800) // x flipped
{
if(tile & PIXEL7) *(where ) = ((tile & PIXEL7)>>SHIFT7) | pal;
if(tile & PIXEL6) *(where+1) = ((tile & PIXEL6)>>SHIFT6) | pal;
if(tile & PIXEL5) *(where+2) = ((tile & PIXEL5)>>SHIFT5) | pal;
if(tile & PIXEL4) *(where+3) = ((tile & PIXEL4)>>SHIFT4) | pal;
if(tile & PIXEL3) *(where+4) = ((tile & PIXEL3)>>SHIFT3) | pal;
if(tile & PIXEL2) *(where+5) = ((tile & PIXEL2)>>SHIFT2) | pal;
if(tile & PIXEL1) *(where+6) = ((tile & PIXEL1)>>SHIFT1) | pal;
if(tile & PIXEL0) *(where+7) = ((tile & PIXEL0)>>SHIFT0) | pal;
} else {
if(tile & PIXEL0) *(where ) = ((tile & PIXEL0)>>SHIFT0) | pal;
if(tile & PIXEL1) *(where+1) = ((tile & PIXEL1)>>SHIFT1) | pal;
if(tile & PIXEL2) *(where+2) = ((tile & PIXEL2)>>SHIFT2) | pal;
if(tile & PIXEL3) *(where+3) = ((tile & PIXEL3)>>SHIFT3) | pal;
if(tile & PIXEL4) *(where+4) = ((tile & PIXEL4)>>SHIFT4) | pal;
if(tile & PIXEL5) *(where+5) = ((tile & PIXEL5)>>SHIFT5) | pal;
if(tile & PIXEL6) *(where+6) = ((tile & PIXEL6)>>SHIFT6) | pal;
if(tile & PIXEL7) *(where+7) = ((tile & PIXEL7)>>SHIFT7) | pal;
}
}
// Blit tile solidly, for 2 byte-per-pixel
inline void md_vdp::draw_tile2_solid(int which, int line, unsigned char *where)
{
unsigned tile, temp, *pal;
unsigned short *wwhere = (unsigned short*)where;
pal = highpal + (which >> 9 & 0x30); // Determine which 16-color palette
temp = *pal; *pal = highpal[reg[7]&0x3f]; // Get background color
if(which & 0x1000) // y flipped
line ^= 7; // take from the bottom, instead of the top
if(reg[12] & 2) // interlace
tile = *(unsigned*)(vram + ((which&0x7ff) << 6) + (line << 3));
else
tile = *(unsigned*)(vram + ((which&0x7ff) << 5) + (line << 2));
// Blit the tile!
if(which & 0x800) // x flipped
{
*(wwhere ) = pal[((tile & PIXEL7)>>SHIFT7)];
*(wwhere+1) = pal[((tile & PIXEL6)>>SHIFT6)];
*(wwhere+2) = pal[((tile & PIXEL5)>>SHIFT5)];
*(wwhere+3) = pal[((tile & PIXEL4)>>SHIFT4)];
*(wwhere+4) = pal[((tile & PIXEL3)>>SHIFT3)];
*(wwhere+5) = pal[((tile & PIXEL2)>>SHIFT2)];
*(wwhere+6) = pal[((tile & PIXEL1)>>SHIFT1)];
*(wwhere+7) = pal[((tile & PIXEL0)>>SHIFT0)];
} else {
*(wwhere ) = pal[((tile & PIXEL0)>>SHIFT0)];
*(wwhere+1) = pal[((tile & PIXEL1)>>SHIFT1)];
*(wwhere+2) = pal[((tile & PIXEL2)>>SHIFT2)];
*(wwhere+3) = pal[((tile & PIXEL3)>>SHIFT3)];
*(wwhere+4) = pal[((tile & PIXEL4)>>SHIFT4)];
*(wwhere+5) = pal[((tile & PIXEL5)>>SHIFT5)];
*(wwhere+6) = pal[((tile & PIXEL6)>>SHIFT6)];
*(wwhere+7) = pal[((tile & PIXEL7)>>SHIFT7)];
}
// Restore the original color
*pal = temp;
}
// Blit tile, leaving color zero transparent, for 2 byte per pixel
inline void md_vdp::draw_tile2(int which, int line, unsigned char *where)
{
unsigned tile, *pal;
unsigned short *wwhere = (unsigned short*)where;
pal = highpal + (which >> 9 & 0x30); // Determine which 16-color palette
if(which & 0x1000) // y flipped
line ^= 7; // take from the bottom, instead of the top
if(reg[12] & 2) // interlace
tile = *(unsigned*)(vram + ((which&0x7ff) << 6) + (line << 3));
else
tile = *(unsigned*)(vram + ((which&0x7ff) << 5) + (line << 2));
// If the tile is all 0's, why waste the time?
if(!tile) return;
// If the tile doesn't have any transparent pixels, draw it solidly.
if (!has_zero_nibbles(tile)) {
if (which & 0x800) {
// x flipped
*(wwhere ) = pal[((tile & PIXEL7)>>SHIFT7)];
*(wwhere+1) = pal[((tile & PIXEL6)>>SHIFT6)];
*(wwhere+2) = pal[((tile & PIXEL5)>>SHIFT5)];
*(wwhere+3) = pal[((tile & PIXEL4)>>SHIFT4)];
*(wwhere+4) = pal[((tile & PIXEL3)>>SHIFT3)];
*(wwhere+5) = pal[((tile & PIXEL2)>>SHIFT2)];
*(wwhere+6) = pal[((tile & PIXEL1)>>SHIFT1)];
*(wwhere+7) = pal[((tile & PIXEL0)>>SHIFT0)];
}
else {
*(wwhere ) = pal[((tile & PIXEL0)>>SHIFT0)];
*(wwhere+1) = pal[((tile & PIXEL1)>>SHIFT1)];
*(wwhere+2) = pal[((tile & PIXEL2)>>SHIFT2)];
*(wwhere+3) = pal[((tile & PIXEL3)>>SHIFT3)];
*(wwhere+4) = pal[((tile & PIXEL4)>>SHIFT4)];
*(wwhere+5) = pal[((tile & PIXEL5)>>SHIFT5)];
*(wwhere+6) = pal[((tile & PIXEL6)>>SHIFT6)];
*(wwhere+7) = pal[((tile & PIXEL7)>>SHIFT7)];
}
return;
}
// Blit the tile!
if(which & 0x800) // x flipped
{
if(tile & PIXEL7) *(wwhere ) = pal[((tile & PIXEL7)>>SHIFT7)];
if(tile & PIXEL6) *(wwhere+1) = pal[((tile & PIXEL6)>>SHIFT6)];
if(tile & PIXEL5) *(wwhere+2) = pal[((tile & PIXEL5)>>SHIFT5)];
if(tile & PIXEL4) *(wwhere+3) = pal[((tile & PIXEL4)>>SHIFT4)];
if(tile & PIXEL3) *(wwhere+4) = pal[((tile & PIXEL3)>>SHIFT3)];
if(tile & PIXEL2) *(wwhere+5) = pal[((tile & PIXEL2)>>SHIFT2)];
if(tile & PIXEL1) *(wwhere+6) = pal[((tile & PIXEL1)>>SHIFT1)];
if(tile & PIXEL0) *(wwhere+7) = pal[((tile & PIXEL0)>>SHIFT0)];
} else {
if(tile & PIXEL0) *(wwhere ) = pal[((tile & PIXEL0)>>SHIFT0)];
if(tile & PIXEL1) *(wwhere+1) = pal[((tile & PIXEL1)>>SHIFT1)];
if(tile & PIXEL2) *(wwhere+2) = pal[((tile & PIXEL2)>>SHIFT2)];
if(tile & PIXEL3) *(wwhere+3) = pal[((tile & PIXEL3)>>SHIFT3)];
if(tile & PIXEL4) *(wwhere+4) = pal[((tile & PIXEL4)>>SHIFT4)];
if(tile & PIXEL5) *(wwhere+5) = pal[((tile & PIXEL5)>>SHIFT5)];
if(tile & PIXEL6) *(wwhere+6) = pal[((tile & PIXEL6)>>SHIFT6)];
if(tile & PIXEL7) *(wwhere+7) = pal[((tile & PIXEL7)>>SHIFT7)];
}
}
inline void md_vdp::draw_tile3_solid(int which, int line, unsigned char *where)
{
unsigned tile, temp, *pal;
uint24_t *wwhere = (uint24_t *)where;
pal = highpal + (which >> 9 & 0x30); // Determine which 16-color palette
temp = *pal; *pal = highpal[reg[7]&0x3f]; // Get background color
if(which & 0x1000) // y flipped
line ^= 7; // take from the bottom, instead of the top
if(reg[12] & 2) // interlace
tile = *(unsigned*)(vram + ((which&0x7ff) << 6) + (line << 3));
else
tile = *(unsigned*)(vram + ((which&0x7ff) << 5) + (line << 2));
// Blit the tile!
if(which & 0x800) // x flipped
{
u24cpy(&wwhere[0], (uint24_t *)&pal[((tile & PIXEL7) >> SHIFT7)]);
u24cpy(&wwhere[1], (uint24_t *)&pal[((tile & PIXEL6) >> SHIFT6)]);
u24cpy(&wwhere[2], (uint24_t *)&pal[((tile & PIXEL5) >> SHIFT5)]);
u24cpy(&wwhere[3], (uint24_t *)&pal[((tile & PIXEL4) >> SHIFT4)]);
u24cpy(&wwhere[4], (uint24_t *)&pal[((tile & PIXEL3) >> SHIFT3)]);
u24cpy(&wwhere[5], (uint24_t *)&pal[((tile & PIXEL2) >> SHIFT2)]);
u24cpy(&wwhere[6], (uint24_t *)&pal[((tile & PIXEL1) >> SHIFT1)]);
u24cpy(&wwhere[7], (uint24_t *)&pal[((tile & PIXEL0) >> SHIFT0)]);
} else {
u24cpy(&wwhere[0], (uint24_t *)&pal[((tile & PIXEL0) >> SHIFT0)]);
u24cpy(&wwhere[1], (uint24_t *)&pal[((tile & PIXEL1) >> SHIFT1)]);
u24cpy(&wwhere[2], (uint24_t *)&pal[((tile & PIXEL2) >> SHIFT2)]);
u24cpy(&wwhere[3], (uint24_t *)&pal[((tile & PIXEL3) >> SHIFT3)]);
u24cpy(&wwhere[4], (uint24_t *)&pal[((tile & PIXEL4) >> SHIFT4)]);
u24cpy(&wwhere[5], (uint24_t *)&pal[((tile & PIXEL5) >> SHIFT5)]);
u24cpy(&wwhere[6], (uint24_t *)&pal[((tile & PIXEL6) >> SHIFT6)]);
u24cpy(&wwhere[7], (uint24_t *)&pal[((tile & PIXEL7) >> SHIFT7)]);
}
// Restore the original color
*pal = temp;
}
inline void md_vdp::draw_tile3(int which, int line, unsigned char *where)
{
unsigned tile, *pal;
uint24_t *wwhere = (uint24_t *)where;
pal = highpal + (which >> 9 & 0x30); // Determine which 16-color palette
if(which & 0x1000) // y flipped
line ^= 7; // take from the bottom, instead of the top
if(reg[12] & 2) // interlace
tile = *(unsigned*)(vram + ((which&0x7ff) << 6) + (line << 3));
else
tile = *(unsigned*)(vram + ((which&0x7ff) << 5) + (line << 2));
// If it's empty, why waste the time?
if(!tile) return;
// If the tile doesn't have any transparent pixels, draw it solidly.
if (!has_zero_nibbles(tile)) {
if (which & 0x800) {
// x flipped
u24cpy(&wwhere[0], (uint24_t *)&pal[((tile & PIXEL7) >> SHIFT7)]);
u24cpy(&wwhere[1], (uint24_t *)&pal[((tile & PIXEL6) >> SHIFT6)]);
u24cpy(&wwhere[2], (uint24_t *)&pal[((tile & PIXEL5) >> SHIFT5)]);
u24cpy(&wwhere[3], (uint24_t *)&pal[((tile & PIXEL4) >> SHIFT4)]);
u24cpy(&wwhere[4], (uint24_t *)&pal[((tile & PIXEL3) >> SHIFT3)]);
u24cpy(&wwhere[5], (uint24_t *)&pal[((tile & PIXEL2) >> SHIFT2)]);
u24cpy(&wwhere[6], (uint24_t *)&pal[((tile & PIXEL1) >> SHIFT1)]);
u24cpy(&wwhere[7], (uint24_t *)&pal[((tile & PIXEL0) >> SHIFT0)]);
}
else {
u24cpy(&wwhere[0], (uint24_t *)&pal[((tile & PIXEL0) >> SHIFT0)]);
u24cpy(&wwhere[1], (uint24_t *)&pal[((tile & PIXEL1) >> SHIFT1)]);
u24cpy(&wwhere[2], (uint24_t *)&pal[((tile & PIXEL2) >> SHIFT2)]);
u24cpy(&wwhere[3], (uint24_t *)&pal[((tile & PIXEL3) >> SHIFT3)]);
u24cpy(&wwhere[4], (uint24_t *)&pal[((tile & PIXEL4) >> SHIFT4)]);
u24cpy(&wwhere[5], (uint24_t *)&pal[((tile & PIXEL5) >> SHIFT5)]);
u24cpy(&wwhere[6], (uint24_t *)&pal[((tile & PIXEL6) >> SHIFT6)]);
u24cpy(&wwhere[7], (uint24_t *)&pal[((tile & PIXEL7) >> SHIFT7)]);
}
return;
}
// Blit the tile!
if(which & 0x800) // x flipped
{
if (tile & PIXEL7)
u24cpy(&wwhere[0],
(uint24_t *)&pal[((tile & PIXEL7) >> SHIFT7)]);
if(tile & PIXEL6)
u24cpy(&wwhere[1],
(uint24_t *)&pal[((tile & PIXEL6) >> SHIFT6)]);
if(tile & PIXEL5)
u24cpy(&wwhere[2],
(uint24_t *)&pal[((tile & PIXEL5) >> SHIFT5)]);
if(tile & PIXEL4)
u24cpy(&wwhere[3],
(uint24_t *)&pal[((tile & PIXEL4) >> SHIFT4)]);
if(tile & PIXEL3)
u24cpy(&wwhere[4],
(uint24_t *)&pal[((tile & PIXEL3) >> SHIFT3)]);
if(tile & PIXEL2)
u24cpy(&wwhere[5],
(uint24_t *)&pal[((tile & PIXEL2) >> SHIFT2)]);
if(tile & PIXEL1)
u24cpy(&wwhere[6],
(uint24_t *)&pal[((tile & PIXEL1) >> SHIFT1)]);
if(tile & PIXEL0)
u24cpy(&wwhere[7],
(uint24_t *)&pal[((tile & PIXEL0) >> SHIFT0)]);
} else {
if(tile & PIXEL0)
u24cpy(&wwhere[0],
(uint24_t *)&pal[((tile & PIXEL0) >> SHIFT0)]);
if(tile & PIXEL1)
u24cpy(&wwhere[1],
(uint24_t *)&pal[((tile & PIXEL1) >> SHIFT1)]);
if(tile & PIXEL2)
u24cpy(&wwhere[2],
(uint24_t *)&pal[((tile & PIXEL2) >> SHIFT2)]);
if(tile & PIXEL3)
u24cpy(&wwhere[3],
(uint24_t *)&pal[((tile & PIXEL3) >> SHIFT3)]);
if(tile & PIXEL4)
u24cpy(&wwhere[4],
(uint24_t *)&pal[((tile & PIXEL4) >> SHIFT4)]);
if(tile & PIXEL5)
u24cpy(&wwhere[5],
(uint24_t *)&pal[((tile & PIXEL5) >> SHIFT5)]);
if(tile & PIXEL6)
u24cpy(&wwhere[6],
(uint24_t *)&pal[((tile & PIXEL6) >> SHIFT6)]);
if(tile & PIXEL7)
u24cpy(&wwhere[7],
(uint24_t *)&pal[((tile & PIXEL7) >> SHIFT7)]);
}
}
// Blit tile solidly, for 4 byte-per-pixel
inline void md_vdp::draw_tile4_solid(int which, int line, unsigned char *where)
{
unsigned tile, temp, *pal;
unsigned *wwhere = (unsigned*)where;
pal = highpal + (which >> 9 & 0x30); // Determine which 16-color palette
temp = *pal; *pal = highpal[reg[7]&0x3f]; // Get background color
if(which & 0x1000) // y flipped
line ^= 7; // take from the bottom, instead of the top
if(reg[12] & 2) // interlace
tile = *(unsigned*)(vram + ((which&0x7ff) << 6) + (line << 3));
else
tile = *(unsigned*)(vram + ((which&0x7ff) << 5) + (line << 2));
// Blit the tile!
if(which & 0x800) // x flipped
{
*(wwhere ) = pal[((tile & PIXEL7)>>SHIFT7)];
*(wwhere+1) = pal[((tile & PIXEL6)>>SHIFT6)];
*(wwhere+2) = pal[((tile & PIXEL5)>>SHIFT5)];
*(wwhere+3) = pal[((tile & PIXEL4)>>SHIFT4)];
*(wwhere+4) = pal[((tile & PIXEL3)>>SHIFT3)];
*(wwhere+5) = pal[((tile & PIXEL2)>>SHIFT2)];
*(wwhere+6) = pal[((tile & PIXEL1)>>SHIFT1)];
*(wwhere+7) = pal[((tile & PIXEL0)>>SHIFT0)];
} else {
*(wwhere ) = pal[((tile & PIXEL0)>>SHIFT0)];
*(wwhere+1) = pal[((tile & PIXEL1)>>SHIFT1)];
*(wwhere+2) = pal[((tile & PIXEL2)>>SHIFT2)];
*(wwhere+3) = pal[((tile & PIXEL3)>>SHIFT3)];
*(wwhere+4) = pal[((tile & PIXEL4)>>SHIFT4)];
*(wwhere+5) = pal[((tile & PIXEL5)>>SHIFT5)];
*(wwhere+6) = pal[((tile & PIXEL6)>>SHIFT6)];
*(wwhere+7) = pal[((tile & PIXEL7)>>SHIFT7)];
}
// Restore the original color
*pal = temp;
}
// Blit tile, leaving color zero transparent, for 4 byte per pixel
inline void md_vdp::draw_tile4(int which, int line, unsigned char *where)
{
unsigned tile, *pal;
unsigned *wwhere = (unsigned*)where;
pal = highpal + (which >> 9 & 0x30); // Determine which 16-color palette
if(which & 0x1000) // y flipped
line ^= 7; // take from the bottom, instead of the top
if(reg[12] & 2) // interlace
tile = *(unsigned*)(vram + ((which&0x7ff) << 6) + (line << 3));
else
tile = *(unsigned*)(vram + ((which&0x7ff) << 5) + (line << 2));
// If the tile is all 0's, why waste the time?
if(!tile) return;
// If the tile doesn't have any transparent pixels, draw it solidly.
if (!has_zero_nibbles(tile)) {
if (which & 0x800) {
// x flipped
*(wwhere ) = pal[((tile & PIXEL7)>>SHIFT7)];
*(wwhere+1) = pal[((tile & PIXEL6)>>SHIFT6)];
*(wwhere+2) = pal[((tile & PIXEL5)>>SHIFT5)];
*(wwhere+3) = pal[((tile & PIXEL4)>>SHIFT4)];
*(wwhere+4) = pal[((tile & PIXEL3)>>SHIFT3)];
*(wwhere+5) = pal[((tile & PIXEL2)>>SHIFT2)];
*(wwhere+6) = pal[((tile & PIXEL1)>>SHIFT1)];
*(wwhere+7) = pal[((tile & PIXEL0)>>SHIFT0)];
}
else {
*(wwhere ) = pal[((tile & PIXEL0)>>SHIFT0)];
*(wwhere+1) = pal[((tile & PIXEL1)>>SHIFT1)];
*(wwhere+2) = pal[((tile & PIXEL2)>>SHIFT2)];
*(wwhere+3) = pal[((tile & PIXEL3)>>SHIFT3)];
*(wwhere+4) = pal[((tile & PIXEL4)>>SHIFT4)];
*(wwhere+5) = pal[((tile & PIXEL5)>>SHIFT5)];
*(wwhere+6) = pal[((tile & PIXEL6)>>SHIFT6)];
*(wwhere+7) = pal[((tile & PIXEL7)>>SHIFT7)];
}
return;
}
// Blit the tile!
if(which & 0x800) // x flipped
{
if(tile & PIXEL7) *(wwhere ) = pal[((tile & PIXEL7)>>SHIFT7)];
if(tile & PIXEL6) *(wwhere+1) = pal[((tile & PIXEL6)>>SHIFT6)];
if(tile & PIXEL5) *(wwhere+2) = pal[((tile & PIXEL5)>>SHIFT5)];
if(tile & PIXEL4) *(wwhere+3) = pal[((tile & PIXEL4)>>SHIFT4)];
if(tile & PIXEL3) *(wwhere+4) = pal[((tile & PIXEL3)>>SHIFT3)];
if(tile & PIXEL2) *(wwhere+5) = pal[((tile & PIXEL2)>>SHIFT2)];
if(tile & PIXEL1) *(wwhere+6) = pal[((tile & PIXEL1)>>SHIFT1)];
if(tile & PIXEL0) *(wwhere+7) = pal[((tile & PIXEL0)>>SHIFT0)];
} else {
if(tile & PIXEL0) *(wwhere ) = pal[((tile & PIXEL0)>>SHIFT0)];
if(tile & PIXEL1) *(wwhere+1) = pal[((tile & PIXEL1)>>SHIFT1)];
if(tile & PIXEL2) *(wwhere+2) = pal[((tile & PIXEL2)>>SHIFT2)];
if(tile & PIXEL3) *(wwhere+3) = pal[((tile & PIXEL3)>>SHIFT3)];
if(tile & PIXEL4) *(wwhere+4) = pal[((tile & PIXEL4)>>SHIFT4)];
if(tile & PIXEL5) *(wwhere+5) = pal[((tile & PIXEL5)>>SHIFT5)];
if(tile & PIXEL6) *(wwhere+6) = pal[((tile & PIXEL6)>>SHIFT6)];
if(tile & PIXEL7) *(wwhere+7) = pal[((tile & PIXEL7)>>SHIFT7)];
}
}
#endif // WITH_X86_TILES
// Draw the window (front or back)
void md_vdp::draw_window(int line, int front)
{
int size;
int x, y, w, start;
int pl, add;
int total_window;
unsigned char *where;
int which;
// Set everything up
y = line >> 3;
total_window = (y < (reg[18]&0x1f)) ^ (reg[18] >> 7);
// Wide or narrow
size = (reg[12] & 1)? 64 : 32;
pl = (reg[3] << 10) + ((y&0x3f)*size*2);
// Wide(320) or narrow(256)?
if(reg[12] & 1)
{
w = 40;
start = -8;
} else {
w = 32;
start = 24;
}
add = -2;
where = dest + (start * (int)Bpp);
for (x = -1; (x < w); ++x) {
if (!total_window) {
if (reg[17] & 0x80) {
if (x < ((reg[17] & 0x1f) << 1))
goto skip;
}
else {
if (x >= ((reg[17] & 0x1f) << 1))
goto skip;
}
}
which = get_word(((unsigned char *)vram) +
(pl + (add & ((size - 1) << 1))));
if ((which >> 15) == front)
draw_tile(which, (line & 7), where);
skip:
add += 2;
where += Bpp_times8;
}
}
inline void md_vdp::get_sprite_info(struct sprite_info& info, int index)
{
uint_fast16_t prop;
info.sprite = (sprite_base + (index << 3));
// Get the sprite's location
info.y = get_word(info.sprite);
info.x = (get_word(info.sprite + 6) & 0x1ff);
// Interlace?
// XXX
// "& 1" below is a workaround for a GCC (g++) <= 4.2.1 bug seen
// in OpenBSD.
// info.inter is a bit-field member of size 1 that normally cannot
// store anything other than 0 or 1, but which does in practice,
// causing info.tile to point to a bad address and crashing.
info.inter = ((reg[12] >> 1) & 1);
// Properties
prop = get_word(info.sprite + 4);
info.prio = (prop >> 15);
info.xflip = (prop >> 11);
info.yflip = (prop >> 12);
info.tile = (uint32_t *)(vram + ((prop & 0x07ff) << (5 + info.inter)));
if (info.inter)
info.y = ((info.y & 0x3fe) >> 1);
else
info.y &= 0x1ff;
info.x -= 0x80;
info.y -= 0x80;
// Narrow mode?
if (!(reg[12] & 1))
info.x += 32;
info.tw = (((info.sprite[2] >> 2) & 0x03) + 1);
info.th = ((info.sprite[2] & 0x03) + 1);
info.w = (info.tw << 3);
info.h = (info.th << 3);
}
void md_vdp::sprite_masking_overflow(int line)
{
int masking_sprite_index;
bool masking_effective;
int frame_limit;
int line_limit;
int dots;
int i;
/*
* Search for the highest priority sprite with x = 0. Call this sprite
* s0. Any sprite with a lower priority than s0 (therefore higher
* index in the array) is not drawn on the scanlines that s0 occupies
* on the y-axis. This is called sprite masking and is used by games
* like Streets of Rage and Lotus Turbo Challenge.
*
* Thanks for Charles MacDonald for explaining this to me (vext01).
*
* This loop also limits the number of sprites per line, which is 20
* in H40 and 16 in H32 _or_ 320 pixels wide in H40 and 256 pixels
* wide in H32, with a possibility for the last sprite to be only
* partially drawn.
*/
masking_sprite_index = -1;
// If sprites on the previous line overflowed, sprite masking becomes
// effective by default for the current line (it normally isn't).
masking_effective = (sprite_overflow_line == (line - 1));
// Set sprites and dots limits for the current line.
if (reg[12] & 1) {
frame_limit = 80;
line_limit = 20;
dots = 320;
}
else {
frame_limit = 64;
line_limit = 16;
dots = 256;
}
for (i = 0; i < sprite_count; i++) {
int x, y, w, h;
int idx;
uint8_t *sprite;
// First, make sure the frame limit hasn't been reached.
idx = sprite_order[i];
if (idx >= frame_limit) {
if (masking_sprite_index == -1)
masking_sprite_index = (i - 1);
break;
}
// Get current sprite coordinates and dimensions.
sprite = (sprite_base + (idx << 3));
x = get_word(sprite + 6) & 0x1ff;
y = get_word(sprite);
if (reg[12] & 2)
y = ((y & 0x3fe) >> 1);
else
y &= 0x1ff;
h = (((sprite[2] & 0x03) << 3) + 8);
w = (((sprite[2] << 1) & 0x18) + 8);
// If this sprite isn't found on the current line, skip it.
if (!(((line + 0x80) >= y) && ((line + 0x80) < (y + h))))
continue;
// Substract sprite from the dots limit and decrease the
// sprites limit.
dots -= w;
--line_limit;
// If this sprite is not a masking sprite (x != 0), sprite
// masking becomes effective. The next sprite with (x == 0)
// will be a masking sprite.
if (x != 0)
masking_effective = true;
// If a dot overflow occured, update sprite_overflow_line with
// the current line. This update must be done only once for a
// given line.
if (dots <= 0) {
sprite_overflow_line = line;
// If no masking sprite index has been set so far, do
// it now. Otherwise reset dots, because this sprite
// must not be truncated.
if (masking_sprite_index == -1)
masking_sprite_index = i;
else
dots = 0;
// Don't process any more sprites, exit from the loop.
break;
}
// Check whether sprites limit has been reached.
if (line_limit == 0) {
// If no masking sprite index has been set so far, do
// it now.
if (masking_sprite_index == -1)
masking_sprite_index = i;
// Trigger sprite overflow bit (d6).
belongs.coo5 |= 0x40;
// Don't process any more sprites, exit from the loop.
break;
}
// If sprite masking is effective and the current sprite is a
// masking sprite (x == 0), if we haven't already found one
// before, use this one, then continue to process the sprites
// list as we still need to know whether a dot overflow
// occured.
if ((masking_effective) &&
(x == 0) &&
(masking_sprite_index == -1))
masking_sprite_index = i;
}
// If no masking sprite index was found, display them all.
if (masking_sprite_index == -1)
masking_sprite_index = (sprite_count - 1);
masking_sprite_index_cache = masking_sprite_index;
dots_cache = dots;
}
inline void md_vdp::sprite_mask_add(uint8_t* dest, int pitch,
struct sprite_info& info, int value)
{
uint32_t *tile = info.tile;
int len = (info.tw * info.h);
int lines = (8 << info.inter);
int line = 0;
int wrap = 0;
int unit = 1;
dest += info.x;
dest += (pitch * info.y);
if (info.yflip) {
dest += (pitch * (info.h - 1));
pitch = -pitch;
}
if (info.xflip) {
dest += (info.w - 1);
unit = -unit;
}
while (len) {
uint_fast32_t dots = be2h32(*tile);
unsigned int tmp;
for (tmp = 0; (tmp != 8); ++tmp) {
assert(dest >= (uint8_t *)sprite_mask);
assert(dest < ((uint8_t *)sprite_mask +
sizeof(sprite_mask)));
/*
* If a non-transparent sprite dot has already been
* drawn here, trigger the collision bit (d5).
* FIXME: doing this here is hackish and doesn't take
* sprites with the high priority bit into account.
*/
if (*dest != 0xff)
belongs.coo5 |= 0x20;
#ifdef WORDS_BIGENDIAN
if (dots & 0x0000000f)
*dest = value;
dots >>= 4;
#else
if (dots & 0xf0000000)
*dest = value;
dots <<= 4;
#endif
dest += unit;
}
++tile;
++line;
if (line == lines) {
/* Next tile. */
line = 0;
++wrap;
if (wrap == info.th) {
/* Next tiles column. */
dest -= (pitch * (info.h - 1));
wrap = 0;
}
else {
/* Next tiles row. */
dest += (pitch - (8 * unit));
}
}
else {
/* Next line of dots. */
dest -= (8 * unit);
dest += pitch;
}
--len;
}
}
void md_vdp::sprite_mask_generate()
{
int i;
memset(sprite_mask, 0xff, sizeof(sprite_mask));
for (i = (sprite_count - 1); (i >= 0); --i) {
sprite_info info;
get_sprite_info(info, sprite_order[i]);
// We only care about sprites with the low priority bit unset.
if (info.prio)
continue;
// Don't bother with hidden sprites.
if ((info.x >= 320) || ((info.x + info.w) < 0))
continue;
if ((info.y >= 256) || ((info.y + info.h) < 0))
continue;
info.x += 0x80;
info.y += 0x80;
// Draw overlap mask for this sprite in a 512x512 virtual area.
sprite_mask_add((uint8_t *)sprite_mask, sizeof(sprite_mask[0]),
info, i);
}
}
void md_vdp::draw_sprites(int line, bool front)
{
unsigned int which;
int tx, ty, x, y, xend, ysize, yoff, i, masking_sprite_index;
int dots;
unsigned char *where;
#ifdef WITH_DEBUG_VDP
static int ant[2];
static unsigned long ant_last[2];
unsigned long ant_cur;
if ((dgen_vdp_sprites_boxing) && (line == 0)) {
ant_cur = pd_usecs();
if ((ant_cur - ant_last[front]) > 100000) {
ant_last[front] = ant_cur;
ant[front] ^= 1;
}
}
#endif
masking_sprite_index = masking_sprite_index_cache;
dots = dots_cache;
// If dots_cache is less than zero, draw the first sprite partially.
if (dots > 0)
dots = 0;
// Sprites have to be in reverse order :P
for (i = masking_sprite_index; i >= 0; --i)
{
sprite_info info;
get_sprite_info(info, sprite_order[i]);
// Only do it if it's on the right priority.
if (info.prio == front)
{
which = get_word(info.sprite + 4);
// Get the sprite's location
y = info.y;
x = info.x;
yoff = (line - y);
xend = ((info.w - 8) + x);
// Partial draw if negative.
xend += dots;
ysize = ((info.h - 8) >> 3);
// Render if this sprite's on this line
if(xend > -8 && x < 320 && yoff >= 0 && yoff <= (ysize<<3)+7)
{
ty = yoff & 7;
// y flipped?
if(which & 0x1000)
which += ysize - (yoff >> 3);
else
which += (yoff >> 3);
++ysize;
// Unconditionally draw this sprite. It's supposed to always
// appear on top of other sprites.
if (!front) {
// x flipped?
if (which & 0x800) {
where = dest + (xend * (int)Bpp);
for(tx = xend; tx >= x; tx -= 8)
{
if(tx > -8 && tx < 320)
draw_tile(which, ty, where);
which += ysize;
where -= Bpp_times8;
}
}
else {
where = dest + (x * (int)Bpp);
for(tx = x; tx <= xend; tx += 8)
{
if(tx > -8 && tx < 320)
draw_tile(which, ty, where);
which += ysize;
where += Bpp_times8;
}
}
}
// Draw sprite with the high priority bit set only where it's
// not covered by a higher priority sprite (lower index in the
// list) but with this bit unset. Those have already been drawn
// during the previous pass.
else {
union {
uint32_t t4[8];
uint24_t t3[8];
uint16_t t2[8];
uint8_t t1[8];
} tile;
// x flipped?
if (which & 0x800) {
where = dest + (xend * (int)Bpp);
for (tx = xend; (tx >= x); tx -= 8) {
if ((tx > -8) && (tx < 320)) {
int xx;
int xo;
memcpy(tile.t1, where, Bpp_times8);
draw_tile(which, ty, tile.t1);
for (xx = tx, xo = 0; (xo != 8); ++xo, ++xx)
if (sprite_mask[(line + 0x80)][(xx + 0x80)] >= i)
memcpy(&dest[(xx * (int)Bpp)],
&tile.t1[(xo * (int)Bpp)],
(int)Bpp);
}
which += ysize;
where -= Bpp_times8;
}
}
else {
where = dest + (x * (int)Bpp);
for (tx = x; (tx <= xend); tx += 8) {
if ((tx > -8) && (tx < 320)) {
int xx;
int xo;
memcpy(tile.t1, where, Bpp_times8);
draw_tile(which, ty, tile.t1);
for (xx = tx, xo = 0; (xo != 8); ++xo, ++xx)
if (sprite_mask[(line + 0x80)][(xx + 0x80)] >= i)
memcpy(&dest[(xx * (int)Bpp)],
&tile.t1[(xo * (int)Bpp)],
(int)Bpp);
}
which += ysize;
where += Bpp_times8;
}
}
}
#ifdef WITH_DEBUG_VDP
if (dgen_vdp_sprites_boxing) {
uint32_t color[2] = {
(uint32_t)dgen_vdp_sprites_boxing_bg,
(uint32_t)dgen_vdp_sprites_boxing_fg
};
int ph;
int fx;
if ((ph = 0, (y == line)) ||
(ph = 1, ((y + info.h - 1) == line)))
for (fx = (ant[front] ^ ph); (fx < info.w); fx += 2)
draw_pixel(this->bmap, (info.x + fx),
line, color[info.prio]);
else
draw_pixel(this->bmap,
(((line & 1) == ant[front]) ?
(info.x + info.w - 1) : info.x),
line, color[info.prio]);
}
#endif
}
}
dots = 0;
}
}
// The body for the next few functions is in an extraneous header file.
// Phil, I hope I left enough in this file for GLOBAL to hack it right. ;)
// Thanks to John Stiles for this trick :)
void md_vdp::draw_plane_back0(int line)
{
#define FRONT 0
#define PLANE 0
#include "ras-drawplane.h"
#undef PLANE
#undef FRONT
}
void md_vdp::draw_plane_back1(int line)
{
#define FRONT 0
#define PLANE 1
#include "ras-drawplane.h"
#undef PLANE
#undef FRONT
}
void md_vdp::draw_plane_front0(int line)
{
#define FRONT 1
#define PLANE 0
#include "ras-drawplane.h"
#undef PLANE
#undef FRONT
}
void md_vdp::draw_plane_front1(int line)
{
#define FRONT 1
#define PLANE 1
#include "ras-drawplane.h"
#undef PLANE
#undef FRONT
}
// Allow frame components to be hidden when WITH_DEBUG_VDP is defined.
#ifdef WITH_DEBUG_VDP
#define vdp_hide_if(a, b) ((a) ? (void)0 : (void)(b))
#else
#define vdp_hide_if(a, b) (void)(b)
#endif
// The main interface function, to generate a scanline
void md_vdp::draw_scanline(struct bmap *bits, int line)
{
unsigned *ptr, i;
// Set the destination in the bmap
bmap = bits;
dest = bits->data + (bits->pitch * (line + 8) + 16);
// If bytes per pixel hasn't yet been set, do it
if ((Bpp == 0) || (Bpp != BITS_TO_BYTES(bits->bpp)))
{
if(bits->bpp <= 8) Bpp = 1;
else if(bits->bpp <= 16) Bpp = 2;
else if(bits->bpp <= 24) Bpp = 3;
else Bpp = 4;
Bpp_times8 = Bpp << 3; // used for tile blitting
#ifdef WITH_X86_TILES
asm_tiles_init(vram, reg, highpal); // pass these values to the asm tiles
#endif
}
// If the palette's been changed, update it
if(dirt[0x34] & 2)
{
ptr = highpal;
// What color depth are we?
switch(bits->bpp)
{
case 24:
#ifdef WORDS_BIGENDIAN
for (i = 0; (i < 128); i += 2)
*ptr++ = (((cram[(i + 1)] & 0x0e) << 28) |
((cram[(i + 1)] & 0xe0) << 16) |
((cram[i] & 0x0e) << 12));
break;
#else
for (i = 0; (i < 128); i += 2)
*ptr++ = (((cram[(i + 1)] & 0x0e) << 4) |
((cram[(i + 1)] & 0xe0) << 16) |
((cram[i] & 0x0e) << 12));
break;
#endif
case 32:
for(i = 0; i < 128; i += 2)
*ptr++ = ((cram[i+1]&0x0e) << 20) |
((cram[i+1]&0xe0) << 8 ) |
((cram[i] &0x0e) << 4 );
break;
case 16:
for(i = 0; i < 128; i += 2)
*ptr++ = ((cram[i+1]&0x0e) << 12) |
((cram[i+1]&0xe0) << 3 ) |
((cram[i] &0x0e) << 1 );
break;
case 15:
for(i = 0; i < 128; i += 2)
*ptr++ = ((cram[i+1]&0x0e) << 11) |
((cram[i+1]&0xe0) << 2 ) |
((cram[i] &0x0e) << 1 );
break;
case 8:
default:
// Let the hardware palette sort it out :P
for(i = 0; i < 64; ++i) *ptr++ = i;
}
// Clean up the dirt
dirt[0x34] &= ~2;
pal_dirty = 1;
}
// Render the screen if it's turned on
if(reg[1] & 0x40)
{
// Recalculate the sprite order, if it's dirty
if((dirt[0x30] & 0x20) || (dirt[0x34] & 1))
{
unsigned next = 0;
// Max number of sprites per frame: 80 in H40, 64 in H32.
int max = ((reg[12] & 1) ? 80 : 64);
// Find the sprite base in VRAM
sprite_base = vram + (reg[5]<<9);
// Order the sprites
sprite_count = sprite_order[0] = 0;
do {
next = sprite_base[(next << 3) + 3];
sprite_order[++sprite_count] = next;
} while (next && sprite_count < max);
// Clean up the dirt
dirt[0x30] &= ~0x20; dirt[0x34] &= ~1;
// Generate overlap mask for sprites with high priority bit
sprite_mask_generate();
}
// Calculate sprite masking and overflow.
sprite_masking_overflow(line);
// Draw, from the bottom up
// Low priority
vdp_hide_if(dgen_vdp_hide_plane_b, draw_plane_back1(line));
vdp_hide_if(dgen_vdp_hide_plane_a, draw_plane_back0(line));
vdp_hide_if(dgen_vdp_hide_plane_w, draw_window(line, 0));
vdp_hide_if(dgen_vdp_hide_sprites, draw_sprites(line, 0));
// High priority
vdp_hide_if(dgen_vdp_hide_plane_b, draw_plane_front1(line));
vdp_hide_if(dgen_vdp_hide_plane_a, draw_plane_front0(line));
vdp_hide_if(dgen_vdp_hide_plane_w, draw_window(line, 1));
vdp_hide_if(dgen_vdp_hide_sprites, draw_sprites(line, 1));
} else {
// The display is off, paint it black
// Do it a dword at a time
unsigned *destl = (unsigned*)dest;
for(i = 0; i < (80 * Bpp); ++i) destl[i] = 0;
}
// If we're in narrow (256) mode, cut off the messy edges
if(!(reg[12] & 1))
{
unsigned *destl = (unsigned*)dest;
for(i = 0; i < Bpp_times8; ++i)
destl[i] = destl[i + (72 * Bpp)] = 0;
}
}
void md_vdp::draw_pixel(struct bmap *bits, int x, int y, uint32_t rgb)
{
uint8_t *out;
if ((x < 0) || (x >= bits->w) || (y < 0) || (y >= bits->h))
return;
out = ((bits->data + (bits->pitch * (y + 8) + 16)) +
(x * BITS_TO_BYTES(bits->bpp)));
switch (bits->bpp) {
uint16_t tmp;
case 32:
memcpy(out, &rgb, sizeof(rgb));
break;
case 24:
u24cpy((uint24_t *)out,
(const uint24_t *)((uint8_t *)&rgb + 1));
break;
case 16:
tmp = (((rgb >> 5) & 0xf800) |
((rgb >> 3) & 0x07e0) |
(rgb & 0x1f));
memcpy(out, &tmp, sizeof(tmp));
break;
case 15:
tmp = (((rgb >> 6) & 0x7c00) |
((rgb >> 3) & 0x03e0) |
(rgb & 0x1f));
memcpy(out, &tmp, sizeof(tmp));
break;
}
}