mirror of https://github.com/stella-emu/stella.git
Huge refactoring of the palette-related code.
This has been developed ad-hoc over the years, with different subsystems (TIA, UI, phosphor, Blargg, etc). This is an attempt to consolidate the code, and also move to C++-style arrays. Still TODO is look into refactoring phosphor stuff out of TIASurface and AtariNTSC classes, since the code is exactly the same, and doesn't really belong in either. This is a major change, so some testing is definitely required.
This commit is contained in:
parent
df4748417d
commit
b276a1e6a7
|
@ -31,28 +31,47 @@
|
|||
#endif
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void AtariNTSC::initialize(const Setup& setup, const uInt8* palette)
|
||||
void AtariNTSC::initialize(const Setup& setup)
|
||||
{
|
||||
init(myImpl, setup);
|
||||
initializePalette(palette);
|
||||
generateKernels();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void AtariNTSC::initializePalette(const uInt8* palette)
|
||||
void AtariNTSC::setPalette(const PaletteArray& palette)
|
||||
{
|
||||
// Palette stores R/G/B data for 'palette_size' entries
|
||||
for ( uInt32 entry = 0; entry < palette_size; ++entry )
|
||||
uInt8* ptr = myRGBPalette.data();
|
||||
for(size_t i = 0; i < palette.size(); ++i)
|
||||
{
|
||||
float r = myImpl.to_float [*palette++],
|
||||
g = myImpl.to_float [*palette++],
|
||||
b = myImpl.to_float [*palette++];
|
||||
*ptr++ = (palette[i] >> 16) & 0xff;
|
||||
*ptr++ = (palette[i] >> 8) & 0xff;
|
||||
*ptr++ = palette[i] & 0xff;
|
||||
}
|
||||
generateKernels();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void AtariNTSC::setPhosphorTable(const PhosphorLUT& table)
|
||||
{
|
||||
myPhosphorLUT = table;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void AtariNTSC::generateKernels()
|
||||
{
|
||||
const uInt8* ptr = myRGBPalette.data();
|
||||
for(size_t entry = 0; entry < myRGBPalette.size() / 3; ++entry)
|
||||
{
|
||||
float r = myImpl.to_float[*ptr++],
|
||||
g = myImpl.to_float[*ptr++],
|
||||
b = myImpl.to_float[*ptr++];
|
||||
float y, i, q; RGB_TO_YIQ( r, g, b, y, i, q );
|
||||
|
||||
// Generate kernel
|
||||
int ir, ig, ib; YIQ_TO_RGB( y, i, q, myImpl.to_rgb.data(), ir, ig, ib );
|
||||
uInt32 rgb = PACK_RGB( ir, ig, ib );
|
||||
|
||||
uInt32* kernel = myColorTable[entry];
|
||||
uInt32* kernel = myColorTable[entry].data();
|
||||
genKernel(myImpl, y, i, q, kernel);
|
||||
|
||||
for ( uInt32 c = 0; c < rgb_kernel_size / 2; ++c )
|
||||
|
@ -306,18 +325,15 @@ void AtariNTSC::renderWithPhosphorThread(const uInt8* atari_in, const uInt32 in_
|
|||
inline uInt32 AtariNTSC::getRGBPhosphor(const uInt32 c, const uInt32 p) const
|
||||
{
|
||||
// Mix current calculated frame with previous displayed frame
|
||||
const uInt8 rc = uInt8(c >> 16);
|
||||
const uInt8 gc = uInt8(c >> 8);
|
||||
const uInt8 bc = uInt8(c);
|
||||
const uInt8 rp = uInt8(p >> 16);
|
||||
const uInt8 gp = uInt8(p >> 8);
|
||||
const uInt8 bp = uInt8(p);
|
||||
const uInt8 rc = static_cast<uInt8>(c >> 16),
|
||||
gc = static_cast<uInt8>(c >> 8),
|
||||
bc = static_cast<uInt8>(c),
|
||||
rp = static_cast<uInt8>(p >> 16),
|
||||
gp = static_cast<uInt8>(p >> 8),
|
||||
bp = static_cast<uInt8>(p);
|
||||
|
||||
const uInt8 rn = myPhosphorPalette[rc][rp];
|
||||
const uInt8 gn = myPhosphorPalette[gc][gp];
|
||||
const uInt8 bn = myPhosphorPalette[bc][bp];
|
||||
|
||||
return (rn << 16) | (gn << 8) | bn;
|
||||
return (myPhosphorLUT[rc][rp] << 16) | (myPhosphorLUT[gc][gp] << 8) |
|
||||
myPhosphorLUT[bc][bp];
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -43,15 +43,14 @@
|
|||
#include <cmath>
|
||||
#include <thread>
|
||||
|
||||
#include "FrameBufferConstants.hxx"
|
||||
#include "bspf.hxx"
|
||||
|
||||
class AtariNTSC
|
||||
{
|
||||
public:
|
||||
static constexpr uInt32 palette_size = 256, entry_size = 2 * 14;
|
||||
|
||||
// By default, threading is turned off
|
||||
AtariNTSC() { enableThreading(false); }
|
||||
// By default, threading is turned off and palette is blank
|
||||
AtariNTSC() { enableThreading(false); myRGBPalette.fill(0); }
|
||||
|
||||
// Image parameters, ranging from -1.0 to 1.0. Actual internal values shown
|
||||
// in parenthesis and should remain fairly stable in future versions.
|
||||
|
@ -78,18 +77,18 @@ class AtariNTSC
|
|||
static const Setup TV_RGB; // crisp image
|
||||
static const Setup TV_Bad; // badly adjusted TV
|
||||
|
||||
// Initializes and adjusts parameters.
|
||||
void initialize(const Setup& setup, const uInt8* palette);
|
||||
void initializePalette(const uInt8* palette);
|
||||
// Initializes and adjusts parameters
|
||||
// Note that this must be called before setting a palette
|
||||
void initialize(const Setup& setup);
|
||||
|
||||
// Set palette for normal Blarrg mode
|
||||
void setPalette(const PaletteArray& palette);
|
||||
// Set phosphor table, for use in calculating phosphor palette
|
||||
void setPhosphorTable(const PhosphorLUT& table);
|
||||
|
||||
// Set up threading
|
||||
void enableThreading(bool enable);
|
||||
|
||||
// Set phosphor palette, for use in Blargg + phosphor mode
|
||||
void setPhosphorPalette(uInt8 palette[256][256]) {
|
||||
memcpy(myPhosphorPalette, palette, 256 * 256);
|
||||
}
|
||||
|
||||
// Filters one or more rows of pixels. Input pixels are 8-bit Atari
|
||||
// palette colors.
|
||||
// In_row_width is the number of pixels to get to the next input row.
|
||||
|
@ -112,6 +111,9 @@ class AtariNTSC
|
|||
}
|
||||
|
||||
private:
|
||||
// Generate kernels from raw RGB palette
|
||||
void generateKernels();
|
||||
|
||||
// Threaded rendering
|
||||
void renderThread(const uInt8* atari_in, const uInt32 in_width,
|
||||
const uInt32 in_height, const uInt32 numThreads, const uInt32 threadNum, void* rgb_out, const uInt32 out_pitch);
|
||||
|
@ -134,6 +136,8 @@ class AtariNTSC
|
|||
PIXEL_out_chunk = 7, // number of output pixels generated per chunk
|
||||
NTSC_black = 0, // palette index for black
|
||||
|
||||
palette_size = 256,
|
||||
entry_size = 2 * 14,
|
||||
alignment_count = 2,
|
||||
burst_count = 1,
|
||||
rescale_in = 8,
|
||||
|
@ -166,8 +170,9 @@ class AtariNTSC
|
|||
luma_cutoff = 0.20F
|
||||
;
|
||||
|
||||
uInt32 myColorTable[palette_size][entry_size];
|
||||
uInt8 myPhosphorPalette[256][256];
|
||||
std::array<uInt8, palette_size*3> myRGBPalette;
|
||||
std::array<std::array<uInt32, entry_size>, palette_size> myColorTable;
|
||||
PhosphorLUT myPhosphorLUT;
|
||||
|
||||
// Rendering threads
|
||||
unique_ptr<std::thread[]> myThreads;
|
||||
|
@ -211,9 +216,9 @@ class AtariNTSC
|
|||
// off a bit. Use atari_ntsc_black for unused pixels.
|
||||
#define ATARI_NTSC_BEGIN_ROW( pixel0, pixel1 ) \
|
||||
unsigned const atari_ntsc_pixel0_ = (pixel0);\
|
||||
uInt32 const* kernel0 = myColorTable[atari_ntsc_pixel0_];\
|
||||
uInt32 const* kernel0 = myColorTable[atari_ntsc_pixel0_].data();\
|
||||
unsigned const atari_ntsc_pixel1_ = (pixel1);\
|
||||
uInt32 const* kernel1 = myColorTable[atari_ntsc_pixel1_];\
|
||||
uInt32 const* kernel1 = myColorTable[atari_ntsc_pixel1_].data();\
|
||||
uInt32 const* kernelx0;\
|
||||
uInt32 const* kernelx1 = kernel0
|
||||
|
||||
|
@ -221,7 +226,7 @@ class AtariNTSC
|
|||
#define ATARI_NTSC_COLOR_IN( index, color ) {\
|
||||
uintptr_t color_;\
|
||||
kernelx##index = kernel##index;\
|
||||
kernel##index = (color_ = (color), myColorTable[color_]);\
|
||||
kernel##index = (color_ = (color), myColorTable[color_].data());\
|
||||
}
|
||||
|
||||
// Generates output in the specified 32-bit format.
|
||||
|
|
|
@ -61,7 +61,7 @@ string NTSCFilter::setPreset(Preset preset)
|
|||
default:
|
||||
return msg;
|
||||
}
|
||||
myNTSC.initialize(mySetup, myTIAPalette);
|
||||
myNTSC.initialize(mySetup);
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ class Settings;
|
|||
|
||||
#include "bspf.hxx"
|
||||
#include "AtariNTSC.hxx"
|
||||
#include "FrameBufferConstants.hxx"
|
||||
|
||||
/**
|
||||
This class is based on the Blargg NTSC filter code from Atari800,
|
||||
|
@ -59,21 +60,11 @@ class NTSCFilter
|
|||
uses this as a baseline for calculating its own internal palette
|
||||
in YIQ format.
|
||||
*/
|
||||
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);
|
||||
void setPalette(const PaletteArray& palette) {
|
||||
myNTSC.setPalette(palette);
|
||||
}
|
||||
|
||||
inline void setPhosphorPalette(uInt8 palette[256][256]) {
|
||||
myNTSC.setPhosphorPalette(palette);
|
||||
void setPhosphorTable(const PhosphorLUT& table) {
|
||||
myNTSC.setPhosphorTable(table);
|
||||
}
|
||||
|
||||
// The following are meant to be used strictly for toggling from the GUI
|
||||
|
@ -146,11 +137,6 @@ class NTSCFilter
|
|||
// Current preset in use
|
||||
Preset myPreset;
|
||||
|
||||
// The base 2600 palette contains 128 normal colours
|
||||
// and 128 black&white colours (PAL colour loss)
|
||||
// Each colour is represented by 3 bytes, in R,G,B order
|
||||
uInt8 myTIAPalette[AtariNTSC::palette_size * 3];
|
||||
|
||||
struct AdjustableTag {
|
||||
const char* const type;
|
||||
float* value;
|
||||
|
|
|
@ -469,10 +469,10 @@ void Console::setPalette(const string& type)
|
|||
{
|
||||
// Look at all the palettes, since we don't know which one is
|
||||
// currently active
|
||||
static uInt32* palettes[3][3] = {
|
||||
{ &ourNTSCPalette[0], &ourPALPalette[0], &ourSECAMPalette[0] },
|
||||
{ &ourNTSCPaletteZ26[0], &ourPALPaletteZ26[0], &ourSECAMPaletteZ26[0] },
|
||||
{ &ourUserNTSCPalette[0], &ourUserPALPalette[0], &ourUserSECAMPalette[0] }
|
||||
static constexpr PaletteArray* palettes[3][3] = {
|
||||
{ &ourNTSCPalette, &ourPALPalette, &ourSECAMPalette },
|
||||
{ &ourNTSCPaletteZ26, &ourPALPaletteZ26, &ourSECAMPaletteZ26 },
|
||||
{ &ourUserNTSCPalette, &ourUserPALPalette, &ourUserSECAMPalette }
|
||||
};
|
||||
|
||||
// See which format we should be using
|
||||
|
@ -485,12 +485,12 @@ void Console::setPalette(const string& type)
|
|||
paletteNum = 2;
|
||||
|
||||
// Now consider the current display format
|
||||
const uInt32* palette =
|
||||
const PaletteArray* palette =
|
||||
(myDisplayFormat.compare(0, 3, "PAL") == 0) ? palettes[paletteNum][1] :
|
||||
(myDisplayFormat.compare(0, 5, "SECAM") == 0) ? palettes[paletteNum][2] :
|
||||
palettes[paletteNum][0];
|
||||
|
||||
myOSystem.frameBuffer().setPalette(palette);
|
||||
myOSystem.frameBuffer().setTIAPalette(*palette);
|
||||
|
||||
if(myTIA->usingFixedColors())
|
||||
myTIA->enableFixedColors(true);
|
||||
|
@ -929,7 +929,7 @@ void Console::loadUserPalette()
|
|||
secam[(i<<1)] = pixel;
|
||||
secam[(i<<1)+1] = 0;
|
||||
}
|
||||
uInt32* ptr = ourUserSECAMPalette;
|
||||
uInt32* ptr = ourUserSECAMPalette.data();
|
||||
for(int i = 0; i < 16; ++i)
|
||||
{
|
||||
uInt32* s = secam;
|
||||
|
@ -1049,7 +1049,7 @@ void Console::stateChanged(EventHandlerState state)
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 Console::ourNTSCPalette[256] = {
|
||||
PaletteArray Console::ourNTSCPalette = {
|
||||
0x000000, 0, 0x4a4a4a, 0, 0x6f6f6f, 0, 0x8e8e8e, 0,
|
||||
0xaaaaaa, 0, 0xc0c0c0, 0, 0xd6d6d6, 0, 0xececec, 0,
|
||||
0x484800, 0, 0x69690f, 0, 0x86861d, 0, 0xa2a22a, 0,
|
||||
|
@ -1085,7 +1085,7 @@ uInt32 Console::ourNTSCPalette[256] = {
|
|||
};
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 Console::ourPALPalette[256] = {
|
||||
PaletteArray Console::ourPALPalette = {
|
||||
0x000000, 0, 0x121212, 0, 0x242424, 0, 0x484848, 0, // 180 0
|
||||
0x6c6c6c, 0, 0x909090, 0, 0xb4b4b4, 0, 0xd8d8d8, 0, // was 0x111111..0xcccccc
|
||||
0x000000, 0, 0x121212, 0, 0x242424, 0, 0x484848, 0, // 198 1
|
||||
|
@ -1121,7 +1121,7 @@ uInt32 Console::ourPALPalette[256] = {
|
|||
};
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 Console::ourSECAMPalette[256] = {
|
||||
PaletteArray Console::ourSECAMPalette = {
|
||||
0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0,
|
||||
0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0,
|
||||
0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0,
|
||||
|
@ -1157,7 +1157,7 @@ uInt32 Console::ourSECAMPalette[256] = {
|
|||
};
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 Console::ourNTSCPaletteZ26[256] = {
|
||||
PaletteArray Console::ourNTSCPaletteZ26 = {
|
||||
0x000000, 0, 0x505050, 0, 0x646464, 0, 0x787878, 0,
|
||||
0x8c8c8c, 0, 0xa0a0a0, 0, 0xb4b4b4, 0, 0xc8c8c8, 0,
|
||||
0x445400, 0, 0x586800, 0, 0x6c7c00, 0, 0x809000, 0,
|
||||
|
@ -1193,7 +1193,7 @@ uInt32 Console::ourNTSCPaletteZ26[256] = {
|
|||
};
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 Console::ourPALPaletteZ26[256] = {
|
||||
PaletteArray Console::ourPALPaletteZ26 = {
|
||||
0x000000, 0, 0x4c4c4c, 0, 0x606060, 0, 0x747474, 0,
|
||||
0x888888, 0, 0x9c9c9c, 0, 0xb0b0b0, 0, 0xc4c4c4, 0,
|
||||
0x000000, 0, 0x4c4c4c, 0, 0x606060, 0, 0x747474, 0,
|
||||
|
@ -1229,7 +1229,7 @@ uInt32 Console::ourPALPaletteZ26[256] = {
|
|||
};
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 Console::ourSECAMPaletteZ26[256] = {
|
||||
PaletteArray Console::ourSECAMPaletteZ26 = {
|
||||
0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0,
|
||||
0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0,
|
||||
0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0,
|
||||
|
@ -1265,10 +1265,10 @@ uInt32 Console::ourSECAMPaletteZ26[256] = {
|
|||
};
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 Console::ourUserNTSCPalette[256] = { 0 }; // filled from external file
|
||||
PaletteArray Console::ourUserNTSCPalette = { 0 }; // filled from external file
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 Console::ourUserPALPalette[256] = { 0 }; // filled from external file
|
||||
PaletteArray Console::ourUserPALPalette = { 0 }; // filled from external file
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 Console::ourUserSECAMPalette[256] = { 0 }; // filled from external file
|
||||
PaletteArray Console::ourUserSECAMPalette = { 0 }; // filled from external file
|
||||
|
|
|
@ -36,6 +36,7 @@ class AudioSettings;
|
|||
#include "Props.hxx"
|
||||
#include "TIAConstants.hxx"
|
||||
#include "FrameBuffer.hxx"
|
||||
#include "FrameBufferConstants.hxx"
|
||||
#include "Serializable.hxx"
|
||||
#include "EventHandlerConstants.hxx"
|
||||
#include "NTSCFilter.hxx"
|
||||
|
@ -422,19 +423,19 @@ class Console : public Serializable, public ConsoleIO
|
|||
AudioSettings& myAudioSettings;
|
||||
|
||||
// Table of RGB values for NTSC, PAL and SECAM
|
||||
static uInt32 ourNTSCPalette[256];
|
||||
static uInt32 ourPALPalette[256];
|
||||
static uInt32 ourSECAMPalette[256];
|
||||
static PaletteArray ourNTSCPalette;
|
||||
static PaletteArray ourPALPalette;
|
||||
static PaletteArray ourSECAMPalette;
|
||||
|
||||
// Table of RGB values for NTSC, PAL and SECAM - Z26 version
|
||||
static uInt32 ourNTSCPaletteZ26[256];
|
||||
static uInt32 ourPALPaletteZ26[256];
|
||||
static uInt32 ourSECAMPaletteZ26[256];
|
||||
static PaletteArray ourNTSCPaletteZ26;
|
||||
static PaletteArray ourPALPaletteZ26;
|
||||
static PaletteArray ourSECAMPaletteZ26;
|
||||
|
||||
// Table of RGB values for NTSC, PAL and SECAM - user-defined
|
||||
static uInt32 ourUserNTSCPalette[256];
|
||||
static uInt32 ourUserPALPalette[256];
|
||||
static uInt32 ourUserSECAMPalette[256];
|
||||
static PaletteArray ourUserNTSCPalette;
|
||||
static PaletteArray ourUserPALPalette;
|
||||
static PaletteArray ourUserSECAMPalette;
|
||||
|
||||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
|
|
|
@ -67,7 +67,7 @@ void FBSurface::pixel(uInt32 x, uInt32 y, ColorId color)
|
|||
// Note: checkbounds() must be done in calling method
|
||||
uInt32* buffer = myPixels + y * myPitch + x;
|
||||
|
||||
*buffer = uInt32(myPalette[color]);
|
||||
*buffer = myPalette[color];
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -140,7 +140,7 @@ void FBSurface::hLine(uInt32 x, uInt32 y, uInt32 x2, ColorId color)
|
|||
|
||||
uInt32* buffer = myPixels + y * myPitch + x;
|
||||
while(x++ <= x2)
|
||||
*buffer++ = uInt32(myPalette[color]);
|
||||
*buffer++ = myPalette[color];
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -152,7 +152,7 @@ void FBSurface::vLine(uInt32 x, uInt32 y, uInt32 y2, ColorId color)
|
|||
uInt32* buffer = static_cast<uInt32*>(myPixels + y * myPitch + x);
|
||||
while(y++ <= y2)
|
||||
{
|
||||
*buffer = uInt32(myPalette[color]);
|
||||
*buffer = myPalette[color];
|
||||
buffer += myPitch;
|
||||
}
|
||||
}
|
||||
|
@ -219,7 +219,7 @@ void FBSurface::drawChar(const GUI::Font& font, uInt8 chr,
|
|||
|
||||
for(int x = 0; x < bbw; x++, mask >>= 1)
|
||||
if(ptr & mask)
|
||||
buffer[x] = uInt32(myPalette[color]);
|
||||
buffer[x] = myPalette[color];
|
||||
|
||||
buffer += myPitch;
|
||||
}
|
||||
|
@ -247,7 +247,7 @@ void FBSurface::drawBitmap(const uInt32* bitmap, uInt32 tx, uInt32 ty,
|
|||
uInt32 mask = 1 << (w - 1);
|
||||
for(uInt32 x = 0; x < w; ++x, mask >>= 1)
|
||||
if(bitmap[y] & mask)
|
||||
buffer[x] = uInt32(myPalette[color]);
|
||||
buffer[x] = myPalette[color];
|
||||
|
||||
buffer += myPitch;
|
||||
}
|
||||
|
@ -449,10 +449,4 @@ bool FBSurface::checkBounds(const uInt32 x, const uInt32 y) const
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const uInt32* FBSurface::myPalette = nullptr;
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool operator==(const FBSurface::Attributes& a1, const FBSurface::Attributes& a2)
|
||||
{
|
||||
return a1.blendalpha == a2.blendalpha && a1.blending == a2.blending;
|
||||
}
|
||||
FullPaletteArray FBSurface::myPalette = { 0 };
|
||||
|
|
|
@ -329,6 +329,10 @@ class FBSurface
|
|||
struct Attributes {
|
||||
bool blending; // Blending is enabled
|
||||
uInt32 blendalpha; // Alpha to use in blending mode (0-100%)
|
||||
|
||||
bool operator==(const Attributes& other) const {
|
||||
return blendalpha == other.blendalpha && blending == other.blending;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -347,7 +351,7 @@ class FBSurface
|
|||
*/
|
||||
virtual void applyAttributes() = 0;
|
||||
|
||||
static void setPalette(const uInt32* palette) { myPalette = palette; }
|
||||
static void setPalette(const FullPaletteArray& palette) { myPalette = palette; }
|
||||
|
||||
protected:
|
||||
/**
|
||||
|
@ -370,12 +374,13 @@ class FBSurface
|
|||
bool isWhiteSpace(const char s) const;
|
||||
|
||||
protected:
|
||||
static const uInt32* myPalette;
|
||||
uInt32* myPixels;
|
||||
uInt32 myPitch;
|
||||
|
||||
Attributes myAttributes;
|
||||
|
||||
static FullPaletteArray myPalette;
|
||||
|
||||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
FBSurface(const FBSurface&) = delete;
|
||||
|
@ -384,6 +389,4 @@ class FBSurface
|
|||
FBSurface& operator=(FBSurface&&) = delete;
|
||||
};
|
||||
|
||||
bool operator==(const FBSurface::Attributes& a1, const FBSurface::Attributes& a2);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -153,27 +153,6 @@ bool FrameBuffer::initialize()
|
|||
return true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBuffer::setUIPalette()
|
||||
{
|
||||
// Set palette for GUI (upper area of array)
|
||||
int palID = 0;
|
||||
if(myOSystem.settings().getString("uipalette") == "classic")
|
||||
palID = 1;
|
||||
else if(myOSystem.settings().getString("uipalette") == "light")
|
||||
palID = 2;
|
||||
|
||||
for(uInt32 i = 0, j = 256; i < kNumColors - 256; ++i, ++j)
|
||||
{
|
||||
uInt8 r = (ourGUIColors[palID][i] >> 16) & 0xff;
|
||||
uInt8 g = (ourGUIColors[palID][i] >> 8) & 0xff;
|
||||
uInt8 b = ourGUIColors[palID][i] & 0xff;
|
||||
|
||||
myPalette[j] = mapRGB(r, g, b);
|
||||
}
|
||||
FBSurface::setPalette(myPalette);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
FBInitStatus FrameBuffer::createDisplay(const string& title,
|
||||
uInt32 width, uInt32 height,
|
||||
|
@ -481,8 +460,8 @@ void FrameBuffer::drawFrameStats(float framesPerSecond)
|
|||
myStatsMsg.surface->invalidate();
|
||||
|
||||
// draw scanlines
|
||||
ColorId color = myOSystem.console().tia().frameBufferScanlinesLastFrame() != myLastScanlines ?
|
||||
kDbgColorRed : myStatsMsg.color;
|
||||
ColorId color = myOSystem.console().tia().frameBufferScanlinesLastFrame() !=
|
||||
myLastScanlines ? kDbgColorRed : myStatsMsg.color;
|
||||
|
||||
ss
|
||||
<< myOSystem.console().tia().frameBufferScanlinesLastFrame()
|
||||
|
@ -504,7 +483,7 @@ void FrameBuffer::drawFrameStats(float framesPerSecond)
|
|||
<< "% speed";
|
||||
|
||||
myStatsMsg.surface->drawString(f, ss.str(), xPos, yPos,
|
||||
myStatsMsg.w, myStatsMsg.color, TextAlign::Left, 0, true, kBGColor);
|
||||
myStatsMsg.w, myStatsMsg.color, TextAlign::Left, 0, true, kBGColor);
|
||||
|
||||
yPos += dy;
|
||||
ss.str("");
|
||||
|
@ -682,20 +661,48 @@ void FrameBuffer::resetSurfaces()
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBuffer::setPalette(const uInt32* raw_palette)
|
||||
void FrameBuffer::setTIAPalette(const PaletteArray& rgb_palette)
|
||||
{
|
||||
// Set palette for normal fill
|
||||
// Create a TIA palette from the raw RGB data
|
||||
PaletteArray tia_palette;
|
||||
for(int i = 0; i < 256; ++i)
|
||||
{
|
||||
uInt8 r = (raw_palette[i] >> 16) & 0xff;
|
||||
uInt8 g = (raw_palette[i] >> 8) & 0xff;
|
||||
uInt8 b = raw_palette[i] & 0xff;
|
||||
uInt8 r = (rgb_palette[i] >> 16) & 0xff;
|
||||
uInt8 g = (rgb_palette[i] >> 8) & 0xff;
|
||||
uInt8 b = rgb_palette[i] & 0xff;
|
||||
|
||||
myPalette[i] = mapRGB(r, g, b);
|
||||
tia_palette[i] = mapRGB(r, g, b);
|
||||
}
|
||||
|
||||
// Remember the TIA palette; place it at the beginning of the full palette
|
||||
std::copy_n(tia_palette.begin(), tia_palette.size(), myFullPalette.begin());
|
||||
|
||||
// Let the TIA surface know about the new palette
|
||||
myTIASurface->setPalette(myPalette, raw_palette);
|
||||
myTIASurface->setPalette(tia_palette, rgb_palette);
|
||||
|
||||
// Since the UI palette shares the TIA palette, we need to update it too
|
||||
setUIPalette();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBuffer::setUIPalette()
|
||||
{
|
||||
// Set palette for UI (upper area of full palette)
|
||||
const UIPaletteArray& ui_palette =
|
||||
(myOSystem.settings().getString("uipalette") == "classic") ? ourClassicUIPalette :
|
||||
(myOSystem.settings().getString("uipalette") == "light") ? ourLightUIPalette :
|
||||
ourStandardUIPalette;
|
||||
|
||||
for(size_t i = 0, j = myFullPalette.size() - ui_palette.size();
|
||||
i < ui_palette.size(); ++i, ++j)
|
||||
{
|
||||
const uInt8 r = (ui_palette[i] >> 16) & 0xff,
|
||||
g = (ui_palette[i] >> 8) & 0xff,
|
||||
b = ui_palette[i] & 0xff;
|
||||
|
||||
myFullPalette[j] = mapRGB(r, g, b);
|
||||
}
|
||||
FBSurface::setPalette(myFullPalette);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -1235,8 +1242,7 @@ void FrameBuffer::VideoModeList::setByStretch(FrameBuffer::VideoMode::Stretch st
|
|||
kColorTitleBarLo Disabled title bar color
|
||||
kColorTitleTextLo Disabled title text color
|
||||
*/
|
||||
uInt32 FrameBuffer::ourGUIColors[3][kNumColors-256] = {
|
||||
// Standard
|
||||
UIPaletteArray FrameBuffer::ourStandardUIPalette = {
|
||||
{ 0x686868, 0x000000, 0xa38c61, 0xdccfa5, 0x404040, // base
|
||||
0x000000, 0xac3410, 0x9f0000, 0xf0f0cf, // text
|
||||
0xc9af7c, 0xf0f0cf, 0xd55941, 0xc80000, // UI elements
|
||||
|
@ -1246,8 +1252,10 @@ uInt32 FrameBuffer::ourGUIColors[3][kNumColors-256] = {
|
|||
0xc80000, 0xffff80, 0xc8c8ff, 0xc80000, // debugger
|
||||
0xac3410, 0xd55941, 0xdccfa5, 0xf0f0cf, 0xa38c61, // slider
|
||||
0xffffff, 0xac3410, 0xf0f0cf, 0x686868, 0xdccfa5 // other
|
||||
},
|
||||
// Classic
|
||||
}
|
||||
};
|
||||
|
||||
UIPaletteArray FrameBuffer::ourClassicUIPalette = {
|
||||
{ 0x686868, 0x000000, 0x404040, 0x404040, 0x404040, // base
|
||||
0x20a020, 0x00ff00, 0xc80000, 0x000000, // text
|
||||
0x000000, 0x000000, 0x00ff00, 0xc80000, // UI elements
|
||||
|
@ -1257,8 +1265,10 @@ uInt32 FrameBuffer::ourGUIColors[3][kNumColors-256] = {
|
|||
0xc80000, 0x00ff00, 0xc8c8ff, 0xc80000, // debugger
|
||||
0x20a020, 0x00ff00, 0x404040, 0x686868, 0x404040, // slider
|
||||
0x00ff00, 0x20a020, 0x000000, 0x686868, 0x404040 // other
|
||||
},
|
||||
// Light
|
||||
}
|
||||
};
|
||||
|
||||
UIPaletteArray FrameBuffer::ourLightUIPalette = {
|
||||
{ 0x808080, 0x000000, 0xc0c0c0, 0xe1e1e1, 0x333333, // base
|
||||
0x000000, 0xBDDEF9, 0x0078d7, 0x000000, // text
|
||||
0xf0f0f0, 0xffffff, 0x0078d7, 0x0f0f0f, // UI elements
|
||||
|
|
|
@ -102,11 +102,6 @@ class FrameBuffer
|
|||
*/
|
||||
bool initialize();
|
||||
|
||||
/**
|
||||
Set palette for user interface
|
||||
*/
|
||||
void setUIPalette();
|
||||
|
||||
/**
|
||||
(Re)creates the framebuffer display. This must be called before any
|
||||
calls are made to derived methods.
|
||||
|
@ -184,6 +179,19 @@ class FrameBuffer
|
|||
const uInt32* data = nullptr
|
||||
);
|
||||
|
||||
/**
|
||||
Set up the TIA/emulation palette. Due to the way the palette is stored,
|
||||
a call to this method implicitly calls setUIPalette() too.
|
||||
|
||||
@param rgb_palette The array of colors in R/G/B format
|
||||
*/
|
||||
void setTIAPalette(const PaletteArray& rgb_palette);
|
||||
|
||||
/**
|
||||
Set palette for user interface.
|
||||
*/
|
||||
void setUIPalette();
|
||||
|
||||
/**
|
||||
Returns the current dimensions of the framebuffer image.
|
||||
Note that this will take into account the current scaling (if any)
|
||||
|
@ -273,13 +281,6 @@ class FrameBuffer
|
|||
*/
|
||||
void toggleGrabMouse();
|
||||
|
||||
/**
|
||||
Set up the TIA/emulation palette for a screen of any depth > 8.
|
||||
|
||||
@param raw_palette The array of colors in R/G/B format
|
||||
*/
|
||||
void setPalette(const uInt32* raw_palette);
|
||||
|
||||
/**
|
||||
Informs the Framebuffer of a change in EventHandler state.
|
||||
*/
|
||||
|
@ -456,9 +457,6 @@ z
|
|||
// The parent system for the framebuffer
|
||||
OSystem& myOSystem;
|
||||
|
||||
// Color palette for TIA and UI modes
|
||||
uInt32 myPalette[256+kNumColors];
|
||||
|
||||
private:
|
||||
/**
|
||||
Draw pending messages.
|
||||
|
@ -625,8 +623,9 @@ z
|
|||
// Holds a reference to all the surfaces that have been created
|
||||
vector<shared_ptr<FBSurface>> mySurfaceList;
|
||||
|
||||
// Holds UI palette data (standard and classic colours)
|
||||
static uInt32 ourGUIColors[3][kNumColors-256];
|
||||
FullPaletteArray myFullPalette;
|
||||
// Holds UI palette data (for each variation)
|
||||
static UIPaletteArray ourStandardUIPalette, ourClassicUIPalette, ourLightUIPalette;
|
||||
|
||||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
|
|
|
@ -102,6 +102,14 @@ static constexpr ColorId
|
|||
kNone = 0 // placeholder to represent default/no color
|
||||
;
|
||||
|
||||
// Palette for normal TIA, UI and both combined
|
||||
using PaletteArray = std::array<uInt32, kColor>;
|
||||
using UIPaletteArray = std::array<uInt32, kNumColors-kColor>;
|
||||
using FullPaletteArray = std::array<uInt32, kNumColors>;
|
||||
|
||||
// Lookup table for phosphor mode, for generating corresponding palette
|
||||
using PhosphorLUT = std::array<std::array<uInt8, kColor>, kColor>;
|
||||
|
||||
// Text alignment modes for drawString()
|
||||
enum class TextAlign {
|
||||
Left,
|
||||
|
|
|
@ -43,7 +43,6 @@ TIASurface::TIASurface(OSystem& system)
|
|||
myUsePhosphor(false),
|
||||
myPhosphorPercent(0.60f),
|
||||
myScanlinesEnabled(false),
|
||||
myPalette(nullptr),
|
||||
mySaveSnapFlag(false)
|
||||
{
|
||||
// Load NTSC filter settings
|
||||
|
@ -119,13 +118,14 @@ cerr << "SLine:\n"
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void TIASurface::setPalette(const uInt32* tia_palette, const uInt32* rgb_palette)
|
||||
void TIASurface::setPalette(const PaletteArray& tia_palette,
|
||||
const PaletteArray& rgb_palette)
|
||||
{
|
||||
myPalette = tia_palette;
|
||||
|
||||
// The NTSC filtering needs access to the raw RGB data, since it calculates
|
||||
// its own internal palette
|
||||
myNTSCFilter.setTIAPalette(rgb_palette);
|
||||
myNTSCFilter.setPalette(rgb_palette);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -226,29 +226,27 @@ void TIASurface::enablePhosphor(bool enable, int blend)
|
|||
// Precalculate the average colors for the 'phosphor' effect
|
||||
if(myUsePhosphor)
|
||||
{
|
||||
for(int c = 255; c >= 0; c--)
|
||||
for(int p = 255; p >= 0; p--)
|
||||
myPhosphorPalette[c][p] = getPhosphor(uInt8(c), uInt8(p));
|
||||
for(int c = 255; c >= 0; --c)
|
||||
for(int p = 255; p >= 0; --p)
|
||||
myPhosphorLUT[c][p] = getPhosphor(uInt8(c), uInt8(p));
|
||||
|
||||
myNTSCFilter.setPhosphorPalette(myPhosphorPalette);
|
||||
myNTSCFilter.setPhosphorTable(myPhosphorLUT);
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
inline uInt32 TIASurface::getRGBPhosphor(const uInt32 c, const uInt32 p) const
|
||||
{
|
||||
#define TO_RGB(color, red, green, blue) \
|
||||
const uInt8 red = color >> 16; const uInt8 green = color >> 8; const uInt8 blue = color;
|
||||
|
||||
TO_RGB(c, rc, gc, bc)
|
||||
TO_RGB(p, rp, gp, bp)
|
||||
|
||||
// Mix current calculated frame with previous displayed frame
|
||||
const uInt8 rn = myPhosphorPalette[rc][rp];
|
||||
const uInt8 gn = myPhosphorPalette[gc][gp];
|
||||
const uInt8 bn = myPhosphorPalette[bc][bp];
|
||||
const uInt8 rc = static_cast<uInt8>(c >> 16),
|
||||
gc = static_cast<uInt8>(c >> 8),
|
||||
bc = static_cast<uInt8>(c),
|
||||
rp = static_cast<uInt8>(p >> 16),
|
||||
gp = static_cast<uInt8>(p >> 8),
|
||||
bp = static_cast<uInt8>(p);
|
||||
|
||||
return (rn << 16) | (gn << 8) | bn;
|
||||
return (myPhosphorLUT[rc][rp] << 16) | (myPhosphorLUT[gc][gp] << 8) |
|
||||
myPhosphorLUT[bc][bp];
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -302,12 +300,16 @@ string TIASurface::effectsInfo() const
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
inline uInt32 TIASurface::averageBuffers(uInt32 bufOfs)
|
||||
{
|
||||
uInt32 c = myRGBFramebuffer[bufOfs];
|
||||
uInt32 p = myPrevRGBFramebuffer[bufOfs];
|
||||
const uInt32 c = myRGBFramebuffer[bufOfs];
|
||||
const uInt32 p = myPrevRGBFramebuffer[bufOfs];
|
||||
|
||||
// Split into RGB values
|
||||
TO_RGB(c, rc, gc, bc)
|
||||
TO_RGB(p, rp, gp, bp)
|
||||
const uInt8 rc = static_cast<uInt8>(c >> 16),
|
||||
gc = static_cast<uInt8>(c >> 8),
|
||||
bc = static_cast<uInt8>(c),
|
||||
rp = static_cast<uInt8>(p >> 16),
|
||||
gp = static_cast<uInt8>(p >> 8),
|
||||
bp = static_cast<uInt8>(p);
|
||||
|
||||
// Mix current calculated buffer with previous calculated buffer (50:50)
|
||||
const uInt8 rn = (rc + rp) / 2;
|
||||
|
@ -315,7 +317,7 @@ inline uInt32 TIASurface::averageBuffers(uInt32 bufOfs)
|
|||
const uInt8 bn = (bc + bp) / 2;
|
||||
|
||||
// return averaged value
|
||||
return (rn << 16) | (gn << 8) | bn;
|
||||
return (rn << 16) | (gn << 8) | bn;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -64,7 +64,7 @@ class TIASurface
|
|||
@param rgb_palette The RGB components of the palette, needed for
|
||||
calculating a phosphor palette
|
||||
*/
|
||||
void setPalette(const uInt32* tia_palette, const uInt32* rgb_palette);
|
||||
void setPalette(const PaletteArray& tia_palette, const PaletteArray& rgb_palette);
|
||||
|
||||
/**
|
||||
Get the TIA base surface for use in saving to a PNG image.
|
||||
|
@ -202,14 +202,14 @@ class TIASurface
|
|||
float myPhosphorPercent;
|
||||
|
||||
// Precalculated averaged phosphor colors
|
||||
uInt8 myPhosphorPalette[256][256];
|
||||
PhosphorLUT myPhosphorLUT;
|
||||
/////////////////////////////////////////////////////////////
|
||||
|
||||
// Use scanlines in TIA rendering mode
|
||||
bool myScanlinesEnabled;
|
||||
|
||||
// Palette for normal TIA rendering mode
|
||||
const uInt32* myPalette;
|
||||
PaletteArray myPalette;
|
||||
|
||||
// Flag for saving a snapshot
|
||||
bool mySaveSnapFlag;
|
||||
|
|
|
@ -28,7 +28,7 @@ class AbstractFrameManager : public Serializable
|
|||
{
|
||||
public:
|
||||
|
||||
using callback = std::function<void()>;
|
||||
using callback = std::function<void()>;
|
||||
|
||||
public:
|
||||
|
||||
|
|
Loading…
Reference in New Issue