BizHawk/psx/octoshock/video/surface.h

336 lines
9.3 KiB
C++

#ifndef __MDFN_SURFACE_H
#define __MDFN_SURFACE_H
struct MDFN_Rect
{
int32 x, y, w, h;
};
enum
{
MDFN_COLORSPACE_RGB = 0,
//MDFN_COLORSPACE_LRGB = 1, // Linear RGB, 16-bit per component, TODO in the future?
//MDFN_COLORSPACE_YUV = 2, // TODO, maybe.
};
struct MDFN_PaletteEntry
{
uint8 r, g, b;
};
/*
template<typename T>
static constexpr INLINE uint64 MDFN_PixelFormat_SetTagT(const uint64 tag)
{
return (tag & ~0xFF) | (sizeof(T) * 8);
}
*/
static constexpr INLINE uint64 MDFN_PixelFormat_MakeTag(const uint8 colorspace,
const uint8 opp,
const uint8 rs, const uint8 gs, const uint8 bs, const uint8 as,
const uint8 rp, const uint8 gp, const uint8 bp, const uint8 ap)
{
// (8 * 6) = 48
return ((uint64)colorspace << 56) | ((uint64)opp << 48) |
((uint64)rs << (0 * 6)) | ((uint64)gs << (1 * 6)) | ((uint64)bs << (2 * 6)) | ((uint64)as << (3 * 6)) |
((uint64)rp << (4 * 6)) | ((uint64)gp << (5 * 6)) | ((uint64)bp << (6 * 6)) | ((uint64)ap << (7 * 6));
}
class MDFN_PixelFormat
{
public:
//
// MDFN_PixelFormat constructors must remain inline for various code to be optimized
// properly by the compiler.
//
INLINE MDFN_PixelFormat(const uint64 tag_) :
tag(tag_),
colorspace((uint8)(tag_ >> 56)),
opp((uint8)(tag_ >> 48)),
Rshift((tag_ >> (0 * 6)) & 0x3F),
Gshift((tag_ >> (1 * 6)) & 0x3F),
Bshift((tag_ >> (2 * 6)) & 0x3F),
Ashift((tag_ >> (3 * 6)) & 0x3F),
Rprec((tag_ >> (4 * 6)) & 0x3F),
Gprec((tag_ >> (5 * 6)) & 0x3F),
Bprec((tag_ >> (6 * 6)) & 0x3F),
Aprec((tag_ >> (7 * 6)) & 0x3F)
{
//
}
INLINE MDFN_PixelFormat() :
tag(0),
colorspace(0),
opp(0),
Rshift(0), Gshift(0), Bshift(0), Ashift(0),
Rprec(0), Gprec(0), Bprec(0), Aprec(0)
{
//
}
INLINE MDFN_PixelFormat(const unsigned int colorspace_,
const uint8 opp_,
const uint8 rs, const uint8 gs, const uint8 bs, const uint8 as,
const uint8 rp = 8, const uint8 gp = 8, const uint8 bp = 8, const uint8 ap = 8) :
tag(MDFN_PixelFormat_MakeTag(colorspace_, opp_, rs, gs, bs, as, rp, gp, bp, ap)),
colorspace(colorspace_),
opp(opp_),
Rshift(rs), Gshift(gs), Bshift(bs), Ashift(as),
Rprec(rp), Gprec(gp), Bprec(bp), Aprec(ap)
{
//
}
//constexpr MDFN_PixelFormat(MDFN_PixelFormat&) = default;
//constexpr MDFN_PixelFormat(MDFN_PixelFormat&&) = default;
//MDFN_PixelFormat& operator=(MDFN_PixelFormat&) = default;
bool operator==(const uint64& t)
{
return tag == t;
}
bool operator==(const MDFN_PixelFormat& a)
{
return tag == a.tag;
}
bool operator!=(const MDFN_PixelFormat& a)
{
return !(*this == a);
}
uint64 tag;
uint8 colorspace;
uint8 opp; // Bytes per pixel; 1, 2, 4 (1 is WIP)
uint8 Rshift; // Bit position of the lowest bit of the red component
uint8 Gshift; // [...] green component
uint8 Bshift; // [...] blue component
uint8 Ashift; // [...] alpha component.
// For 16bpp, WIP
uint8 Rprec;
uint8 Gprec;
uint8 Bprec;
uint8 Aprec;
// Creates a color value for the surface corresponding to the 8-bit R/G/B/A color passed.
INLINE uint32 MakeColor(uint8 r, uint8 g, uint8 b, uint8 a = 0) const
{
if(opp == 2)
{
uint32 ret;
ret = ((r * ((1 << Rprec) - 1) + 127) / 255) << Rshift;
ret |= ((g * ((1 << Gprec) - 1) + 127) / 255) << Gshift;
ret |= ((b * ((1 << Bprec) - 1) + 127) / 255) << Bshift;
ret |= ((a * ((1 << Aprec) - 1) + 127) / 255) << Ashift;
return ret;
}
else
return (r << Rshift) | (g << Gshift) | (b << Bshift) | (a << Ashift);
}
INLINE MDFN_PaletteEntry MakePColor(uint8 r, uint8 g, uint8 b) const
{
MDFN_PaletteEntry ret;
ret.r = ((r * ((1 << Rprec) - 1) + 127) / 255) << Rshift;
ret.g = ((g * ((1 << Gprec) - 1) + 127) / 255) << Gshift;
ret.b = ((b * ((1 << Bprec) - 1) + 127) / 255) << Bshift;
return ret;
}
INLINE void DecodePColor(const MDFN_PaletteEntry& pe, uint8 &r, uint8 &g, uint8 &b) const
{
r = ((pe.r >> Rshift) & ((1 << Rprec) - 1)) * 255 / ((1 << Rprec) - 1);
g = ((pe.g >> Gshift) & ((1 << Gprec) - 1)) * 255 / ((1 << Gprec) - 1);
b = ((pe.b >> Bshift) & ((1 << Bprec) - 1)) * 255 / ((1 << Bprec) - 1);
}
// Gets the R/G/B/A values for the passed 32-bit surface pixel value
INLINE void DecodeColor(uint32 value, int &r, int &g, int &b, int &a) const
{
if(opp == 2)
{
r = ((value >> Rshift) & ((1 << Rprec) - 1)) * 255 / ((1 << Rprec) - 1);
g = ((value >> Gshift) & ((1 << Gprec) - 1)) * 255 / ((1 << Gprec) - 1);
b = ((value >> Bshift) & ((1 << Bprec) - 1)) * 255 / ((1 << Bprec) - 1);
a = ((value >> Ashift) & ((1 << Aprec) - 1)) * 255 / ((1 << Aprec) - 1);
}
else
{
r = (value >> Rshift) & 0xFF;
g = (value >> Gshift) & 0xFF;
b = (value >> Bshift) & 0xFF;
a = (value >> Ashift) & 0xFF;
}
}
MDFN_HIDE static const uint8 LUT5to8[32];
MDFN_HIDE static const uint8 LUT6to8[64];
MDFN_HIDE static const uint8 LUT8to5[256];
MDFN_HIDE static const uint8 LUT8to6[256];
INLINE void DecodeColor(uint32 value, int &r, int &g, int &b) const
{
int dummy_a;
DecodeColor(value, r, g, b, dummy_a);
}
static INLINE void TDecodeColor(uint64 tag, uint32 c, int* r, int* g, int* b)
{
if(tag == IRGB16_1555)
{
*r = LUT5to8[(c >> 10) & 0x1F];
*g = LUT5to8[(c >> 5) & 0x1F];
*b = LUT5to8[(c >> 0) & 0x1F];
//*a = 0;
}
else if(tag == RGB16_565)
{
*r = LUT5to8[(c >> 11) & 0x1F];
*g = LUT6to8[(c >> 5) & 0x3F];
*b = LUT5to8[(c >> 0) & 0x1F];
//*a = 0;
}
else
{
MDFN_PixelFormat pf = tag;
pf.DecodeColor(c, *r, *g, *b);
}
}
static INLINE uint32 TMakeColor(uint64 tag, uint8 r, uint8 g, uint8 b)
{
if(tag == IRGB16_1555)
return (LUT8to5[r] << 10) | (LUT8to5[g] << 5) | (LUT8to5[b] << 0);
else if(tag == RGB16_565)
return (LUT8to5[r] << 11) | (LUT8to6[g] << 5) | (LUT8to5[b] << 0);
else
{
MDFN_PixelFormat pf = tag;
return pf.MakeColor(r, g, b);
}
}
enum : uint64
{
//
// All 24 possible RGB-colorspace xxxx32_8888 formats are supported by core Mednafen and emulation modules,
// but the ones not enumerated here will be less performant.
//
// In regards to emulation modules' video output, the alpha channel is for internal use,
// and should be ignored by driver-side/frontend code.
//
ABGR32_8888 = MDFN_PixelFormat_MakeTag(MDFN_COLORSPACE_RGB, 4, /**/ 0, 8, 16, 24, /**/ 8, 8, 8, 8),
ARGB32_8888 = MDFN_PixelFormat_MakeTag(MDFN_COLORSPACE_RGB, 4, /**/ 16, 8, 0, 24, /**/ 8, 8, 8, 8),
RGBA32_8888 = MDFN_PixelFormat_MakeTag(MDFN_COLORSPACE_RGB, 4, /**/ 24, 16, 8, 0, /**/ 8, 8, 8, 8),
BGRA32_8888 = MDFN_PixelFormat_MakeTag(MDFN_COLORSPACE_RGB, 4, /**/ 8, 16, 24, 0, /**/ 8, 8, 8, 8),
//
// These two RGB16 formats are the only 16-bit formats fully supported by core Mednafen code,
// and most emulation modules(also see MDFNGI::ExtraVideoFormatSupport)
//
// Alpha shift/precision weirdness for internal emulation module use.
//
IRGB16_1555 = MDFN_PixelFormat_MakeTag(MDFN_COLORSPACE_RGB, 2, /**/ 10, 5, 0, 16, /**/ 5, 5, 5, 8),
RGB16_565 = MDFN_PixelFormat_MakeTag(MDFN_COLORSPACE_RGB, 2, /**/ 11, 5, 0, 16, /**/ 5, 6, 5, 8),
//
// Following formats are not supported by emulation modules, and only partially supported by core
// Mednafen code:
//
ARGB16_4444 = MDFN_PixelFormat_MakeTag(MDFN_COLORSPACE_RGB, 2, /**/ 8, 4, 0, 12, /**/ 4, 4, 4, 4),
//
// TODO: Following two hackyish formats are only valid when used as a destination pixel format with
// MDFN_PixelFormatConverter
//
// RGB8X3_888 = MDFN_PixelFormat_MakeTag(MDFN_COLORSPACE_RGB, 3, /**/ 0, 1, 2, 0, /**/ 8, 8, 8, 0),
// BGR8X3_888 = MDFN_PixelFormat_MakeTag(MDFN_COLORSPACE_RGB, 3, /**/ 2, 1, 0, 0, /**/ 8, 8, 8, 0),
//
// TODO:
//RGB8P_888 = MDFN_PixelFormat_MakeTag(MDFN_COLORSPACE_RGB, 1, /**/ 0, 0, 0, 8, /**/ 8, 8, 8, 0),
//RGB8P_666 = MDFN_PixelFormat_MakeTag(MDFN_COLORSPACE_RGB, 1, /**/ 0, 0, 0, 8, /**/ 6, 6, 6, 0),
};
}; // MDFN_PixelFormat;
// 8bpp support is incomplete
class MDFN_Surface
{
public:
MDFN_Surface();
MDFN_Surface(void *const p_pixels, const uint32 p_width, const uint32 p_height, const uint32 p_pitchinpix, const MDFN_PixelFormat &nf, const bool alloc_init_pixels = true);
~MDFN_Surface();
uint8 *pixels8;
uint16 *pixels16;
uint32 *pixels;
template<typename T>
T* pix(void)
{
if(sizeof(T) == 1)
return (T*)pixels8;
else if(sizeof(T) == 2)
return (T*)pixels16;
else if(sizeof(T) == 4)
return (T*)pixels;
else
return NULL;
}
MDFN_PaletteEntry *palette;
bool pixels_is_external;
// w, h, and pitch32 should always be > 0
int32 w;
int32 h;
union
{
int32 pitch32; // In pixels, not in bytes.
int32 pitchinpix; // New name, new code should use this.
};
MDFN_PixelFormat format;
void Fill(uint8 r, uint8 g, uint8 b, uint8 a);
void SetFormat(const MDFN_PixelFormat &new_format, bool convert);
// Creates a 32-bit value for the surface corresponding to the R/G/B/A color passed.
INLINE uint32 MakeColor(uint8 r, uint8 g, uint8 b, uint8 a = 0) const
{
return(format.MakeColor(r, g, b, a));
}
// Gets the R/G/B/A values for the passed 32-bit surface pixel value
INLINE void DecodeColor(uint32 value, int &r, int &g, int &b, int &a) const
{
format.DecodeColor(value, r, g, b, a);
}
INLINE void DecodeColor(uint32 value, int &r, int &g, int &b) const
{
int dummy_a;
DecodeColor(value, r, g, b, dummy_a);
}
private:
void Init(void *const p_pixels, const uint32 p_width, const uint32 p_height, const uint32 p_pitchinpix, const MDFN_PixelFormat &nf, const bool alloc_init_pixels);
};
#endif