mirror of
https://github.com/RetroDECK/Supermodel.git
synced 2024-11-22 22:05:38 +00:00
1073 lines
25 KiB
C
1073 lines
25 KiB
C
/*
|
|
* Sega Model 3 Emulator
|
|
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License Version 2 as published
|
|
* by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program (license.txt); if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
/*
|
|
* tilegen.c
|
|
*
|
|
* Tilemap generator.
|
|
*
|
|
* Palette Notes:
|
|
* - Each palette entry occupies 32 bits. Only the second 16 bits are
|
|
* actually used.
|
|
* - The format of a 16-bit palette entry is: AGGGGGBBBBBRRRRR
|
|
*
|
|
* Register Notes:
|
|
*
|
|
* 0x20 -- Layer Colors:
|
|
*
|
|
* 31 23 20 0
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* |-|-|-|-|-|-|-|-|D|C|B|A|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
*
|
|
* D = Layer 0xFE000 color control (0 = 8-bit, 1 = 4-bit)
|
|
* C = Layer 0xFC000 color control (0 = 8-bit, 1 = 4-bit)
|
|
* B = Layer 0xFA000 color control (0 = 8-bit, 1 = 4-bit)
|
|
* A = Layer 0xF8000 color control (0 = 8-bit, 1 = 4-bit)
|
|
*/
|
|
|
|
#include "model3.h"
|
|
|
|
/******************************************************************/
|
|
/* Privates */
|
|
/******************************************************************/
|
|
|
|
/*
|
|
* NOTE: It is critical that vram be set to NULL if it has not yet been
|
|
* allocated because tilegen_set_layer_format() will try to use it to
|
|
* recache the palette.
|
|
*/
|
|
|
|
static UINT8 *vram = NULL; // 2D VRAM (passed to tilegen_init())
|
|
static UINT8 reg[0x100]; // tilemap generator registers
|
|
|
|
/*
|
|
* Register Macros
|
|
*/
|
|
|
|
#define REG_LAYER_COLORS 0x20
|
|
|
|
/*
|
|
* Pre-Decoded Palette Data
|
|
*
|
|
* Depending on the renderer color depth, the data is either 32-bit RGBA8 or
|
|
* 16-bit RGB5A1. The actual order of the fields is obtained from the renderer
|
|
* but it is guaranteed that for 16-bit modes, the color components will each
|
|
* be 5 bits and the alpha will be 1 and for the 32-bit modes, all components
|
|
* will be 8 bits.
|
|
*
|
|
* For alpha channel: All bits set means the color is opaque, all bits clear
|
|
* means the color is transparent. No other bit combinations should be used.
|
|
*/
|
|
|
|
static UINT32 *pal;
|
|
|
|
/*
|
|
* Layer Format
|
|
*
|
|
* Information that is passed by the renderer on the format of layers. Bit
|
|
* position 0 is the LSB (none of that backwards IBM junk ;)) RGBA bit
|
|
* positions give the position of the LSB of the field.
|
|
*/
|
|
|
|
static UINT pitch; // layer pitch (in pixels)
|
|
static UINT rpos, gpos, bpos, apos; // R, G, B, A bit positions
|
|
static INT bpp; // 15 or 32 only
|
|
|
|
static int tilemap_is_dirty[4];
|
|
static int tilemap_dirty[4][64*64];
|
|
static int tilemap_depth[4][64*64];
|
|
static int tilemap_redraw[4];
|
|
|
|
/******************************************************************/
|
|
/* Rendering */
|
|
/******************************************************************/
|
|
|
|
/*
|
|
* PUTPIXELx_xx():
|
|
*
|
|
* A handy macro used within the draw_tile_xbit_xx() macros to plot a pixel
|
|
* and advance the buffer pointer.
|
|
*/
|
|
|
|
#define PUTPIXEL8_NP(bp) \
|
|
do \
|
|
{ \
|
|
*buf++ = pal[((pattern >> bp) & 0xFF) | pal_bits]; \
|
|
} while (0)
|
|
|
|
#define PUTPIXEL4_NP(bp) \
|
|
do \
|
|
{ \
|
|
*buf++ = pal[((pattern >> bp) & 0xF) | pal_bits]; \
|
|
} while (0)
|
|
|
|
|
|
#define PUTPIXEL8(bp) \
|
|
do \
|
|
{ \
|
|
*buf++ = ((pattern >> bp) & 0xff) | pal_bits; \
|
|
} while(0)
|
|
|
|
#define PUTPIXEL4(bp) \
|
|
do \
|
|
{ \
|
|
*buf++ = ((pattern >> bp) & 0xf) | pal_bits; \
|
|
} while(0)
|
|
|
|
static void draw_tile_8bit(UINT tile, UINT16 *buf)
|
|
{
|
|
UINT tile_offs; // offset of tile within VRAM
|
|
UINT pal_bits; // color palette bits obtained from tile
|
|
UINT y;
|
|
UINT32 pattern; // 4 pattern pixels fetched at once
|
|
|
|
/*
|
|
* Calculate tile offset; each tile occupies 64 bytes when using 8-bit
|
|
* pixels
|
|
*/
|
|
|
|
//tile_offs = tile & 0x3fff;
|
|
//tile_offs *= 64;
|
|
tile_offs = ((tile & 0x3fff) << 1) | ((tile >> 15) & 1);
|
|
tile_offs *= 32;
|
|
|
|
/*
|
|
* Obtain upper color bits; the lower 8 bits come from the tile pattern
|
|
*/
|
|
|
|
pal_bits = tile & 0x7F00;
|
|
|
|
/*
|
|
* Draw!
|
|
*/
|
|
|
|
for (y = 0; y < 8; y++)
|
|
{
|
|
/*
|
|
* Fetch first 4 pixels and draw them
|
|
*/
|
|
|
|
pattern = *((UINT32 *) &vram[tile_offs]);
|
|
tile_offs += 4;
|
|
PUTPIXEL8(24);
|
|
PUTPIXEL8(16);
|
|
PUTPIXEL8(8);
|
|
PUTPIXEL8(0);
|
|
|
|
/*
|
|
* Next 4
|
|
*/
|
|
|
|
pattern = *((UINT32 *) &vram[tile_offs]);
|
|
tile_offs += 4;
|
|
PUTPIXEL8(24);
|
|
PUTPIXEL8(16);
|
|
PUTPIXEL8(8);
|
|
PUTPIXEL8(0);
|
|
|
|
/*
|
|
* Move to the next line
|
|
*/
|
|
|
|
buf += (pitch - 8); // next line in layer buffer
|
|
}
|
|
}
|
|
|
|
static void draw_tile_4bit(UINT tile, UINT16 *buf)
|
|
{
|
|
UINT tile_offs; // offset of tile within VRAM
|
|
UINT pal_bits; // color palette bits obtained from tile
|
|
UINT y;
|
|
UINT32 pattern; // 8 pattern pixels fetched at once
|
|
|
|
/*
|
|
* Calculate tile offset; each tile occupies 32 bytes when using 4-bit
|
|
* pixels
|
|
*/
|
|
|
|
tile_offs = ((tile & 0x3fff) << 1) | ((tile >> 15) & 1);
|
|
tile_offs *= 32;
|
|
|
|
/*
|
|
* Obtain upper color bits; the lower 4 bits come from the tile pattern
|
|
*/
|
|
|
|
pal_bits = tile & 0x7FF0;
|
|
|
|
/*
|
|
* Draw!
|
|
*/
|
|
|
|
for (y = 0; y < 8; y++)
|
|
{
|
|
pattern = *((UINT32 *) &vram[tile_offs]);
|
|
|
|
/*
|
|
* Draw the 8 pixels we've fetched
|
|
*/
|
|
|
|
PUTPIXEL4(28);
|
|
PUTPIXEL4(24);
|
|
PUTPIXEL4(20);
|
|
PUTPIXEL4(16);
|
|
PUTPIXEL4(12);
|
|
PUTPIXEL4(8);
|
|
PUTPIXEL4(4);
|
|
PUTPIXEL4(0);
|
|
|
|
/*
|
|
* Move to the next line
|
|
*/
|
|
|
|
tile_offs += 4; // next tile pattern line
|
|
buf += (pitch - 8); // next line in layer buffer
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void draw_tile_8bit_np(UINT tile, UINT32 *buf)
|
|
{
|
|
UINT tile_offs; // offset of tile within VRAM
|
|
UINT pal_bits; // color palette bits obtained from tile
|
|
UINT y;
|
|
UINT32 pattern; // 4 pattern pixels fetched at once
|
|
|
|
/*
|
|
* Calculate tile offset; each tile occupies 64 bytes when using 8-bit
|
|
* pixels
|
|
*/
|
|
|
|
//tile_offs = tile & 0x3fff;
|
|
//tile_offs *= 64;
|
|
tile_offs = ((tile & 0x3fff) << 1) | ((tile >> 15) & 1);
|
|
tile_offs *= 32;
|
|
|
|
/*
|
|
* Obtain upper color bits; the lower 8 bits come from the tile pattern
|
|
*/
|
|
|
|
pal_bits = tile & 0x7F00;
|
|
|
|
/*
|
|
* Draw!
|
|
*/
|
|
|
|
for (y = 0; y < 8; y++)
|
|
{
|
|
/*
|
|
* Fetch first 4 pixels and draw them
|
|
*/
|
|
|
|
pattern = *((UINT32 *) &vram[tile_offs]);
|
|
tile_offs += 4;
|
|
PUTPIXEL8_NP(24);
|
|
PUTPIXEL8_NP(16);
|
|
PUTPIXEL8_NP(8);
|
|
PUTPIXEL8_NP(0);
|
|
|
|
/*
|
|
* Next 4
|
|
*/
|
|
|
|
pattern = *((UINT32 *) &vram[tile_offs]);
|
|
tile_offs += 4;
|
|
PUTPIXEL8_NP(24);
|
|
PUTPIXEL8_NP(16);
|
|
PUTPIXEL8_NP(8);
|
|
PUTPIXEL8_NP(0);
|
|
|
|
/*
|
|
* Move to the next line
|
|
*/
|
|
|
|
buf += (pitch - 8); // next line in layer buffer
|
|
}
|
|
}
|
|
|
|
static void draw_tile_4bit_np(UINT tile, UINT32 *buf)
|
|
{
|
|
UINT tile_offs; // offset of tile within VRAM
|
|
UINT pal_bits; // color palette bits obtained from tile
|
|
UINT y;
|
|
UINT32 pattern; // 8 pattern pixels fetched at once
|
|
|
|
/*
|
|
* Calculate tile offset; each tile occupies 32 bytes when using 4-bit
|
|
* pixels
|
|
*/
|
|
|
|
tile_offs = ((tile & 0x3fff) << 1) | ((tile >> 15) & 1);
|
|
tile_offs *= 32;
|
|
|
|
/*
|
|
* Obtain upper color bits; the lower 4 bits come from the tile pattern
|
|
*/
|
|
|
|
pal_bits = tile & 0x7FF0;
|
|
|
|
/*
|
|
* Draw!
|
|
*/
|
|
|
|
for (y = 0; y < 8; y++)
|
|
{
|
|
pattern = *((UINT32 *) &vram[tile_offs]);
|
|
|
|
/*
|
|
* Draw the 8 pixels we've fetched
|
|
*/
|
|
|
|
PUTPIXEL4_NP(28);
|
|
PUTPIXEL4_NP(24);
|
|
PUTPIXEL4_NP(20);
|
|
PUTPIXEL4_NP(16);
|
|
PUTPIXEL4_NP(12);
|
|
PUTPIXEL4_NP(8);
|
|
PUTPIXEL4_NP(4);
|
|
PUTPIXEL4_NP(0);
|
|
|
|
/*
|
|
* Move to the next line
|
|
*/
|
|
|
|
tile_offs += 4; // next tile pattern line
|
|
buf += (pitch - 8); // next line in layer buffer
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
/*
|
|
* draw_layer_8bit_32():
|
|
*
|
|
* Draws an entire layer of 8-bit tiles to a 32-bit layer buffer.
|
|
*/
|
|
|
|
static void draw_layer_8bit(UINT16 *layer, int layer_num)
|
|
{
|
|
int ty, tx;
|
|
int tilenum;
|
|
UINT32 tile;
|
|
UINT32 addr = 0xf8000 + (layer_num * 0x2000);
|
|
|
|
if (tilemap_is_dirty[layer_num] == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
tilemap_is_dirty[layer_num] = 0;
|
|
|
|
tilenum = 0;
|
|
for (ty = 0; ty < 64; ty++)
|
|
{
|
|
for (tx = 0; tx < 64; tx+=2)
|
|
{
|
|
if (tilemap_redraw[layer_num] || tilemap_dirty[layer_num][tilenum+0])
|
|
{
|
|
tilemap_depth[layer_num][tilenum+0] = 0;
|
|
tilemap_dirty[layer_num][tilenum+0] = 0;
|
|
tile = *((UINT32 *) &vram[addr]) >> 16;
|
|
|
|
draw_tile_8bit(tile & 0xffff, layer);
|
|
}
|
|
if (tilemap_redraw[layer_num] || tilemap_dirty[layer_num][tilenum+1])
|
|
{
|
|
tilemap_depth[layer_num][tilenum+1] = 0;
|
|
tilemap_dirty[layer_num][tilenum+1] = 0;
|
|
tile = *((UINT32 *) &vram[addr]) >> 0;
|
|
|
|
draw_tile_8bit(tile & 0xffff, layer+8);
|
|
}
|
|
|
|
addr += 4;
|
|
layer += 16;
|
|
tilenum+=2;
|
|
}
|
|
|
|
//addr += (64 - 62) * 2;
|
|
layer += (7 * pitch) + (pitch - 512); // next tile row
|
|
}
|
|
|
|
tilemap_redraw[layer_num] = 0;
|
|
}
|
|
|
|
/*
|
|
* draw_layer_4bit_32():
|
|
*
|
|
* Draws an entire layer of 4-bit tiles to a 32-bit layer buffer.
|
|
*/
|
|
|
|
static void draw_layer_4bit(UINT16 *layer, int layer_num)
|
|
{
|
|
int ty, tx;
|
|
int tilenum;
|
|
UINT32 tile;
|
|
UINT32 addr = 0xf8000 + (layer_num * 0x2000);
|
|
|
|
if (tilemap_is_dirty[layer_num] == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
tilemap_is_dirty[layer_num] = 0;
|
|
|
|
tilenum = 0;
|
|
for (ty = 0; ty < 64; ty++)
|
|
{
|
|
for (tx = 0; tx < 64; tx+=2)
|
|
{
|
|
if (tilemap_redraw[layer_num] || tilemap_dirty[layer_num][tilenum+0])
|
|
{
|
|
tilemap_depth[layer_num][tilenum+0] = 1;
|
|
tilemap_dirty[layer_num][tilenum+0] = 0;
|
|
tile = *((UINT32 *) &vram[addr]) >> 16;
|
|
|
|
draw_tile_4bit(tile & 0xffff, layer);
|
|
}
|
|
if (tilemap_redraw[layer_num] || tilemap_dirty[layer_num][tilenum+1])
|
|
{
|
|
tilemap_depth[layer_num][tilenum+0] = 1;
|
|
tilemap_dirty[layer_num][tilenum+1] = 0;
|
|
tile = *((UINT32 *) &vram[addr]) >> 0;
|
|
|
|
draw_tile_4bit(tile & 0xffff, layer+8);
|
|
}
|
|
|
|
addr += 4;
|
|
layer += 16;
|
|
tilenum+=2;
|
|
}
|
|
|
|
//addr += (64 - 62) * 2;
|
|
layer += (7 * pitch) + (pitch - 512); // next tile row
|
|
}
|
|
|
|
tilemap_redraw[layer_num] = 0;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
/*
|
|
* draw_layer_8bit_32():
|
|
*
|
|
* Draws an entire layer of 8-bit tiles to a 32-bit layer buffer.
|
|
*/
|
|
|
|
static void draw_layer_8bit_np(UINT32 *layer, int layer_num)
|
|
{
|
|
int ty, tx;
|
|
int tilenum;
|
|
UINT32 tile;
|
|
UINT32 addr = 0xf8000 + (layer_num * 0x2000);
|
|
|
|
if (tilemap_is_dirty[layer_num] == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
tilemap_is_dirty[layer_num] = 0;
|
|
|
|
tilenum = 0;
|
|
for (ty = 0; ty < 64; ty++)
|
|
{
|
|
for (tx = 0; tx < 64; tx+=2)
|
|
{
|
|
if (tilemap_redraw[layer_num] || tilemap_dirty[layer_num][tilenum+0])
|
|
{
|
|
tilemap_depth[layer_num][tilenum+0] = 0;
|
|
tilemap_dirty[layer_num][tilenum+0] = 0;
|
|
tile = *((UINT32 *) &vram[addr]) >> 16;
|
|
|
|
draw_tile_8bit_np(tile & 0xffff, layer);
|
|
}
|
|
if (tilemap_redraw[layer_num] || tilemap_dirty[layer_num][tilenum+1])
|
|
{
|
|
tilemap_depth[layer_num][tilenum+1] = 0;
|
|
tilemap_dirty[layer_num][tilenum+1] = 0;
|
|
tile = *((UINT32 *) &vram[addr]) >> 0;
|
|
|
|
draw_tile_8bit_np(tile & 0xffff, layer+8);
|
|
}
|
|
|
|
addr += 4;
|
|
layer += 16;
|
|
tilenum+=2;
|
|
}
|
|
|
|
//addr += (64 - 62) * 2;
|
|
layer += (7 * pitch) + (pitch - 512); // next tile row
|
|
}
|
|
|
|
tilemap_redraw[layer_num] = 0;
|
|
}
|
|
|
|
/*
|
|
* draw_layer_4bit_32():
|
|
*
|
|
* Draws an entire layer of 4-bit tiles to a 32-bit layer buffer.
|
|
*/
|
|
|
|
static void draw_layer_4bit_np(UINT32 *layer, int layer_num)
|
|
{
|
|
int ty, tx;
|
|
int tilenum;
|
|
UINT32 tile;
|
|
UINT32 addr = 0xf8000 + (layer_num * 0x2000);
|
|
|
|
if (tilemap_is_dirty[layer_num] == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
tilemap_is_dirty[layer_num] = 0;
|
|
|
|
tilenum = 0;
|
|
for (ty = 0; ty < 64; ty++)
|
|
{
|
|
for (tx = 0; tx < 64; tx+=2)
|
|
{
|
|
if (tilemap_redraw[layer_num] || tilemap_dirty[layer_num][tilenum+0])
|
|
{
|
|
tilemap_depth[layer_num][tilenum+0] = 1;
|
|
tilemap_dirty[layer_num][tilenum+0] = 0;
|
|
tile = *((UINT32 *) &vram[addr]) >> 16;
|
|
|
|
draw_tile_4bit_np(tile & 0xffff, layer);
|
|
}
|
|
if (tilemap_redraw[layer_num] || tilemap_dirty[layer_num][tilenum+1])
|
|
{
|
|
tilemap_depth[layer_num][tilenum+0] = 1;
|
|
tilemap_dirty[layer_num][tilenum+1] = 0;
|
|
tile = *((UINT32 *) &vram[addr]) >> 0;
|
|
|
|
draw_tile_4bit_np(tile & 0xffff, layer+8);
|
|
}
|
|
|
|
addr += 4;
|
|
layer += 16;
|
|
tilenum+=2;
|
|
}
|
|
|
|
//addr += (64 - 62) * 2;
|
|
layer += (7 * pitch) + (pitch - 512); // next tile row
|
|
}
|
|
|
|
tilemap_redraw[layer_num] = 0;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
/*
|
|
* void tilegen_update(void);
|
|
*
|
|
* Renders up to 4 layers for the current frame.
|
|
*/
|
|
|
|
void tilegen_update(void)
|
|
{
|
|
UINT8 *layer;
|
|
UINT layer_colors, layer_color_mask;
|
|
FLAGS layer_enable_mask;
|
|
int i, j;
|
|
UINT32 renderer_features;
|
|
|
|
/*
|
|
* Render layers
|
|
*/
|
|
|
|
PROFILE_SECT_ENTRY("tilegen");
|
|
|
|
renderer_features = osd_renderer_get_features();
|
|
|
|
layer_colors = BSWAP32(*(UINT32 *) ®[REG_LAYER_COLORS]);
|
|
layer_color_mask = 0x00100000; // first layer color bit (moves left)
|
|
layer_enable_mask = 1;
|
|
|
|
// layer_colors = 0; // enable this to force 8-bit mode for VF3
|
|
|
|
// update palette if the renderer supports paletting
|
|
if (renderer_features & RENDERER_FEATURE_PALETTE)
|
|
{
|
|
UINT32 *palette;
|
|
int pwidth;
|
|
int ppitch;
|
|
int pheight;
|
|
int p = 0;
|
|
|
|
osd_renderer_get_palette_buffer(&palette, &pwidth, &ppitch);
|
|
|
|
pheight = 0x10000 / pwidth;
|
|
for (j=0; j < 128; j++)
|
|
{
|
|
int pindex = j * ppitch;
|
|
p = j * 256;
|
|
for (i=0; i < 256; i++)
|
|
{
|
|
int a,r,g,b;
|
|
UINT32 rgba;
|
|
UINT16 pix;
|
|
|
|
pix = pal[p];
|
|
|
|
a = (pix & 0x8000) ? 0x00 : 0xff;
|
|
b = (pix >> 10) & 0x1f;
|
|
g = (pix >> 5) & 0x1f;
|
|
r = (pix & 0x1f);
|
|
b = (b << 3) | (b >> 2);
|
|
g = (g << 3) | (g >> 2);
|
|
r = (r << 3) | (r >> 2);
|
|
|
|
rgba = (a << 24) | (r << 16) | (g << 8) | (b << 0);
|
|
palette[pindex + i] = rgba;
|
|
p++;
|
|
|
|
// a very hackish way to counter the effect of using colours as texture coords
|
|
if (i == 239)
|
|
p--;
|
|
}
|
|
}
|
|
|
|
osd_renderer_free_palette_buffer();
|
|
}
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
if ((m3_config.layer_enable & layer_enable_mask))
|
|
{
|
|
osd_renderer_get_layer_buffer(i, &layer, &pitch);
|
|
|
|
if (renderer_features & RENDERER_FEATURE_PALETTE)
|
|
{
|
|
if ((layer_colors & layer_color_mask))
|
|
{
|
|
draw_layer_4bit((UINT16 *) layer, i);
|
|
}
|
|
else
|
|
{
|
|
draw_layer_8bit((UINT16 *) layer, i);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((layer_colors & layer_color_mask))
|
|
{
|
|
draw_layer_4bit_np((UINT16 *) layer, i);
|
|
}
|
|
else
|
|
{
|
|
draw_layer_8bit_np((UINT16 *) layer, i);
|
|
}
|
|
}
|
|
|
|
osd_renderer_free_layer_buffer(i);
|
|
}
|
|
layer_color_mask <<= 1;
|
|
layer_enable_mask <<= 1;
|
|
}
|
|
|
|
PROFILE_SECT_EXIT("tilegen");
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* VRAM Access */
|
|
/******************************************************************/
|
|
|
|
static void mark_tilemap_dirty(int layer)
|
|
{
|
|
tilemap_is_dirty[layer] = 1;
|
|
tilemap_redraw[layer] = 1;
|
|
}
|
|
|
|
/*
|
|
* UINT16 tilegen_vram_read_16(UINT32 addr);
|
|
*
|
|
* Reads a 16-bit word from VRAM.
|
|
*
|
|
* Parameters:
|
|
* addr = Address.
|
|
*
|
|
* Returns:
|
|
* Data read.
|
|
*/
|
|
|
|
UINT16 tilegen_vram_read_16(UINT32 addr)
|
|
{
|
|
return(BSWAP16(*(UINT16 *)&vram[addr & 0x1FFFFF]));
|
|
}
|
|
|
|
/*
|
|
* UINT32 tilegen_vram_read_32(UINT32 addr);
|
|
*
|
|
* Reads a 32-bit word from VRAM.
|
|
*
|
|
* Parameters:
|
|
* addr = Address.
|
|
*
|
|
* Returns:
|
|
* Data read.
|
|
*/
|
|
|
|
UINT32 tilegen_vram_read_32(UINT32 addr)
|
|
{
|
|
return(BSWAP32(*(UINT32 *)&vram[addr & 0x1FFFFF]));
|
|
}
|
|
|
|
/*
|
|
* void tilegen_vram_write_32(UINT32 addr, UINT32 data);
|
|
*
|
|
* Writes a 32-bit word to VRAM. Palette decoding is handled here.
|
|
*
|
|
* Parameters:
|
|
* addr = Address.
|
|
* data = Data.
|
|
*/
|
|
|
|
void tilegen_vram_write_32(UINT32 addr, UINT32 data)
|
|
{
|
|
UINT color;
|
|
|
|
addr &= 0x1FFFFF;
|
|
data = BSWAP32(data); // return to its natural order (as on PPC)
|
|
|
|
if (addr < 0xf8000)
|
|
{
|
|
*(UINT32 *)&vram[addr] = data;
|
|
}
|
|
else if (addr >= 0x0f8000 && addr < 0x100000)
|
|
{
|
|
UINT32 old_data;
|
|
int ad, layer, layer_depth, old_depth;
|
|
|
|
ad = addr - 0xf8000;
|
|
layer = ad / 0x2000;
|
|
|
|
old_data = *(UINT32 *)&vram[addr];
|
|
layer_depth = (BSWAP32(*(UINT32 *) ®[REG_LAYER_COLORS]) >> (20+layer)) & 1;
|
|
old_depth = tilemap_depth[layer][((ad & 0x1fff) / 2)];
|
|
|
|
if (data != old_data || layer_depth != old_depth)
|
|
{
|
|
*(UINT32 *)&vram[addr] = data;
|
|
|
|
//ad = addr - 0xf8000;
|
|
//layer = ad / 0x2000;
|
|
tilemap_dirty[layer][((ad & 0x1fff) / 2) + 0] = 1;
|
|
tilemap_dirty[layer][((ad & 0x1fff) / 2) + 1] = 1;
|
|
tilemap_is_dirty[layer] = 1;
|
|
}
|
|
}
|
|
else if (addr >= 0x100000 && addr < 0x120000) // palette
|
|
{
|
|
UINT32 renderer_features = osd_renderer_get_features();
|
|
|
|
*(UINT32 *)&vram[addr] = data;
|
|
color = (addr - 0x100000) / 4; // color number
|
|
|
|
if (renderer_features & RENDERER_FEATURE_PALETTE)
|
|
{
|
|
pal[color] = data;
|
|
}
|
|
else
|
|
{
|
|
int a = (data & 0x8000) ? 0 : 0xff;
|
|
int r = (data >> 10) & 0x1f;
|
|
int g = (data >> 5) & 0x1f;
|
|
int b = (data >> 0) & 0x1f;
|
|
r = (r << 3) | (r >> 2);
|
|
g = (g << 3) | (g >> 2);
|
|
b = (b << 3) | (b >> 2);
|
|
pal[color] = (a << 24) | (r << 16) | (g << 8) | (b);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void recache_palette(void)
|
|
{
|
|
UINT32 i;
|
|
|
|
for (i = 0x100000; i < 0x11FFFF; i += 4)
|
|
tilegen_vram_write_32(i, BSWAP32(*(UINT32 *) &vram[i]));
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* Tilegen I/O Port Access */
|
|
/******************************************************************/
|
|
|
|
/*
|
|
* UINT32 tilegen_read_32(UINT32 a);
|
|
*
|
|
* Reads a 32-bit word from the tilemap generator register area.
|
|
*
|
|
* Parameters:
|
|
* a = Address.
|
|
*
|
|
* Returns:
|
|
* Data read.
|
|
*/
|
|
|
|
UINT32 tilegen_read_32(UINT32 a)
|
|
{
|
|
// LOG("MODEL3.LOG", "TILEGEN: %08X: read 32 %08X\n", PPC_PC, a);
|
|
//message(0, "tilegen: %08X: read 32 %08X", PPC_PC, a);
|
|
|
|
a &= 0xFF;
|
|
|
|
switch(a)
|
|
{
|
|
|
|
case 0x00: // Status/Control
|
|
// 0x20 (latch) controls layer pairing
|
|
return(0 << 24);
|
|
}
|
|
|
|
return(BSWAP32(*(UINT32 *)®[a]));
|
|
}
|
|
|
|
/*
|
|
* void tilegen_write_32(UINT32 a, UINT32 d);
|
|
*
|
|
* Writes a 32-bit word to the tilemap generator register area.
|
|
*
|
|
* Parameters:
|
|
* a = Address.
|
|
* d = Data.
|
|
*/
|
|
|
|
void tilegen_write_32(UINT32 a, UINT32 d)
|
|
{
|
|
/* data is written as 32-bit, but only higher byte is used */
|
|
|
|
// LOG("MODEL3.LOG", "TILEGEN: %08X: write 32 %08X = %08X\n", PPC_PC, a, d);
|
|
|
|
a &= 0xFF;
|
|
|
|
//if (a != 0x60 && a != 0x64 && a != 0x68 && a != 0x6c &&
|
|
// a != 0x10 && a != 0x0c && a != 0x40 && a != 0x44)
|
|
//printf("tilegen: %08X, %08X\n", a, d);
|
|
|
|
switch(a)
|
|
{
|
|
case 0x00:
|
|
case 0x04:
|
|
case 0x08:
|
|
case 0x0C:
|
|
break;
|
|
case 0x10:
|
|
model3_remove_irq((UINT8) (d >> 24));
|
|
break;
|
|
case 0x14:
|
|
case 0x18:
|
|
case 0x1C:
|
|
break;
|
|
case 0x20:
|
|
{
|
|
UINT32 olddata = *(UINT32 *)®[a];
|
|
UINT32 newdata = BSWAP32(d);
|
|
|
|
if ((olddata & 0x100000) != (newdata & 0x100000))
|
|
mark_tilemap_dirty(0);
|
|
if ((olddata & 0x200000) != (newdata & 0x200000))
|
|
mark_tilemap_dirty(1);
|
|
if ((olddata & 0x400000) != (newdata & 0x400000))
|
|
mark_tilemap_dirty(2);
|
|
if ((olddata & 0x800000) != (newdata & 0x800000))
|
|
mark_tilemap_dirty(3);
|
|
|
|
/**(UINT32 *)®[0x60] &= ~0x80000000;
|
|
*(UINT32 *)®[0x64] &= ~0x80000000;
|
|
*(UINT32 *)®[0x68] &= ~0x80000000;
|
|
*(UINT32 *)®[0x6c] &= ~0x80000000;*/
|
|
break;
|
|
}
|
|
case 0x24:
|
|
case 0x40:
|
|
case 0x44:
|
|
break;
|
|
case 0x60:
|
|
case 0x64:
|
|
case 0x68:
|
|
case 0x6C:
|
|
break;
|
|
}
|
|
|
|
*(UINT32 *)®[a] = BSWAP32(d);
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* Set Up, Shut Down, and State Management */
|
|
/******************************************************************/
|
|
|
|
/*
|
|
* void tilegen_save_state(FILE *fp);
|
|
*
|
|
* Saves the state of the tile generator to a file.
|
|
*
|
|
* Parameters:
|
|
* fp = File to save to.
|
|
*/
|
|
|
|
void tilegen_save_state(FILE *fp)
|
|
{
|
|
fwrite(vram, sizeof(UINT8), 1*1024*1024+2*65536, fp);
|
|
fwrite(reg, sizeof(UINT8), 0x100, fp);
|
|
}
|
|
|
|
/*
|
|
* void tilegen_load_state(FILE *fp);
|
|
*
|
|
* Loads the state of the tile generator from a file.
|
|
*
|
|
* Parameters:
|
|
* fp = File to load from.
|
|
*/
|
|
|
|
void tilegen_load_state(FILE *fp)
|
|
{
|
|
fread(vram, sizeof(UINT8), 1*1024*1024+2*65536, fp);
|
|
fread(reg, sizeof(UINT8), 0x100, fp);
|
|
recache_palette();
|
|
|
|
mark_tilemap_dirty(0);
|
|
mark_tilemap_dirty(1);
|
|
mark_tilemap_dirty(2);
|
|
mark_tilemap_dirty(3);
|
|
}
|
|
|
|
/*
|
|
* void tilegen_shutdown(void);
|
|
*
|
|
* Shuts down the tilemap generator.
|
|
*/
|
|
|
|
void tilegen_shutdown(void)
|
|
{
|
|
vram = NULL;
|
|
SAFE_FREE(pal);
|
|
}
|
|
|
|
/*
|
|
* void tilegen_init(UINT8 *vramptr);
|
|
*
|
|
* Initializes the tilemap generator.
|
|
*
|
|
* Parameters:
|
|
* vramptr = Pointer to 2D VRAM.
|
|
*/
|
|
|
|
void tilegen_init(UINT8 *vramptr)
|
|
{
|
|
vram = vramptr;
|
|
|
|
mark_tilemap_dirty(0);
|
|
mark_tilemap_dirty(1);
|
|
mark_tilemap_dirty(2);
|
|
mark_tilemap_dirty(3);
|
|
|
|
pal = malloc(sizeof(UINT32) * 65536);
|
|
|
|
atexit(tilegen_shutdown);
|
|
}
|
|
|
|
BOOL tilegen_is_layer_enabled(int layer)
|
|
{
|
|
if (layer == 1 && stricmp(m3_config.game_id, "lostwsga") == 0)
|
|
return FALSE;
|
|
|
|
switch (layer)
|
|
{
|
|
case 0:
|
|
return *(UINT32 *)®[0x60] & 0x80000000 ? 1 : 0;
|
|
case 1:
|
|
return *(UINT32 *)®[0x64] & 0x80000000 ? 1 : 0;
|
|
case 2:
|
|
return *(UINT32 *)®[0x68] & 0x80000000 ? 1 : 0;
|
|
case 3:
|
|
return *(UINT32 *)®[0x6c] & 0x80000000 ? 1 : 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
UINT32 tilegen_get_layer_color_offset(int layer)
|
|
{
|
|
switch (layer)
|
|
{
|
|
case 0:
|
|
case 1:
|
|
{
|
|
INT8 r = (*(UINT32 *)®[0x40] >> 16) & 0xff;
|
|
INT8 g = (*(UINT32 *)®[0x40] >> 8) & 0xff;
|
|
INT8 b = (*(UINT32 *)®[0x40] >> 0) & 0xff;
|
|
|
|
r += 127;
|
|
g += 127;
|
|
b += 127;
|
|
|
|
return (r << 16) | (g << 8) | (b);
|
|
}
|
|
|
|
case 2:
|
|
case 3:
|
|
{
|
|
UINT8 r = (*(UINT32 *)®[0x44] >> 16) & 0xff;
|
|
UINT8 g = (*(UINT32 *)®[0x44] >> 8) & 0xff;
|
|
UINT8 b = (*(UINT32 *)®[0x44] >> 0) & 0xff;
|
|
|
|
r ^= 0x80;
|
|
g ^= 0x80;
|
|
b ^= 0x80;
|
|
|
|
return (r << 16) | (g << 8) | (b);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
UINT32 *tilegen_get_priority_buffer(void)
|
|
{
|
|
return (UINT32 *)&vram[0xf7000];
|
|
}
|
|
|
|
BOOL tilegen_is_priority_enabled(void)
|
|
{
|
|
UINT32 v = *(UINT32 *)®[0x20];
|
|
return (v & 0x80) ? TRUE : FALSE;
|
|
}
|
|
|
|
UINT32 tilegen_get_layer_scroll_pos(int layer)
|
|
{
|
|
UINT32 s = *(UINT32 *)®[0x60 + (layer*4)];
|
|
return s & 0x7fff7fff;
|
|
}
|
|
|
|
/*
|
|
* void tilegen_reset(void);
|
|
*
|
|
* Resets the tilemap generator. The registers are put into a reset state and
|
|
* the palette is zeroed out.
|
|
*/
|
|
|
|
void tilegen_reset(void)
|
|
{
|
|
memset(reg, 0xFF, 0x100);
|
|
memset(pal, 0x00, 65536 * sizeof(UINT32));
|
|
}
|