ras.cpp
来自「DGen源码最后版本」· C++ 代码 · 共 784 行 · 第 1/2 页
CPP
784 行
// 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 "md.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 IS_BIG_ENDIAN
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 IS_BIG_ENDIAN
# 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 // IS_BIG_ENDIAN
# 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 // IS_BIG_ENDIAN
#ifdef ASM_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 // ASM_TILES
// 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;
// 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;
// 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;
unsigned char *pal;
pal = ((unsigned char*)highpal) + (which >> 7 & 0xc0); // Determine 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 (this is UGLY! Do you know of a better way? :P)
if(which & 0x800)
{
*(where ) = pal[((tile & 0x0f000000)>>22)+1];
*(where+1 ) = pal[((tile & 0x0f000000)>>22)+2];
*(where+2 ) = pal[((tile & 0x0f000000)>>22) ];
*(where+3 ) = pal[((tile & 0xf0000000)>>26)+1];
*(where+4 ) = pal[((tile & 0xf0000000)>>26)+2];
*(where+5 ) = pal[((tile & 0xf0000000)>>26) ];
*(where+6 ) = pal[((tile & 0x000f0000)>>14)+1];
*(where+7 ) = pal[((tile & 0x000f0000)>>14)+2];
*(where+8 ) = pal[((tile & 0x000f0000)>>14) ];
*(where+9 ) = pal[((tile & 0x00f00000)>>18)+1];
*(where+10) = pal[((tile & 0x00f00000)>>18)+2];
*(where+11) = pal[((tile & 0x00f00000)>>18) ];
*(where+12) = pal[((tile & 0x00000f00)>> 6)+1];
*(where+13) = pal[((tile & 0x00000f00)>> 6)+2];
*(where+14) = pal[((tile & 0x00000f00)>> 6) ];
*(where+15) = pal[((tile & 0x0000f000)>>10)+1];
*(where+16) = pal[((tile & 0x0000f000)>>10)+2];
*(where+17) = pal[((tile & 0x0000f000)>>10) ];
*(where+18) = pal[((tile & 0x0000000f)<< 2)+1];
*(where+19) = pal[((tile & 0x0000000f)<< 2)+2];
*(where+20) = pal[((tile & 0x0000000f)<< 2) ];
*(where+21) = pal[((tile & 0x000000f0)>> 2)+1];
*(where+22) = pal[((tile & 0x000000f0)>> 2)+2];
*(where+23) = pal[((tile & 0x000000f0)>> 2) ];
} else {
*(where ) = pal[((tile & 0x000000f0)>> 2)+1];
*(where+ 1) = pal[((tile & 0x000000f0)>> 2)+2];
*(where+ 2) = pal[((tile & 0x000000f0)>> 2) ];
*(where+ 3) = pal[((tile & 0x0000000f)<< 2)+1];
*(where+ 4) = pal[((tile & 0x0000000f)<< 2)+2];
*(where+ 5) = pal[((tile & 0x0000000f)<< 2) ];
*(where+ 6) = pal[((tile & 0x0000f000)>>10)+1];
*(where+ 7) = pal[((tile & 0x0000f000)>>10)+2];
*(where+ 8) = pal[((tile & 0x0000f000)>>10) ];
*(where+ 9) = pal[((tile & 0x00000f00)>> 6)+1];
*(where+10) = pal[((tile & 0x00000f00)>> 6)+2];
*(where+11) = pal[((tile & 0x00000f00)>> 6) ];
*(where+12) = pal[((tile & 0x00f00000)>>18)+1];
*(where+13) = pal[((tile & 0x00f00000)>>18)+2];
*(where+14) = pal[((tile & 0x00f00000)>>18) ];
*(where+15) = pal[((tile & 0x000f0000)>>14)+1];
*(where+16) = pal[((tile & 0x000f0000)>>14)+2];
*(where+17) = pal[((tile & 0x000f0000)>>14) ];
*(where+18) = pal[((tile & 0xf0000000)>>26)+1];
*(where+19) = pal[((tile & 0xf0000000)>>26)+2];
*(where+20) = pal[((tile & 0xf0000000)>>26) ];
*(where+21) = pal[((tile & 0x0f000000)>>22)+1];
*(where+22) = pal[((tile & 0x0f000000)>>22)+2];
*(where+23) = pal[((tile & 0x0f000000)>>22) ];
}
}
inline void md_vdp::draw_tile3(int which, int line, unsigned char *where)
{
unsigned tile;
unsigned char *pal;
pal = ((unsigned char*)highpal) + (which >> 7 & 0xc0); // Determine 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;
// Blit the tile (this is UGLY! Do you know of a better way? :P)
if(which & 0x800)
{
// The numbers are a little wierd, because of little endian. *gag*
// <SARCASM>Thanks Intel!</SARCASM>
if(tile & 0x0f000000) { *(where ) = pal[((tile & 0x0f000000)>>22)+1];
*(where+1 ) = pal[((tile & 0x0f000000)>>22)+2];
*(where+2 ) = pal[((tile & 0x0f000000)>>22) ]; }
if(tile & 0xf0000000) { *(where+3 ) = pal[((tile & 0xf0000000)>>26)+1];
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?