Qt 4.8
Classes | Public Functions | Private Functions | Properties | Friends | List of all members
QScanConverter Class Reference

Classes

struct  Intersection
 
struct  Line
 

Public Functions

void begin (int top, int bottom, int left, int right, Qt::FillRule fillRule, QSpanBuffer *spanBuffer)
 
void end ()
 
void mergeCurve (const QT_FT_Vector &a, const QT_FT_Vector &b, const QT_FT_Vector &c, const QT_FT_Vector &d)
 
void mergeLine (QT_FT_Vector a, QT_FT_Vector b)
 
 QScanConverter ()
 
 ~QScanConverter ()
 

Private Functions

void allocate (int size)
 
bool clip (Q16Dot16 &xFP, int &iTop, int &iBottom, Q16Dot16 slopeFP, Q16Dot16 edgeFP, int winding)
 
void emitNode (const Intersection *node)
 
void emitSpans (int chunk)
 
void mergeIntersection (Intersection *head, const Intersection &isect)
 
void prepareChunk ()
 

Properties

QDataBuffer< Line * > m_active
 
int m_alloc
 
int m_bottom
 
int m_fillRuleMask
 
Intersectionm_intersections
 
Q16Dot16 m_leftFP
 
QDataBuffer< Linem_lines
 
Q16Dot16 m_rightFP
 
int m_size
 
QSpanBufferm_spanBuffer
 
int m_top
 
int m_winding
 
int m_x
 
int m_y
 

Friends

template<typename T >
void qScanConvert (QScanConverter &d, T allVertical)
 

Detailed Description

Definition at line 125 of file qrasterizer.cpp.

Constructors and Destructors

◆ QScanConverter()

QScanConverter::QScanConverter ( )

Definition at line 206 of file qrasterizer.cpp.

207  : m_lines(0)
208  , m_alloc(0)
209  , m_size(0)
210  , m_intersections(0)
211  , m_active(0)
212 {
213 }
QDataBuffer< Line > m_lines
QDataBuffer< Line * > m_active
Intersection * m_intersections

◆ ~QScanConverter()

QScanConverter::~QScanConverter ( )

Definition at line 215 of file qrasterizer.cpp.

216 {
217  if (m_intersections)
218  free(m_intersections);
219 }
Intersection * m_intersections

Functions

◆ allocate()

void QScanConverter::allocate ( int  size)
inlineprivate

Definition at line 448 of file qrasterizer.cpp.

Referenced by end(), and prepareChunk().

449 {
450  if (m_alloc < size) {
451  int newAlloc = qMax(size, 2 * m_alloc);
452  m_intersections = q_check_ptr((Intersection *)realloc(m_intersections, newAlloc * sizeof(Intersection)));
453  m_alloc = newAlloc;
454  }
455 }
T * q_check_ptr(T *p)
Definition: qglobal.h:1857
Q_DECL_CONSTEXPR const T & qMax(const T &a, const T &b)
Definition: qglobal.h:1217
Intersection * m_intersections

◆ begin()

void QScanConverter::begin ( int  top,
int  bottom,
int  left,
int  right,
Qt::FillRule  fillRule,
QSpanBuffer spanBuffer 
)

Definition at line 221 of file qrasterizer.cpp.

Referenced by QRasterizer::rasterize().

223 {
224  m_top = top;
225  m_bottom = bottom;
228 
229  m_lines.reset();
230 
231  m_fillRuleMask = fillRule == Qt::WindingFill ? ~0x0 : 0x1;
232  m_spanBuffer = spanBuffer;
233 }
QSpanBuffer * m_spanBuffer
QDataBuffer< Line > m_lines
Q_CORE_EXPORT QTextStream & right(QTextStream &s)
#define IntToQ16Dot16(i)
Definition: qrasterizer.cpp:56
Q16Dot16 m_leftFP
Q_CORE_EXPORT QTextStream & left(QTextStream &s)
Q16Dot16 m_rightFP

◆ clip()

bool QScanConverter::clip ( Q16Dot16 xFP,
int &  iTop,
int &  iBottom,
Q16Dot16  slopeFP,
Q16Dot16  edgeFP,
int  winding 
)
inlineprivate

Definition at line 524 of file qrasterizer.cpp.

Referenced by mergeLine().

525 {
526  bool right = edgeFP == m_rightFP;
527 
528  if (xFP == edgeFP) {
529  if ((slopeFP > 0) ^ right)
530  return false;
531  else {
532  Line line = { edgeFP, 0, iTop, iBottom, winding };
533  m_lines.add(line);
534  return true;
535  }
536  }
537 
538  Q16Dot16 lastFP = xFP + slopeFP * (iBottom - iTop);
539 
540  if (lastFP == edgeFP) {
541  if ((slopeFP < 0) ^ right)
542  return false;
543  else {
544  Line line = { edgeFP, 0, iTop, iBottom, winding };
545  m_lines.add(line);
546  return true;
547  }
548  }
549 
550  // does line cross edge?
551  if ((lastFP < edgeFP) ^ (xFP < edgeFP)) {
552  Q16Dot16 deltaY = Q16Dot16((edgeFP - xFP) / Q16Dot16ToFloat(slopeFP));
553 
554  if ((xFP < edgeFP) ^ right) {
555  // top segment needs to be clipped
556  int iHeight = Q16Dot16ToInt(deltaY + 1);
557  int iMiddle = iTop + iHeight;
558 
559  Line line = { edgeFP, 0, iTop, iMiddle, winding };
560  m_lines.add(line);
561 
562  if (iMiddle != iBottom) {
563  xFP += slopeFP * (iHeight + 1);
564  iTop = iMiddle + 1;
565  } else
566  return true;
567  } else {
568  // bottom segment needs to be clipped
569  int iHeight = Q16Dot16ToInt(deltaY);
570  int iMiddle = iTop + iHeight;
571 
572  if (iMiddle != iBottom) {
573  Line line = { edgeFP, 0, iMiddle + 1, iBottom, winding };
574  m_lines.add(line);
575 
576  iBottom = iMiddle;
577  }
578  }
579  return false;
580  } else if ((xFP < edgeFP) ^ right) {
581  Line line = { edgeFP, 0, iTop, iBottom, winding };
582  m_lines.add(line);
583  return true;
584  }
585 
586  return false;
587 }
QDataBuffer< Line > m_lines
Q_CORE_EXPORT QTextStream & right(QTextStream &s)
#define Q16Dot16ToFloat(i)
Definition: qrasterizer.cpp:54
#define Q16Dot16ToInt(i)
Definition: qrasterizer.cpp:57
int Q16Dot16
Definition: qrasterizer.cpp:53
Q16Dot16 m_rightFP

◆ emitNode()

void QScanConverter::emitNode ( const Intersection node)
private

Definition at line 243 of file qrasterizer.cpp.

Referenced by emitSpans().

244 {
245 tail_call:
246  if (node->left)
247  emitNode(node + node->left);
248 
250  m_spanBuffer->addSpan(m_x, node->x - m_x, m_y, 0xff);
251 
252  m_x = node->x;
253  m_winding += node->winding;
254 
255  if (node->right) {
256  node += node->right;
257  goto tail_call;
258  }
259 }
QSpanBuffer * m_spanBuffer
void addSpan(int x, unsigned int len, int y, unsigned char coverage)
Definition: qrasterizer.cpp:89
void emitNode(const Intersection *node)

◆ emitSpans()

void QScanConverter::emitSpans ( int  chunk)
private

Definition at line 261 of file qrasterizer.cpp.

Referenced by end().

262 {
263  for (int dy = 0; dy < CHUNK_SIZE; ++dy) {
264  m_x = 0;
265  m_y = chunk + dy;
266  m_winding = 0;
267 
269  }
270 }
#define CHUNK_SIZE
void emitNode(const Intersection *node)
Intersection * m_intersections

◆ end()

void QScanConverter::end ( )

Definition at line 381 of file qrasterizer.cpp.

Referenced by QRasterizer::rasterize().

382 {
383  if (m_lines.isEmpty())
384  return;
385 
386  if (m_lines.size() <= 32) {
387  bool allVertical = true;
388  for (int i = 0; i < m_lines.size(); ++i) {
389  if (m_lines.at(i).delta) {
390  allVertical = false;
391  break;
392  }
393  }
394  if (allVertical)
396  else
398  } else {
399  for (int chunkTop = m_top; chunkTop <= m_bottom; chunkTop += CHUNK_SIZE) {
400  prepareChunk();
401 
402  Intersection isect = { 0, 0, 0, 0 };
403 
404  const int chunkBottom = chunkTop + CHUNK_SIZE;
405  for (int i = 0; i < m_lines.size(); ++i) {
406  Line &line = m_lines.at(i);
407 
408  if ((line.bottom < chunkTop) || (line.top > chunkBottom))
409  continue;
410 
411  const int top = qMax(0, line.top - chunkTop);
412  const int bottom = qMin(CHUNK_SIZE, line.bottom + 1 - chunkTop);
413  allocate(m_size + bottom - top);
414 
415  isect.winding = line.winding;
416 
417  Intersection *it = m_intersections + top;
418  Intersection *end = m_intersections + bottom;
419 
420  if (line.delta) {
421  for (; it != end; ++it) {
422  isect.x = Q16Dot16ToInt(line.x);
423  line.x += line.delta;
424  mergeIntersection(it, isect);
425  }
426  } else {
427  isect.x = Q16Dot16ToInt(line.x);
428  for (; it != end; ++it)
429  mergeIntersection(it, isect);
430  }
431  }
432 
433  emitSpans(chunkTop);
434  }
435  }
436 
437  if (m_alloc > 1024) {
438  free(m_intersections);
439  m_alloc = 0;
440  m_size = 0;
441  m_intersections = 0;
442  }
443 
444  if (m_lines.size() > 1024)
445  m_lines.shrink(1024);
446 }
void mergeIntersection(Intersection *head, const Intersection &isect)
friend void qScanConvert(QScanConverter &d, T allVertical)
Q_DECL_CONSTEXPR const T & qMin(const T &a, const T &b)
Definition: qglobal.h:1215
#define it(className, varName)
QDataBuffer< Line > m_lines
Q_DECL_CONSTEXPR const T & qMax(const T &a, const T &b)
Definition: qglobal.h:1217
#define CHUNK_SIZE
#define Q16Dot16ToInt(i)
Definition: qrasterizer.cpp:57
void allocate(int size)
Intersection * m_intersections
void emitSpans(int chunk)

◆ mergeCurve()

void QScanConverter::mergeCurve ( const QT_FT_Vector a,
const QT_FT_Vector b,
const QT_FT_Vector c,
const QT_FT_Vector d 
)

Definition at line 477 of file qrasterizer.cpp.

Referenced by QRasterizer::rasterize().

479 {
480  // make room for 32 splits
481  QT_FT_Vector beziers[4 + 3 * 32];
482 
483  QT_FT_Vector *b = beziers;
484 
485  b[0] = pa;
486  b[1] = pb;
487  b[2] = pc;
488  b[3] = pd;
489 
490  const QT_FT_Pos flatness = 16;
491 
492  while (b >= beziers) {
493  QT_FT_Vector delta = { b[3].x - b[0].x, b[3].y - b[0].y };
494  QT_FT_Pos l = qAbs(delta.x) + qAbs(delta.y);
495 
496  bool belowThreshold;
497  if (l > 64) {
498  qlonglong d2 = qAbs(qlonglong(b[1].x-b[0].x) * qlonglong(delta.y) -
499  qlonglong(b[1].y-b[0].y) * qlonglong(delta.x));
500  qlonglong d3 = qAbs(qlonglong(b[2].x-b[0].x) * qlonglong(delta.y) -
501  qlonglong(b[2].y-b[0].y) * qlonglong(delta.x));
502 
503  qlonglong d = d2 + d3;
504 
505  belowThreshold = (d <= qlonglong(flatness) * qlonglong(l));
506  } else {
507  QT_FT_Pos d = qAbs(b[0].x-b[1].x) + qAbs(b[0].y-b[1].y) +
508  qAbs(b[0].x-b[2].x) + qAbs(b[0].y-b[2].y);
509 
510  belowThreshold = (d <= flatness);
511  }
512 
513  if (belowThreshold || b == beziers + 3 * 32) {
514  mergeLine(b[0], b[3]);
515  b -= 3;
516  continue;
517  }
518 
519  split(b);
520  b += 3;
521  }
522 }
Q_DECL_CONSTEXPR T qAbs(const T &t)
Definition: qglobal.h:1201
static void split(QT_FT_Vector *b)
void mergeLine(QT_FT_Vector a, QT_FT_Vector b)
QFactoryLoader * l
QT_FT_BEGIN_HEADER typedef signed int QT_FT_Pos
qint64 qlonglong
Definition: qglobal.h:951

◆ mergeIntersection()

void QScanConverter::mergeIntersection ( Intersection head,
const Intersection isect 
)
inlineprivate

Definition at line 457 of file qrasterizer.cpp.

Referenced by end().

458 {
459  Intersection *current = it;
460 
461  while (isect.x != current->x) {
462  int &next = isect.x < current->x ? current->left : current->right;
463  if (next)
464  current += next;
465  else {
466  Intersection *last = m_intersections + m_size;
467  next = last - current;
468  *last = isect;
469  ++m_size;
470  return;
471  }
472  }
473 
474  current->winding += isect.winding;
475 }
#define it(className, varName)
Intersection * m_intersections

◆ mergeLine()

void QScanConverter::mergeLine ( QT_FT_Vector  a,
QT_FT_Vector  b 
)

Definition at line 589 of file qrasterizer.cpp.

Referenced by mergeCurve(), and QRasterizer::rasterize().

590 {
591  int winding = 1;
592 
593  if (a.y > b.y) {
594  qSwap(a, b);
595  winding = -1;
596  }
597 
598  a.x += COORD_OFFSET;
599  a.y += COORD_OFFSET;
600  b.x += COORD_OFFSET;
601  b.y += COORD_OFFSET;
602 
603  int iTop = qMax(m_top, int((a.y + 32 - COORD_ROUNDING) >> 6));
604  int iBottom = qMin(m_bottom, int((b.y - 32 - COORD_ROUNDING) >> 6));
605 
606  if (iTop <= iBottom) {
607  Q16Dot16 aFP = Q16Dot16Factor/2 + (a.x << 10) - COORD_ROUNDING;
608 
609  if (b.x == a.x) {
610  Line line = { qBound(m_leftFP, aFP, m_rightFP), 0, iTop, iBottom, winding };
611  m_lines.add(line);
612  } else {
613  const qreal slope = (b.x - a.x) / qreal(b.y - a.y);
614 
615  const Q16Dot16 slopeFP = FloatToQ16Dot16(slope);
616 
617  Q16Dot16 xFP = aFP + Q16Dot16Multiply(slopeFP,
618  IntToQ16Dot16(iTop)
619  + Q16Dot16Factor/2 - (a.y << 10));
620 
621  if (clip(xFP, iTop, iBottom, slopeFP, m_leftFP, winding))
622  return;
623 
624  if (clip(xFP, iTop, iBottom, slopeFP, m_rightFP, winding))
625  return;
626 
627  Q_ASSERT(xFP >= m_leftFP);
628 
629  Line line = { xFP, slopeFP, iTop, iBottom, winding };
630  m_lines.add(line);
631  }
632  }
633 }
double qreal
Definition: qglobal.h:1193
#define Q16Dot16Factor
Definition: qrasterizer.cpp:58
Q_DECL_CONSTEXPR const T & qMin(const T &a, const T &b)
Definition: qglobal.h:1215
QDataBuffer< Line > m_lines
#define COORD_OFFSET
Definition: qrasterizer.cpp:66
bool clip(Q16Dot16 &xFP, int &iTop, int &iBottom, Q16Dot16 slopeFP, Q16Dot16 edgeFP, int winding)
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
Q_DECL_CONSTEXPR const T & qMax(const T &a, const T &b)
Definition: qglobal.h:1217
#define Q16Dot16Multiply(x, y)
Definition: qrasterizer.cpp:60
void qSwap(T &value1, T &value2)
Definition: qglobal.h:2181
#define FloatToQ16Dot16(i)
Definition: qrasterizer.cpp:55
#define IntToQ16Dot16(i)
Definition: qrasterizer.cpp:56
int Q16Dot16
Definition: qrasterizer.cpp:53
Q_DECL_CONSTEXPR const T & qBound(const T &min, const T &val, const T &max)
Definition: qglobal.h:1219
Q16Dot16 m_leftFP
#define COORD_ROUNDING
Definition: qrasterizer.cpp:65
Q16Dot16 m_rightFP

◆ prepareChunk()

void QScanConverter::prepareChunk ( )
private

Definition at line 235 of file qrasterizer.cpp.

Referenced by end().

236 {
237  m_size = CHUNK_SIZE;
238 
240  memset(m_intersections, 0, CHUNK_SIZE * sizeof(Intersection));
241 }
#define CHUNK_SIZE
void allocate(int size)
Intersection * m_intersections

Friends and Related Functions

◆ qScanConvert

template<typename T >
void qScanConvert ( QScanConverter d,
allVertical 
)
friend

Definition at line 319 of file qrasterizer.cpp.

Referenced by end().

320 {
321  if (!d.m_lines.size()) {
322  d.m_active.reset();
323  return;
324  }
325  qSort(d.m_lines.data(), d.m_lines.data() + d.m_lines.size(), QT_PREPEND_NAMESPACE(topOrder));
326  int line = 0;
327  for (int y = d.m_lines.first().top; y <= d.m_bottom; ++y) {
328  for (; line < d.m_lines.size() && d.m_lines.at(line).top == y; ++line) {
329  // add node to active list
330  if (allVertical()) {
331  QScanConverter::Line *l = &d.m_lines.at(line);
332  d.m_active.resize(d.m_active.size() + 1);
333  int j;
334  for (j = d.m_active.size() - 2; j >= 0 && QT_PREPEND_NAMESPACE(xOrder)(l, d.m_active.at(j)); --j)
335  d.m_active.at(j+1) = d.m_active.at(j);
336  d.m_active.at(j+1) = l;
337  } else {
338  d.m_active << &d.m_lines.at(line);
339  }
340  }
341 
342  int numActive = d.m_active.size();
343  if (!allVertical()) {
344  // use insertion sort instead of qSort, as the active edge list is quite small
345  // and in the average case already sorted
346  for (int i = 1; i < numActive; ++i) {
347  QScanConverter::Line *l = d.m_active.at(i);
348  int j;
349  for (j = i-1; j >= 0 && QT_PREPEND_NAMESPACE(xOrder)(l, d.m_active.at(j)); --j)
350  d.m_active.at(j+1) = d.m_active.at(j);
351  d.m_active.at(j+1) = l;
352  }
353  }
354 
355  int x = 0;
356  int winding = 0;
357  for (int i = 0; i < numActive; ++i) {
358  QScanConverter::Line *node = d.m_active.at(i);
359 
360  const int current = Q16Dot16ToInt(node->x);
361  if (winding & d.m_fillRuleMask)
362  d.m_spanBuffer->addSpan(x, current - x, y, 0xff);
363 
364  x = current;
365  winding += node->winding;
366 
367  if (node->bottom == y) {
368  // remove node from active list
369  for (int j = i; j < numActive - 1; ++j)
370  d.m_active.at(j) = d.m_active.at(j+1);
371 
372  d.m_active.resize(--numActive);
373  --i;
374  } else if (!allVertical())
375  node->x += node->delta;
376  }
377  }
378  d.m_active.reset();
379 }
QSpanBuffer * m_spanBuffer
QDataBuffer< Line > m_lines
void addSpan(int x, unsigned int len, int y, unsigned char coverage)
Definition: qrasterizer.cpp:89
QDataBuffer< Line * > m_active
static bool topOrder(const QScanConverter::Line &a, const QScanConverter::Line &b)
#define QT_PREPEND_NAMESPACE(name)
This macro qualifies identifier with the full namespace.
Definition: qglobal.h:87
void qSort(RandomAccessIterator start, RandomAccessIterator end)
Definition: qalgorithms.h:177
static bool xOrder(const QScanConverter::Line *a, const QScanConverter::Line *b)
#define Q16Dot16ToInt(i)
Definition: qrasterizer.cpp:57
QFactoryLoader * l

Properties

◆ m_active

QDataBuffer<Line *> QScanConverter::m_active
private

Definition at line 189 of file qrasterizer.cpp.

Referenced by qScanConvert().

◆ m_alloc

int QScanConverter::m_alloc
private

Definition at line 170 of file qrasterizer.cpp.

Referenced by allocate(), and end().

◆ m_bottom

int QScanConverter::m_bottom
private

Definition at line 174 of file qrasterizer.cpp.

Referenced by begin(), end(), mergeLine(), and qScanConvert().

◆ m_fillRuleMask

int QScanConverter::m_fillRuleMask
private

Definition at line 179 of file qrasterizer.cpp.

Referenced by begin(), emitNode(), and qScanConvert().

◆ m_intersections

Intersection* QScanConverter::m_intersections
private

◆ m_leftFP

Q16Dot16 QScanConverter::m_leftFP
private

Definition at line 176 of file qrasterizer.cpp.

Referenced by begin(), and mergeLine().

◆ m_lines

QDataBuffer<Line> QScanConverter::m_lines
private

Definition at line 168 of file qrasterizer.cpp.

Referenced by begin(), clip(), end(), mergeLine(), and qScanConvert().

◆ m_rightFP

Q16Dot16 QScanConverter::m_rightFP
private

Definition at line 177 of file qrasterizer.cpp.

Referenced by begin(), clip(), and mergeLine().

◆ m_size

int QScanConverter::m_size
private

Definition at line 171 of file qrasterizer.cpp.

Referenced by end(), mergeIntersection(), and prepareChunk().

◆ m_spanBuffer

QSpanBuffer* QScanConverter::m_spanBuffer
private

Definition at line 187 of file qrasterizer.cpp.

Referenced by begin(), emitNode(), and qScanConvert().

◆ m_top

int QScanConverter::m_top
private

Definition at line 173 of file qrasterizer.cpp.

Referenced by begin(), end(), and mergeLine().

◆ m_winding

int QScanConverter::m_winding
private

Definition at line 183 of file qrasterizer.cpp.

Referenced by emitNode(), and emitSpans().

◆ m_x

int QScanConverter::m_x
private

Definition at line 181 of file qrasterizer.cpp.

Referenced by emitNode(), and emitSpans().

◆ m_y

int QScanConverter::m_y
private

Definition at line 182 of file qrasterizer.cpp.

Referenced by emitNode(), and emitSpans().


The documentation for this class was generated from the following file: