graph.cpp
来自「DGen源码最后版本」· C++ 代码 · 共 441 行
CPP
441 行
// DGen v1.13+
#include <stdio.h>
#include "md.h"
static unsigned int highpal[64]={0};
int medley_marker=0;
static int know_blank=-1;
#ifdef ASM_TILES
#include "gra.h"
// PR | P1 | P0 | VF | HF | XXXXXXXXXX
// PR = Priority bit. If bit is set tile is shown in front of sprites.
// P1 - P0 = Sets palette of tile. (0 - 3)
// VF - Vertically flips tile.
// HF - Horizontally flips tile.
// The last ten bits are the tile number (0 - 2047=0x7ff)
// Assembler version of draw_tile
static int draw_tile(struct bmap *bm,struct dgen_sinfo *si,int ox,int oy,unsigned tile,
int ymin,int ymax)
{
int ret=0;
int tile_off,pal_off;
int fx,fy;
unsigned char *tilep;
int i,blank;
if (tile==know_blank) { ret=0; goto end; }
if ((si->vdp_reg[12]&6)==6) // interlace mode
tile_off=(tile&0x3ff)<<6;
else tile_off=(tile&0x7ff)<<5;
tilep=si->vram+tile_off;
// Check if the tile is blank
blank=1;
{
unsigned int *lw; int lwds;
lwds=8; if ((si->vdp_reg[12]&6)==6) lwds<<=1;
lw=(unsigned int *)tilep;
for (i=0;i<lwds;i++) { if (*lw++) { blank=0; break; } }
}
if (blank) {know_blank=tile; ret=0; goto end;}
pal_off=(tile&0x6000)>>9;
fy=(tile&0x1000)?1:0;
fx=(tile&0x0800)?1:0;
// Dave: I believe these checks are only used for clipping sprites
// but I am not sure.
if (ox<-8) {ret=1; goto end;}
if (ox>=320) {ret=1; goto end;}
if (oy<ymin-8) {ret=1; goto end;}
if (oy>=ymax) {ret=1; goto end;}
// shift by eight for messy border
ox+=8; oy+=8;
{
int fn_num=0;
unsigned char *dest;
dest=bm->data+(oy*bm->pitch)+ox*((bm->bpp+7)>>3);
if (fx) fn_num|=1; if (fy) fn_num|=2;
if (bm->bpp<=8) ;
else if (bm->bpp<=16) fn_num|=4;
else if (bm->bpp<=24) fn_num|=8;
else fn_num|=12;
if ((si->vdp_reg[12]&6)==6) fn_num|=16; // interlace mode
// tf_tab contains all the variants
(tf_tab[fn_num])(dest,bm->pitch,tilep,highpal+pal_off);
}
end:
return ret;
}
#endif
// Register #11
// Bit 2 : Vertical Scroll Control 1: An offset per 16 pixels
// 0: A Screen offset
// Bit 1-0 : Horizontal Scroll Control
// 00 : A Screen offset
// 01 : Not Used
// 10 : An offset per cellule
// 11 : An offser per line
// Register #13
// Address of base for Horizontal Scrolls/$400 (B800)
static int draw_plane(struct bmap *bm,struct dgen_sinfo *si,int ab,int high,
int ymin,int ymax)
{
int psx,psy; // playfield size
int x=0,y=0,maxx=40,fixx=0;
int hscroll_base=0,hscrolloff;
static int playinfo[4]={0x20,0x40,0x40,0x80};
psx=si->vdp_reg[0x10]; psy=psx>>4; psx&=3; psy&=3;
// 00=32 cell 01=64 cell, 11=128 cell
psx=playinfo[psx];
psy=playinfo[psy];
hscroll_base=(si->vdp_reg[13]<<10)+ab*2;
// for (y=-1;y<28;y++)
for (y=(ymin/8)-1;y<(ymax/8);y++)
{
int pl;
unsigned short xoff=0,yoff=0;
int add=0;
int window_all=0;
if (ab<2)
{
yoff= si->vsram[(ab*2+0)&0x7f]; yoff<<=8; yoff|=si->vsram[(ab*2+1)&0x7f];
if ((si->vdp_reg[12]&6)==6)
yoff/=2; // interlace mode
if ((si->vdp_reg[0xb]&3)<=1) hscrolloff=0; else hscrolloff=y*4*8;
if (hscrolloff<0) hscrolloff=0;
xoff= si->vram[(hscroll_base+hscrolloff+0)&0xffff]; xoff<<=8;
xoff|=si->vram[(hscroll_base+hscrolloff+1)&0xffff];
}
if (ab==0) pl=(si->vdp_reg[0x02]<<10);
else if (ab==1) pl=(si->vdp_reg[0x04]<<13);
else
{
// Window
pl=(si->vdp_reg[0x03]<<10);
window_all=0;
if (si->vdp_reg[0x12]&0x80)
{ if (y>=(si->vdp_reg[0x12]&0x1f)) window_all=1; }
else
{ if (y< (si->vdp_reg[0x12]&0x1f)) window_all=1; }
psy=64;
if ((si->vdp_reg[0xc]&1)==0) // 32 horiz
psx=32; else psx=64;
}
yoff=-yoff;
pl+=((-((yoff)>>3)+y)&(psy-1))*psx*2;
add=(-(xoff>>3)-1)<<1;
if ((si->vdp_reg[0xc]&1)==0) { maxx=32; fixx=4; } else { maxx=40; fixx=0; }
for (x=-1;x<maxx;x++)
{
unsigned int tile;
int ta;
if ((ab>=2)&&(!window_all))
{
// Window
if (si->vdp_reg[0x11]&0x80)
{ if (x< ((si->vdp_reg[0x11]&0x1f)<<1) ) goto xskip; }
else
{ if (x>= ((si->vdp_reg[0x11]&0x1f)<<1) ) goto xskip; }
}
ta=(pl+(add&((psx-1)<<1)));
tile=(si->vram[(ta+0)&0xffff]<<8)+si->vram[(ta+1)&0xffff];
if ( ((tile&0x8000)==0x8000) == high )
draw_tile(bm,si,((x+fixx)<<3)+(xoff&7),(y<<3)+(yoff&7),tile
,ymin,ymax);
xskip:
add+=2;
}
}
return 0;
}
static int draw_sprites(struct bmap *bm,struct dgen_sinfo *si,int high,
int ymin,int ymax)
{
static unsigned sprite_order[0x100]={0};
int spr=0,sprite_count=0,i=0;
spr=(si->vdp_reg[0x05]<<9);
{
int i;
// Calculate the sprite order (needs to be rendered backwards)
sprite_count=0;
sprite_order[0]=0;
for (i=1;i<=0x100;i++)
{
unsigned char next;
next=si->vram[(spr+sprite_order[i-1]*8+3)&0xffff];
if ((next==0)||(i>=0x100)) { sprite_count=i; break; }
sprite_order[i]=next;
}
}
for (i=sprite_count-1;i>=0;i--)
{
//byte 0-1 : Y-axis (0 to 511)+$80
//byte 2 : SIze (bit 0-1 : height 0-3+1 , Bit 2-3 : width 0-3+1)
//byte 3 : Link Data ( next sprite in the list or 0 for end of list)
//byte 4-5 : First number tile sprite (Explained below)
//bute 6-7 : X-axis (0 to 511)+$80
int sprno,x,y,xs,ys,tile,tx,ty;
int fx,fy;
sprno=sprite_order[i];
y=(si->vram[(spr+sprno*8+0)&0xffff]<<8)+si->vram[(spr+sprno*8+1)&0xffff];
x=(si->vram[(spr+sprno*8+6)&0xffff]<<8)+si->vram[(spr+sprno*8+7)&0xffff];
x&=0x1ff;
if ((si->vdp_reg[12]&6)==6)
{
// interlace mode
y&=0x3ff;
y>>=1; // interlace mode
}
else y&=0x1ff;
y-=0x80;
x-=0x80;
if ((si->vdp_reg[0xc]&1)==0) x+=4*8;
ys=si->vram[(spr+sprno*8+2)&0xffff];
xs=ys>>2; xs&=3; ys&=3; xs++; ys++;
tile=si->vram[(spr+sprno*8+4)&0xffff]; tile<<=8;
tile+=si->vram[(spr+sprno*8+5)&0xffff];
fy=(tile&0x1000)?1:0;
fx=(tile&0x0800)?1:0;
for (tx=0;tx<xs;tx++)
{
for (ty=0;ty<ys;ty++)
{
int dx=x+(fx?xs-tx-1:tx)*8, dy=y+(fy?ys-ty-1:ty)*8;
if ( ((tile&0x8000)==0x8000) == high )
draw_tile(bm,si,dx,dy,tile,ymin,ymax);
tile++;
}
}
}
return 0;
}
// This allows you to get the palette, mess around with it
// (e.g. contrast/brightness)
// and then pass it back
int get_md_palette(unsigned char pal[256],unsigned char *cram)
{
int c;
if (pal==NULL) return 1;
for (c=0;c<64;c++)
{
int r,g,b;
b=(cram[c*2+0]&0x0e)<<4;
g=(cram[c*2+1]&0xe0);
r=(cram[c*2+1]&0x0e)<<4;
if (medley_marker) {int tmp; tmp=g; g=b; b=tmp;}
pal[c*4+0]=r;
pal[c*4+1]=g;
pal[c*4+2]=b;
}
return 0;
}
// Must pass a struct bm with size 320+16 by 240+16
// PASSPAL is now INPUT not output - use get_md_palette first
// (Don't worry: If you pass NULL this function will
// call get_md_palette for you)
int draw_md_graphics
(struct bmap *bm,unsigned char passpal[256],struct dgen_sinfo *si,
int ymin,int ymax,int layer_sel)
{
unsigned char ifneedpal[256],*pal;
know_blank=-1;
if (ymax<ymin) ymax=ymin;
if (ymin<0) ymin=0;
else if (ymin>224) ymin=224;
if (ymax<0) ymax=0;
else if (ymax>224) ymax=224;
if (passpal!=0) pal=passpal;
else
{
get_md_palette(ifneedpal,si->cram);
pal=ifneedpal;
}
// Get colors (decoded in above function)
{
int c;
for (c=0;c<64;c++)
{
int r,g,b;
r=pal[c*4+0];
g=pal[c*4+1];
b=pal[c*4+2];
if (bm->bpp<=8) highpal[c]=c;
else if (bm->bpp<=15) highpal[c]=((r>>3)<<10) + ((g>>3)<<5) + (b>>3);
else if (bm->bpp<=16) highpal[c]=((r>>3)<<11) + ((g>>2)<<5) + (b>>3);
else if (bm->bpp<=32) highpal[c]=(r<<16) + (g<<8) + b;
}
}
#ifdef ASM_TILES
{
unsigned char *start; int bytes; unsigned int colr;
start=bm->data+(8+ymin)*bm->pitch;
bytes=(ymax-ymin)*bm->pitch;
if (bm->bpp<=8) colr=si->vdp_reg[7]&63;
else colr=highpal[si->vdp_reg[7]&63];
// Note - this fast version assumes you can write across the entire bitmap:
// it definitely won't work on a screen bitmap!
if (bm->bpp<=8)
clear_to_col_8 (start,bytes/1,colr);
else if (bm->bpp<=16)
clear_to_col_16(start,bytes/2,colr);
else if (bm->bpp<=24)
clear_to_col_24(start,bytes/3,colr);
else if (bm->bpp<=32)
clear_to_col_32(start,bytes/4,colr);
}
#else
{
int x,y;
if (bm->bpp<=8)
{
for (y=8+ymin;y<8+ymax;y++)
for (x=8;x<320+8;x++)
*((unsigned char *)(bm->data+y*bm->pitch+x*1))=si->vdp_reg[7]&63;
}
else if (bm->bpp<=16)
{
for (y=8+ymin;y<8+ymax;y++)
for (x=8;x<320+8;x++)
*((unsigned short *)(bm->data+y*bm->pitch+x*2))=highpal[si->vdp_reg[7]&63];
}
else if (bm->bpp<=24)
{
for (y=8+ymin;y<8+ymax;y++)
for (x=8;x<320+8;x++)
{
int clr,cr,cg,cb; unsigned char *pix;
clr=highpal[si->vdp_reg[7]&63];
cr=clr>>16; cg=clr>>8; cb=clr; cr&=0xff; cg&=0xff; cb&=0xff;
pix=(bm->data+y*bm->pitch+x*3);
pix[0]=cb; pix[1]=cg; pix[2]=cr;
}
}
else if (bm->bpp<=32)
{
for (y=8+ymin;y<8+ymax;y++)
for (x=8;x<320+8;x++)
*((unsigned int *)(bm->data+y*bm->pitch+x*4))=highpal[si->vdp_reg[7]&63];
}
}
#endif
// draw a and b low/high and sprites in the right order
if (layer_sel&1) draw_plane (bm,si,1,0,ymin,ymax); // B Low
if (layer_sel&2) draw_plane (bm,si,0,0,ymin,ymax); // A Low
if (layer_sel&4) draw_plane (bm,si,2,0,ymin,ymax); // Win Low
if (layer_sel&8) draw_sprites(bm,si,0 ,ymin,ymax); // Spr Low
if (layer_sel&16) draw_plane (bm,si,1,1,ymin,ymax); // B High
if (layer_sel&32) draw_plane (bm,si,0,1,ymin,ymax); // A High
if (layer_sel&64) draw_plane (bm,si,2,1,ymin,ymax); // Win High
if (layer_sel&128) draw_sprites(bm,si,1 ,ymin,ymax); // Spr High
// herzog order - currently a mystery
/*
if (layer_sel&1) draw_plane (bm,si,1,0,ymin,ymax); // B Low
if (layer_sel&16) draw_plane (bm,si,1,1,ymin,ymax); // B High
if (layer_sel&8) draw_sprites(bm,si,0 ,ymin,ymax); // Spr Low
if (layer_sel&2) draw_plane (bm,si,0,0,ymin,ymax); // A Low
if (layer_sel&32) draw_plane (bm,si,0,1,ymin,ymax); // A High
if (layer_sel&128) draw_sprites(bm,si,1 ,ymin,ymax); // Spr High
if (layer_sel&4) draw_plane (bm,si,2,0,ymin,ymax); // Win Low
if (layer_sel&64) draw_plane (bm,si,2,1,ymin,ymax); // Win High
*/
#ifdef ASM_TILES
if ((si->vdp_reg[0xc]&1)==0)
{
int y,colr;
// Remove the messy edges of the thinner 32 column mode
unsigned char *lne=bm->data+bm->pitch*8;
if (bm->bpp<=8) colr=si->vdp_reg[7]&63;
else colr=highpal[si->vdp_reg[7]&63];
for (y=0;y<224;y++)
{
unsigned char *pstr;
int pixst,pixcnt;
pixst=8; pixcnt=8+4*8-8;
pstr=lne+((bm->bpp+7)>>3)*pixst;
if (bm->bpp<=8) clear_to_col_8(pstr,pixcnt,colr);
else if (bm->bpp<=16) clear_to_col_16(pstr,pixcnt,colr);
else if (bm->bpp<=24) clear_to_col_24(pstr,pixcnt,colr);
else if (bm->bpp<=32) clear_to_col_32(pstr,pixcnt,colr);
pixst=8+36*8; pixcnt=8+320 - (8+36*8);
pstr=lne+((bm->bpp+7)>>3)*pixst;
if (bm->bpp<=8) clear_to_col_8(pstr,pixcnt,colr);
else if (bm->bpp<=16) clear_to_col_16(pstr,pixcnt,colr);
else if (bm->bpp<=24) clear_to_col_24(pstr,pixcnt,colr);
else if (bm->bpp<=32) clear_to_col_32(pstr,pixcnt,colr);
lne+=bm->pitch;
}
}
#endif
if (0)
{
int x,y;
// show tiles
for (y=0;y<32;y++)
for (x=0;x<16;x++)
draw_tile(bm,si,x*8,y*8,(0xc000/32)+y*16+x,ymin,ymax);
}
return 0;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?