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();
}
//=============================================================================
//=============================================================================
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,
@ -4268,6 +4716,7 @@ void quickPut(const TRasterP &dn, const TRasterP &up, const TAffine &aff,
TRaster32P up32 = up;
TRasterGR8P dn8 = dn;
TRasterGR8P up8 = up;
TRaster64P dn64 = dn;
TRaster64P up64 = up;
if (up8 && dn32) {
@ -4294,6 +4743,10 @@ void quickPut(const TRasterP &dn, const TRasterP &up, const TAffine &aff,
}
} else if (dn32 && up64)
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
throw TRopException("raster type mismatch");
}

View file

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

View file

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

View file

@ -45,6 +45,7 @@ enum PreferencesItemId {
colorCalibrationEnabled,
colorCalibrationLutPaths,
showIconsInMenu,
displayIn30bit,
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) {
return quickOverPixT<TPixel64, USHORT>(bot, top);
}
@ -532,20 +538,24 @@ void mult(T &pixout, const T &pixin, double v) {
g = pixin.g + v;
b = pixin.b + v;
m = pixin.m + v;
pixout.r =
(r < 0) ? 0 : ((r < T::maxChannelValue)
pixout.r = (r < 0)
? 0
: ((r < T::maxChannelValue)
? troundp(r * (pixout.r / (double)T::maxChannelValue))
: pixout.r);
pixout.g =
(g < 0) ? 0 : ((g < T::maxChannelValue)
pixout.g = (g < 0)
? 0
: ((g < T::maxChannelValue)
? troundp(g * (pixout.g / (double)T::maxChannelValue))
: pixout.g);
pixout.b =
(b < 0) ? 0 : ((b < T::maxChannelValue)
pixout.b = (b < 0)
? 0
: ((b < T::maxChannelValue)
? troundp(b * (pixout.b / (double)T::maxChannelValue))
: pixout.b);
pixout.m =
(m < 0) ? 0 : ((m < T::maxChannelValue)
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,
std::vector<int> flipConsoleButtonMask, UCHAR flags,
bool isColorModel) //, bool showOnlyPlayBackgroundButton)
: QWidget(parent),
m_viewerTitle(viewerTitle),
m_levelNames(),
m_levels(),
m_playSound(false),
m_snd(0),
m_player(0)
: QWidget(parent)
, m_viewerTitle(viewerTitle)
, m_levelNames()
, m_levels()
, m_playSound(false)
, m_snd(0)
, m_player(0)
//, m_doCompare(false)
,
m_currentFrameToSave(0),
m_lw(),
m_lr(),
m_loadPopup(0),
m_savePopup(0),
m_shrink(1),
m_isPreviewFx(false),
m_previewedFx(0),
m_previewXsh(0),
m_previewUpdateTimer(this),
m_xl(0),
m_title1(),
m_poolIndex(-1),
m_freezed(false),
m_loadbox(),
m_dim(),
m_loadboxes(),
m_freezeButton(0),
m_flags(flags) {
, m_currentFrameToSave(0)
, m_lw()
, m_lr()
, m_loadPopup(0)
, m_savePopup(0)
, m_shrink(1)
, m_isPreviewFx(false)
, m_previewedFx(0)
, m_previewXsh(0)
, m_previewUpdateTimer(this)
, m_xl(0)
, m_title1()
, m_poolIndex(-1)
, m_freezed(false)
, m_loadbox()
, m_dim()
, m_loadboxes()
, m_freezeButton(0)
, m_flags(flags) {
setAcceptDrops(true);
setFocusPolicy(Qt::StrongFocus);
@ -1141,8 +1140,7 @@ void FlipBook::setLevel(const TFilePath &fp, TPalette *palette, int from,
levelToPush.m_incrementalIndexing = incrementalIndexing;
int formatIdx = Preferences::instance()->matchLevelFormat(fp);
if (formatIdx >= 0 &&
Preferences::instance()
if (formatIdx >= 0 && Preferences::instance()
->levelFormat(formatIdx)
.m_options.m_premultiply) {
levelToPush.m_premultiply = true;
@ -1595,6 +1593,9 @@ TImageP FlipBook::getCurrentImage(int frame) {
lx = m_loadbox.getLx();
}
if (Preferences::instance()->is30bitDisplayEnabled())
ir->enable16BitRead(true);
TImageP img = ir->load();
if (img) {

View file

@ -244,6 +244,11 @@ ImageViewer::ImageViewer(QWidget *parent, FlipBook *flipbook,
if (Preferences::instance()->isColorCalibrationEnabled())
m_lutCalibrator = new LutCalibrator();
#if QT_VERSION >= 0x051000
if (Preferences::instance()->is30bitDisplayEnabled())
setTextureFormat(TGL_TexFmt10);
#endif
}
//-----------------------------------------------------------------------------
@ -488,6 +493,11 @@ void ImageViewer::resizeGL(int w, int h) {
// remake fbo with new size
if (m_lutCalibrator && m_lutCalibrator->isValid()) {
if (m_fbo) delete m_fbo;
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);
}
}
@ -495,6 +505,7 @@ void ImageViewer::resizeGL(int w, int h) {
//-----------------------------------------------------------------------------
void ImageViewer::paintGL() {
initializeOpenGLFunctions();
if (m_lutCalibrator && m_lutCalibrator->isValid()) m_fbo->bind();
TDimension viewerSize(width(), height());
@ -1422,8 +1433,14 @@ void ImageViewer::onPreferenceChanged(const QString& prefName) {
m_lutCalibrator->initialize();
connect(context(), SIGNAL(aboutToBeDestroyed()), this,
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());
}
doneCurrent();
}
update();

View file

@ -528,6 +528,16 @@ int main(int argc, char *argv[]) {
crInstall(&pInfo);
#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
TThread::init();

View file

@ -270,6 +270,89 @@ Preferences::LevelFormat PreferencesPopup::FormatProperties::levelFormat()
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
//**********************************************************************************
@ -691,6 +774,13 @@ void PreferencesPopup::onLutPathChanged() {
//-----------------------------------------------------------------------------
void PreferencesPopup::onCheck30bitDisplay() {
Display30bitChecker checker(this);
checker.exec();
}
//-----------------------------------------------------------------------------
void PreferencesPopup::onAddLevelFormat() {
bool ok = true;
QString formatName = DVGui::getText(tr("New Level Format"),
@ -1016,6 +1106,7 @@ QString PreferencesPopup::getUIString(PreferencesItemId id) {
{colorCalibrationLutPaths,
tr("3DLUT File for [%1]:")
.arg(LutManager::instance()->getMonitorName())},
{displayIn30bit, tr("30bit Display*")},
{showIconsInMenu, tr("Show Icons In Menu*")},
{viewerIndicatorEnabled, tr("Show Viewer Indicators")},
@ -1456,11 +1547,14 @@ QWidget* PreferencesPopup::createInterfacePage() {
for (const QString& name : m_pref->getLanguageList())
languageItemList.push_back(ComboBoxItem(name, name));
QPushButton* check30bitBtn = new QPushButton(tr("Check Availability"));
QWidget* widget = new QWidget(this);
QGridLayout* lay = new QGridLayout();
setupLayout(lay);
insertUI(CurrentStyleSheetName, lay, styleSheetItemList);
int row = lay->rowCount();
// lay->addWidget(new QLabel(tr("Icon Theme*:"), this), 2, 0,
// Qt::AlignRight | Qt::AlignVCenter);
@ -1488,6 +1582,11 @@ QWidget* PreferencesPopup::createInterfacePage() {
// insertUI(interfaceFontStyle, lay, buildFontStyleList());
QGridLayout* colorCalibLay = insertGroupBoxUI(colorCalibrationEnabled, lay);
{ insertUI(colorCalibrationLutPaths, colorCalibLay); }
#if QT_VERSION >= 0x051000
insertUI(displayIn30bit, lay);
row = lay->rowCount();
lay->addWidget(check30bitBtn, row - 1, 3);
#endif
// insertUI(showIconsInMenu, lay);
lay->setRowStretch(lay->rowCount(), 1);
@ -1504,6 +1603,8 @@ QWidget* PreferencesPopup::createInterfacePage() {
ret = ret && connect(TApp::instance()->getCurrentScene(),
SIGNAL(pixelUnitSelected(bool)), this,
SLOT(onPixelUnitExternallySelected(bool)));
ret = ret && connect(check30bitBtn, SIGNAL(clicked()), this,
SLOT(onCheck30bitDisplay()));
assert(ret);
m_onEditedFuncMap.insert(CurrentStyleSheetName,

View file

@ -17,6 +17,9 @@
// Qt includes
#include <QComboBox>
#include <QFontComboBox>
#include <QOpenGLWidget>
#include <QSurfaceFormat>
#include <QOpenGLFunctions>
//==============================================================
@ -65,6 +68,7 @@ public:
private:
class FormatProperties;
class Display30bitChecker;
private:
Preferences* m_pref;
@ -173,6 +177,7 @@ private slots:
void onPixelUnitExternallySelected(bool on);
void onInterfaceFontChanged(const QString& text);
void onLutPathChanged();
void onCheck30bitDisplay();
void onAddLevelFormat();
void onRemoveLevelFormat();
@ -212,4 +217,36 @@ private slots:
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

View file

@ -1070,7 +1070,9 @@ void PreviewFxInstance::doOnRenderRasterCompleted(
/*-- 16bpcで計算された場合、結果をDitheringする --*/
TRasterP rasA = renderData.m_rasA;
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());
TRop::convert(auxA, rasA); // dithering

View file

@ -835,6 +835,10 @@ SceneViewer::SceneViewer(ImageUtils::FullScreenWidget *parent)
if (Preferences::instance()->isColorCalibrationEnabled())
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();
connect(context(), SIGNAL(aboutToBeDestroyed()), this,
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());
}
doneCurrent();
}
update();
@ -1279,6 +1289,11 @@ void SceneViewer::resizeGL(int w, int h) {
// remake fbo with new size
if (m_lutCalibrator && m_lutCalibrator->isValid()) {
if (m_fbo) delete m_fbo;
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);
}

View file

@ -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));
if (rect.isEmpty()) return;
TRaster32P ras;
TRasterP ras;
// TRaster32P ras;
TRasterP _rin = rin;
TAffine aff;
if (m_vSettings.m_useTexture) {
@ -398,6 +399,17 @@ void Painter::doFlushRasterImages(const TRasterP &rin, int bg,
// 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();
bool showChannelsOnMatte =
@ -433,9 +445,14 @@ void Painter::doFlushRasterImages(const TRasterP &rin, int bg,
// Image size is a 0 point. Do nothing
if (rect.x0 == rect.x1 && rect.y0 == rect.y1) return;
if (is16bpc) {
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)
quickput(ras, keepChannels(_rin, m_palette, chan), m_palette,
@ -463,8 +480,9 @@ void Painter::doFlushRasterImages(const TRasterP &rin, int bg,
glRasterPos2d(rect.x0, rect.y0);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glDrawPixels(ras->getWrap(), ras->getLy(), TGL_FMT, TGL_TYPE,
ras->getRawData());
glDrawPixels(ras->getWrap(), ras->getLy(), TGL_FMT,
(is16bpc) ? TGL_TYPE16 : TGL_TYPE,
(GLvoid *)ras->getRawData());
CHECK_ERRORS_BY_GL
@ -657,7 +675,8 @@ void ImagePainter::paintImage(const TImageP &image, const TDimension &imageSize,
// be done on black bg!
if (!vimg)
painter.flushRasterImages(
loadbox, visualSettings.m_doCompare ? compareSettings.m_compareX
loadbox,
visualSettings.m_doCompare ? compareSettings.m_compareX
: DefaultCompareValue,
visualSettings.m_doCompare ? compareSettings.m_compareY
: DefaultCompareValue,

View file

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