mirror of https://github.com/stella-emu/stella.git
Rearranged some Blargg code, added comments, general cleanups.
For now, Blargg phosphor mode simply shows the same image as without phosphor. This is a WIP, and if we can't get it finished for 5.0, it will be released as-is. Phosphor blend now defaults to 0 in the base properties, and is converted to 50 before being passed to higher levels. This needs to change when we get to issue #144.
This commit is contained in:
parent
fa76042790
commit
bd78683274
|
@ -69,24 +69,24 @@ void AtariNTSC::initializePalette(const uInt8* palette)
|
|||
void AtariNTSC::blitSingle(const uInt8* atari_in, uInt32 in_width,
|
||||
uInt32 in_height, void* rgb_out, uInt32 out_pitch)
|
||||
{
|
||||
uInt32 const chunk_count = (in_width - 1) / AN_in_chunk;
|
||||
uInt32 const chunk_count = (in_width - 1) / PIXEL_in_chunk;
|
||||
while ( in_height-- )
|
||||
{
|
||||
const uInt8* line_in = atari_in;
|
||||
ATARI_NTSC_BEGIN_ROW( &myNTSC, AN_black, line_in[0] );
|
||||
ATARI_NTSC_BEGIN_ROW( NTSC_black, line_in[0] );
|
||||
uInt32* restrict line_out = static_cast<uInt32*>(rgb_out);
|
||||
++line_in;
|
||||
|
||||
for ( uInt32 n = chunk_count; n; --n )
|
||||
{
|
||||
/* order of input and output pixels must not be altered */
|
||||
ATARI_NTSC_COLOR_IN( 0, &myNTSC, line_in[0] );
|
||||
ATARI_NTSC_COLOR_IN( 0, line_in[0] );
|
||||
ATARI_NTSC_RGB_OUT_8888( 0, line_out[0] );
|
||||
ATARI_NTSC_RGB_OUT_8888( 1, line_out[1] );
|
||||
ATARI_NTSC_RGB_OUT_8888( 2, line_out[2] );
|
||||
ATARI_NTSC_RGB_OUT_8888( 3, line_out[3] );
|
||||
|
||||
ATARI_NTSC_COLOR_IN( 1, &myNTSC, line_in[1] );
|
||||
ATARI_NTSC_COLOR_IN( 1, line_in[1] );
|
||||
ATARI_NTSC_RGB_OUT_8888( 4, line_out[4] );
|
||||
ATARI_NTSC_RGB_OUT_8888( 5, line_out[5] );
|
||||
ATARI_NTSC_RGB_OUT_8888( 6, line_out[6] );
|
||||
|
@ -96,13 +96,13 @@ void AtariNTSC::blitSingle(const uInt8* atari_in, uInt32 in_width,
|
|||
}
|
||||
|
||||
/* finish final pixels */
|
||||
ATARI_NTSC_COLOR_IN( 0, &myNTSC, AN_black );
|
||||
ATARI_NTSC_COLOR_IN( 0, NTSC_black );
|
||||
ATARI_NTSC_RGB_OUT_8888( 0, line_out[0] );
|
||||
ATARI_NTSC_RGB_OUT_8888( 1, line_out[1] );
|
||||
ATARI_NTSC_RGB_OUT_8888( 2, line_out[2] );
|
||||
ATARI_NTSC_RGB_OUT_8888( 3, line_out[3] );
|
||||
|
||||
ATARI_NTSC_COLOR_IN( 1, &myNTSC, AN_black );
|
||||
ATARI_NTSC_COLOR_IN( 1, NTSC_black );
|
||||
ATARI_NTSC_RGB_OUT_8888( 4, line_out[4] );
|
||||
ATARI_NTSC_RGB_OUT_8888( 5, line_out[5] );
|
||||
ATARI_NTSC_RGB_OUT_8888( 6, line_out[6] );
|
||||
|
@ -112,67 +112,6 @@ void AtariNTSC::blitSingle(const uInt8* atari_in, uInt32 in_width,
|
|||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
void atari_ntsc_blit_double( atari_ntsc_t const* ntsc,
|
||||
atari_ntsc_in_t const* atari_in1, atari_ntsc_in_t const* atari_in2,
|
||||
uInt32 in_width, uInt32 in_height, void* rgb_out, uInt32 out_pitch )
|
||||
{
|
||||
#define TO_DOUBLE(pixel1, pixel2) (((pixel1>>1)<<7)+(pixel2>>1))
|
||||
|
||||
uInt32 const chunk_count = (in_width - 1) / atari_ntsc_in_chunk;
|
||||
while ( in_height-- )
|
||||
{
|
||||
atari_ntsc_in_t const* line_in1 = atari_in1;
|
||||
atari_ntsc_in_t const* line_in2 = atari_in2;
|
||||
ATARI_NTSC_BEGIN_ROW( ntsc,
|
||||
TO_DOUBLE(atari_ntsc_black, atari_ntsc_black),
|
||||
TO_DOUBLE(line_in1[0], line_in2[0]) );
|
||||
uInt32* restrict line_out = static_cast<uInt32*>(rgb_out);
|
||||
++line_in1;
|
||||
++line_in2;
|
||||
|
||||
for ( uInt32 n = chunk_count; n; --n )
|
||||
{
|
||||
/* order of input and output pixels must not be altered */
|
||||
ATARI_NTSC_COLOR_IN( 0, ntsc,
|
||||
TO_DOUBLE(line_in1[0], line_in2[0]) );
|
||||
ATARI_NTSC_RGB_OUT_8888( 0, line_out[0] );
|
||||
ATARI_NTSC_RGB_OUT_8888( 1, line_out[1] );
|
||||
ATARI_NTSC_RGB_OUT_8888( 2, line_out[2] );
|
||||
ATARI_NTSC_RGB_OUT_8888( 3, line_out[3] );
|
||||
|
||||
ATARI_NTSC_COLOR_IN( 1, ntsc,
|
||||
TO_DOUBLE(line_in1[1], line_in2[1]) );
|
||||
ATARI_NTSC_RGB_OUT_8888( 4, line_out[4] );
|
||||
ATARI_NTSC_RGB_OUT_8888( 5, line_out[5] );
|
||||
ATARI_NTSC_RGB_OUT_8888( 6, line_out[6] );
|
||||
|
||||
line_in1 += 2;
|
||||
line_in2 += 2;
|
||||
line_out += 7;
|
||||
}
|
||||
|
||||
/* finish final pixels */
|
||||
ATARI_NTSC_COLOR_IN( 0, ntsc,
|
||||
TO_DOUBLE(atari_ntsc_black, atari_ntsc_black) );
|
||||
ATARI_NTSC_RGB_OUT_8888( 0, line_out[0] );
|
||||
ATARI_NTSC_RGB_OUT_8888( 1, line_out[1] );
|
||||
ATARI_NTSC_RGB_OUT_8888( 2, line_out[2] );
|
||||
ATARI_NTSC_RGB_OUT_8888( 3, line_out[3] );
|
||||
|
||||
ATARI_NTSC_COLOR_IN( 1, ntsc,
|
||||
TO_DOUBLE(atari_ntsc_black, atari_ntsc_black) );
|
||||
ATARI_NTSC_RGB_OUT_8888( 4, line_out[4] );
|
||||
ATARI_NTSC_RGB_OUT_8888( 5, line_out[5] );
|
||||
ATARI_NTSC_RGB_OUT_8888( 6, line_out[6] );
|
||||
|
||||
atari_in1 += in_width;
|
||||
atari_in2 += in_width;
|
||||
rgb_out = static_cast<char*>(rgb_out) + out_pitch;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void AtariNTSC::init(init_t& impl, const Setup& setup)
|
||||
{
|
||||
|
|
|
@ -31,6 +31,12 @@
|
|||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
The class is basically a thin wrapper around atari_ntsc_xxx structs
|
||||
and methods, so that the rest of the codebase isn't affected by
|
||||
updated versions of Blargg code.
|
||||
*/
|
||||
|
||||
#ifndef ATARI_NTSC_HXX
|
||||
#define ATARI_NTSC_HXX
|
||||
|
||||
|
@ -82,25 +88,25 @@ class AtariNTSC
|
|||
void blitSingle(const uInt8* atari_in, uInt32 in_width, uInt32 in_height,
|
||||
void* rgb_out, uInt32 out_pitch);
|
||||
|
||||
// Number of output pixels written by blitter for given input width.
|
||||
// Width might be rounded down slightly; use inWidth() on result to
|
||||
// find rounded value. Guaranteed not to round 160 down at all.
|
||||
static uInt32 outWidth(uInt32 in_width) {
|
||||
return ((((in_width) - 1) / AN_in_chunk + 1)* AN_out_chunk);
|
||||
}
|
||||
|
||||
// Number of input pixels that will fit within given output width.
|
||||
// Might be rounded down slightly; use outWidth() on result to find
|
||||
// rounded value.
|
||||
static uInt32 inWidth( uInt32 out_width ) {
|
||||
return (((out_width) / AN_out_chunk - 1) * AN_in_chunk + 1);
|
||||
return (((out_width) / PIXEL_out_chunk - 1) * PIXEL_in_chunk + 1);
|
||||
}
|
||||
|
||||
// Number of output pixels written by blitter for given input width.
|
||||
// Width might be rounded down slightly; use inWidth() on result to
|
||||
// find rounded value. Guaranteed not to round 160 down at all.
|
||||
static uInt32 outWidth(uInt32 in_width) {
|
||||
return ((((in_width) - 1) / PIXEL_in_chunk + 1)* PIXEL_out_chunk);
|
||||
}
|
||||
|
||||
private:
|
||||
enum {
|
||||
AN_in_chunk = 2, // number of input pixels read per chunk
|
||||
AN_out_chunk = 7, // number of output pixels generated per chunk
|
||||
AN_black = 0, // palette index for black
|
||||
PIXEL_in_chunk = 2, // number of input pixels read per chunk
|
||||
PIXEL_out_chunk = 7, // number of output pixels generated per chunk
|
||||
NTSC_black = 0, // palette index for black
|
||||
|
||||
alignment_count = 2,
|
||||
burst_count = 1,
|
||||
|
@ -166,12 +172,20 @@ class AtariNTSC
|
|||
|
||||
// Begins outputting row and starts two pixels. First pixel will be cut
|
||||
// off a bit. Use atari_ntsc_black for unused pixels.
|
||||
#define ATARI_NTSC_BEGIN_ROW( ntsc, pixel0, pixel1 ) \
|
||||
ATARI_NTSC_BEGIN_ROW_6_( pixel0, pixel1, ATARI_NTSC_ENTRY_, ntsc )
|
||||
#define ATARI_NTSC_BEGIN_ROW( pixel0, pixel1 ) \
|
||||
unsigned const atari_ntsc_pixel0_ = (pixel0);\
|
||||
uInt32 const* kernel0 = myNTSC.table[atari_ntsc_pixel0_];\
|
||||
unsigned const atari_ntsc_pixel1_ = (pixel1);\
|
||||
uInt32 const* kernel1 = myNTSC.table[atari_ntsc_pixel1_];\
|
||||
uInt32 const* kernelx0;\
|
||||
uInt32 const* kernelx1 = kernel0
|
||||
|
||||
// Begins input pixel
|
||||
#define ATARI_NTSC_COLOR_IN( in_index, ntsc, color_in ) \
|
||||
ATARI_NTSC_COLOR_IN_( in_index, color_in, ATARI_NTSC_ENTRY_, ntsc )
|
||||
#define ATARI_NTSC_COLOR_IN( index, color ) {\
|
||||
unsigned color_;\
|
||||
kernelx##index = kernel##index;\
|
||||
kernel##index = (color_ = (color), myNTSC.table[color_]);\
|
||||
}
|
||||
|
||||
// Generates output in the specified 32-bit format (x = junk bits).
|
||||
// native: xxxRRRRR RRRxxGGG GGGGGxxB BBBBBBBx (native internal format)
|
||||
|
@ -184,18 +198,7 @@ class AtariNTSC
|
|||
rgb_out = (raw_>>5 & 0x00FF0000)|(raw_>>3 & 0x0000FF00)|(raw_>>1 & 0x000000FF);\
|
||||
}
|
||||
|
||||
#define ATARI_NTSC_ENTRY_( ntsc, n ) (ntsc)->table [n]
|
||||
|
||||
// common 3->7 ntsc macros
|
||||
#define ATARI_NTSC_BEGIN_ROW_6_( pixel0, pixel1, ENTRY, table ) \
|
||||
unsigned const atari_ntsc_pixel0_ = (pixel0);\
|
||||
uInt32 const* kernel0 = ENTRY( table, atari_ntsc_pixel0_ );\
|
||||
unsigned const atari_ntsc_pixel1_ = (pixel1);\
|
||||
uInt32 const* kernel1 = ENTRY( table, atari_ntsc_pixel1_ );\
|
||||
uInt32 const* kernelx0;\
|
||||
uInt32 const* kernelx1 = kernel0
|
||||
|
||||
// common ntsc macros
|
||||
// Common ntsc macros
|
||||
#define atari_ntsc_clamp_mask (rgb_builder * 3 / 2)
|
||||
#define atari_ntsc_clamp_add (rgb_builder * 0x101)
|
||||
#define ATARI_NTSC_CLAMP_( io, shift ) {\
|
||||
|
@ -206,13 +209,7 @@ class AtariNTSC
|
|||
io &= clamp;\
|
||||
}
|
||||
|
||||
#define ATARI_NTSC_COLOR_IN_( index, color, ENTRY, table ) {\
|
||||
unsigned color_;\
|
||||
kernelx##index = kernel##index;\
|
||||
kernel##index = (color_ = (color), ENTRY( table, color_ ));\
|
||||
}
|
||||
|
||||
// kernel generation
|
||||
// Kernel generation
|
||||
#define ROTATE_IQ( i, q, sin_b, cos_b ) {\
|
||||
float t;\
|
||||
t = i * cos_b - q * sin_b;\
|
||||
|
|
|
@ -28,46 +28,6 @@ NTSCFilter::NTSCFilter()
|
|||
{
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void NTSCFilter::setTIAPalette(const TIASurface& tiaSurface, const uInt32* palette)
|
||||
{
|
||||
// Normal TIA palette contains 256 colours, where every odd indexed colour
|
||||
// is used for PAL colour-loss effect
|
||||
// This can't be emulated here, since the memory requirements would be too
|
||||
// great (a 4x increase)
|
||||
// Therefore, we need to skip every second index, since the array passed to
|
||||
// the Blargg code assumes 128 colours
|
||||
uInt8* ptr = myTIAPalette;
|
||||
|
||||
#if 0
|
||||
// Set palette for phosphor effect
|
||||
for(int i = 0; i < 256; i+=2)
|
||||
{
|
||||
for(int j = 0; j < 256; j+=2)
|
||||
{
|
||||
uInt8 ri = (palette[i] >> 16) & 0xff;
|
||||
uInt8 gi = (palette[i] >> 8) & 0xff;
|
||||
uInt8 bi = palette[i] & 0xff;
|
||||
uInt8 rj = (palette[j] >> 16) & 0xff;
|
||||
uInt8 gj = (palette[j] >> 8) & 0xff;
|
||||
uInt8 bj = palette[j] & 0xff;
|
||||
|
||||
*ptr++ = tiaSurface.getPhosphor(ri, rj);
|
||||
*ptr++ = tiaSurface.getPhosphor(gi, gj);
|
||||
*ptr++ = tiaSurface.getPhosphor(bi, bj);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// Set palette for normal fill
|
||||
for(int i = 0; i < 256; ++i)
|
||||
{
|
||||
*ptr++ = (palette[i] >> 16) & 0xff;
|
||||
*ptr++ = (palette[i] >> 8) & 0xff;
|
||||
*ptr++ = palette[i] & 0xff;
|
||||
}
|
||||
updateFilter();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string NTSCFilter::setPreset(Preset preset)
|
||||
{
|
||||
|
@ -98,7 +58,7 @@ string NTSCFilter::setPreset(Preset preset)
|
|||
default:
|
||||
return msg;
|
||||
}
|
||||
updateFilter();
|
||||
myNTSC.initialize(mySetup, myTIAPalette);
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
|
|
@ -32,9 +32,7 @@ class Settings;
|
|||
and is derived from 'filter_ntsc.(h|c)'. Original code based on
|
||||
implementation from http://www.slack.net/~ant.
|
||||
|
||||
The class is basically a thin wrapper around atari_ntsc_xxx structs
|
||||
and methods, so that the rest of the codebase isn't affected by
|
||||
updated versions of Blargg code.
|
||||
The class is basically a thin wrapper around the AtariNTSC class.
|
||||
*/
|
||||
class NTSCFilter
|
||||
{
|
||||
|
@ -64,7 +62,18 @@ class NTSCFilter
|
|||
uses this as a baseline for calculating its own internal palette
|
||||
in YIQ format.
|
||||
*/
|
||||
void setTIAPalette(const TIASurface& tiaSurface, const uInt32* palette);
|
||||
inline void setTIAPalette(const uInt32* palette) {
|
||||
uInt8* ptr = myTIAPalette;
|
||||
|
||||
// Set palette for normal fill
|
||||
for(uInt32 i = 0; i < AtariNTSC::palette_size; ++i)
|
||||
{
|
||||
*ptr++ = (palette[i] >> 16) & 0xff;
|
||||
*ptr++ = (palette[i] >> 8) & 0xff;
|
||||
*ptr++ = palette[i] & 0xff;
|
||||
}
|
||||
myNTSC.initializePalette(myTIAPalette);
|
||||
}
|
||||
|
||||
// The following are meant to be used strictly for toggling from the GUI
|
||||
string setPreset(Preset preset);
|
||||
|
@ -72,13 +81,6 @@ class NTSCFilter
|
|||
// Get current preset info encoded as a string
|
||||
string getPreset() const;
|
||||
|
||||
// Reinitialises the NTSC filter (automatically called after settings
|
||||
// have changed)
|
||||
inline void updateFilter()
|
||||
{
|
||||
myNTSC.initialize(mySetup, myTIAPalette);
|
||||
}
|
||||
|
||||
// Get adjustables for the given preset
|
||||
// Values will be scaled to 0 - 100 range, independent of how
|
||||
// they're actually stored internally
|
||||
|
@ -106,8 +108,6 @@ class NTSCFilter
|
|||
|
||||
// Perform Blargg filtering on input buffer, place results in
|
||||
// output buffer
|
||||
// In the current implementation, the source pitch is always the
|
||||
// same as the actual width
|
||||
inline void blit_single(uInt8* src_buf, uInt32 src_width, uInt32 src_height,
|
||||
uInt32* dest_buf, uInt32 dest_pitch)
|
||||
{
|
||||
|
|
|
@ -63,10 +63,10 @@ void Properties::set(PropertyType key, const string& value)
|
|||
break;
|
||||
}
|
||||
|
||||
case Display_PPBlend:
|
||||
case Display_PPBlend: // FIXME - handle global default
|
||||
{
|
||||
int blend = atoi(myProperties[key].c_str());
|
||||
if(blend < 0 || blend > 100) blend = 30;
|
||||
if(blend < 1 || blend > 100) blend = 50;
|
||||
ostringstream buf;
|
||||
buf << blend;
|
||||
myProperties[key] = buf.str();
|
||||
|
@ -261,7 +261,14 @@ void Properties::print() const
|
|||
void Properties::setDefaults()
|
||||
{
|
||||
for(int i = 0; i < LastPropType; ++i)
|
||||
{
|
||||
if(i == Display_PPBlend) // special case, handle global default
|
||||
{
|
||||
myProperties[i] = "50"; // FIXME - for now, just use 50
|
||||
}
|
||||
else
|
||||
myProperties[i] = ourDefaultProperties[i];
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -324,7 +331,7 @@ const char* Properties::ourDefaultProperties[LastPropType] = {
|
|||
"0", // Display.YStart
|
||||
"0", // Display.Height
|
||||
"NO", // Display.Phosphor
|
||||
"30" // Display.PPBlend
|
||||
"0" // Display.PPBlend
|
||||
};
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -30,7 +30,7 @@ TIASurface::TIASurface(OSystem& system)
|
|||
: myOSystem(system),
|
||||
myFB(system.frameBuffer()),
|
||||
myTIA(nullptr),
|
||||
myFilterType(kNormal),
|
||||
myFilter(Filter::Normal),
|
||||
myUsePhosphor(false),
|
||||
myPhosphorPercent(0.60f),
|
||||
myScanlinesEnabled(false),
|
||||
|
@ -53,6 +53,8 @@ TIASurface::TIASurface(OSystem& system)
|
|||
|
||||
// Base TIA surface for use in taking snapshots in 1x mode
|
||||
myBaseTiaSurface = myFB.allocateSurface(kTIAW*2, kTIAH);
|
||||
|
||||
memset(myRGBFramebuffer, 0, 160 * FrameManager::frameBufferHeight);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -97,7 +99,7 @@ void TIASurface::setPalette(const uInt32* tia_palette, const uInt32* rgb_palette
|
|||
|
||||
// The NTSC filtering needs access to the raw RGB data, since it calculates
|
||||
// its own internal palette
|
||||
myNTSCFilter.setTIAPalette(*this, rgb_palette);
|
||||
myNTSCFilter.setTIAPalette(rgb_palette);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -124,7 +126,7 @@ const FBSurface& TIASurface::baseSurface(GUI::Rect& rect) const
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 TIASurface::pixel(uInt32 idx, uInt8 shift) const
|
||||
uInt32 TIASurface::pixel(uInt32 idx, uInt8 shift)
|
||||
{
|
||||
uInt8 c = *(myTIA->frameBuffer() + idx) | shift;
|
||||
|
||||
|
@ -132,13 +134,13 @@ uInt32 TIASurface::pixel(uInt32 idx, uInt8 shift) const
|
|||
return myPalette[c];
|
||||
else
|
||||
{
|
||||
const uInt32 p = *(myTIA->rgbFramebuffer() + idx);
|
||||
const uInt32 p = myRGBFramebuffer[idx];
|
||||
|
||||
// Mix current calculated frame with previous displayed frame
|
||||
const uInt32 retVal = getRGBPhosphor(myPalette[c], p, shift);
|
||||
|
||||
// Store back into displayed frame buffer (for next frame)
|
||||
*(myTIA->rgbFramebuffer() + idx) = retVal;
|
||||
myRGBFramebuffer[idx] = retVal;
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
@ -225,7 +227,7 @@ void TIASurface::enablePhosphor(bool enable, int blend)
|
|||
{
|
||||
myUsePhosphor = enable;
|
||||
myPhosphorPercent = blend / 100.0;
|
||||
myFilterType = FilterType(enable ? myFilterType | 0x01 : myFilterType & 0x10);
|
||||
myFilter = Filter(enable ? uInt8(myFilter) | 0x01 : uInt8(myFilter) & 0x10);
|
||||
myTiaSurface->setDirty();
|
||||
mySLineSurface->setDirty();
|
||||
}
|
||||
|
@ -238,15 +240,15 @@ inline uInt32 TIASurface::getRGBPhosphor(uInt32 c, uInt32 p, uInt8 shift) const
|
|||
myFB.getRGB(c, &rc, &gc, &bc);
|
||||
myFB.getRGB(p, &rp, &gp, &bp);
|
||||
|
||||
// mix current calculated frame with previous displayed frame
|
||||
// Mix current calculated frame with previous displayed frame
|
||||
uInt8 rn = getPhosphor(rc, rp);
|
||||
uInt8 gn = getPhosphor(gc, gp);
|
||||
uInt8 bn = getPhosphor(bc, bp);
|
||||
|
||||
if(shift)
|
||||
{
|
||||
// convert RGB to grayscale
|
||||
rn = gn = bn = (uInt8)(0.2126*rn + 0.7152*gn + 0.0722*bn);
|
||||
// Convert RGB to grayscale
|
||||
rn = gn = bn = uInt8(0.2126*rn + 0.7152*gn + 0.0722*bn);
|
||||
}
|
||||
|
||||
return myFB.mapRGB(rn, gn, bn);
|
||||
|
@ -255,7 +257,7 @@ inline uInt32 TIASurface::getRGBPhosphor(uInt32 c, uInt32 p, uInt8 shift) const
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void TIASurface::enableNTSC(bool enable)
|
||||
{
|
||||
myFilterType = FilterType(enable ? myFilterType | 0x10 : myFilterType & 0x01);
|
||||
myFilter = Filter(enable ? uInt8(myFilter) | 0x10 : uInt8(myFilter) & 0x01);
|
||||
|
||||
// Normal vs NTSC mode uses different source widths
|
||||
myTiaSurface->setSrcSize(enable ? AtariNTSC::outWidth(160) : 160, myTIA->height());
|
||||
|
@ -281,19 +283,19 @@ string TIASurface::effectsInfo() const
|
|||
const FBSurface::Attributes& attr = mySLineSurface->attributes();
|
||||
|
||||
ostringstream buf;
|
||||
switch(myFilterType)
|
||||
switch(myFilter)
|
||||
{
|
||||
case kNormal:
|
||||
case Filter::Normal:
|
||||
buf << "Disabled, normal mode";
|
||||
break;
|
||||
case kPhosphor:
|
||||
case Filter::Phosphor:
|
||||
buf << "Disabled, phosphor mode";
|
||||
break;
|
||||
case kBlarggNormal:
|
||||
case Filter::BlarggNormal:
|
||||
buf << myNTSCFilter.getPreset() << ", scanlines=" << attr.blendalpha << "/"
|
||||
<< (attr.smoothing ? "inter" : "nointer");
|
||||
break;
|
||||
case kBlarggPhosphor:
|
||||
case Filter::BlarggPhosphor:
|
||||
buf << myNTSCFilter.getPreset() << ", phosphor, scanlines="
|
||||
<< attr.blendalpha << "/" << (attr.smoothing ? "inter" : "nointer");
|
||||
break;
|
||||
|
@ -304,36 +306,36 @@ string TIASurface::effectsInfo() const
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void TIASurface::render()
|
||||
{
|
||||
// Copy the mediasource framebuffer to the RGB texture
|
||||
// In hardware rendering mode, it's faster to just assume that the screen
|
||||
// is dirty and always do an update
|
||||
|
||||
uInt8* tiaFrame = myTIA->frameBuffer();
|
||||
uInt32* rgbFrame = myTIA->rgbFramebuffer();
|
||||
uInt32 width = myTIA->width();
|
||||
uInt32 height = myTIA->height();
|
||||
|
||||
uInt32 *buffer, pitch;
|
||||
myTiaSurface->basePtr(buffer, pitch);
|
||||
uInt32 *out, outPitch;
|
||||
myTiaSurface->basePtr(out, outPitch);
|
||||
|
||||
switch(myFilterType)
|
||||
switch(myFilter)
|
||||
{
|
||||
case kNormal:
|
||||
case Filter::Normal:
|
||||
{
|
||||
uInt8* in = myTIA->frameBuffer();
|
||||
|
||||
uInt32 bufofsY = 0, screenofsY = 0, pos = 0;
|
||||
for(uInt32 y = 0; y < height; ++y)
|
||||
{
|
||||
pos = screenofsY;
|
||||
for(uInt32 x = 0; x < width; ++x)
|
||||
buffer[pos++] = myPalette[tiaFrame[bufofsY + x]];
|
||||
out[pos++] = myPalette[in[bufofsY + x]];
|
||||
|
||||
bufofsY += width;
|
||||
screenofsY += pitch;
|
||||
screenofsY += outPitch;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kPhosphor:
|
||||
|
||||
case Filter::Phosphor:
|
||||
{
|
||||
uInt8* tiaIn = myTIA->frameBuffer();
|
||||
uInt32* rgbIn = myRGBFramebuffer;
|
||||
|
||||
uInt32 bufofsY = 0, screenofsY = 0, pos = 0;
|
||||
for(uInt32 y = 0; y < height; ++y)
|
||||
{
|
||||
|
@ -341,29 +343,30 @@ void TIASurface::render()
|
|||
for(uInt32 x = 0; x < width; ++x)
|
||||
{
|
||||
const uInt32 bufofs = bufofsY + x;
|
||||
const uInt8 c = tiaFrame[bufofs];
|
||||
const uInt32 retVal = getRGBPhosphor(myPalette[c], rgbFrame[bufofs]);
|
||||
const uInt8 c = tiaIn[bufofs];
|
||||
const uInt32 retVal = getRGBPhosphor(myPalette[c], rgbIn[bufofs]);
|
||||
|
||||
// Store back into displayed frame buffer (for next frame)
|
||||
rgbFrame[bufofs] = retVal;
|
||||
buffer[pos++] = retVal;
|
||||
rgbIn[bufofs] = retVal;
|
||||
out[pos++] = retVal;
|
||||
}
|
||||
bufofsY += width;
|
||||
screenofsY += pitch;
|
||||
screenofsY += outPitch;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kBlarggNormal:
|
||||
|
||||
case Filter::BlarggNormal:
|
||||
{
|
||||
myNTSCFilter.blit_single(tiaFrame, width, height, buffer, pitch << 2);
|
||||
myNTSCFilter.blit_single(myTIA->frameBuffer(), width, height,
|
||||
out, outPitch << 2);
|
||||
break;
|
||||
}
|
||||
case kBlarggPhosphor:
|
||||
|
||||
case Filter::BlarggPhosphor:
|
||||
{
|
||||
#if 0 // FIXME
|
||||
myNTSCFilter.blit_double(currentFrame, previousFrame, width, height,
|
||||
buffer, pitch << 2);
|
||||
#endif
|
||||
myNTSCFilter.blit_single(myTIA->frameBuffer(), width, height,
|
||||
out, outPitch << 2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ class FrameBuffer;
|
|||
class FBSurface;
|
||||
class VideoMode;
|
||||
|
||||
#include "FrameManager.hxx"
|
||||
#include "Rect.hxx"
|
||||
#include "NTSCFilter.hxx"
|
||||
#include "bspf.hxx"
|
||||
|
@ -73,7 +74,7 @@ class TIASurface
|
|||
Get the TIA pixel associated with the given TIA buffer index,
|
||||
shifting by the given offset (for greyscale values).
|
||||
*/
|
||||
uInt32 pixel(uInt32 idx, uInt8 shift = 0) const;
|
||||
uInt32 pixel(uInt32 idx, uInt8 shift = 0);
|
||||
|
||||
/**
|
||||
Get the NTSCFilter object associated with the framebuffer
|
||||
|
@ -118,7 +119,7 @@ class TIASurface
|
|||
|
||||
@return Averaged value of the two colors
|
||||
*/
|
||||
uInt8 getPhosphor(uInt8 c1, uInt8 c2) const {
|
||||
inline uInt8 getPhosphor(uInt8 c1, uInt8 c2) const {
|
||||
// Use maximum of current and decayed previous values
|
||||
c2 = uInt8(c2 * myPhosphorPercent);
|
||||
if(c1 > c2) return c1; // raise (assumed immediate)
|
||||
|
@ -139,7 +140,7 @@ class TIASurface
|
|||
Enable/disable/query NTSC filtering effects.
|
||||
*/
|
||||
void enableNTSC(bool enable);
|
||||
bool ntscEnabled() const { return myFilterType & 0x10; }
|
||||
bool ntscEnabled() const { return uInt8(myFilter) & 0x10; }
|
||||
string effectsInfo() const;
|
||||
|
||||
/**
|
||||
|
@ -156,13 +157,13 @@ class TIASurface
|
|||
|
||||
// Enumeration created such that phosphor off/on is in LSB,
|
||||
// and Blargg off/on is in MSB
|
||||
enum FilterType {
|
||||
kNormal = 0x00,
|
||||
kPhosphor = 0x01,
|
||||
kBlarggNormal = 0x10,
|
||||
kBlarggPhosphor = 0x11
|
||||
enum class Filter: uInt8 {
|
||||
Normal = 0x00,
|
||||
Phosphor = 0x01,
|
||||
BlarggNormal = 0x10,
|
||||
BlarggPhosphor = 0x11
|
||||
};
|
||||
FilterType myFilterType;
|
||||
Filter myFilter;
|
||||
|
||||
enum TIAConstants {
|
||||
kTIAW = 160,
|
||||
|
@ -173,11 +174,17 @@ class TIASurface
|
|||
// NTSC object to use in TIA rendering mode
|
||||
NTSCFilter myNTSCFilter;
|
||||
|
||||
// Use phosphor effect (aka no flicker on 30Hz screens)
|
||||
/////////////////////////////////////////////////////////////
|
||||
// Phosphor mode items (aka reduced flicker on 30Hz screens)
|
||||
// RGB frame buffer
|
||||
uInt32 myRGBFramebuffer[160 * FrameManager::frameBufferHeight];
|
||||
|
||||
// Use phosphor effect
|
||||
bool myUsePhosphor;
|
||||
|
||||
// Amount to blend when using phosphor effect
|
||||
float myPhosphorPercent;
|
||||
/////////////////////////////////////////////////////////////
|
||||
|
||||
// Use scanlines in TIA rendering mode
|
||||
bool myScanlinesEnabled;
|
||||
|
|
|
@ -88,9 +88,6 @@ TIA::TIA(Console& console, Sound& sound, Settings& settings)
|
|||
}
|
||||
);
|
||||
|
||||
myFramebuffer = make_ptr<uInt8[]>(160 * FrameManager::frameBufferHeight);
|
||||
myRGBFramebuffer = make_ptr<uInt32[]>(160 * FrameManager::frameBufferHeight);
|
||||
|
||||
myTIAPinsDriven = mySettings.getBool("tiadriven");
|
||||
|
||||
myBackground.setTIA(this);
|
||||
|
@ -155,8 +152,7 @@ void TIA::reset()
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void TIA::frameReset()
|
||||
{
|
||||
memset(myFramebuffer.get(), 0, 160 * FrameManager::frameBufferHeight);
|
||||
memset(myRGBFramebuffer.get(), 0, 160 * FrameManager::frameBufferHeight);
|
||||
memset(myFramebuffer, 0, 160 * FrameManager::frameBufferHeight);
|
||||
myAutoFrameEnabled = mySettings.getInt("framerate") <= 0;
|
||||
enableColorLoss(mySettings.getBool("colorloss"));
|
||||
}
|
||||
|
@ -712,7 +708,7 @@ bool TIA::saveDisplay(Serializer& out) const
|
|||
{
|
||||
try
|
||||
{
|
||||
out.putByteArray(myFramebuffer.get(), 160*FrameManager::frameBufferHeight);
|
||||
out.putByteArray(myFramebuffer, 160*FrameManager::frameBufferHeight);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
|
@ -729,7 +725,7 @@ bool TIA::loadDisplay(Serializer& in)
|
|||
try
|
||||
{
|
||||
// Reset frame buffer pointer and data
|
||||
in.getByteArray(myFramebuffer.get(), 160*FrameManager::frameBufferHeight);
|
||||
in.getByteArray(myFramebuffer, 160*FrameManager::frameBufferHeight);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
|
@ -1027,12 +1023,12 @@ void TIA::onFrameComplete()
|
|||
mySystem->resetCycles();
|
||||
|
||||
if (myXAtRenderingStart > 0)
|
||||
memset(myFramebuffer.get(), 0, myXAtRenderingStart);
|
||||
memset(myFramebuffer, 0, myXAtRenderingStart);
|
||||
|
||||
// Blank out any extra lines not drawn this frame
|
||||
const uInt32 missingScanlines = myFrameManager.missingScanlines();
|
||||
if (missingScanlines > 0)
|
||||
memset(myFramebuffer.get() + 160 * myFrameManager.getY(), 0, missingScanlines * 160);
|
||||
memset(myFramebuffer + 160 * myFrameManager.getY(), 0, missingScanlines * 160);
|
||||
|
||||
// Recalculate framerate, attempting to auto-correct for scanline 'jumps'
|
||||
if(myAutoFrameEnabled)
|
||||
|
@ -1143,7 +1139,7 @@ void TIA::applyRsync()
|
|||
|
||||
myHctrDelta = 225 - myHctr;
|
||||
if (myFrameManager.isRendering())
|
||||
memset(myFramebuffer.get() + myFrameManager.getY() * 160 + x, 0, 160 - x);
|
||||
memset(myFramebuffer + myFrameManager.getY() * 160 + x, 0, 160 - x);
|
||||
|
||||
myHctr = 225;
|
||||
}
|
||||
|
@ -1176,7 +1172,7 @@ void TIA::cloneLastLine()
|
|||
|
||||
if (!myFrameManager.isRendering() || y == 0) return;
|
||||
|
||||
uInt8* buffer = myFramebuffer.get();
|
||||
uInt8* buffer = myFramebuffer;
|
||||
|
||||
memcpy(buffer + y * 160, buffer + (y-1) * 160, 160);
|
||||
}
|
||||
|
@ -1243,7 +1239,7 @@ void TIA::renderPixel(uInt32 x, uInt32 y)
|
|||
break;
|
||||
}
|
||||
|
||||
myFramebuffer.get()[y * 160 + x] = myFrameManager.vblank() ? 0 : color;
|
||||
myFramebuffer[y * 160 + x] = myFrameManager.vblank() ? 0 : color;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -1269,8 +1265,7 @@ void TIA::flushLineCache()
|
|||
void TIA::clearHmoveComb()
|
||||
{
|
||||
if (myFrameManager.isRendering() && myHstate == HState::blank)
|
||||
memset(myFramebuffer.get() + myFrameManager.getY() * 160,
|
||||
myColorHBlank, 8);
|
||||
memset(myFramebuffer + myFrameManager.getY() * 160, myColorHBlank, 8);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -157,10 +157,9 @@ class TIA : public Device
|
|||
void update();
|
||||
|
||||
/**
|
||||
Returns a pointer to the internal frame buffer(s).
|
||||
Returns a pointer to the internal frame buffer.
|
||||
*/
|
||||
uInt8* frameBuffer() const { return myFramebuffer.get(); }
|
||||
uInt32* rgbFramebuffer() const { return myRGBFramebuffer.get(); }
|
||||
uInt8* frameBuffer() const { return (uInt8*)(myFramebuffer); }
|
||||
|
||||
/**
|
||||
Answers dimensional info about the framebuffer.
|
||||
|
@ -468,11 +467,8 @@ class TIA : public Device
|
|||
LatchedInput myInput0;
|
||||
LatchedInput myInput1;
|
||||
|
||||
// Pointer to the internal frame buffer
|
||||
BytePtr myFramebuffer;
|
||||
|
||||
// Pointer to the RGB frame buffer (used for phosphor)
|
||||
std::unique_ptr<uInt32[]> myRGBFramebuffer;
|
||||
// Pointer to the internal color-index-based frame buffer
|
||||
uInt8 myFramebuffer[160 * FrameManager::frameBufferHeight];
|
||||
|
||||
bool myTIAPinsDriven;
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ my @prop_defaults = (
|
|||
"0",
|
||||
"0",
|
||||
"NO",
|
||||
"30"
|
||||
"0"
|
||||
);
|
||||
|
||||
# Load and parse a properties file into an hash table of property
|
||||
|
|
Loading…
Reference in New Issue