30 bit display feature

This commit is contained in:
shun-iwasawa 2021-10-07 11:47:55 +09:00 committed by manongjohn
parent 795c8cae04
commit a55f60e466
14 changed files with 747 additions and 73 deletions

View file

@ -942,6 +942,454 @@ void doQuickPutNoFilter(const TRaster32P &dn, const TRasterGR8P &up,
up->unlock(); up->unlock();
} }
//=============================================================================
//=============================================================================
void doQuickPutNoFilter(const TRaster64P &dn, const TRaster64P &up,
const TAffine &aff, bool doPremultiply,
bool firstColumn) {
// se aff := TAffine(sx, 0, tx, 0, sy, ty) e' degenere la controimmagine
// di up e' un segmento (o un punto)
if ((aff.a11 * aff.a22 - aff.a12 * aff.a21) == 0) return;
// contatore bit di shift
const int PADN = 16;
// max dimensioni di up gestibili (limite imposto dal numero di bit
// disponibili per la parte intera di xL, yL)
assert(std::max(up->getLx(), up->getLy()) <
(1 << (8 * sizeof(int) - PADN - 1)));
TRectD boundingBoxD =
TRectD(convert(dn->getBounds())) *
(aff * TRectD(-0.5, -0.5, up->getLx() - 0.5, up->getLy() - 0.5));
// clipping
if (boundingBoxD.x0 >= boundingBoxD.x1 || boundingBoxD.y0 >= boundingBoxD.y1)
return;
// clipping y su dn
int yMin = std::max(tfloor(boundingBoxD.y0), 0);
// clipping y su dn
int yMax = std::min(tceil(boundingBoxD.y1), dn->getLy() - 1);
// clipping x su dn
int xMin = std::max(tfloor(boundingBoxD.x0), 0);
// clipping x su dn
int xMax = std::min(tceil(boundingBoxD.x1), dn->getLx() - 1);
// inversa di aff
TAffine invAff = inv(aff);
// nel disegnare la y-esima scanline di dn, il passaggio al pixel
// successivo comporta l'incremento (deltaXD, deltaYD) delle coordinate del
// pixel corrispondente di up
double deltaXD = invAff.a11;
double deltaYD = invAff.a21;
// deltaXD "TLonghizzato" (round)
int deltaXL = tround(deltaXD * (1 << PADN));
// deltaYD "TLonghizzato" (round)
int deltaYL = tround(deltaYD * (1 << PADN));
// se aff "TLonghizzata" (round) e' degenere la controimmagine di up e' un
// segmento (o un punto)
if ((deltaXL == 0) && (deltaYL == 0)) return;
// TINT32 predecessore di up->getLx()
int lxPred = up->getLx() * (1 << PADN) - 1;
// TINT32 predecessore di up->getLy()
int lyPred = up->getLy() * (1 << PADN) - 1;
int dnWrap = dn->getWrap();
int upWrap = up->getWrap();
dn->lock();
up->lock();
TPixel64 *dnRow = dn->pixels(yMin);
TPixel64 *upBasePix = up->pixels();
// scorre le scanline di boundingBoxD
for (int y = yMin; y <= yMax; y++, dnRow += dnWrap) {
// (1) equazione k-parametrica della y-esima scanline di boundingBoxD:
// (xMin, y) + k*(1, 0), k = 0, ..., (xMax - xMin)
// (2) equazione k-parametrica dell'immagine mediante invAff di (1):
// invAff*(xMin, y) + k*(deltaXD, deltaYD),
// k = kMin, ..., kMax con 0 <= kMin <= kMax <= (xMax - xMin)
// calcola kMin, kMax per la scanline corrente
// intersecando la (2) con i lati di up
// il segmento [a, b] di up e' la controimmagine mediante aff della
// porzione di scanline [ (xMin, y), (xMax, y) ] di dn
// TPointD b = invAff*TPointD(xMax, y);
TPointD a = invAff * TPointD(xMin, y);
// (xL0, yL0) sono le coordinate di a (inizializzate per il round)
// in versione "TLonghizzata"
// 0 <= xL0 + k*deltaXL
// < up->getLx()*(1<<PADN)
//
// 0 <= kMinX
// <= kMin
// <= k
// <= kMax
// <= kMaxX
// <= (xMax - xMin)
//
// 0 <= yL0 + k*deltaYL
// < up->getLy()*(1<<PADN)
// 0 <= kMinY
// <= kMin
// <= k
// <= kMax
// <= kMaxY
// <= (xMax - xMin)
// xL0 inizializzato per il round
int xL0 = tround((a.x + 0.5) * (1 << PADN));
// yL0 inizializzato per il round
int yL0 = tround((a.y + 0.5) * (1 << PADN));
// calcola kMinX, kMaxX, kMinY, kMaxY
int kMinX = 0, kMaxX = xMax - xMin; // clipping su dn
int kMinY = 0, kMaxY = xMax - xMin; // clipping su dn
// 0 <= xL0 + k*deltaXL
// < up->getLx()*(1<<PADN)
// <=>
// 0 <= xL0 + k*deltaXL
// <= lxPred
//
// 0 <= yL0 + k*deltaYL
// < up->getLy()*(1<<PADN)
// <=>
// 0 <= yL0 + k*deltaYL
// <= lyPred
// calcola kMinX, kMaxX
if (deltaXL == 0) {
// [a, b] verticale esterno ad up+(bordo destro/basso)
if ((xL0 < 0) || (lxPred < xL0)) continue;
// altrimenti usa solo
// kMinY, kMaxY ((deltaXL != 0) || (deltaYL != 0))
} else if (deltaXL > 0) {
// [a, b] esterno ad up+(bordo destro/basso)
if (lxPred < xL0) continue;
kMaxX = (lxPred - xL0) / deltaXL; // floor
if (xL0 < 0) {
kMinX = ((-xL0) + deltaXL - 1) / deltaXL; // ceil
}
} else // (deltaXL < 0)
{
// [a, b] esterno ad up+(bordo destro/basso)
if (xL0 < 0) continue;
kMaxX = xL0 / (-deltaXL); // floor
if (lxPred < xL0) {
kMinX = (xL0 - lxPred - deltaXL - 1) / (-deltaXL); // ceil
}
}
// calcola kMinY, kMaxY
if (deltaYL == 0) {
// [a, b] orizzontale esterno ad up+(bordo destro/basso)
if ((yL0 < 0) || (lyPred < yL0)) continue;
// altrimenti usa solo
// kMinX, kMaxX ((deltaXL != 0) || (deltaYL != 0))
} else if (deltaYL > 0) {
// [a, b] esterno ad up+(bordo destro/basso)
if (lyPred < yL0) continue;
kMaxY = (lyPred - yL0) / deltaYL; // floor
if (yL0 < 0) {
kMinY = ((-yL0) + deltaYL - 1) / deltaYL; // ceil
}
} else // (deltaYL < 0)
{
// [a, b] esterno ad up+(bordo destro/basso)
if (yL0 < 0) continue;
kMaxY = yL0 / (-deltaYL); // floor
if (lyPred < yL0) {
kMinY = (yL0 - lyPred - deltaYL - 1) / (-deltaYL); // ceil
}
}
// calcola kMin, kMax effettuando anche il clippind su dn
int kMin = std::max({kMinX, kMinY, (int)0});
int kMax = std::min({kMaxX, kMaxY, xMax - xMin});
TPixel64 *dnPix = dnRow + xMin + kMin;
TPixel64 *dnEndPix = dnRow + xMin + kMax + 1;
// (xL, yL) sono le coordinate (inizializzate per il round)
// in versione "TLonghizzata" del pixel corrente di up
int xL = xL0 + (kMin - 1) * deltaXL; // inizializza xL
int yL = yL0 + (kMin - 1) * deltaYL; // inizializza yL
// scorre i pixel sulla y-esima scanline di boundingBoxD
for (; dnPix < dnEndPix; ++dnPix) {
xL += deltaXL;
yL += deltaYL;
// il punto di up TPointD(xL/(1<<PADN), yL/(1<<PADN)) e'
// approssimato con (xI, yI)
int xI = xL >> PADN; // round
int yI = yL >> PADN; // round
assert((0 <= xI) && (xI <= up->getLx() - 1) && (0 <= yI) &&
(yI <= up->getLy() - 1));
TPixel64 upPix = *(upBasePix + (yI * upWrap + xI));
if (firstColumn) upPix.m = 65535;
if (upPix.m == 0) continue;
if (upPix.m == 65535)
*dnPix = upPix;
else if (doPremultiply)
*dnPix = quickOverPixPremult(*dnPix, upPix);
else
*dnPix = quickOverPix(*dnPix, upPix);
}
}
dn->unlock();
up->unlock();
}
//=============================================================================
void doQuickPutNoFilter(const TRaster64P &dn, const TRaster32P &up,
const TAffine &aff, bool doPremultiply,
bool firstColumn) {
// se aff := TAffine(sx, 0, tx, 0, sy, ty) e' degenere la controimmagine
// di up e' un segmento (o un punto)
if ((aff.a11 * aff.a22 - aff.a12 * aff.a21) == 0) return;
// contatore bit di shift
const int PADN = 16;
// max dimensioni di up gestibili (limite imposto dal numero di bit
// disponibili per la parte intera di xL, yL)
assert(std::max(up->getLx(), up->getLy()) <
(1 << (8 * sizeof(int) - PADN - 1)));
TRectD boundingBoxD =
TRectD(convert(dn->getBounds())) *
(aff * TRectD(-0.5, -0.5, up->getLx() - 0.5, up->getLy() - 0.5));
// clipping
if (boundingBoxD.x0 >= boundingBoxD.x1 || boundingBoxD.y0 >= boundingBoxD.y1)
return;
// clipping y su dn
int yMin = std::max(tfloor(boundingBoxD.y0), 0);
// clipping y su dn
int yMax = std::min(tceil(boundingBoxD.y1), dn->getLy() - 1);
// clipping x su dn
int xMin = std::max(tfloor(boundingBoxD.x0), 0);
// clipping x su dn
int xMax = std::min(tceil(boundingBoxD.x1), dn->getLx() - 1);
// inversa di aff
TAffine invAff = inv(aff);
// nel disegnare la y-esima scanline di dn, il passaggio al pixel
// successivo comporta l'incremento (deltaXD, deltaYD) delle coordinate del
// pixel corrispondente di up
double deltaXD = invAff.a11;
double deltaYD = invAff.a21;
// deltaXD "TLonghizzato" (round)
int deltaXL = tround(deltaXD * (1 << PADN));
// deltaYD "TLonghizzato" (round)
int deltaYL = tround(deltaYD * (1 << PADN));
// se aff "TLonghizzata" (round) e' degenere la controimmagine di up e' un
// segmento (o un punto)
if ((deltaXL == 0) && (deltaYL == 0)) return;
// TINT32 predecessore di up->getLx()
int lxPred = up->getLx() * (1 << PADN) - 1;
// TINT32 predecessore di up->getLy()
int lyPred = up->getLy() * (1 << PADN) - 1;
int dnWrap = dn->getWrap();
int upWrap = up->getWrap();
dn->lock();
up->lock();
TPixel64 *dnRow = dn->pixels(yMin);
TPixel32 *upBasePix = up->pixels();
// scorre le scanline di boundingBoxD
for (int y = yMin; y <= yMax; y++, dnRow += dnWrap) {
// (1) equazione k-parametrica della y-esima scanline di boundingBoxD:
// (xMin, y) + k*(1, 0), k = 0, ..., (xMax - xMin)
// (2) equazione k-parametrica dell'immagine mediante invAff di (1):
// invAff*(xMin, y) + k*(deltaXD, deltaYD),
// k = kMin, ..., kMax con 0 <= kMin <= kMax <= (xMax - xMin)
// calcola kMin, kMax per la scanline corrente
// intersecando la (2) con i lati di up
// il segmento [a, b] di up e' la controimmagine mediante aff della
// porzione di scanline [ (xMin, y), (xMax, y) ] di dn
// TPointD b = invAff*TPointD(xMax, y);
TPointD a = invAff * TPointD(xMin, y);
// (xL0, yL0) sono le coordinate di a (inizializzate per il round)
// in versione "TLonghizzata"
// 0 <= xL0 + k*deltaXL
// < up->getLx()*(1<<PADN)
//
// 0 <= kMinX
// <= kMin
// <= k
// <= kMax
// <= kMaxX
// <= (xMax - xMin)
//
// 0 <= yL0 + k*deltaYL
// < up->getLy()*(1<<PADN)
// 0 <= kMinY
// <= kMin
// <= k
// <= kMax
// <= kMaxY
// <= (xMax - xMin)
// xL0 inizializzato per il round
int xL0 = tround((a.x + 0.5) * (1 << PADN));
// yL0 inizializzato per il round
int yL0 = tround((a.y + 0.5) * (1 << PADN));
// calcola kMinX, kMaxX, kMinY, kMaxY
int kMinX = 0, kMaxX = xMax - xMin; // clipping su dn
int kMinY = 0, kMaxY = xMax - xMin; // clipping su dn
// 0 <= xL0 + k*deltaXL
// < up->getLx()*(1<<PADN)
// <=>
// 0 <= xL0 + k*deltaXL
// <= lxPred
//
// 0 <= yL0 + k*deltaYL
// < up->getLy()*(1<<PADN)
// <=>
// 0 <= yL0 + k*deltaYL
// <= lyPred
// calcola kMinX, kMaxX
if (deltaXL == 0) {
// [a, b] verticale esterno ad up+(bordo destro/basso)
if ((xL0 < 0) || (lxPred < xL0)) continue;
// altrimenti usa solo
// kMinY, kMaxY ((deltaXL != 0) || (deltaYL != 0))
} else if (deltaXL > 0) {
// [a, b] esterno ad up+(bordo destro/basso)
if (lxPred < xL0) continue;
kMaxX = (lxPred - xL0) / deltaXL; // floor
if (xL0 < 0) {
kMinX = ((-xL0) + deltaXL - 1) / deltaXL; // ceil
}
} else // (deltaXL < 0)
{
// [a, b] esterno ad up+(bordo destro/basso)
if (xL0 < 0) continue;
kMaxX = xL0 / (-deltaXL); // floor
if (lxPred < xL0) {
kMinX = (xL0 - lxPred - deltaXL - 1) / (-deltaXL); // ceil
}
}
// calcola kMinY, kMaxY
if (deltaYL == 0) {
// [a, b] orizzontale esterno ad up+(bordo destro/basso)
if ((yL0 < 0) || (lyPred < yL0)) continue;
// altrimenti usa solo
// kMinX, kMaxX ((deltaXL != 0) || (deltaYL != 0))
} else if (deltaYL > 0) {
// [a, b] esterno ad up+(bordo destro/basso)
if (lyPred < yL0) continue;
kMaxY = (lyPred - yL0) / deltaYL; // floor
if (yL0 < 0) {
kMinY = ((-yL0) + deltaYL - 1) / deltaYL; // ceil
}
} else // (deltaYL < 0)
{
// [a, b] esterno ad up+(bordo destro/basso)
if (yL0 < 0) continue;
kMaxY = yL0 / (-deltaYL); // floor
if (lyPred < yL0) {
kMinY = (yL0 - lyPred - deltaYL - 1) / (-deltaYL); // ceil
}
}
// calcola kMin, kMax effettuando anche il clippind su dn
int kMin = std::max({kMinX, kMinY, (int)0});
int kMax = std::min({kMaxX, kMaxY, xMax - xMin});
TPixel64 *dnPix = dnRow + xMin + kMin;
TPixel64 *dnEndPix = dnRow + xMin + kMax + 1;
// (xL, yL) sono le coordinate (inizializzate per il round)
// in versione "TLonghizzata" del pixel corrente di up
int xL = xL0 + (kMin - 1) * deltaXL; // inizializza xL
int yL = yL0 + (kMin - 1) * deltaYL; // inizializza yL
// scorre i pixel sulla y-esima scanline di boundingBoxD
for (; dnPix < dnEndPix; ++dnPix) {
xL += deltaXL;
yL += deltaYL;
// il punto di up TPointD(xL/(1<<PADN), yL/(1<<PADN)) e'
// approssimato con (xI, yI)
int xI = xL >> PADN; // round
int yI = yL >> PADN; // round
assert((0 <= xI) && (xI <= up->getLx() - 1) && (0 <= yI) &&
(yI <= up->getLy() - 1));
TPixel32 upPix = *(upBasePix + (yI * upWrap + xI));
if (firstColumn) upPix.m = 255;
if (upPix.m == 0) continue;
TPixel64 upPix64 = toPixel64(upPix);
if (upPix.m == 255)
*dnPix = upPix64;
else if (doPremultiply)
*dnPix = quickOverPixPremult(*dnPix, upPix64);
else
*dnPix = quickOverPix(*dnPix, upPix64);
}
}
dn->unlock();
up->unlock();
}
//============================================================================= //=============================================================================
void doQuickPutFilter(const TRaster32P &dn, const TRaster32P &up, double sx, void doQuickPutFilter(const TRaster32P &dn, const TRaster32P &up, double sx,
@ -4268,6 +4716,7 @@ void quickPut(const TRasterP &dn, const TRasterP &up, const TAffine &aff,
TRaster32P up32 = up; TRaster32P up32 = up;
TRasterGR8P dn8 = dn; TRasterGR8P dn8 = dn;
TRasterGR8P up8 = up; TRasterGR8P up8 = up;
TRaster64P dn64 = dn;
TRaster64P up64 = up; TRaster64P up64 = up;
if (up8 && dn32) { if (up8 && dn32) {
@ -4294,6 +4743,10 @@ void quickPut(const TRasterP &dn, const TRasterP &up, const TAffine &aff,
} }
} else if (dn32 && up64) } else if (dn32 && up64)
doQuickPutNoFilter(dn32, up64, aff, doPremultiply, firstColumn); doQuickPutNoFilter(dn32, up64, aff, doPremultiply, firstColumn);
else if (dn64 && up64)
doQuickPutNoFilter(dn64, up64, aff, doPremultiply, firstColumn);
else if (dn64 && up32)
doQuickPutNoFilter(dn64, up32, aff, doPremultiply, firstColumn);
else else
throw TRopException("raster type mismatch"); throw TRopException("raster type mismatch");
} }

View file

@ -68,6 +68,12 @@ class TCubic;
#define TGL_TYPE GL_UNSIGNED_BYTE #define TGL_TYPE GL_UNSIGNED_BYTE
#endif #endif
//=============================================================================
// settings for 30bit display
#define TGL_TexFmt10 GL_RGB10_A2
#define TGL_TYPE16 GL_UNSIGNED_SHORT
//============================================================================= //=============================================================================
#ifdef _DEBUG #ifdef _DEBUG

View file

@ -234,6 +234,7 @@ public:
} }
void setColorCalibrationLutPath(QString monitorName, QString path); void setColorCalibrationLutPath(QString monitorName, QString path);
QString getColorCalibrationLutPath(QString &monitorName) const; QString getColorCalibrationLutPath(QString &monitorName) const;
bool is30bitDisplayEnabled() const { return getBoolValue(displayIn30bit); }
bool isViewerIndicatorEnabled() const { bool isViewerIndicatorEnabled() const {
return getBoolValue(viewerIndicatorEnabled); return getBoolValue(viewerIndicatorEnabled);

View file

@ -45,6 +45,7 @@ enum PreferencesItemId {
colorCalibrationEnabled, colorCalibrationEnabled,
colorCalibrationLutPaths, colorCalibrationLutPaths,
showIconsInMenu, showIconsInMenu,
displayIn30bit,
viewerIndicatorEnabled, viewerIndicatorEnabled,
//---------- //----------

View file

@ -236,6 +236,12 @@ inline TPixel32 quickOverPixPremult(const TPixel32 &bot, const TPixel32 &top) {
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
inline TPixel64 quickOverPixPremult(const TPixel64 &bot, const TPixel64 &top) {
return quickOverPixPremultT<TPixel64, USHORT>(bot, top);
}
//-----------------------------------------------------------------------------
inline TPixel64 quickOverPix(const TPixel64 &bot, const TPixel64 &top) { inline TPixel64 quickOverPix(const TPixel64 &bot, const TPixel64 &top) {
return quickOverPixT<TPixel64, USHORT>(bot, top); return quickOverPixT<TPixel64, USHORT>(bot, top);
} }
@ -294,7 +300,7 @@ inline TPixel32 overPixOnBlack(const TPixel32 &top) {
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
/*! this function combines two GR8 pixels returning the darker. /*! this function combines two GR8 pixels returning the darker.
*/ */
inline TPixelGR8 over(const TPixelGR8 &bot, const TPixelGR8 &top) { inline TPixelGR8 over(const TPixelGR8 &bot, const TPixelGR8 &top) {
return TPixelGR8(std::min(bot.value, top.value)); return TPixelGR8(std::min(bot.value, top.value));
@ -528,26 +534,30 @@ void sub(T &pixout, const T &pixin, double v) {
template <class T> template <class T>
void mult(T &pixout, const T &pixin, double v) { void mult(T &pixout, const T &pixin, double v) {
double r, g, b, m; double r, g, b, m;
r = pixin.r + v; r = pixin.r + v;
g = pixin.g + v; g = pixin.g + v;
b = pixin.b + v; b = pixin.b + v;
m = pixin.m + v; m = pixin.m + v;
pixout.r = pixout.r = (r < 0)
(r < 0) ? 0 : ((r < T::maxChannelValue) ? 0
? troundp(r * (pixout.r / (double)T::maxChannelValue)) : ((r < T::maxChannelValue)
: pixout.r); ? troundp(r * (pixout.r / (double)T::maxChannelValue))
pixout.g = : pixout.r);
(g < 0) ? 0 : ((g < T::maxChannelValue) pixout.g = (g < 0)
? troundp(g * (pixout.g / (double)T::maxChannelValue)) ? 0
: pixout.g); : ((g < T::maxChannelValue)
pixout.b = ? troundp(g * (pixout.g / (double)T::maxChannelValue))
(b < 0) ? 0 : ((b < T::maxChannelValue) : pixout.g);
? troundp(b * (pixout.b / (double)T::maxChannelValue)) pixout.b = (b < 0)
: pixout.b); ? 0
pixout.m = : ((b < T::maxChannelValue)
(m < 0) ? 0 : ((m < T::maxChannelValue) ? troundp(b * (pixout.b / (double)T::maxChannelValue))
? troundp(m * (pixout.m / (double)T::maxChannelValue)) : pixout.b);
: pixout.m); pixout.m = (m < 0)
? 0
: ((m < T::maxChannelValue)
? troundp(m * (pixout.m / (double)T::maxChannelValue))
: pixout.m);
} }
//--------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------

View file

@ -163,34 +163,33 @@ inline TRectD getImageBoundsD(const TImageP &img) {
FlipBook::FlipBook(QWidget *parent, QString viewerTitle, FlipBook::FlipBook(QWidget *parent, QString viewerTitle,
std::vector<int> flipConsoleButtonMask, UCHAR flags, std::vector<int> flipConsoleButtonMask, UCHAR flags,
bool isColorModel) //, bool showOnlyPlayBackgroundButton) bool isColorModel) //, bool showOnlyPlayBackgroundButton)
: QWidget(parent), : QWidget(parent)
m_viewerTitle(viewerTitle), , m_viewerTitle(viewerTitle)
m_levelNames(), , m_levelNames()
m_levels(), , m_levels()
m_playSound(false), , m_playSound(false)
m_snd(0), , m_snd(0)
m_player(0) , m_player(0)
//, m_doCompare(false) //, m_doCompare(false)
, , m_currentFrameToSave(0)
m_currentFrameToSave(0), , m_lw()
m_lw(), , m_lr()
m_lr(), , m_loadPopup(0)
m_loadPopup(0), , m_savePopup(0)
m_savePopup(0), , m_shrink(1)
m_shrink(1), , m_isPreviewFx(false)
m_isPreviewFx(false), , m_previewedFx(0)
m_previewedFx(0), , m_previewXsh(0)
m_previewXsh(0), , m_previewUpdateTimer(this)
m_previewUpdateTimer(this), , m_xl(0)
m_xl(0), , m_title1()
m_title1(), , m_poolIndex(-1)
m_poolIndex(-1), , m_freezed(false)
m_freezed(false), , m_loadbox()
m_loadbox(), , m_dim()
m_dim(), , m_loadboxes()
m_loadboxes(), , m_freezeButton(0)
m_freezeButton(0), , m_flags(flags) {
m_flags(flags) {
setAcceptDrops(true); setAcceptDrops(true);
setFocusPolicy(Qt::StrongFocus); setFocusPolicy(Qt::StrongFocus);
@ -1103,7 +1102,7 @@ void FlipBook::setLevel(const TFilePath &fp, TPalette *palette, int from,
fromIndex = level->begin()->first.getNumber(); fromIndex = level->begin()->first.getNumber();
toIndex = (--level->end())->first.getNumber(); toIndex = (--level->end())->first.getNumber();
if (m_imageViewer->isColorModel()) if (m_imageViewer->isColorModel())
current = m_flipConsole->getCurrentFrame(); current = m_flipConsole->getCurrentFrame();
incrementalIndexing = true; incrementalIndexing = true;
} else { } else {
TLevel::Iterator it = level->begin(); TLevel::Iterator it = level->begin();
@ -1141,10 +1140,9 @@ void FlipBook::setLevel(const TFilePath &fp, TPalette *palette, int from,
levelToPush.m_incrementalIndexing = incrementalIndexing; levelToPush.m_incrementalIndexing = incrementalIndexing;
int formatIdx = Preferences::instance()->matchLevelFormat(fp); int formatIdx = Preferences::instance()->matchLevelFormat(fp);
if (formatIdx >= 0 && if (formatIdx >= 0 && Preferences::instance()
Preferences::instance() ->levelFormat(formatIdx)
->levelFormat(formatIdx) .m_options.m_premultiply) {
.m_options.m_premultiply) {
levelToPush.m_premultiply = true; levelToPush.m_premultiply = true;
} }
@ -1595,6 +1593,9 @@ TImageP FlipBook::getCurrentImage(int frame) {
lx = m_loadbox.getLx(); lx = m_loadbox.getLx();
} }
if (Preferences::instance()->is30bitDisplayEnabled())
ir->enable16BitRead(true);
TImageP img = ir->load(); TImageP img = ir->load();
if (img) { if (img) {
@ -2146,7 +2147,7 @@ void FlipBook::minimize(bool doMinimize) {
*/ */
void FlipBook::loadAndCacheAllTlvImages(Level level, int fromFrame, void FlipBook::loadAndCacheAllTlvImages(Level level, int fromFrame,
int toFrame) { int toFrame) {
TFilePath fp = level.m_fp; TFilePath fp = level.m_fp;
if (!m_lr || (fp != m_lr->getFilePath())) m_lr = TLevelReaderP(fp); if (!m_lr || (fp != m_lr->getFilePath())) m_lr = TLevelReaderP(fp);
if (!m_lr) return; if (!m_lr) return;
@ -2223,7 +2224,7 @@ FlipBook *viewFile(const TFilePath &path, int from, int to, int step,
if (step == -1 || shrink == -1) { if (step == -1 || shrink == -1) {
int _step = 1, _shrink = 1; int _step = 1, _shrink = 1;
Preferences::instance()->getViewValues(_shrink, _step); Preferences::instance()->getViewValues(_shrink, _step);
if (step == -1) step = _step; if (step == -1) step = _step;
if (shrink == -1) shrink = _shrink; if (shrink == -1) shrink = _shrink;
} }

View file

@ -244,6 +244,11 @@ ImageViewer::ImageViewer(QWidget *parent, FlipBook *flipbook,
if (Preferences::instance()->isColorCalibrationEnabled()) if (Preferences::instance()->isColorCalibrationEnabled())
m_lutCalibrator = new LutCalibrator(); m_lutCalibrator = new LutCalibrator();
#if QT_VERSION >= 0x051000
if (Preferences::instance()->is30bitDisplayEnabled())
setTextureFormat(TGL_TexFmt10);
#endif
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -488,13 +493,19 @@ void ImageViewer::resizeGL(int w, int h) {
// remake fbo with new size // remake fbo with new size
if (m_lutCalibrator && m_lutCalibrator->isValid()) { if (m_lutCalibrator && m_lutCalibrator->isValid()) {
if (m_fbo) delete m_fbo; if (m_fbo) delete m_fbo;
m_fbo = new QOpenGLFramebufferObject(w, h); if (Preferences::instance()->is30bitDisplayEnabled()) {
QOpenGLFramebufferObjectFormat format;
format.setInternalTextureFormat(TGL_TexFmt10);
m_fbo = new QOpenGLFramebufferObject(w, h, format);
} else // normally, initialize with GL_RGBA8 format
m_fbo = new QOpenGLFramebufferObject(w, h);
} }
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void ImageViewer::paintGL() { void ImageViewer::paintGL() {
initializeOpenGLFunctions();
if (m_lutCalibrator && m_lutCalibrator->isValid()) m_fbo->bind(); if (m_lutCalibrator && m_lutCalibrator->isValid()) m_fbo->bind();
TDimension viewerSize(width(), height()); TDimension viewerSize(width(), height());
@ -1422,8 +1433,14 @@ void ImageViewer::onPreferenceChanged(const QString& prefName) {
m_lutCalibrator->initialize(); m_lutCalibrator->initialize();
connect(context(), SIGNAL(aboutToBeDestroyed()), this, connect(context(), SIGNAL(aboutToBeDestroyed()), this,
SLOT(onContextAboutToBeDestroyed())); SLOT(onContextAboutToBeDestroyed()));
if (m_lutCalibrator->isValid() && !m_fbo) if (m_lutCalibrator->isValid() && !m_fbo) {
if (Preferences::instance()->is30bitDisplayEnabled()) {
QOpenGLFramebufferObjectFormat format;
format.setInternalTextureFormat(TGL_TexFmt10);
m_fbo = new QOpenGLFramebufferObject(width(), height(), format);
} else // normally, initialize with GL_RGBA8 format
m_fbo = new QOpenGLFramebufferObject(width(), height()); m_fbo = new QOpenGLFramebufferObject(width(), height());
}
doneCurrent(); doneCurrent();
} }
update(); update();

View file

@ -528,6 +528,16 @@ int main(int argc, char *argv[]) {
crInstall(&pInfo); crInstall(&pInfo);
#endif #endif
// prepare for 30bit display
if (Preferences::instance()->is30bitDisplayEnabled()) {
QSurfaceFormat sFmt = QSurfaceFormat::defaultFormat();
sFmt.setRedBufferSize(10);
sFmt.setGreenBufferSize(10);
sFmt.setBlueBufferSize(10);
sFmt.setAlphaBufferSize(2);
QSurfaceFormat::setDefaultFormat(sFmt);
}
// Initialize thread components // Initialize thread components
TThread::init(); TThread::init();

View file

@ -270,6 +270,89 @@ Preferences::LevelFormat PreferencesPopup::FormatProperties::levelFormat()
return lf; return lf;
} }
//**********************************************************************************
// PreferencesPopup::Display30bitCheckerView implementation
//**********************************************************************************
PreferencesPopup::Display30bitChecker::GLView::GLView(QWidget* parent,
bool is30bit)
: QOpenGLWidget(parent), m_is30bit(is30bit) {
setFixedSize(500, 100);
#if QT_VERSION >= 0x051000
if (m_is30bit) setTextureFormat(TGL_TexFmt10);
#endif
}
void PreferencesPopup::Display30bitChecker::GLView::initializeGL() {
initializeOpenGLFunctions();
glClear(GL_COLOR_BUFFER_BIT);
}
void PreferencesPopup::Display30bitChecker::GLView::resizeGL(int width,
int height) {
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 1, 0, 1, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void PreferencesPopup::Display30bitChecker::GLView::paintGL() {
initializeOpenGLFunctions();
glPushMatrix();
glBegin(GL_QUADS);
glColor3d(0.071, 0.153, 0.0);
glVertex3d(0, 0, 0);
glVertex3d(0, 1, 0);
glColor3d(0.141, 0.239, 0.0);
glVertex3d(1, 1, 0);
glVertex3d(1, 0, 0);
glEnd();
glPopMatrix();
}
//-------------------------
PreferencesPopup::Display30bitChecker::Display30bitChecker(
PreferencesPopup* parent)
: QDialog(parent) {
setModal(true);
m_currentDefaultFormat = QSurfaceFormat::defaultFormat();
setWindowTitle(tr("Check 30bit display availability"));
QSurfaceFormat sFmt = m_currentDefaultFormat;
sFmt.setRedBufferSize(10);
sFmt.setGreenBufferSize(10);
sFmt.setBlueBufferSize(10);
sFmt.setAlphaBufferSize(2);
QSurfaceFormat::setDefaultFormat(sFmt);
GLView* view8bit = new GLView(this, false);
GLView* view10bit = new GLView(this, true);
QPushButton* closeBtn = new QPushButton(tr("Close"), this);
QString infoLabel = tr(
"If the lower gradient looks smooth and has no banding compared to the upper gradient,\n\
30bit display is available in the current configuration.");
QVBoxLayout* lay = new QVBoxLayout();
lay->setMargin(10);
lay->setSpacing(10);
{
lay->addWidget(view8bit);
lay->addWidget(view10bit);
lay->addWidget(new QLabel(infoLabel, this));
lay->addWidget(closeBtn, 0, Qt::AlignCenter);
}
setLayout(lay);
lay->setSizeConstraint(QLayout::SetFixedSize);
connect(closeBtn, SIGNAL(clicked()), this, SLOT(accept()));
}
PreferencesPopup::Display30bitChecker::~Display30bitChecker() {
QSurfaceFormat::setDefaultFormat(m_currentDefaultFormat);
}
//********************************************************************************** //**********************************************************************************
// PreferencesPopup implementation // PreferencesPopup implementation
//********************************************************************************** //**********************************************************************************
@ -691,6 +774,13 @@ void PreferencesPopup::onLutPathChanged() {
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void PreferencesPopup::onCheck30bitDisplay() {
Display30bitChecker checker(this);
checker.exec();
}
//-----------------------------------------------------------------------------
void PreferencesPopup::onAddLevelFormat() { void PreferencesPopup::onAddLevelFormat() {
bool ok = true; bool ok = true;
QString formatName = DVGui::getText(tr("New Level Format"), QString formatName = DVGui::getText(tr("New Level Format"),
@ -1016,6 +1106,7 @@ QString PreferencesPopup::getUIString(PreferencesItemId id) {
{colorCalibrationLutPaths, {colorCalibrationLutPaths,
tr("3DLUT File for [%1]:") tr("3DLUT File for [%1]:")
.arg(LutManager::instance()->getMonitorName())}, .arg(LutManager::instance()->getMonitorName())},
{displayIn30bit, tr("30bit Display*")},
{showIconsInMenu, tr("Show Icons In Menu*")}, {showIconsInMenu, tr("Show Icons In Menu*")},
{viewerIndicatorEnabled, tr("Show Viewer Indicators")}, {viewerIndicatorEnabled, tr("Show Viewer Indicators")},
@ -1456,11 +1547,14 @@ QWidget* PreferencesPopup::createInterfacePage() {
for (const QString& name : m_pref->getLanguageList()) for (const QString& name : m_pref->getLanguageList())
languageItemList.push_back(ComboBoxItem(name, name)); languageItemList.push_back(ComboBoxItem(name, name));
QPushButton* check30bitBtn = new QPushButton(tr("Check Availability"));
QWidget* widget = new QWidget(this); QWidget* widget = new QWidget(this);
QGridLayout* lay = new QGridLayout(); QGridLayout* lay = new QGridLayout();
setupLayout(lay); setupLayout(lay);
insertUI(CurrentStyleSheetName, lay, styleSheetItemList); insertUI(CurrentStyleSheetName, lay, styleSheetItemList);
int row = lay->rowCount();
// lay->addWidget(new QLabel(tr("Icon Theme*:"), this), 2, 0, // lay->addWidget(new QLabel(tr("Icon Theme*:"), this), 2, 0,
// Qt::AlignRight | Qt::AlignVCenter); // Qt::AlignRight | Qt::AlignVCenter);
@ -1488,6 +1582,11 @@ QWidget* PreferencesPopup::createInterfacePage() {
// insertUI(interfaceFontStyle, lay, buildFontStyleList()); // insertUI(interfaceFontStyle, lay, buildFontStyleList());
QGridLayout* colorCalibLay = insertGroupBoxUI(colorCalibrationEnabled, lay); QGridLayout* colorCalibLay = insertGroupBoxUI(colorCalibrationEnabled, lay);
{ insertUI(colorCalibrationLutPaths, colorCalibLay); } { insertUI(colorCalibrationLutPaths, colorCalibLay); }
#if QT_VERSION >= 0x051000
insertUI(displayIn30bit, lay);
row = lay->rowCount();
lay->addWidget(check30bitBtn, row - 1, 3);
#endif
// insertUI(showIconsInMenu, lay); // insertUI(showIconsInMenu, lay);
lay->setRowStretch(lay->rowCount(), 1); lay->setRowStretch(lay->rowCount(), 1);
@ -1504,6 +1603,8 @@ QWidget* PreferencesPopup::createInterfacePage() {
ret = ret && connect(TApp::instance()->getCurrentScene(), ret = ret && connect(TApp::instance()->getCurrentScene(),
SIGNAL(pixelUnitSelected(bool)), this, SIGNAL(pixelUnitSelected(bool)), this,
SLOT(onPixelUnitExternallySelected(bool))); SLOT(onPixelUnitExternallySelected(bool)));
ret = ret && connect(check30bitBtn, SIGNAL(clicked()), this,
SLOT(onCheck30bitDisplay()));
assert(ret); assert(ret);
m_onEditedFuncMap.insert(CurrentStyleSheetName, m_onEditedFuncMap.insert(CurrentStyleSheetName,

View file

@ -17,6 +17,9 @@
// Qt includes // Qt includes
#include <QComboBox> #include <QComboBox>
#include <QFontComboBox> #include <QFontComboBox>
#include <QOpenGLWidget>
#include <QSurfaceFormat>
#include <QOpenGLFunctions>
//============================================================== //==============================================================
@ -65,6 +68,7 @@ public:
private: private:
class FormatProperties; class FormatProperties;
class Display30bitChecker;
private: private:
Preferences* m_pref; Preferences* m_pref;
@ -173,6 +177,7 @@ private slots:
void onPixelUnitExternallySelected(bool on); void onPixelUnitExternallySelected(bool on);
void onInterfaceFontChanged(const QString& text); void onInterfaceFontChanged(const QString& text);
void onLutPathChanged(); void onLutPathChanged();
void onCheck30bitDisplay();
void onAddLevelFormat(); void onAddLevelFormat();
void onRemoveLevelFormat(); void onRemoveLevelFormat();
@ -212,4 +217,36 @@ private slots:
void updateEnabledStatus(); void updateEnabledStatus();
}; };
//**********************************************************************************
// PreferencesPopup::Display30bitCheckerView definition
//**********************************************************************************
class PreferencesPopup::Display30bitChecker final : public QDialog {
Q_OBJECT
QSurfaceFormat m_currentDefaultFormat;
private:
class GLView;
public:
Display30bitChecker(PreferencesPopup* parent);
~Display30bitChecker();
};
class PreferencesPopup::Display30bitChecker::GLView final
: public QOpenGLWidget,
protected QOpenGLFunctions {
Q_OBJECT
bool m_is30bit;
public:
GLView(QWidget* parent, bool is30bit);
protected:
void initializeGL() override;
void resizeGL(int width, int height) override;
void paintGL() override;
};
#endif // PREFERENCESPOPUP_H #endif // PREFERENCESPOPUP_H

View file

@ -1070,7 +1070,9 @@ void PreviewFxInstance::doOnRenderRasterCompleted(
/*-- 16bpcで計算された場合、結果をDitheringする --*/ /*-- 16bpcで計算された場合、結果をDitheringする --*/
TRasterP rasA = renderData.m_rasA; TRasterP rasA = renderData.m_rasA;
TRasterP rasB = renderData.m_rasB; TRasterP rasB = renderData.m_rasB;
if (rasA->getPixelSize() == 8) // render in 64 bits // dither the 16bpc image IF the "30bit display" prefernce option is OFF
if (rasA->getPixelSize() == 8 &&
!Preferences::instance()->is30bitDisplayEnabled()) // render in 64 bits
{ {
TRaster32P auxA(rasA->getLx(), rasA->getLy()); TRaster32P auxA(rasA->getLx(), rasA->getLy());
TRop::convert(auxA, rasA); // dithering TRop::convert(auxA, rasA); // dithering

View file

@ -835,6 +835,10 @@ SceneViewer::SceneViewer(ImageUtils::FullScreenWidget *parent)
if (Preferences::instance()->isColorCalibrationEnabled()) if (Preferences::instance()->isColorCalibrationEnabled())
m_lutCalibrator = new LutCalibrator(); m_lutCalibrator = new LutCalibrator();
#if QT_VERSION >= 0x051000
if (Preferences::instance()->is30bitDisplayEnabled())
setTextureFormat(TGL_TexFmt10);
#endif
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -1220,8 +1224,14 @@ void SceneViewer::onPreferenceChanged(const QString &prefName) {
m_lutCalibrator->initialize(); m_lutCalibrator->initialize();
connect(context(), SIGNAL(aboutToBeDestroyed()), this, connect(context(), SIGNAL(aboutToBeDestroyed()), this,
SLOT(onContextAboutToBeDestroyed())); SLOT(onContextAboutToBeDestroyed()));
if (m_lutCalibrator->isValid() && !m_fbo) if (m_lutCalibrator->isValid() && !m_fbo) {
m_fbo = new QOpenGLFramebufferObject(width(), height()); if (Preferences::instance()->is30bitDisplayEnabled()) {
QOpenGLFramebufferObjectFormat format;
format.setInternalTextureFormat(TGL_TexFmt10);
m_fbo = new QOpenGLFramebufferObject(width(), height(), format);
} else // normally, initialize with GL_RGBA8 format
m_fbo = new QOpenGLFramebufferObject(width(), height());
}
doneCurrent(); doneCurrent();
} }
update(); update();
@ -1279,7 +1289,12 @@ void SceneViewer::resizeGL(int w, int h) {
// remake fbo with new size // remake fbo with new size
if (m_lutCalibrator && m_lutCalibrator->isValid()) { if (m_lutCalibrator && m_lutCalibrator->isValid()) {
if (m_fbo) delete m_fbo; if (m_fbo) delete m_fbo;
m_fbo = new QOpenGLFramebufferObject(w, h); if (Preferences::instance()->is30bitDisplayEnabled()) {
QOpenGLFramebufferObjectFormat format;
format.setInternalTextureFormat(TGL_TexFmt10);
m_fbo = new QOpenGLFramebufferObject(w, h, format);
} else // normally, initialize with GL_RGBA8 format
m_fbo = new QOpenGLFramebufferObject(w, h);
} }
// for updating the navigator in levelstrip // for updating the navigator in levelstrip

View file

@ -205,7 +205,7 @@ void Painter::flushRasterImages(const TRect &loadbox, double compareX,
glDisable(GL_STENCIL_TEST); glDisable(GL_STENCIL_TEST);
#ifdef GL_EXT_convolution #ifdef GL_EXT_convolution
if( GLEW_EXT_convolution ) { if (GLEW_EXT_convolution) {
glDisable(GL_CONVOLUTION_1D_EXT); glDisable(GL_CONVOLUTION_1D_EXT);
glDisable(GL_CONVOLUTION_2D_EXT); glDisable(GL_CONVOLUTION_2D_EXT);
glDisable(GL_SEPARABLE_2D_EXT); glDisable(GL_SEPARABLE_2D_EXT);
@ -213,14 +213,14 @@ void Painter::flushRasterImages(const TRect &loadbox, double compareX,
#endif #endif
#ifdef GL_EXT_histogram #ifdef GL_EXT_histogram
if( GLEW_EXT_histogram ) { if (GLEW_EXT_histogram) {
glDisable(GL_HISTOGRAM_EXT); glDisable(GL_HISTOGRAM_EXT);
glDisable(GL_MINMAX_EXT); glDisable(GL_MINMAX_EXT);
} }
#endif #endif
#ifdef GL_EXT_texture3D #ifdef GL_EXT_texture3D
if( GL_EXT_texture3D ) { if (GL_EXT_texture3D) {
glDisable(GL_TEXTURE_3D_EXT); glDisable(GL_TEXTURE_3D_EXT);
} }
#endif #endif
@ -363,7 +363,8 @@ void Painter::doFlushRasterImages(const TRasterP &rin, int bg,
TRect rect(tfloor(bbox.x0), tfloor(bbox.y0), tceil(bbox.x1), tceil(bbox.y1)); TRect rect(tfloor(bbox.x0), tfloor(bbox.y0), tceil(bbox.x1), tceil(bbox.y1));
if (rect.isEmpty()) return; if (rect.isEmpty()) return;
TRaster32P ras; TRasterP ras;
// TRaster32P ras;
TRasterP _rin = rin; TRasterP _rin = rin;
TAffine aff; TAffine aff;
if (m_vSettings.m_useTexture) { if (m_vSettings.m_useTexture) {
@ -398,6 +399,17 @@ void Painter::doFlushRasterImages(const TRasterP &rin, int bg,
// a quickput approximation? // a quickput approximation?
} }
// when the "30bit display" preference option is enabled,
// image previewed in 16bpc is not dithered & converted to 8bpc,
// but is kept the channel depth as 16bpc.
bool is16bpc = false;
if (_rin->getPixelSize() == 8) {
TRaster64P rasAux(ras->getLx(), ras->getLy());
TRop::convert(rasAux, ras);
ras = rasAux;
is16bpc = true;
}
ras->lock(); ras->lock();
bool showChannelsOnMatte = bool showChannelsOnMatte =
@ -433,8 +445,13 @@ void Painter::doFlushRasterImages(const TRasterP &rin, int bg,
// Image size is a 0 point. Do nothing // Image size is a 0 point. Do nothing
if (rect.x0 == rect.x1 && rect.y0 == rect.y1) return; if (rect.x0 == rect.x1 && rect.y0 == rect.y1) return;
TRaster32P raux = ras->extract(rect); if (is16bpc) {
raux->fill(bg == 0x40000 ? TPixel::Black : TPixel::White); TRaster64P raux = ras->extract(rect);
raux->fill(bg == 0x40000 ? TPixel64::Black : TPixel64::White);
} else {
TRaster32P raux = ras->extract(rect);
raux->fill(bg == 0x40000 ? TPixel::Black : TPixel::White);
}
} }
if (showChannelsOnMatte) if (showChannelsOnMatte)
@ -463,8 +480,9 @@ void Painter::doFlushRasterImages(const TRasterP &rin, int bg,
glRasterPos2d(rect.x0, rect.y0); glRasterPos2d(rect.x0, rect.y0);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glDrawPixels(ras->getWrap(), ras->getLy(), TGL_FMT, TGL_TYPE, glDrawPixels(ras->getWrap(), ras->getLy(), TGL_FMT,
ras->getRawData()); (is16bpc) ? TGL_TYPE16 : TGL_TYPE,
(GLvoid *)ras->getRawData());
CHECK_ERRORS_BY_GL CHECK_ERRORS_BY_GL
@ -507,7 +525,7 @@ void Painter::onVectorImage(TVectorImage *vi) {
TVectorRenderData rd(m_aff, clipRect, vi->getPalette(), 0, TVectorRenderData rd(m_aff, clipRect, vi->getPalette(), 0,
true // alfa enabled true // alfa enabled
); );
if (m_vSettings.m_useChecks) { if (m_vSettings.m_useChecks) {
ToonzCheck *tc = ToonzCheck::instance(); ToonzCheck *tc = ToonzCheck::instance();
int checks = tc->getChecks(); // &ToonzCheck::eBlackBg int checks = tc->getChecks(); // &ToonzCheck::eBlackBg
@ -657,8 +675,9 @@ void ImagePainter::paintImage(const TImageP &image, const TDimension &imageSize,
// be done on black bg! // be done on black bg!
if (!vimg) if (!vimg)
painter.flushRasterImages( painter.flushRasterImages(
loadbox, visualSettings.m_doCompare ? compareSettings.m_compareX loadbox,
: DefaultCompareValue, visualSettings.m_doCompare ? compareSettings.m_compareX
: DefaultCompareValue,
visualSettings.m_doCompare ? compareSettings.m_compareY visualSettings.m_doCompare ? compareSettings.m_compareY
: DefaultCompareValue, : DefaultCompareValue,
compareSettings.m_swapCompared); compareSettings.m_swapCompared);

View file

@ -439,6 +439,7 @@ void Preferences::definePreferenceItems() {
false); false);
define(colorCalibrationLutPaths, "colorCalibrationLutPaths", define(colorCalibrationLutPaths, "colorCalibrationLutPaths",
QMetaType::QVariantMap, QVariantMap()); QMetaType::QVariantMap, QVariantMap());
define(displayIn30bit, "displayIn30bit", QMetaType::Bool, false);
// hide menu icons by default in macOS since the icon color may not match with // hide menu icons by default in macOS since the icon color may not match with
// the system color theme // the system color theme