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 + -
显示快捷键?