⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cpugraphics.pas

📁 一个不出名的GBA模拟器
💻 PAS
📖 第 1 页 / 共 3 页
字号:
//////////////////////////////////////////////////////////////////////
//                                                                  //
// cpuGraphics.pas: CPU graphics subsystem                          //
//   Implements the HV timer system and all of the rendering code   //
//                                                                  //
// The contents of this file are subject to the Bottled Light       //
// Public License Version 1.0 (the "License"); you may not use this //
// file except in compliance with the License. You may obtain a     //
// copy of the License at http://www.bottledlight.com/BLPL/         //
//                                                                  //
// Software distributed under the License is distributed on an      //
// "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or   //
// implied. See the License for the specific language governing     //
// rights and limitations under the License.                        //
//                                                                  //
// The Original Code is the Mappy VM Core, released April 1st, 2003 //
// The Initial Developer of the Original Code is Bottled Light,     //
// Inc. Portions created by Bottled Light, Inc. are Copyright       //
// (C) 2001 - 2003 Bottled Light, Inc. All Rights Reserved.         //
//                                                                  //
// Author(s):                                                       //
//   Michael Noland (joat), michael@bottledlight.com                //
//                                                                  //
// Changelog:                                                       //
//   1.0: First public release (April 1st, 2003)                    //
//                                                                  //
// Notes:                                                           //
//   The code here comes as close to emulating macros in Object     //
//   Pascal as you're ever likely to see, and it isn't pretty.      //
//   The offending code is there to implement the myriad rendering  //
//   combinations for sprites and backgrounds. In all, there are 40 //
//   combinations for sprites, and 20 for backgrounds, a staggering //
//   amount of code duplication.  Instead, there are 13 gfx*.pas    //
//   files that implement different background or sprite types, and //
//   two additional files (gfxDrawPixel.pas & gfxDrawPixelInc.pas)  //
//   that implement drawing an individual pixel.  These are bound   //
//   together using a bunch of DEFINES and included into this file. //
//                                                                  //
//   Its nasty, its ugly, its unholy, but its *still* better than   //
//   the alternative.                                               //
//                                                                  //
//   If I were to write this again, I'd probably play around with   //
//   runtime code generation like some of the newer software 3d     //
//   engines use, where they create a specific shader on the fly    //
//   from component blocks.  I could do that every time the mode    //
//   is switched, or just generate all of them at startup.          //
//                                                                  //
//   While we're on the subject of possibly deranged design         //
//   choices, why not look at the sprite system.  Its designed to   //
//   render sprites in the correct order, supporting all of the     //
//   beautifully flawed scenarios that might arise, when the sprite //
//   render quota runs out or multiple blendable sprites overlap.   //
//   The current code fufils its design criteria, but is pretty     //
//   inefficient in the process, with lots of array walking, and a  //
//   nasty amount of data translation from OAM to my own            //
//   TSpriteEntry format, all per scanline.                         //
//                                                                  //
//   One option that might be fruitful to look into is caching a    //
//   set of TSpriteEntry's every time OAM is written to, which is   //
//   something I've tried to avoid, but it may pay off considerably //
//   in terms of speed.  I haven't actually profiled the graphics   //
//   code in a long time tho, it may not even be worth pursuing.    //
//                                                                  //
//////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////
unit cpuGraphics; ////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////
interface ////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

uses
  SysUtils, nexus, AddressSpace, cpuSound;

//////////////////////////////////////////////////////////////////////

// HBlank() is called every time the HBlankEvent timer elapses
procedure HBlank;

//////////////////////////////////////////////////////////////////////
// Exported functions ////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

// vmGetLaterID() returns a layer ID for the pixel rendered on the
// current scanline at offset x.
function vmGetLayerID(x: integer): byte;

// vmDrawScanline() does just as it suggests.  Width can only be 240
// or 256 (other values will probably work, but its only provided for
// the VRAM observer to render a 256 swath of the screen)
function vmDrawScanline(y, width: integer): Puint16;

// vmRenderSprite() renders the y-th scanline of the i-th sprite to
// the buffer passed in as line.  It is only used for the sprite
// observer currently.
procedure vmRenderSprite(i: integer; y: integer; line: Puint16);

//////////////////////////////////////////////////////////////////////

exports
  vmGetLayerID,
  vmDrawScanline,
  vmRenderSprite;

//////////////////////////////////////////////////////////////////////
implementation ///////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

uses
  Math, cpuMemory, cpuMisc, cpuPeripherals;

//////////////////////////////////////////////////////////////////////

type
  TSpriteEntry = record
    a, b, c, index: uint16;
    priority, width, height, run: byte;
    x, y: integer;
    rotscale, doublesize: boolean;
    next, typ: byte;
  end;
  PSpriteEntry = ^TSpriteEntry;

  TSpriteRenderFunc = procedure (y: integer; entry: PSpriteEntry; line: Puint16; wins, ids: Puint8; mask: byte);
  TTextRenderFunc = procedure (y: integer; line: Puint16; wins, ids: Puint8; mask: byte; CR, scrollX, scrollY: uint16);
  TRSRenderFunc = procedure (y: integer; line: Puint16; wins, ids: Puint8; mask: byte; CR: uint16; params: PRotScaleSet);

//////////////////////////////////////////////////////////////////////
// Globals shared between the rendering functions ////////////////////
//////////////////////////////////////////////////////////////////////

var
  // The temporary sprite tree (pretty inefficient)
  spriteTable: array[0..127] of TSpriteEntry;

  // the last sprite entry to draw (for the scanline limit)
  lastEntry: integer;

  // The chain heads for the sprite renderer (god, what was I
  // thinking when I wrote this crackheaded code)
  spritePoints: array[0..4] of integer;

  // Stuff used for a single rendered scanline
  screenData: array[0..255] of uint16;
  winData: array[0..255] of byte;
  idData: array[0..255] of byte;

  // 240 (256 used for vram viewer)
  gfxScreenWidth: integer;

//////////////////////////////////////////////////////////////////////

{$HINTS OFF}

//////////////////////////////////////////////////////////////////////

{$DEFINE SPRITE}

//////////////////////////////////////////////////////////////////////

procedure RenderRS256Color1DSprite0(y: integer; entry: PSpriteEntry; line: Puint16; wins, ids: Puint8; mask: byte);
{$INCLUDE gfxDrawRS1D256Sprite.pas}
{$DEFINE BLEND}{$DEFINE ABLEND}
procedure RenderRS256Color1DSprite1(y: integer; entry: PSpriteEntry; line: Puint16; wins, ids: Puint8; mask: byte);
{$INCLUDE gfxDrawRS1D256Sprite.pas}
{$UNDEF ABLEND}{$DEFINE FADEUP}
procedure RenderRS256Color1DSprite2(y: integer; entry: PSpriteEntry; line: Puint16; wins, ids: Puint8; mask: byte);
{$INCLUDE gfxDrawRS1D256Sprite.pas}
{$UNDEF FADEUP}{$DEFINE FADEDOWN}
procedure RenderRS256Color1DSprite3(y: integer; entry: PSpriteEntry; line: Puint16; wins, ids: Puint8; mask: byte);
{$INCLUDE gfxDrawRS1D256Sprite.pas}
{$UNDEF FADEDOWN}{$UNDEF BLEND}
{$DEFINE OBJWIN}
procedure RenderRS256Color1DSprite4(y: integer; entry: PSpriteEntry; line: Puint16; wins, ids: Puint8; mask: byte);
{$INCLUDE gfxDrawRS1D256Sprite.pas}
{$UNDEF OBJWIN}

//////////////////////////////////////////////////////////////////////

procedure RenderRS16Color1DSprite0(y: integer; entry: PSpriteEntry; line: Puint16; wins, ids: Puint8; mask: byte);
{$INCLUDE gfxDrawRS1D16Sprite.pas}
{$DEFINE BLEND}{$DEFINE ABLEND}
procedure RenderRS16Color1DSprite1(y: integer; entry: PSpriteEntry; line: Puint16; wins, ids: Puint8; mask: byte);
{$INCLUDE gfxDrawRS1D16Sprite.pas}
{$UNDEF ABLEND}{$DEFINE FADEUP}
procedure RenderRS16Color1DSprite2(y: integer; entry: PSpriteEntry; line: Puint16; wins, ids: Puint8; mask: byte);
{$INCLUDE gfxDrawRS1D16Sprite.pas}
{$UNDEF FADEUP}{$DEFINE FADEDOWN}
procedure RenderRS16Color1DSprite3(y: integer; entry: PSpriteEntry; line: Puint16; wins, ids: Puint8; mask: byte);
{$INCLUDE gfxDrawRS1D16Sprite.pas}
{$UNDEF FADEDOWN}{$UNDEF BLEND}
{$DEFINE OBJWIN}
procedure RenderRS16Color1DSprite4(y: integer; entry: PSpriteEntry; line: Puint16; wins, ids: Puint8; mask: byte);
{$INCLUDE gfxDrawRS1D16Sprite.pas}
{$UNDEF OBJWIN}

//////////////////////////////////////////////////////////////////////

procedure RenderRS256Color2DSprite0(y: integer; entry: PSpriteEntry; line: Puint16; wins, ids: Puint8; mask: byte);
{$INCLUDE gfxDrawRS2D256Sprite.pas}
{$DEFINE BLEND}{$DEFINE ABLEND}
procedure RenderRS256Color2DSprite1(y: integer; entry: PSpriteEntry; line: Puint16; wins, ids: Puint8; mask: byte);
{$INCLUDE gfxDrawRS2D256Sprite.pas}
{$UNDEF ABLEND}{$DEFINE FADEUP}
procedure RenderRS256Color2DSprite2(y: integer; entry: PSpriteEntry; line: Puint16; wins, ids: Puint8; mask: byte);
{$INCLUDE gfxDrawRS2D256Sprite.pas}
{$UNDEF FADEUP}{$DEFINE FADEDOWN}
procedure RenderRS256Color2DSprite3(y: integer; entry: PSpriteEntry; line: Puint16; wins, ids: Puint8; mask: byte);
{$INCLUDE gfxDrawRS2D256Sprite.pas}
{$UNDEF FADEDOWN}{$UNDEF BLEND}
{$DEFINE OBJWIN}
procedure RenderRS256Color2DSprite4(y: integer; entry: PSpriteEntry; line: Puint16; wins, ids: Puint8; mask: byte);
{$INCLUDE gfxDrawRS2D256Sprite.pas}
{$UNDEF OBJWIN}

//////////////////////////////////////////////////////////////////////

procedure RenderRS16Color2DSprite0(y: integer; entry: PSpriteEntry; line: Puint16; wins, ids: Puint8; mask: byte);
{$INCLUDE gfxDrawRS2D16Sprite.pas}
{$DEFINE BLEND}{$DEFINE ABLEND}
procedure RenderRS16Color2DSprite1(y: integer; entry: PSpriteEntry; line: Puint16; wins, ids: Puint8; mask: byte);
{$INCLUDE gfxDrawRS2D16Sprite.pas}
{$UNDEF ABLEND}{$DEFINE FADEUP}
procedure RenderRS16Color2DSprite2(y: integer; entry: PSpriteEntry; line: Puint16; wins, ids: Puint8; mask: byte);
{$INCLUDE gfxDrawRS2D16Sprite.pas}
{$UNDEF FADEUP}{$DEFINE FADEDOWN}
procedure RenderRS16Color2DSprite3(y: integer; entry: PSpriteEntry; line: Puint16; wins, ids: Puint8; mask: byte);
{$INCLUDE gfxDrawRS2D16Sprite.pas}
{$UNDEF FADEDOWN}{$UNDEF BLEND}
{$DEFINE OBJWIN}
procedure RenderRS16Color2DSprite4(y: integer; entry: PSpriteEntry; line: Puint16; wins, ids: Puint8; mask: byte);
{$INCLUDE gfxDrawRS2D16Sprite.pas}
{$UNDEF OBJWIN}

//////////////////////////////////////////////////////////////////////

procedure Render16Color1DSprite0(y: integer; entry: PSpriteEntry; line: Puint16; wins, ids: Puint8; mask: byte);
{$INCLUDE gfxDraw1D16Sprite.pas}
{$DEFINE BLEND}{$DEFINE ABLEND}
procedure Render16Color1DSprite1(y: integer; entry: PSpriteEntry; line: Puint16; wins, ids: Puint8; mask: byte);
{$INCLUDE gfxDraw1D16Sprite.pas}
{$UNDEF ABLEND}{$DEFINE FADEUP}
procedure Render16Color1DSprite2(y: integer; entry: PSpriteEntry; line: Puint16; wins, ids: Puint8; mask: byte);
{$INCLUDE gfxDraw1D16Sprite.pas}
{$UNDEF FADEUP}{$DEFINE FADEDOWN}
procedure Render16Color1DSprite3(y: integer; entry: PSpriteEntry; line: Puint16; wins, ids: Puint8; mask: byte);
{$INCLUDE gfxDraw1D16Sprite.pas}
{$UNDEF FADEDOWN}{$UNDEF BLEND}
{$DEFINE OBJWIN}
procedure Render16Color1DSprite4(y: integer; entry: PSpriteEntry; line: Puint16; wins, ids: Puint8; mask: byte);
{$INCLUDE gfxDraw1D16Sprite.pas}
{$UNDEF OBJWIN}

//////////////////////////////////////////////////////////////////////

procedure Render256Color1DSprite0(y: integer; entry: PSpriteEntry; line: Puint16; wins, ids: Puint8; mask: byte);
{$INCLUDE gfxDraw1D256Sprite.pas}
{$DEFINE BLEND}{$DEFINE ABLEND}
procedure Render256Color1DSprite1(y: integer; entry: PSpriteEntry; line: Puint16; wins, ids: Puint8; mask: byte);
{$INCLUDE gfxDraw1D256Sprite.pas}
{$UNDEF ABLEND}{$DEFINE FADEUP}
procedure Render256Color1DSprite2(y: integer; entry: PSpriteEntry; line: Puint16; wins, ids: Puint8; mask: byte);
{$INCLUDE gfxDraw1D256Sprite.pas}
{$UNDEF FADEUP}{$DEFINE FADEDOWN}
procedure Render256Color1DSprite3(y: integer; entry: PSpriteEntry; line: Puint16; wins, ids: Puint8; mask: byte);
{$INCLUDE gfxDraw1D256Sprite.pas}
{$UNDEF FADEDOWN}{$UNDEF BLEND}
{$DEFINE OBJWIN}
procedure Render256Color1DSprite4(y: integer; entry: PSpriteEntry; line: Puint16; wins, ids: Puint8; mask: byte);
{$INCLUDE gfxDraw1D256Sprite.pas}
{$UNDEF OBJWIN}

//////////////////////////////////////////////////////////////////////

procedure Render16Color2DSprite0(y: integer; entry: PSpriteEntry; line: Puint16; wins, ids: Puint8; mask: byte);
{$INCLUDE gfxDraw2D16Sprite.pas}
{$DEFINE BLEND}{$DEFINE ABLEND}
procedure Render16Color2DSprite1(y: integer; entry: PSpriteEntry; line: Puint16; wins, ids: Puint8; mask: byte);
{$INCLUDE gfxDraw2D16Sprite.pas}
{$UNDEF ABLEND}{$DEFINE FADEUP}
procedure Render16Color2DSprite2(y: integer; entry: PSpriteEntry; line: Puint16; wins, ids: Puint8; mask: byte);
{$INCLUDE gfxDraw2D16Sprite.pas}
{$UNDEF FADEUP}{$DEFINE FADEDOWN}
procedure Render16Color2DSprite3(y: integer; entry: PSpriteEntry; line: Puint16; wins, ids: Puint8; mask: byte);
{$INCLUDE gfxDraw2D16Sprite.pas}
{$UNDEF FADEDOWN}{$UNDEF BLEND}
{$DEFINE OBJWIN}
procedure Render16Color2DSprite4(y: integer; entry: PSpriteEntry; line: Puint16; wins, ids: Puint8; mask: byte);
{$INCLUDE gfxDraw2D16Sprite.pas}
{$UNDEF OBJWIN}

//////////////////////////////////////////////////////////////////////

procedure Render256Color2DSprite0(y: integer; entry: PSpriteEntry; line: Puint16; wins, ids: Puint8; mask: byte);
{$INCLUDE gfxDraw2D256Sprite.pas}
{$DEFINE BLEND}{$DEFINE ABLEND}
procedure Render256Color2DSprite1(y: integer; entry: PSpriteEntry; line: Puint16; wins, ids: Puint8; mask: byte);
{$INCLUDE gfxDraw2D256Sprite.pas}
{$UNDEF ABLEND}{$DEFINE FADEUP}
procedure Render256Color2DSprite2(y: integer; entry: PSpriteEntry; line: Puint16; wins, ids: Puint8; mask: byte);
{$INCLUDE gfxDraw2D256Sprite.pas}
{$UNDEF FADEUP}{$DEFINE FADEDOWN}
procedure Render256Color2DSprite3(y: integer; entry: PSpriteEntry; line: Puint16; wins, ids: Puint8; mask: byte);
{$INCLUDE gfxDraw2D256Sprite.pas}
{$UNDEF FADEDOWN}{$UNDEF BLEND}
{$DEFINE OBJWIN}
procedure Render256Color2DSprite4(y: integer; entry: PSpriteEntry; line: Puint16; wins, ids: Puint8; mask: byte);
{$INCLUDE gfxDraw2D256Sprite.pas}
{$UNDEF OBJWIN}

//////////////////////////////////////////////////////////////////////

{$UNDEF SPRITE}

//////////////////////////////////////////////////////////////////////

const
  sprite16_1D: array[0..4] of TSpriteRenderFunc =
    (Render16Color1DSprite0, Render16Color1DSprite1, Render16Color1DSprite2, Render16Color1DSprite3, Render16Color1DSprite4);
  sprite16_2D: array[0..4] of TSpriteRenderFunc =
    (Render16Color2DSprite0, Render16Color2DSprite1, Render16Color2DSprite2, Render16Color2DSprite3, Render16Color2DSprite4);
  sprite256_1D: array[0..4] of TSpriteRenderFunc =
    (Render256Color1DSprite0, Render256Color1DSprite1, Render256Color1DSprite2, Render256Color1DSprite3, Render256Color1DSprite4);
  sprite256_2D: array[0..4] of TSpriteRenderFunc =
    (Render256Color2DSprite0, Render256Color2DSprite1, Render256Color2DSprite2, Render256Color2DSprite3, Render256Color2DSprite4);

//////////////////////////////////////////////////////////////////////

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -