mirror of https://github.com/KLayout/klayout.git
A refactoring attempt for the Retina display issue (#94)
This is what's been done: - remove the old double and single buffering /w mask approach - modify the bitmap rendering so it's done in a offscreen image before subsampling (effect: rulers display smoothly in subsampling mode) - refactoring the "device pixel ratio" topic: Made the DPR a variable, viewport width is scaled up to reflect the true image size, inserted #ifdef's for Qt4. DISCLAIMER: I don't know whether this still works - I don't have a Retina display :-(
This commit is contained in:
parent
a6738f5be4
commit
0a01946202
|
|
@ -424,6 +424,7 @@ bitmaps_to_image_rgb (const std::vector<lay::ViewOp> &view_ops_in,
|
||||||
const lay::LineStyles &ls,
|
const lay::LineStyles &ls,
|
||||||
QImage *pimage, unsigned int width, unsigned int height,
|
QImage *pimage, unsigned int width, unsigned int height,
|
||||||
bool use_bitmap_index,
|
bool use_bitmap_index,
|
||||||
|
bool transparent,
|
||||||
QMutex *mutex)
|
QMutex *mutex)
|
||||||
{
|
{
|
||||||
unsigned int n_in = view_ops_in.size ();
|
unsigned int n_in = view_ops_in.size ();
|
||||||
|
|
@ -583,11 +584,15 @@ bitmaps_to_image_rgb (const std::vector<lay::ViewOp> &view_ops_in,
|
||||||
unsigned int i = 0;
|
unsigned int i = 0;
|
||||||
for (unsigned int x = 0; x < width; x += 32, ++i) {
|
for (unsigned int x = 0; x < width; x += 32, ++i) {
|
||||||
|
|
||||||
lay::color_t y[32] = {
|
lay::color_t y[32];
|
||||||
fill_bits, fill_bits, fill_bits, fill_bits, fill_bits, fill_bits, fill_bits, fill_bits,
|
if (transparent) {
|
||||||
fill_bits, fill_bits, fill_bits, fill_bits, fill_bits, fill_bits, fill_bits, fill_bits,
|
for (int i = 0; i < 32; ++i) {
|
||||||
fill_bits, fill_bits, fill_bits, fill_bits, fill_bits, fill_bits, fill_bits, fill_bits,
|
y[i] = 0;
|
||||||
fill_bits, fill_bits, fill_bits, fill_bits, fill_bits, fill_bits, fill_bits, fill_bits,
|
}
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < 32; ++i) {
|
||||||
|
y[i] = fill_bits;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
lay::color_t z[32] = {
|
lay::color_t z[32] = {
|
||||||
|
|
@ -603,17 +608,32 @@ bitmaps_to_image_rgb (const std::vector<lay::ViewOp> &view_ops_in,
|
||||||
|
|
||||||
dptr = dptr_end - nwords + i;
|
dptr = dptr_end - nwords + i;
|
||||||
for (int j = masks.size () - 1; j >= 0; --j) {
|
for (int j = masks.size () - 1; j >= 0; --j) {
|
||||||
|
|
||||||
uint32_t d = *dptr;
|
uint32_t d = *dptr;
|
||||||
if (d != 0) {
|
if (d != 0) {
|
||||||
uint32_t m = 1;
|
|
||||||
for (unsigned int k = 0; k < 32 && x + k < width; ++k, m <<= 1) {
|
if (transparent) {
|
||||||
if ((d & m) != 0) {
|
uint32_t m = 1;
|
||||||
y [k] |= masks [j].first & z [k];
|
for (unsigned int k = 0; k < 32 && x + k < width; ++k, m <<= 1) {
|
||||||
z [k] &= masks [j].second;
|
if ((d & m) != 0) {
|
||||||
|
y [k] |= (masks [j].first & z [k]) | fill_bits;
|
||||||
|
z [k] &= masks [j].second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
uint32_t m = 1;
|
||||||
|
for (unsigned int k = 0; k < 32 && x + k < width; ++k, m <<= 1) {
|
||||||
|
if ((d & m) != 0) {
|
||||||
|
y [k] |= masks [j].first & z [k];
|
||||||
|
z [k] &= masks [j].second;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dptr -= nwords;
|
dptr -= nwords;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int k = 0; k < 32 && x + k < width; ++k) {
|
for (unsigned int k = 0; k < 32 && x + k < width; ++k) {
|
||||||
|
|
@ -843,7 +863,8 @@ bitmaps_to_image (const std::vector<lay::ViewOp> &view_ops_in,
|
||||||
if (pimage->depth () <= 1) {
|
if (pimage->depth () <= 1) {
|
||||||
bitmaps_to_image_mono (view_ops_in, pbitmaps_in, dp, ls, pimage, width, height, use_bitmap_index, mutex);
|
bitmaps_to_image_mono (view_ops_in, pbitmaps_in, dp, ls, pimage, width, height, use_bitmap_index, mutex);
|
||||||
} else {
|
} else {
|
||||||
bitmaps_to_image_rgb (view_ops_in, pbitmaps_in, dp, ls, pimage, width, height, use_bitmap_index, mutex);
|
bool transparent = (pimage->format () == QImage::Format_ARGB32);
|
||||||
|
bitmaps_to_image_rgb (view_ops_in, pbitmaps_in, dp, ls, pimage, width, height, use_bitmap_index, transparent, mutex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QBuffer>
|
#include <QBuffer>
|
||||||
|
#include <QWheelEvent>
|
||||||
|
|
||||||
#include "tlTimer.h"
|
#include "tlTimer.h"
|
||||||
#include "tlLog.h"
|
#include "tlLog.h"
|
||||||
|
|
@ -130,19 +131,6 @@ std::string ImageCacheEntry::to_string () const
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
#if defined (_WIN32) || defined (Q_WS_MAC) || QT_VERSION >= 0x40600
|
|
||||||
// Windows build runs well with single buffering
|
|
||||||
// and Qt built with double buffering.
|
|
||||||
// The same is true vor MAC OS X
|
|
||||||
// In Qt 4.8 the SINGLE_BUFFERED_MASK implementation no longer
|
|
||||||
// works properly and double buffering is default anyway.
|
|
||||||
# define SINGLE_BUFFERED
|
|
||||||
#else
|
|
||||||
// X11 runs better with the SINGLE_BUFFERED_MASK scheme
|
|
||||||
// # define SINGLE_BUFFERED
|
|
||||||
# define SINGLE_BUFFERED_MASK
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
blowup (const QImage &src, QImage &dest, unsigned int os)
|
blowup (const QImage &src, QImage &dest, unsigned int os)
|
||||||
{
|
{
|
||||||
|
|
@ -164,28 +152,46 @@ blowup (const QImage &src, QImage &dest, unsigned int os)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
subsample (const QImage &src, QImage &dest, unsigned int os)
|
subsample (const QImage &src, QImage &dest, unsigned int os, double g)
|
||||||
{
|
{
|
||||||
// TODO: this is probably not compatible with the endianess of SPARC ..
|
// TODO: this is probably not compatible with the endianess of SPARC ..
|
||||||
|
|
||||||
double g = 2.0; // is something 1.8 .. 2.2
|
// LUT's for combining the RGB channels
|
||||||
|
|
||||||
|
// forward transformation table
|
||||||
unsigned short lut1[256];
|
unsigned short lut1[256];
|
||||||
for (unsigned int i = 0; i < 256; ++i) {
|
for (unsigned int i = 0; i < 256; ++i) {
|
||||||
double f = (65536 / (os * os)) - 1;
|
double f = (65536 / (os * os)) - 1;
|
||||||
lut1[i] = (unsigned short)std::min (f, std::max (0.0, floor (0.5 + pow (i / 255.0, g) * f)));
|
lut1[i] = (unsigned short)std::min (f, std::max (0.0, floor (0.5 + pow (i / 255.0, g) * f)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// backward transformation table
|
||||||
unsigned char lut2[65536];
|
unsigned char lut2[65536];
|
||||||
for (unsigned int i = 0; i < 65536; ++i) {
|
for (unsigned int i = 0; i < 65536; ++i) {
|
||||||
double f = os * os * ((65536 / (os * os)) - 1);
|
double f = os * os * ((65536 / (os * os)) - 1);
|
||||||
lut2[i] = (unsigned char)std::min (255.0, std::max (0.0, floor (0.5 + pow (i / f, 1.0 / g) * 255.0)));
|
lut2[i] = (unsigned char)std::min (255.0, std::max (0.0, floor (0.5 + pow (i / f, 1.0 / g) * 255.0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LUT's for alpha channel
|
||||||
|
|
||||||
|
// forward transformation table
|
||||||
|
unsigned short luta1[256];
|
||||||
|
for (unsigned int i = 0; i < 256; ++i) {
|
||||||
|
double f = (65536 / (os * os)) - 1;
|
||||||
|
luta1[i] = (unsigned short)std::min (f, std::max (0.0, floor (0.5 + (i / 255.0) * f)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// backward transformation table
|
||||||
|
unsigned char luta2[65536];
|
||||||
|
for (unsigned int i = 0; i < 65536; ++i) {
|
||||||
|
double f = os * os * ((65536 / (os * os)) - 1);
|
||||||
|
luta2[i] = (unsigned char)std::min (255.0, std::max (0.0, floor (0.5 + (i / f) * 255.0)));
|
||||||
|
}
|
||||||
|
|
||||||
unsigned int ymax = dest.height ();
|
unsigned int ymax = dest.height ();
|
||||||
unsigned int xmax = dest.width ();
|
unsigned int xmax = dest.width ();
|
||||||
|
|
||||||
unsigned short *buffer = new unsigned short[xmax * 3];
|
unsigned short *buffer = new unsigned short[xmax * 4];
|
||||||
|
|
||||||
for (unsigned int y = 0; y < ymax; ++y) {
|
for (unsigned int y = 0; y < ymax; ++y) {
|
||||||
|
|
||||||
|
|
@ -199,16 +205,18 @@ subsample (const QImage &src, QImage &dest, unsigned int os)
|
||||||
pdest[0] = lut1[psrc[0]];
|
pdest[0] = lut1[psrc[0]];
|
||||||
pdest[1] = lut1[psrc[1]];
|
pdest[1] = lut1[psrc[1]];
|
||||||
pdest[2] = lut1[psrc[2]];
|
pdest[2] = lut1[psrc[2]];
|
||||||
|
pdest[3] = luta1[psrc[3]];
|
||||||
psrc += 4;
|
psrc += 4;
|
||||||
|
|
||||||
for (unsigned int j = os; j > 1; j--) {
|
for (unsigned int j = os; j > 1; j--) {
|
||||||
pdest[0] += lut1[psrc[0]];
|
pdest[0] += lut1[psrc[0]];
|
||||||
pdest[1] += lut1[psrc[1]];
|
pdest[1] += lut1[psrc[1]];
|
||||||
pdest[2] += lut1[psrc[2]];
|
pdest[2] += lut1[psrc[2]];
|
||||||
|
pdest[3] += luta1[psrc[3]];
|
||||||
psrc += 4;
|
psrc += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
pdest += 3;
|
pdest += 4;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -225,10 +233,11 @@ subsample (const QImage &src, QImage &dest, unsigned int os)
|
||||||
pdest[0] += lut1[psrc[0]];
|
pdest[0] += lut1[psrc[0]];
|
||||||
pdest[1] += lut1[psrc[1]];
|
pdest[1] += lut1[psrc[1]];
|
||||||
pdest[2] += lut1[psrc[2]];
|
pdest[2] += lut1[psrc[2]];
|
||||||
|
pdest[3] += luta1[psrc[3]];
|
||||||
psrc += 4;
|
psrc += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
pdest += 3;
|
pdest += 4;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -243,7 +252,7 @@ subsample (const QImage &src, QImage &dest, unsigned int os)
|
||||||
*pdest++ = lut2[*psrc++];
|
*pdest++ = lut2[*psrc++];
|
||||||
*pdest++ = lut2[*psrc++];
|
*pdest++ = lut2[*psrc++];
|
||||||
*pdest++ = lut2[*psrc++];
|
*pdest++ = lut2[*psrc++];
|
||||||
*pdest++ = 0xff;
|
*pdest++ = luta2[*psrc++];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -253,64 +262,6 @@ subsample (const QImage &src, QImage &dest, unsigned int os)
|
||||||
delete[] buffer;
|
delete[] buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
subsample (unsigned char *data, unsigned int width, unsigned int height, unsigned int os)
|
|
||||||
{
|
|
||||||
if (os == 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int nbytes = (width * os + 7) / 8;
|
|
||||||
|
|
||||||
unsigned char *psrc = data;
|
|
||||||
unsigned char *pdest = psrc;
|
|
||||||
|
|
||||||
for (unsigned int y = 0; y < height; ++y) {
|
|
||||||
|
|
||||||
unsigned int bdest = 0;
|
|
||||||
unsigned int bsrc = 0;
|
|
||||||
|
|
||||||
unsigned char dd = 0;
|
|
||||||
unsigned char m = 0x01;
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < nbytes; ++i) {
|
|
||||||
|
|
||||||
unsigned char *p = psrc++;
|
|
||||||
unsigned char d = *p;
|
|
||||||
for (unsigned int j = 1; j < os; ++j) {
|
|
||||||
p += nbytes;
|
|
||||||
d |= *p;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned int b = 0; b < 8; ++b) {
|
|
||||||
if ((d & 1) != 0) {
|
|
||||||
dd |= m;
|
|
||||||
}
|
|
||||||
d >>= 1;
|
|
||||||
if (++bsrc == os) {
|
|
||||||
bsrc = 0;
|
|
||||||
++bdest;
|
|
||||||
m <<= 1;
|
|
||||||
if (bdest == 8) {
|
|
||||||
*pdest++ = dd;
|
|
||||||
bdest = 0;
|
|
||||||
dd = 0;
|
|
||||||
m = 0x01;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
psrc += nbytes * (os - 1);
|
|
||||||
|
|
||||||
if (bdest > 0) {
|
|
||||||
*pdest++ = dd;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
invert (unsigned char *data, unsigned int width, unsigned int height)
|
invert (unsigned char *data, unsigned int width, unsigned int height)
|
||||||
{
|
{
|
||||||
|
|
@ -329,6 +280,7 @@ LayoutCanvas::LayoutCanvas (QWidget *parent, lay::LayoutView *view, const char *
|
||||||
mp_image (0), mp_image_bg (0), mp_pixmap (0),
|
mp_image (0), mp_image_bg (0), mp_pixmap (0),
|
||||||
m_background (0), m_foreground (0), m_active (0),
|
m_background (0), m_foreground (0), m_active (0),
|
||||||
m_oversampling (1),
|
m_oversampling (1),
|
||||||
|
m_dpr (1),
|
||||||
m_need_redraw (false),
|
m_need_redraw (false),
|
||||||
m_redraw_clearing (false),
|
m_redraw_clearing (false),
|
||||||
m_redraw_force_update (true),
|
m_redraw_force_update (true),
|
||||||
|
|
@ -337,9 +289,18 @@ LayoutCanvas::LayoutCanvas (QWidget *parent, lay::LayoutView *view, const char *
|
||||||
m_do_end_of_drawing_dm (this, &LayoutCanvas::do_end_of_drawing),
|
m_do_end_of_drawing_dm (this, &LayoutCanvas::do_end_of_drawing),
|
||||||
m_image_cache_size (1)
|
m_image_cache_size (1)
|
||||||
{
|
{
|
||||||
|
#if QT_VERSION > 0x050000
|
||||||
|
m_dpr = devicePixelRatio ();
|
||||||
|
#else
|
||||||
|
m_dpr = 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// The gamma value used for subsampling: something between 1.8 and 2.2.
|
||||||
|
m_gamma = 2.0;
|
||||||
|
|
||||||
// some reasonable initializations for the size
|
// some reasonable initializations for the size
|
||||||
m_viewport.set_size (100, 100);
|
m_viewport.set_size (100, 100);
|
||||||
m_viewport_l.set_size (m_viewport.width () * m_oversampling * 2, m_viewport.height () * m_oversampling * 2);
|
m_viewport_l.set_size (m_viewport.width () * m_oversampling, m_viewport.height () * m_oversampling);
|
||||||
|
|
||||||
mp_redraw_thread = new lay::RedrawThread (this, view);
|
mp_redraw_thread = new lay::RedrawThread (this, view);
|
||||||
|
|
||||||
|
|
@ -347,9 +308,6 @@ LayoutCanvas::LayoutCanvas (QWidget *parent, lay::LayoutView *view, const char *
|
||||||
set_colors (palette ().color (QPalette::Normal, QPalette::Background),
|
set_colors (palette ().color (QPalette::Normal, QPalette::Background),
|
||||||
palette ().color (QPalette::Normal, QPalette::Text),
|
palette ().color (QPalette::Normal, QPalette::Text),
|
||||||
palette ().color (QPalette::Normal, QPalette::Mid));
|
palette ().color (QPalette::Normal, QPalette::Mid));
|
||||||
#ifndef SINGLE_BUFFERED
|
|
||||||
setAttribute (Qt::WA_PaintOnScreen);
|
|
||||||
#endif
|
|
||||||
setAttribute (Qt::WA_NoSystemBackground);
|
setAttribute (Qt::WA_NoSystemBackground);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -416,7 +374,7 @@ LayoutCanvas::set_oversampling (unsigned int os)
|
||||||
if (os != m_oversampling) {
|
if (os != m_oversampling) {
|
||||||
m_image_cache.clear ();
|
m_image_cache.clear ();
|
||||||
m_oversampling = os;
|
m_oversampling = os;
|
||||||
m_viewport_l.set_size (m_viewport.width () * m_oversampling * 2, m_viewport.height () * m_oversampling * 2);
|
m_viewport_l.set_size (m_viewport.width () * m_oversampling, m_viewport.height () * m_oversampling);
|
||||||
do_redraw_all ();
|
do_redraw_all ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -469,7 +427,7 @@ LayoutCanvas::prepare_drawing ()
|
||||||
{
|
{
|
||||||
if (m_need_redraw) {
|
if (m_need_redraw) {
|
||||||
|
|
||||||
BitmapViewObjectCanvas::set_size (m_viewport_l.width (), m_viewport_l.height (), 1.0 / double (m_oversampling) / 2);
|
BitmapViewObjectCanvas::set_size (m_viewport_l.width (), m_viewport_l.height (), 1.0 / double (m_oversampling * m_dpr));
|
||||||
|
|
||||||
if (! mp_image ||
|
if (! mp_image ||
|
||||||
(unsigned int) mp_image->width () != m_viewport_l.width () ||
|
(unsigned int) mp_image->width () != m_viewport_l.width () ||
|
||||||
|
|
@ -478,7 +436,9 @@ LayoutCanvas::prepare_drawing ()
|
||||||
delete mp_image;
|
delete mp_image;
|
||||||
}
|
}
|
||||||
mp_image = new QImage (m_viewport_l.width (), m_viewport_l.height (), QImage::Format_RGB32);
|
mp_image = new QImage (m_viewport_l.width (), m_viewport_l.height (), QImage::Format_RGB32);
|
||||||
mp_image->setDevicePixelRatio(2.0);
|
#if QT_VERSION > 0x050000
|
||||||
|
mp_image->setDevicePixelRatio (double (m_dpr));
|
||||||
|
#endif
|
||||||
if (mp_pixmap) {
|
if (mp_pixmap) {
|
||||||
delete mp_pixmap;
|
delete mp_pixmap;
|
||||||
mp_pixmap = 0;
|
mp_pixmap = 0;
|
||||||
|
|
@ -506,7 +466,7 @@ LayoutCanvas::prepare_drawing ()
|
||||||
++c;
|
++c;
|
||||||
}
|
}
|
||||||
|
|
||||||
mp_redraw_thread->commit (m_layers, m_viewport_l, 1.0 / double (m_oversampling) / 2);
|
mp_redraw_thread->commit (m_layers, m_viewport_l, 1.0 / double (m_oversampling * m_dpr));
|
||||||
|
|
||||||
if (tl::verbosity () >= 20) {
|
if (tl::verbosity () >= 20) {
|
||||||
tl::info << "Restored image from cache";
|
tl::info << "Restored image from cache";
|
||||||
|
|
@ -556,7 +516,7 @@ LayoutCanvas::prepare_drawing ()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_redraw_clearing) {
|
if (m_redraw_clearing) {
|
||||||
mp_redraw_thread->start (mp_view->synchronous () ? 0 : mp_view->drawing_workers (), m_layers, m_viewport_l, 1.0 / double (m_oversampling) / 2, m_redraw_force_update);
|
mp_redraw_thread->start (mp_view->synchronous () ? 0 : mp_view->drawing_workers (), m_layers, m_viewport_l, 1.0 / double (m_oversampling * m_dpr), m_redraw_force_update);
|
||||||
} else {
|
} else {
|
||||||
mp_redraw_thread->restart (m_need_redraw_layer);
|
mp_redraw_thread->restart (m_need_redraw_layer);
|
||||||
}
|
}
|
||||||
|
|
@ -637,11 +597,6 @@ LayoutCanvas::paintEvent (QPaintEvent *)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// prepare a buffer
|
|
||||||
size_t nbytes = (m_viewport_l.width () + 7) / 8 * m_viewport_l.height ();
|
|
||||||
unsigned char *p_data = new unsigned char [nbytes];
|
|
||||||
memset (p_data, 0, nbytes);
|
|
||||||
|
|
||||||
// create a base pixmap consisting of the layout with background
|
// create a base pixmap consisting of the layout with background
|
||||||
// and static foreground objects
|
// and static foreground objects
|
||||||
|
|
||||||
|
|
@ -661,16 +616,20 @@ LayoutCanvas::paintEvent (QPaintEvent *)
|
||||||
if (fg_bitmaps () > 0) {
|
if (fg_bitmaps () > 0) {
|
||||||
|
|
||||||
QImage full_image (*mp_image);
|
QImage full_image (*mp_image);
|
||||||
full_image.setDevicePixelRatio(2.0);
|
#if QT_VERSION > 0x050000
|
||||||
|
full_image.setDevicePixelRatio (double (m_dpr));
|
||||||
|
#endif
|
||||||
bitmaps_to_image (fg_view_op_vector (), fg_bitmap_vector (), dither_pattern (), line_styles (), &full_image, m_viewport_l.width (), m_viewport_l.height (), false, &m_mutex);
|
bitmaps_to_image (fg_view_op_vector (), fg_bitmap_vector (), dither_pattern (), line_styles (), &full_image, m_viewport_l.width (), m_viewport_l.height (), false, &m_mutex);
|
||||||
|
|
||||||
// render the foreground parts ..
|
// render the foreground parts ..
|
||||||
if (m_oversampling == 1) {
|
if (m_oversampling == 1) {
|
||||||
*mp_pixmap = QPixmap::fromImage (full_image); // Qt 4.6.0 workaround
|
*mp_pixmap = QPixmap::fromImage (full_image); // Qt 4.6.0 workaround
|
||||||
} else {
|
} else {
|
||||||
QImage subsampled_image (m_viewport.width () * 2, m_viewport.height () * 2, mp_image->format ());
|
QImage subsampled_image (m_viewport.width (), m_viewport.height (), mp_image->format ());
|
||||||
subsampled_image.setDevicePixelRatio(2.0);
|
#if QT_VERSION > 0x050000
|
||||||
subsample (full_image, subsampled_image, m_oversampling);
|
subsampled_image.setDevicePixelRatio (double (m_dpr));
|
||||||
|
#endif
|
||||||
|
subsample (full_image, subsampled_image, m_oversampling, m_gamma);
|
||||||
*mp_pixmap = QPixmap::fromImage (subsampled_image); // Qt 4.6.0 workaround
|
*mp_pixmap = QPixmap::fromImage (subsampled_image); // Qt 4.6.0 workaround
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -680,9 +639,11 @@ LayoutCanvas::paintEvent (QPaintEvent *)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
QImage subsampled_image (m_viewport.width () * 2, m_viewport.height () * 2, mp_image->format ());
|
QImage subsampled_image (m_viewport.width (), m_viewport.height (), mp_image->format ());
|
||||||
subsampled_image.setDevicePixelRatio(2.0);
|
#if QT_VERSION > 0x050000
|
||||||
subsample (*mp_image, subsampled_image, m_oversampling);
|
subsampled_image.setDevicePixelRatio (double (m_dpr));
|
||||||
|
#endif
|
||||||
|
subsample (*mp_image, subsampled_image, m_oversampling, m_gamma);
|
||||||
*mp_pixmap = QPixmap::fromImage (subsampled_image);
|
*mp_pixmap = QPixmap::fromImage (subsampled_image);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -692,109 +653,36 @@ LayoutCanvas::paintEvent (QPaintEvent *)
|
||||||
// erase any previous data
|
// erase any previous data
|
||||||
clear_fg_bitmaps ();
|
clear_fg_bitmaps ();
|
||||||
|
|
||||||
// render foreground content
|
// render dynamic foreground content
|
||||||
do_render (m_viewport_l, *this, false);
|
do_render (m_viewport_l, *this, false);
|
||||||
|
|
||||||
#if defined(SINGLE_BUFFERED)
|
|
||||||
|
|
||||||
// Single-buffering scheme - somewhat more flickering
|
|
||||||
// but less resource requirements.
|
|
||||||
|
|
||||||
// produce the pixmap first and then overdraw with dynamic content.
|
// produce the pixmap first and then overdraw with dynamic content.
|
||||||
QPainter painter (this);
|
QPainter painter (this);
|
||||||
painter.drawPixmap (QPoint (0, 0), *mp_pixmap);
|
painter.drawPixmap (QPoint (0, 0), *mp_pixmap);
|
||||||
|
|
||||||
// dynamic bitmaps are always drawn in transparent mode ..
|
if (fg_bitmaps () > 0) {
|
||||||
painter.setBackgroundMode (Qt::TransparentMode);
|
|
||||||
|
|
||||||
// create QBitmap objects and paint them for the bitmaps
|
QImage full_image (mp_image->size ().width (), mp_image->size ().height (), QImage::Format_ARGB32);
|
||||||
// present
|
full_image.fill (0);
|
||||||
for (unsigned int n = 0; n < fg_bitmaps (); ++n) {
|
|
||||||
if (fg_bitmap (n) != 0) {
|
|
||||||
memset (p_data, 0, nbytes);
|
|
||||||
bitmap_to_bitmap (fg_style (n), *fg_bitmap (n), p_data, m_viewport_l.width (), m_viewport_l.height (), dither_pattern (), line_styles ());
|
|
||||||
subsample (p_data, m_viewport.width (), m_viewport.height (), m_oversampling * 2);
|
|
||||||
QBitmap bitmap = QBitmap::fromData (QSize (m_viewport.width (), m_viewport.height ()), p_data);
|
|
||||||
QPen pen (QRgb (fg_style (n).ormask ()));
|
|
||||||
//pen.setWidthF(1.5);
|
|
||||||
painter.setPen (pen);
|
|
||||||
painter.drawPixmap (0, 0, bitmap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif defined(SINGLE_BUFFERED_MASK)
|
|
||||||
|
|
||||||
// Single-buffering scheme with mask - somewhat more flickering
|
|
||||||
// but less resource requirements.
|
|
||||||
|
|
||||||
// combine the bitmaps into a mask
|
|
||||||
for (unsigned int n = 0; n < fg_bitmaps (); ++n) {
|
|
||||||
if (fg_bitmap (n) != 0) {
|
|
||||||
bitmap_to_bitmap (fg_style (n), *fg_bitmap (n), p_data, m_viewport_l.width (), m_viewport_l.height (), dither_pattern ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// invert and subsample the mask
|
|
||||||
subsample (p_data, m_viewport.width (), m_viewport.height (), m_oversampling * 2);
|
|
||||||
invert (p_data, m_viewport.width (), m_viewport.height ());
|
|
||||||
|
|
||||||
// create the mask
|
|
||||||
QBitmap mask = QBitmap::fromData (QSize (m_viewport.width (), m_viewport.height ()), p_data);
|
|
||||||
mp_pixmap->setMask (mask);
|
|
||||||
|
|
||||||
// produce the pixmap with the mask
|
|
||||||
QPainter painter (this);
|
|
||||||
painter.drawPixmap (QPoint (0, 0), *mp_pixmap);
|
|
||||||
|
|
||||||
// dynamic bitmaps are always drawn in transparent mode ..
|
|
||||||
painter.setBackgroundMode (Qt::TransparentMode);
|
|
||||||
|
|
||||||
// create QBitmap objects and paint them for the bitmaps
|
|
||||||
// present
|
|
||||||
for (unsigned int n = 0; n < fg_bitmaps (); ++n) {
|
|
||||||
if (fg_bitmap (n) != 0) {
|
|
||||||
memset (p_data, 0, nbytes);
|
|
||||||
bitmap_to_bitmap (fg_style (n), *fg_bitmap (n), p_data, m_viewport_l.width (), m_viewport_l.height (), dither_pattern ());
|
|
||||||
subsample (p_data, m_viewport.width (), m_viewport.height (), m_oversampling * 2);
|
|
||||||
QBitmap bitmap = QBitmap::fromData (QSize (m_viewport.width (), m_viewport.height ()), p_data);
|
|
||||||
painter.setPen (QRgb (fg_style (n).ormask ()));
|
|
||||||
painter.drawPixmap (0, 0, bitmap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
// Double-buffering scheme - somewhat less flickering but
|
|
||||||
// only efficient if the QImage has the precise size and
|
|
||||||
// at the cost of twice the X resource requirements.
|
|
||||||
|
|
||||||
// create an intermediate pixmap
|
|
||||||
QPixmap px (*mp_pixmap);
|
|
||||||
|
|
||||||
// dynamic bitmaps are always drawn in transparent mode ..
|
|
||||||
QPainter painter (&px);
|
|
||||||
painter.setBackgroundMode (Qt::TransparentMode);
|
|
||||||
|
|
||||||
// create QBitmap objects and paint them for the bitmaps
|
|
||||||
// present
|
|
||||||
for (unsigned int n = 0; n < fg_bitmaps (); ++n) {
|
|
||||||
if (fg_bitmap (n) != 0) {
|
|
||||||
memset (p_data, 0, nbytes);
|
|
||||||
bitmap_to_bitmap (fg_style (n), *fg_bitmap (n), p_data, m_viewport.width (), m_viewport.height (), dither_pattern ());
|
|
||||||
QBitmap bitmap = QBitmap::fromData (QSize (m_viewport.width (), m_viewport.height ()), p_data);
|
|
||||||
painter.setPen (QRgb (fg_style (n).ormask ()));
|
|
||||||
painter.drawPixmap (0, 0, bitmap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// produce the combined pixmap on the window
|
|
||||||
QPainter screen_painter (this);
|
|
||||||
screen_painter.drawPixmap (QPoint (0, 0), px);
|
|
||||||
|
|
||||||
|
#if QT_VERSION > 0x050000
|
||||||
|
full_image.setDevicePixelRatio (double (m_dpr));
|
||||||
#endif
|
#endif
|
||||||
|
bitmaps_to_image (fg_view_op_vector (), fg_bitmap_vector (), dither_pattern (), line_styles (), &full_image, m_viewport_l.width (), m_viewport_l.height (), false, &m_mutex);
|
||||||
|
|
||||||
// delete buffer
|
// render the foreground parts ..
|
||||||
delete [] p_data;
|
if (m_oversampling == 1) {
|
||||||
|
painter.drawPixmap (QPoint (0, 0), QPixmap::fromImage (full_image));
|
||||||
|
} else {
|
||||||
|
QImage subsampled_image (m_viewport.width (), m_viewport.height (), QImage::Format_ARGB32);
|
||||||
|
#if QT_VERSION > 0x050000
|
||||||
|
subsampled_image.setDevicePixelRatio (double (m_dpr));
|
||||||
|
#endif
|
||||||
|
subsample (full_image, subsampled_image, m_oversampling, m_gamma);
|
||||||
|
painter.drawPixmap (QPoint (0, 0), QPixmap::fromImage (subsampled_image));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// erase dynamic bitmaps
|
// erase dynamic bitmaps
|
||||||
clear_fg_bitmaps ();
|
clear_fg_bitmaps ();
|
||||||
|
|
@ -815,6 +703,9 @@ public:
|
||||||
: BitmapViewObjectCanvas (width_l, height_l, resolution),
|
: BitmapViewObjectCanvas (width_l, height_l, resolution),
|
||||||
m_bg (bg), m_fg (fg), m_ac (ac), mp_image (img)
|
m_bg (bg), m_fg (fg), m_ac (ac), mp_image (img)
|
||||||
{
|
{
|
||||||
|
// TODO: Good choice?
|
||||||
|
m_gamma = 2.0;
|
||||||
|
|
||||||
if (img->width () != int (width_l) || img->height () != int (height_l)) {
|
if (img->width () != int (width_l) || img->height () != int (height_l)) {
|
||||||
mp_image_l = new QImage (width_l, height_l, img->format ());
|
mp_image_l = new QImage (width_l, height_l, img->format ());
|
||||||
mp_image_l->fill (bg.rgb ());
|
mp_image_l->fill (bg.rgb ());
|
||||||
|
|
@ -859,7 +750,7 @@ public:
|
||||||
unsigned int os = mp_image_l->width () / width;
|
unsigned int os = mp_image_l->width () / width;
|
||||||
blowup (*mp_image, *mp_image_l, os);
|
blowup (*mp_image, *mp_image_l, os);
|
||||||
bitmaps_to_image (fg_view_op_vector (), fg_bitmap_vector (), dp, ls, mp_image_l, mp_image_l->width (), mp_image_l->height (), false, 0);
|
bitmaps_to_image (fg_view_op_vector (), fg_bitmap_vector (), dp, ls, mp_image_l, mp_image_l->width (), mp_image_l->height (), false, 0);
|
||||||
subsample (*mp_image_l, *mp_image, os);
|
subsample (*mp_image_l, *mp_image, os, m_gamma);
|
||||||
} else {
|
} else {
|
||||||
bitmaps_to_image (fg_view_op_vector (), fg_bitmap_vector (), dp, ls, mp_image, width, height, false, 0);
|
bitmaps_to_image (fg_view_op_vector (), fg_bitmap_vector (), dp, ls, mp_image, width, height, false, 0);
|
||||||
}
|
}
|
||||||
|
|
@ -870,7 +761,7 @@ public:
|
||||||
{
|
{
|
||||||
if (mp_image_l && mp_image->width () > 0) {
|
if (mp_image_l && mp_image->width () > 0) {
|
||||||
unsigned int os = mp_image_l->width () / mp_image->width ();
|
unsigned int os = mp_image_l->width () / mp_image->width ();
|
||||||
subsample (*mp_image_l, *mp_image, os);
|
subsample (*mp_image_l, *mp_image, os, m_gamma);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -878,6 +769,7 @@ private:
|
||||||
QColor m_bg, m_fg, m_ac;
|
QColor m_bg, m_fg, m_ac;
|
||||||
QImage *mp_image;
|
QImage *mp_image;
|
||||||
QImage *mp_image_l;
|
QImage *mp_image_l;
|
||||||
|
double m_gamma;
|
||||||
};
|
};
|
||||||
|
|
||||||
QImage
|
QImage
|
||||||
|
|
@ -896,7 +788,7 @@ LayoutCanvas::image_with_options (unsigned int width, unsigned int height, int l
|
||||||
linewidth = 1;
|
linewidth = 1;
|
||||||
}
|
}
|
||||||
if (resolution <= 0.0) {
|
if (resolution <= 0.0) {
|
||||||
resolution = 2.0 / oversampling;
|
resolution = 1.0 / oversampling;
|
||||||
}
|
}
|
||||||
if (background == QColor ()) {
|
if (background == QColor ()) {
|
||||||
background = background_color ();
|
background = background_color ();
|
||||||
|
|
@ -986,7 +878,7 @@ LayoutCanvas::screenshot ()
|
||||||
QImage img (m_viewport.width (), m_viewport.height (), QImage::Format_RGB32);
|
QImage img (m_viewport.width (), m_viewport.height (), QImage::Format_RGB32);
|
||||||
img.fill (m_background);
|
img.fill (m_background);
|
||||||
|
|
||||||
DetachedViewObjectCanvas vo_canvas (background_color (), foreground_color (), active_color (), m_viewport_l.width (), m_viewport_l.height (), 1.0 / double (m_oversampling) / 2, &img);
|
DetachedViewObjectCanvas vo_canvas (background_color (), foreground_color (), active_color (), m_viewport_l.width (), m_viewport_l.height (), 1.0 / double (m_oversampling * m_dpr), &img);
|
||||||
|
|
||||||
// and paint the background objects. It uses "img" to paint on.
|
// and paint the background objects. It uses "img" to paint on.
|
||||||
do_render_bg (m_viewport_l, vo_canvas);
|
do_render_bg (m_viewport_l, vo_canvas);
|
||||||
|
|
@ -1014,8 +906,8 @@ LayoutCanvas::resizeEvent (QResizeEvent *)
|
||||||
m_image_cache.clear ();
|
m_image_cache.clear ();
|
||||||
|
|
||||||
// set the viewport to the new size
|
// set the viewport to the new size
|
||||||
m_viewport.set_size (width (), height ());
|
m_viewport.set_size (width () * m_dpr, height () * m_dpr);
|
||||||
m_viewport_l.set_size (width () * m_oversampling * 2, height () * m_oversampling * 2);
|
m_viewport_l.set_size (width () * m_oversampling * m_dpr, height () * m_oversampling * m_dpr);
|
||||||
mouse_event_trans (m_viewport.trans ());
|
mouse_event_trans (m_viewport.trans ());
|
||||||
do_redraw_all (true);
|
do_redraw_all (true);
|
||||||
viewport_changed_event ();
|
viewport_changed_event ();
|
||||||
|
|
|
||||||
|
|
@ -367,6 +367,8 @@ private:
|
||||||
lay::DitherPattern m_dither_pattern;
|
lay::DitherPattern m_dither_pattern;
|
||||||
lay::LineStyles m_line_styles;
|
lay::LineStyles m_line_styles;
|
||||||
unsigned int m_oversampling;
|
unsigned int m_oversampling;
|
||||||
|
unsigned int m_dpr;
|
||||||
|
double m_gamma;
|
||||||
|
|
||||||
bool m_need_redraw;
|
bool m_need_redraw;
|
||||||
bool m_redraw_clearing;
|
bool m_redraw_clearing;
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,8 @@ void
|
||||||
RubberBox::render (const Viewport &vp, ViewObjectCanvas &canvas)
|
RubberBox::render (const Viewport &vp, ViewObjectCanvas &canvas)
|
||||||
{
|
{
|
||||||
lay::Renderer &r = canvas.renderer ();
|
lay::Renderer &r = canvas.renderer ();
|
||||||
lay::CanvasPlane *plane = canvas.plane (lay::ViewOp (m_color, lay::ViewOp::Copy, 0, m_stipple, 0));
|
int lw = int (0.5 + 1.0 / r.resolution ());
|
||||||
|
lay::CanvasPlane *plane = canvas.plane (lay::ViewOp (m_color, lay::ViewOp::Copy, 0, m_stipple, 0, lay::ViewOp::Rect, lw));
|
||||||
if (plane) {
|
if (plane) {
|
||||||
r.draw (vp.trans () * db::DBox (m_p1, m_p2), 0, plane, 0, 0);
|
r.draw (vp.trans () * db::DBox (m_p1, m_p2), 0, plane, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue