mirror of
https://github.com/ekeeke/Genesis-Plus-GX.git
synced 2024-12-27 19:51:48 +01:00
~modified RGB565 color palette
This commit is contained in:
parent
086548476c
commit
9800c00f5a
@ -7,7 +7,7 @@ Genesis Plus GX 1.3.2 (??/??/????) (Eke-Eke)
|
|||||||
|
|
||||||
* optimized SN76489 core
|
* optimized SN76489 core
|
||||||
* modified SN76489 cut-off frequency (thanks to Steve Snake)
|
* modified SN76489 cut-off frequency (thanks to Steve Snake)
|
||||||
* added SN76489 linear synthesis using Blip Buffer (thanks to Blargg)
|
* modified SN76489 core to use Blip Buffer linear synthesis , Noise channel is now linear averaged (thanks to Blargg)
|
||||||
* added an option to boost SN76489 Noise Channel
|
* added an option to boost SN76489 Noise Channel
|
||||||
* removed now outdated Gens YM2612 core
|
* removed now outdated Gens YM2612 core
|
||||||
* improved YM2612 emulation accuracy (SSG-EG, CSM mode...) (thanks to Nemesis for his tests on real hardware)
|
* improved YM2612 emulation accuracy (SSG-EG, CSM mode...) (thanks to Nemesis for his tests on real hardware)
|
||||||
|
755
source/render.c
755
source/render.c
@ -41,34 +41,6 @@ typedef struct
|
|||||||
uint8 enable;
|
uint8 enable;
|
||||||
}clip_t;
|
}clip_t;
|
||||||
|
|
||||||
/* Function prototypes */
|
|
||||||
static void palette_init(void);
|
|
||||||
static void make_name_lut(void);
|
|
||||||
static uint32 make_lut_bg(uint32 bx, uint32 ax);
|
|
||||||
static uint32 make_lut_obj(uint32 bx, uint32 sx);
|
|
||||||
static uint32 make_lut_bg_ste(uint32 bx, uint32 ax);
|
|
||||||
static uint32 make_lut_obj_ste(uint32 bx, uint32 sx);
|
|
||||||
static uint32 make_lut_bgobj_ste(uint32 bx, uint32 sx);
|
|
||||||
static void color_update_16(int index, uint16 data);
|
|
||||||
#ifndef NGC
|
|
||||||
static void color_update_8(int index, uint16 data);
|
|
||||||
static void color_update_15(int index, uint16 data);
|
|
||||||
static void color_update_32(int index, uint16 data);
|
|
||||||
static inline void remap_8(uint8 *src, uint8 *dst, uint8 *table, int length);
|
|
||||||
static inline void remap_16(uint8 *src, uint16 *dst, uint16 *table, int length);
|
|
||||||
static inline void remap_32(uint8 *src, uint32 *dst, uint32 *table, int length);
|
|
||||||
#else
|
|
||||||
static inline void remap_texture(uint8 *src, uint16 *dst, uint32 tiles);
|
|
||||||
#endif
|
|
||||||
static inline void merge(uint8 *srca, uint8 *srcb, uint8 *dst, uint8 *table, uint32 width);
|
|
||||||
static inline void update_bg_pattern_cache(uint32 index);
|
|
||||||
static inline uint32 get_hscroll(uint32 line);
|
|
||||||
static void render_bg(uint32 line, uint32 width);
|
|
||||||
static void render_bg_im2(uint32 line, uint32 width, uint32 odd);
|
|
||||||
static void render_bg_vs(uint32 line, uint32 width);
|
|
||||||
static void render_obj(uint32 line, uint8 *buf, uint8 *table);
|
|
||||||
static void render_obj_im2(uint32 line, uint32 odd, uint8 *buf, uint8 *table);
|
|
||||||
|
|
||||||
#undef ALIGN_LONG
|
#undef ALIGN_LONG
|
||||||
#ifdef ALIGN_LONG
|
#ifdef ALIGN_LONG
|
||||||
/* Or change the names if you depend on these from elsewhere.. */
|
/* Or change the names if you depend on these from elsewhere.. */
|
||||||
@ -110,8 +82,8 @@ static __inline__ void WRITE_LONG(void *address, uint32 data)
|
|||||||
*((uint8 *)address) = (data >> 24);
|
*((uint8 *)address) = (data >> 24);
|
||||||
#endif /* LSB_FIRST */
|
#endif /* LSB_FIRST */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else *(uint32 *)address = data;
|
else *(uint32 *)address = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* ALIGN_LONG */
|
#endif /* ALIGN_LONG */
|
||||||
@ -327,10 +299,9 @@ static __inline__ void WRITE_LONG(void *address, uint32 data)
|
|||||||
*lb++ = table[(*lb << 8) |(*src++ | palette)];
|
*lb++ = table[(*lb << 8) |(*src++ | palette)];
|
||||||
.. claiming the result on lb is undefined.
|
.. claiming the result on lb is undefined.
|
||||||
So we manually advance lb and use constant offsets into the line buffer.
|
So we manually advance lb and use constant offsets into the line buffer.
|
||||||
*/
|
|
||||||
|
|
||||||
/* added sprite collision detection:
|
Added sprite collision detection
|
||||||
check if non-transparent sprite data has been previously drawn
|
(check if non-transparent sprite data has been previously drawn)
|
||||||
*/
|
*/
|
||||||
#define DRAW_SPRITE_TILE \
|
#define DRAW_SPRITE_TILE \
|
||||||
for(i=0; i<8; i++) \
|
for(i=0; i<8; i++) \
|
||||||
@ -340,22 +311,67 @@ static __inline__ void WRITE_LONG(void *address, uint32 data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Pixel creation macros, input is four bits each */
|
/**************************************************/
|
||||||
#ifndef NGC
|
/* Pixel creation macros */
|
||||||
|
/* Input is four bits each (R,G,B), 12 bits total */
|
||||||
/* 8:8:8 RGB */
|
/* Color range depends on the S/TE mode: */
|
||||||
#define MAKE_PIXEL_32(r,g,b) ((r) << 20 | (g) << 12 | (b) << 4)
|
/* */
|
||||||
|
/* normal mode : xxx0 (0-14) */
|
||||||
/* 5:5:5 RGB */
|
/* shadow mode : 0xxx (0-7) */
|
||||||
#define MAKE_PIXEL_15(r,g,b) ((r) << 11 | (g) << 6 | (b) << 1)
|
/* highlight mode: 1xxx (8-15) */
|
||||||
|
/* */
|
||||||
/* 3:3:2 RGB */
|
/* with xxx0 = original 4-bits CRAM value */
|
||||||
#define MAKE_PIXEL_8(r,g,b) ((r) << 5 | (g) << 2 | ((b) >> 1))
|
/**************************************************/
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* 5:6:5 RGB */
|
/* 5:6:5 RGB */
|
||||||
#define MAKE_PIXEL_16(r,g,b) ((r) << 11 | (g) << 5 | (b))
|
/* This RGB format uses 5 or 6bits color */
|
||||||
|
/* 4 bits color value need to be dithered */
|
||||||
|
/* to match the whole color range: */
|
||||||
|
/* */
|
||||||
|
/* R,B (5 bits) : yyyyy (0-31) */
|
||||||
|
/* G (6 bits) : yyyyyy (0-63) */
|
||||||
|
/* */
|
||||||
|
/* normal mode : xxx0 (0-14) */
|
||||||
|
/* 0000 -> 00000 (000000) */
|
||||||
|
/* 0010 -> 00100 (001000) */
|
||||||
|
/* 0100 -> 01000 (010001) */
|
||||||
|
/* 0110 -> 01100 (011001) */
|
||||||
|
/* 1000 -> 10001 (100010) */
|
||||||
|
/* 1010 -> 10101 (101010) */
|
||||||
|
/* 1100 -> 11001 (110011) */
|
||||||
|
/* 1110 -> 11101 (111011) */
|
||||||
|
/* */
|
||||||
|
/* shadow mode : 0xxx (0-7) */
|
||||||
|
/* 0000 -> 00000 (000000) */
|
||||||
|
/* 0001 -> 00010 (000100) */
|
||||||
|
/* 0010 -> 00100 (001000) */
|
||||||
|
/* 0011 -> 00110 (001100) */
|
||||||
|
/* 0100 -> 01000 (010001) */
|
||||||
|
/* 0101 -> 01010 (010101) */
|
||||||
|
/* 0110 -> 01100 (011001) */
|
||||||
|
/* 0111 -> 01110 (011101) */
|
||||||
|
/* */
|
||||||
|
/* highlight mode: 1xxx (8-15) */
|
||||||
|
/* 1000 -> 10001 (100010) */
|
||||||
|
/* 1001 -> 10011 (100110) */
|
||||||
|
/* 1010 -> 10101 (101010) */
|
||||||
|
/* 1011 -> 10111 (101110) */
|
||||||
|
/* 1100 -> 11001 (110011) */
|
||||||
|
/* 1101 -> 11011 (110111) */
|
||||||
|
/* 1110 -> 11101 (111011) */
|
||||||
|
/* 1111 -> 11111 (111111) */
|
||||||
|
/* */
|
||||||
|
/******************************************/
|
||||||
|
#define MAKE_PIXEL_16(r,g,b) (((r) << 12) | (((r) >> 3) << 12) | ((g) << 7) | (((g) >> 2) << 5) | ((b) << 1) | ((b) >> 3) )
|
||||||
|
|
||||||
|
#ifndef NGC
|
||||||
|
/* 8:8:8 RGB */
|
||||||
|
#define MAKE_PIXEL_32(r,g,b) ((r) << 20 | (g) << 12 | (b) << 4)
|
||||||
|
/* 5:5:5 RGB */
|
||||||
|
#define MAKE_PIXEL_15(r,g,b) ((r) << 11 | (g) << 6 | (b) << 1)
|
||||||
|
/* 3:3:2 RGB */
|
||||||
|
#define MAKE_PIXEL_8(r,g,b) ((r) << 5 | (g) << 2 | ((b) >> 1))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* Clip data */
|
/* Clip data */
|
||||||
@ -411,347 +427,6 @@ static uint8 obj_buf[0x200]; /* Object layer line buffer */
|
|||||||
/* Sprite line buffer data */
|
/* Sprite line buffer data */
|
||||||
static uint32 object_index_count;
|
static uint32 object_index_count;
|
||||||
|
|
||||||
/*
|
|
||||||
3:3:3 to 5:6:5 RGB pixel extrapolation tables
|
|
||||||
this is used to convert 3bits RGB values to 5bits (R,B) or 6bits (G) values
|
|
||||||
there is three color modes:
|
|
||||||
normal: RGB range is [0;MAX]
|
|
||||||
half: RGB range is [0;MAX/2] (shadow mode)
|
|
||||||
high: RGB range is [MAX/2;MAX] (highlight mode)
|
|
||||||
|
|
||||||
MAX is 31 (R,B) or 63 (G) for 5:6:5 pixels and 7 (R,G,B) for 3:3:3 pixels
|
|
||||||
MAX/2 is rounded to inferior value (15, 31 or 3)
|
|
||||||
|
|
||||||
the extrapolation is linear and calculated like this:
|
|
||||||
|
|
||||||
for (i=0; i<8; i++)
|
|
||||||
{
|
|
||||||
rgb565_norm[0][i] = round(((double)i * 31.0) / 7.0);
|
|
||||||
rgb565_norm[1][i] = round(((double)i * 63.0) / 7.0);
|
|
||||||
|
|
||||||
rgb565_half[0][i] = round(((double)i * 31.0) / 7.0 / 2.0);
|
|
||||||
rgb565_half[1][i] = round(((double)i * 63.0) / 7.0 / 2.0);
|
|
||||||
|
|
||||||
rgb565_high[0][i] = round(((double)i * 31.0) / 7.0 / 2.0 + 15.5);
|
|
||||||
rgb565_high[1][i] = round(((double)i * 63.0) / 7.0 / 2.0 + 31.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
static const uint8 rgb565_norm[2][8] =
|
|
||||||
{
|
|
||||||
{0 , 4, 9, 13, 18, 22, 27, 31},
|
|
||||||
{0 , 9, 18, 27, 36, 45, 54, 63}
|
|
||||||
};
|
|
||||||
|
|
||||||
static const uint8 rgb565_half[2][8] =
|
|
||||||
{
|
|
||||||
{0 , 2, 4, 6, 9, 11, 13, 15},
|
|
||||||
{0 , 4, 9, 13, 18, 22, 27, 31}
|
|
||||||
};
|
|
||||||
|
|
||||||
static const uint8 rgb565_high[2][8] =
|
|
||||||
{
|
|
||||||
{15, 17, 19, 21, 24, 26, 28, 31},
|
|
||||||
{31, 35, 40, 44, 49, 53, 58, 63}
|
|
||||||
};
|
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
/* Init, reset, shutdown routines */
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
void render_init(void)
|
|
||||||
{
|
|
||||||
int bx, ax, i;
|
|
||||||
|
|
||||||
/* Allocate and align pixel look-up tables */
|
|
||||||
if (lut_base == NULL) lut_base = malloc ((LUT_MAX * LUT_SIZE) + LUT_SIZE);
|
|
||||||
lut[0] = (uint8 *) (((uint32) lut_base + LUT_SIZE) & ~(LUT_SIZE - 1));
|
|
||||||
for (i = 1; i < LUT_MAX; i += 1) lut[i] = lut[0] + (i * LUT_SIZE);
|
|
||||||
|
|
||||||
/* Make pixel look-up table data */
|
|
||||||
for (bx = 0; bx < 0x100; bx += 1)
|
|
||||||
for (ax = 0; ax < 0x100; ax += 1)
|
|
||||||
{
|
|
||||||
uint16 index = (bx << 8) | (ax);
|
|
||||||
lut[0][index] = make_lut_bg (bx, ax);
|
|
||||||
lut[1][index] = make_lut_obj (bx, ax);
|
|
||||||
lut[2][index] = make_lut_bg_ste (bx, ax);
|
|
||||||
lut[3][index] = make_lut_obj_ste (bx, ax);
|
|
||||||
lut[4][index] = make_lut_bgobj_ste (bx, ax);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make pixel data tables */
|
|
||||||
palette_init();
|
|
||||||
|
|
||||||
/* Set up color update function */
|
|
||||||
#ifndef NGC
|
|
||||||
switch(bitmap.depth)
|
|
||||||
{
|
|
||||||
case 8: color_update = color_update_8; break;
|
|
||||||
case 15: color_update = color_update_15; break;
|
|
||||||
case 16: color_update = color_update_16; break;
|
|
||||||
case 32: color_update = color_update_32; break;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
color_update = color_update_16;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Make sprite name look-up table */
|
|
||||||
make_name_lut();
|
|
||||||
}
|
|
||||||
|
|
||||||
void render_reset(void)
|
|
||||||
{
|
|
||||||
/* Clear display bitmap */
|
|
||||||
memset(bitmap.data, 0, bitmap.pitch * bitmap.height);
|
|
||||||
|
|
||||||
memset(bg_buf, 0, sizeof(bg_buf));
|
|
||||||
memset(tmp_buf, 0, sizeof(tmp_buf));
|
|
||||||
memset(nta_buf, 0, sizeof(nta_buf));
|
|
||||||
memset(ntb_buf, 0, sizeof(ntb_buf));
|
|
||||||
memset(obj_buf, 0, sizeof(obj_buf));
|
|
||||||
|
|
||||||
#ifndef NGC
|
|
||||||
memset(&pixel_8, 0, sizeof(pixel_8));
|
|
||||||
memset(&pixel_15, 0, sizeof(pixel_15));
|
|
||||||
memset(&pixel_32, 0, sizeof(pixel_32));
|
|
||||||
#endif
|
|
||||||
memset(&pixel_16, 0, sizeof(pixel_16));
|
|
||||||
|
|
||||||
window_clip();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void render_shutdown(void)
|
|
||||||
{
|
|
||||||
if(lut_base) free(lut_base);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
/* Line render function */
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
void render_line(uint32 line, uint32 overscan)
|
|
||||||
{
|
|
||||||
uint32 width = bitmap.viewport.w;
|
|
||||||
uint32 x_offset = bitmap.viewport.x;
|
|
||||||
|
|
||||||
/* display OFF */
|
|
||||||
if (reg[0] & 0x01) return;
|
|
||||||
|
|
||||||
/* background color (blanked display or vertical borders) */
|
|
||||||
if (!(reg[1] & 0x40) || overscan)
|
|
||||||
{
|
|
||||||
width += 2 * x_offset;
|
|
||||||
memset(&tmp_buf[0x20 - x_offset], 0x40, width);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
uint8 *lb = tmp_buf;
|
|
||||||
|
|
||||||
/* update pattern generator */
|
|
||||||
if (bg_list_index)
|
|
||||||
{
|
|
||||||
update_bg_pattern_cache(bg_list_index);
|
|
||||||
bg_list_index = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* double-resolution mode */
|
|
||||||
if(im2_flag)
|
|
||||||
{
|
|
||||||
uint32 odd = odd_frame;
|
|
||||||
|
|
||||||
/* render BG layers */
|
|
||||||
render_bg_im2(line, width, odd);
|
|
||||||
|
|
||||||
if (reg[12] & 8)
|
|
||||||
{
|
|
||||||
/* Shadow & Highlight */
|
|
||||||
merge(&nta_buf[0x20], &ntb_buf[0x20], &bg_buf[0x20], lut[2], width);
|
|
||||||
memset(&obj_buf[0x20], 0, width);
|
|
||||||
if (object_index_count) render_obj_im2(line, odd, obj_buf, lut[3]);
|
|
||||||
merge(&obj_buf[0x20], &bg_buf[0x20], &lb[0x20], lut[4], width);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
merge(&nta_buf[0x20], &ntb_buf[0x20], &lb[0x20], lut[0], width);
|
|
||||||
if (object_index_count) render_obj_im2(line, odd, lb, lut[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* render BG layers */
|
|
||||||
if(reg[11] & 4) render_bg_vs(line, width);
|
|
||||||
else render_bg(line, width);
|
|
||||||
|
|
||||||
if(reg[12] & 8)
|
|
||||||
{
|
|
||||||
/* Shadow & Highlight */
|
|
||||||
merge(&nta_buf[0x20], &ntb_buf[0x20], &bg_buf[0x20], lut[2], width);
|
|
||||||
memset(&obj_buf[0x20], 0, width);
|
|
||||||
render_obj(line, obj_buf, lut[3]);
|
|
||||||
merge(&obj_buf[0x20], &bg_buf[0x20], &lb[0x20], lut[4], width);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
merge(&nta_buf[0x20], &ntb_buf[0x20], &lb[0x20], lut[0], width);
|
|
||||||
render_obj(line, lb, lut[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Mode 4 feature only (unemulated, no games rely on this) */
|
|
||||||
/*if(!(reg[1] & 0x04) && (reg[0] & 0x20)) memset(&lb[0x20], 0x40, 0x08);*/
|
|
||||||
|
|
||||||
/* borders */
|
|
||||||
if (x_offset)
|
|
||||||
{
|
|
||||||
memset(&lb[0x20 - x_offset], 0x40, x_offset);
|
|
||||||
memset(&lb[0x20 + width], 0x40, x_offset);
|
|
||||||
width += 2 * x_offset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* pixel color remapping */
|
|
||||||
remap_buffer(line,width);
|
|
||||||
}
|
|
||||||
|
|
||||||
void remap_buffer(uint32 line, uint32 width)
|
|
||||||
{
|
|
||||||
/* get line offset from framebuffer */
|
|
||||||
line = (line + bitmap.viewport.y) % lines_per_frame;
|
|
||||||
|
|
||||||
/* double resolution mode */
|
|
||||||
if (config.render && interlaced) line = (line * 2) + odd_frame;
|
|
||||||
|
|
||||||
/* NTSC Filter */
|
|
||||||
if (config.ntsc)
|
|
||||||
{
|
|
||||||
if (reg[12]&1) md_ntsc_blit(&md_ntsc, ( MD_NTSC_IN_T const * )pixel_16, tmp_buf+0x20-bitmap.viewport.x, width, line);
|
|
||||||
else sms_ntsc_blit(&sms_ntsc, ( SMS_NTSC_IN_T const * )pixel_16, tmp_buf+0x20-bitmap.viewport.x, width, line);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef NGC
|
|
||||||
/* directly fill the RGB565 texture */
|
|
||||||
/* one tile is 32 byte = 4x4 pixels */
|
|
||||||
/* tiles are stored continuously in texture memory */
|
|
||||||
width = width >> 2;
|
|
||||||
int offset = ((width << 5) * (line >> 2)) + ((line & 3) * 8);
|
|
||||||
remap_texture(tmp_buf+0x20-bitmap.viewport.x, (uint16 *)(texturemem + offset), width);
|
|
||||||
|
|
||||||
#else
|
|
||||||
void *out =((void *)&bitmap.data[(line * bitmap.pitch)]);
|
|
||||||
switch(bitmap.depth)
|
|
||||||
{
|
|
||||||
case 8:
|
|
||||||
remap_8(tmp_buf+0x20-bitmap.viewport.x, (uint8 *)out, pixel_8, width);
|
|
||||||
break;
|
|
||||||
case 15:
|
|
||||||
remap_16(tmp_buf+0x20-bitmap.viewport.x, (uint16 *)out, pixel_15, width);
|
|
||||||
break;
|
|
||||||
case 16:
|
|
||||||
remap_16(tmp_buf+0x20-bitmap.viewport.x, (uint16 *)out, pixel_16, width);
|
|
||||||
break;
|
|
||||||
case 32:
|
|
||||||
remap_32(tmp_buf+0x20-bitmap.viewport.x, (uint32 *)out, pixel_32, width);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Update Window Clipping (only called when registers change) */
|
|
||||||
void window_clip(void)
|
|
||||||
{
|
|
||||||
/* Window size and invert flags */
|
|
||||||
int hp = (reg[17] & 0x1f);
|
|
||||||
int hf = (reg[17] >> 7) & 1;
|
|
||||||
|
|
||||||
/* Display size */
|
|
||||||
int sw = bitmap.viewport.w >> 4;
|
|
||||||
|
|
||||||
/* Clear clipping data */
|
|
||||||
memset(&clip, 0, sizeof(clip));
|
|
||||||
|
|
||||||
/* Perform horizontal clipping; the results are applied in reverse
|
|
||||||
if the horizontal inversion flag is set */
|
|
||||||
int a = hf;
|
|
||||||
int w = hf ^ 1;
|
|
||||||
|
|
||||||
if(hp)
|
|
||||||
{
|
|
||||||
if(hp > sw)
|
|
||||||
{
|
|
||||||
/* Plane W takes up entire line */
|
|
||||||
clip[w].right = sw;
|
|
||||||
clip[w].enable = 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Window takes left side, Plane A takes right side */
|
|
||||||
clip[w].right = hp;
|
|
||||||
clip[a].left = hp;
|
|
||||||
clip[a].right = sw;
|
|
||||||
clip[0].enable = clip[1].enable = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Plane A takes up entire line */
|
|
||||||
clip[a].right = sw;
|
|
||||||
clip[a].enable = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
/* Sprites Parsing function */
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
void parse_satb(uint32 line)
|
|
||||||
{
|
|
||||||
uint8 sizetab[] = {8, 16, 24, 32};
|
|
||||||
uint32 link = 0;
|
|
||||||
uint32 count, ypos, size, height;
|
|
||||||
|
|
||||||
uint32 limit = (reg[12] & 1) ? 20 : 16;
|
|
||||||
uint32 total = limit << 2;
|
|
||||||
|
|
||||||
uint16 *p = (uint16 *) &vram[satb];
|
|
||||||
uint16 *q = (uint16 *) &sat[0];
|
|
||||||
|
|
||||||
object_index_count = 0;
|
|
||||||
|
|
||||||
for(count = 0; count < total; count += 1)
|
|
||||||
{
|
|
||||||
ypos = (q[link] >> im2_flag) & 0x1FF;
|
|
||||||
size = q[link + 1] >> 8;
|
|
||||||
height = sizetab[size & 3];
|
|
||||||
|
|
||||||
if((line >= ypos) && (line < (ypos + height)))
|
|
||||||
{
|
|
||||||
/* sprite limit (max. 16 or 20 sprites displayed per line) */
|
|
||||||
if(object_index_count == limit)
|
|
||||||
{
|
|
||||||
if(vint_pending == 0) status |= 0x40;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// using xpos from internal satb stops sprite x
|
|
||||||
// scrolling in bloodlin.bin,
|
|
||||||
// but this seems to go against the test prog
|
|
||||||
object_info[object_index_count].attr = p[link + 2];
|
|
||||||
object_info[object_index_count].xpos = p[link + 3];
|
|
||||||
object_info[object_index_count].ypos = ypos;
|
|
||||||
object_info[object_index_count].size = size;
|
|
||||||
++object_index_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
link = (q[link + 1] & 0x7F) << 2;
|
|
||||||
if(link == 0) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------*/
|
/*--------------------------------------------------------------------------*/
|
||||||
/* Look-up table functions (handles priority between layers pixels) */
|
/* Look-up table functions (handles priority between layers pixels) */
|
||||||
/*--------------------------------------------------------------------------*/
|
/*--------------------------------------------------------------------------*/
|
||||||
@ -782,11 +457,10 @@ static void palette_init(void)
|
|||||||
pixel_32_lut[2][i] = MAKE_PIXEL_32(r|8,g|8,b|8);
|
pixel_32_lut[2][i] = MAKE_PIXEL_32(r|8,g|8,b|8);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* RGB 565 format: we extrapolate each 3-bit value into a 5-bit (R,B) or 6-bit (G) value
|
pixel_16_lut[0][i] = MAKE_PIXEL_16(r,g,b);
|
||||||
this is needed to correctly cover full color range: [0-31] for R,B or [0-63] for G */
|
pixel_16_lut[1][i] = MAKE_PIXEL_16(r<<1,g<<1,b<<1);
|
||||||
pixel_16_lut[0][i] = MAKE_PIXEL_16(rgb565_half[0][r],rgb565_half[1][g],rgb565_half[0][b]);
|
|
||||||
pixel_16_lut[1][i] = MAKE_PIXEL_16(rgb565_norm[0][r],rgb565_norm[1][g],rgb565_norm[0][b]);
|
pixel_16_lut[2][i] = MAKE_PIXEL_16(r|8,g|8,b|8);
|
||||||
pixel_16_lut[2][i] = MAKE_PIXEL_16(rgb565_high[0][r],rgb565_high[1][g],rgb565_high[0][b]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1849,3 +1523,298 @@ static void render_obj_im2(uint32 line, uint32 odd, uint8 *buf, uint8 *table)
|
|||||||
spr_over = 0;
|
spr_over = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
/* Init, reset, shutdown routines */
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
void render_init(void)
|
||||||
|
{
|
||||||
|
int bx, ax, i;
|
||||||
|
|
||||||
|
/* Allocate and align pixel look-up tables */
|
||||||
|
if (lut_base == NULL) lut_base = malloc ((LUT_MAX * LUT_SIZE) + LUT_SIZE);
|
||||||
|
lut[0] = (uint8 *) (((uint32) lut_base + LUT_SIZE) & ~(LUT_SIZE - 1));
|
||||||
|
for (i = 1; i < LUT_MAX; i += 1) lut[i] = lut[0] + (i * LUT_SIZE);
|
||||||
|
|
||||||
|
/* Make pixel look-up table data */
|
||||||
|
for (bx = 0; bx < 0x100; bx += 1)
|
||||||
|
for (ax = 0; ax < 0x100; ax += 1)
|
||||||
|
{
|
||||||
|
uint16 index = (bx << 8) | (ax);
|
||||||
|
lut[0][index] = make_lut_bg (bx, ax);
|
||||||
|
lut[1][index] = make_lut_obj (bx, ax);
|
||||||
|
lut[2][index] = make_lut_bg_ste (bx, ax);
|
||||||
|
lut[3][index] = make_lut_obj_ste (bx, ax);
|
||||||
|
lut[4][index] = make_lut_bgobj_ste (bx, ax);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make pixel data tables */
|
||||||
|
palette_init();
|
||||||
|
|
||||||
|
/* Set up color update function */
|
||||||
|
#ifndef NGC
|
||||||
|
switch(bitmap.depth)
|
||||||
|
{
|
||||||
|
case 8: color_update = color_update_8; break;
|
||||||
|
case 15: color_update = color_update_15; break;
|
||||||
|
case 16: color_update = color_update_16; break;
|
||||||
|
case 32: color_update = color_update_32; break;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
color_update = color_update_16;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Make sprite name look-up table */
|
||||||
|
make_name_lut();
|
||||||
|
}
|
||||||
|
|
||||||
|
void render_reset(void)
|
||||||
|
{
|
||||||
|
/* Clear display bitmap */
|
||||||
|
memset(bitmap.data, 0, bitmap.pitch * bitmap.height);
|
||||||
|
|
||||||
|
memset(bg_buf, 0, sizeof(bg_buf));
|
||||||
|
memset(tmp_buf, 0, sizeof(tmp_buf));
|
||||||
|
memset(nta_buf, 0, sizeof(nta_buf));
|
||||||
|
memset(ntb_buf, 0, sizeof(ntb_buf));
|
||||||
|
memset(obj_buf, 0, sizeof(obj_buf));
|
||||||
|
|
||||||
|
#ifndef NGC
|
||||||
|
memset(&pixel_8, 0, sizeof(pixel_8));
|
||||||
|
memset(&pixel_15, 0, sizeof(pixel_15));
|
||||||
|
memset(&pixel_32, 0, sizeof(pixel_32));
|
||||||
|
#endif
|
||||||
|
memset(&pixel_16, 0, sizeof(pixel_16));
|
||||||
|
|
||||||
|
window_clip();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void render_shutdown(void)
|
||||||
|
{
|
||||||
|
if(lut_base) free(lut_base);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
/* Line render function */
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
void render_line(uint32 line, uint32 overscan)
|
||||||
|
{
|
||||||
|
uint32 width = bitmap.viewport.w;
|
||||||
|
uint32 x_offset = bitmap.viewport.x;
|
||||||
|
|
||||||
|
/* display OFF */
|
||||||
|
if (reg[0] & 0x01) return;
|
||||||
|
|
||||||
|
/* background color (blanked display or vertical borders) */
|
||||||
|
if (!(reg[1] & 0x40) || overscan)
|
||||||
|
{
|
||||||
|
width += 2 * x_offset;
|
||||||
|
memset(&tmp_buf[0x20 - x_offset], 0x40, width);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint8 *lb = tmp_buf;
|
||||||
|
|
||||||
|
/* update pattern generator */
|
||||||
|
if (bg_list_index)
|
||||||
|
{
|
||||||
|
update_bg_pattern_cache(bg_list_index);
|
||||||
|
bg_list_index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* double-resolution mode */
|
||||||
|
if(im2_flag)
|
||||||
|
{
|
||||||
|
uint32 odd = odd_frame;
|
||||||
|
|
||||||
|
/* render BG layers */
|
||||||
|
render_bg_im2(line, width, odd);
|
||||||
|
|
||||||
|
if (reg[12] & 8)
|
||||||
|
{
|
||||||
|
/* Shadow & Highlight */
|
||||||
|
merge(&nta_buf[0x20], &ntb_buf[0x20], &bg_buf[0x20], lut[2], width);
|
||||||
|
memset(&obj_buf[0x20], 0, width);
|
||||||
|
if (object_index_count) render_obj_im2(line, odd, obj_buf, lut[3]);
|
||||||
|
merge(&obj_buf[0x20], &bg_buf[0x20], &lb[0x20], lut[4], width);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
merge(&nta_buf[0x20], &ntb_buf[0x20], &lb[0x20], lut[0], width);
|
||||||
|
if (object_index_count) render_obj_im2(line, odd, lb, lut[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* render BG layers */
|
||||||
|
if(reg[11] & 4) render_bg_vs(line, width);
|
||||||
|
else render_bg(line, width);
|
||||||
|
|
||||||
|
if(reg[12] & 8)
|
||||||
|
{
|
||||||
|
/* Shadow & Highlight */
|
||||||
|
merge(&nta_buf[0x20], &ntb_buf[0x20], &bg_buf[0x20], lut[2], width);
|
||||||
|
memset(&obj_buf[0x20], 0, width);
|
||||||
|
render_obj(line, obj_buf, lut[3]);
|
||||||
|
merge(&obj_buf[0x20], &bg_buf[0x20], &lb[0x20], lut[4], width);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
merge(&nta_buf[0x20], &ntb_buf[0x20], &lb[0x20], lut[0], width);
|
||||||
|
render_obj(line, lb, lut[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mode 4 feature only (unemulated, no games rely on this) */
|
||||||
|
/*if(!(reg[1] & 0x04) && (reg[0] & 0x20)) memset(&lb[0x20], 0x40, 0x08);*/
|
||||||
|
|
||||||
|
/* borders */
|
||||||
|
if (x_offset)
|
||||||
|
{
|
||||||
|
memset(&lb[0x20 - x_offset], 0x40, x_offset);
|
||||||
|
memset(&lb[0x20 + width], 0x40, x_offset);
|
||||||
|
width += 2 * x_offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* pixel color remapping */
|
||||||
|
remap_buffer(line,width);
|
||||||
|
}
|
||||||
|
|
||||||
|
void remap_buffer(uint32 line, uint32 width)
|
||||||
|
{
|
||||||
|
/* get line offset from framebuffer */
|
||||||
|
line = (line + bitmap.viewport.y) % lines_per_frame;
|
||||||
|
|
||||||
|
/* double resolution mode */
|
||||||
|
if (config.render && interlaced) line = (line * 2) + odd_frame;
|
||||||
|
|
||||||
|
/* NTSC Filter */
|
||||||
|
if (config.ntsc)
|
||||||
|
{
|
||||||
|
if (reg[12]&1) md_ntsc_blit(&md_ntsc, ( MD_NTSC_IN_T const * )pixel_16, tmp_buf+0x20-bitmap.viewport.x, width, line);
|
||||||
|
else sms_ntsc_blit(&sms_ntsc, ( SMS_NTSC_IN_T const * )pixel_16, tmp_buf+0x20-bitmap.viewport.x, width, line);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef NGC
|
||||||
|
/* directly fill the RGB565 texture */
|
||||||
|
/* one tile is 32 byte = 4x4 pixels */
|
||||||
|
/* tiles are stored continuously in texture memory */
|
||||||
|
width = width >> 2;
|
||||||
|
int offset = ((width << 5) * (line >> 2)) + ((line & 3) * 8);
|
||||||
|
remap_texture(tmp_buf+0x20-bitmap.viewport.x, (uint16 *)(texturemem + offset), width);
|
||||||
|
|
||||||
|
#else
|
||||||
|
void *out =((void *)&bitmap.data[(line * bitmap.pitch)]);
|
||||||
|
switch(bitmap.depth)
|
||||||
|
{
|
||||||
|
case 8:
|
||||||
|
remap_8(tmp_buf+0x20-bitmap.viewport.x, (uint8 *)out, pixel_8, width);
|
||||||
|
break;
|
||||||
|
case 15:
|
||||||
|
remap_16(tmp_buf+0x20-bitmap.viewport.x, (uint16 *)out, pixel_15, width);
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
remap_16(tmp_buf+0x20-bitmap.viewport.x, (uint16 *)out, pixel_16, width);
|
||||||
|
break;
|
||||||
|
case 32:
|
||||||
|
remap_32(tmp_buf+0x20-bitmap.viewport.x, (uint32 *)out, pixel_32, width);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update Window Clipping (only called when registers change) */
|
||||||
|
void window_clip(void)
|
||||||
|
{
|
||||||
|
/* Window size and invert flags */
|
||||||
|
int hp = (reg[17] & 0x1f);
|
||||||
|
int hf = (reg[17] >> 7) & 1;
|
||||||
|
|
||||||
|
/* Display size */
|
||||||
|
int sw = bitmap.viewport.w >> 4;
|
||||||
|
|
||||||
|
/* Clear clipping data */
|
||||||
|
memset(&clip, 0, sizeof(clip));
|
||||||
|
|
||||||
|
/* Perform horizontal clipping; the results are applied in reverse
|
||||||
|
if the horizontal inversion flag is set */
|
||||||
|
int a = hf;
|
||||||
|
int w = hf ^ 1;
|
||||||
|
|
||||||
|
if(hp)
|
||||||
|
{
|
||||||
|
if(hp > sw)
|
||||||
|
{
|
||||||
|
/* Plane W takes up entire line */
|
||||||
|
clip[w].right = sw;
|
||||||
|
clip[w].enable = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Window takes left side, Plane A takes right side */
|
||||||
|
clip[w].right = hp;
|
||||||
|
clip[a].left = hp;
|
||||||
|
clip[a].right = sw;
|
||||||
|
clip[0].enable = clip[1].enable = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Plane A takes up entire line */
|
||||||
|
clip[a].right = sw;
|
||||||
|
clip[a].enable = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
/* Sprites Parsing function */
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
void parse_satb(uint32 line)
|
||||||
|
{
|
||||||
|
uint8 sizetab[] = {8, 16, 24, 32};
|
||||||
|
uint32 link = 0;
|
||||||
|
uint32 count, ypos, size, height;
|
||||||
|
|
||||||
|
uint32 limit = (reg[12] & 1) ? 20 : 16;
|
||||||
|
uint32 total = limit << 2;
|
||||||
|
|
||||||
|
uint16 *p = (uint16 *) &vram[satb];
|
||||||
|
uint16 *q = (uint16 *) &sat[0];
|
||||||
|
|
||||||
|
object_index_count = 0;
|
||||||
|
|
||||||
|
for(count = 0; count < total; count += 1)
|
||||||
|
{
|
||||||
|
ypos = (q[link] >> im2_flag) & 0x1FF;
|
||||||
|
size = q[link + 1] >> 8;
|
||||||
|
height = sizetab[size & 3];
|
||||||
|
|
||||||
|
if((line >= ypos) && (line < (ypos + height)))
|
||||||
|
{
|
||||||
|
/* sprite limit (max. 16 or 20 sprites displayed per line) */
|
||||||
|
if(object_index_count == limit)
|
||||||
|
{
|
||||||
|
if(vint_pending == 0) status |= 0x40;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// using xpos from internal satb stops sprite x
|
||||||
|
// scrolling in bloodlin.bin,
|
||||||
|
// but this seems to go against the test prog
|
||||||
|
object_info[object_index_count].attr = p[link + 2];
|
||||||
|
object_info[object_index_count].xpos = p[link + 3];
|
||||||
|
object_info[object_index_count].ypos = ypos;
|
||||||
|
object_info[object_index_count].size = size;
|
||||||
|
++object_index_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
link = (q[link + 1] & 0x7F) << 2;
|
||||||
|
if(link == 0) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -410,7 +410,6 @@ void vdp_ctrl_w(unsigned int data)
|
|||||||
*/
|
*/
|
||||||
unsigned int vdp_ctrl_r(void)
|
unsigned int vdp_ctrl_r(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
/* update FIFO flags */
|
/* update FIFO flags */
|
||||||
fifo_update();
|
fifo_update();
|
||||||
if (fifo_write_cnt < 4)
|
if (fifo_write_cnt < 4)
|
||||||
|
Loading…
Reference in New Issue
Block a user