Numworks Epsilon  1.4.1
Graphing Calculator Operating System
context_rect.cpp
Go to the documentation of this file.
1 #include <kandinsky/context.h>
2 #include <assert.h>
3 
4 KDRect KDContext::absoluteFillRect(KDRect rect) {
5  return rect.translatedBy(m_origin).intersectedWith(m_clippingRect);
6 }
7 
8 void KDContext::fillRect(KDRect rect, KDColor color) {
9  KDRect absoluteRect = absoluteFillRect(rect);
10  if (absoluteRect.isEmpty()) {
11  return;
12  }
13  pushRectUniform(absoluteRect, color);
14 }
15 
16 /* Note: we support the case where workingBuffer IS equal to pixels */
17 void KDContext::fillRectWithPixels(KDRect rect, const KDColor * pixels, KDColor * workingBuffer) {
18  KDRect absoluteRect = absoluteFillRect(rect);
19 
20  if (absoluteRect.isEmpty()) {
21  return;
22  }
23 
24  /* Caution:
25  * The absoluteRect may have a SMALLER size than the original rect because it
26  * has been clipped. Therefore we cannot assume that the mask can be read as a
27  * continuous area. */
28 
29  if (absoluteRect.width() == rect.width() && absoluteRect.height() == rect.height()) {
30  pushRect(absoluteRect, pixels);
31  return;
32  }
33 
34  KDCoordinate startingI = m_clippingRect.x() - rect.translatedBy(m_origin).x();
35  KDCoordinate startingJ = m_clippingRect.y() - rect.translatedBy(m_origin).y();
36  startingI = startingI > 0 ? startingI : 0;
37  startingJ = startingJ > 0 ? startingJ : 0;
38 
39  /* If the rect has indeed been clipped, we only want to push the correct
40  * discontinuous extract of pixels. We want also to minimize calls to pushRect
41  * (time consuming). If a working buffer is available, we can fill it by
42  * concatenating extracted rows of 'pixels' to call pushRect only once on the
43  * absoluteRect. However, if we do not have a working buffer, we push row by
44  * row extracts of 'pixels' calling pushRect multiple times. */
45 
46  if (workingBuffer == nullptr) {
47  for (KDCoordinate j=0; j<absoluteRect.height(); j++) {
48  KDRect absoluteRow = KDRect(absoluteRect.x(), absoluteRect.y()+j, absoluteRect.width(), 1);
49  KDColor * rowPixels = (KDColor *)pixels+startingI+rect.width()*(startingJ+j);
50  pushRect(absoluteRow, rowPixels);
51  }
52  } else {
53  for (KDCoordinate j=0; j<absoluteRect.height(); j++) {
54  for (KDCoordinate i=0; i<absoluteRect.width(); i++) {
55  workingBuffer[i+absoluteRect.width()*j] = pixels[startingI+i+rect.width()*(startingJ+j)];
56  }
57  }
58  pushRect(absoluteRect, workingBuffer);
59  }
60 }
61 
62 // Mask's size must be rect.size
63 // WorkingBuffer, same deal
64 // TODO: should we avoid pullRect by giving a 'memory' working buffer?
65 void KDContext::blendRectWithMask(KDRect rect, KDColor color, const uint8_t * mask, KDColor * workingBuffer) {
66  KDRect absoluteRect = absoluteFillRect(rect);
67 
68  /* Caution:
69  * The absoluteRect may have a SMALLER size than the original rect because it
70  * has been clipped. Therefore we cannot assume that the mask can be read as a
71  * continuous area. */
72 
73  pullRect(absoluteRect, workingBuffer);
74  KDCoordinate startingI = m_clippingRect.x() - rect.translatedBy(m_origin).x();
75  KDCoordinate startingJ = m_clippingRect.y() - rect.translatedBy(m_origin).y();
76  startingI = startingI > 0 ? startingI : 0;
77  startingJ = startingJ > 0 ? startingJ : 0;
78  for (KDCoordinate j=0; j<absoluteRect.height(); j++) {
79  for (KDCoordinate i=0; i<absoluteRect.width(); i++) {
80  KDColor * currentPixelAdress = workingBuffer + i + absoluteRect.width()*j;
81  const uint8_t * currentMaskAddress = mask + i + startingI + rect.width()*(j + startingJ);
82  *currentPixelAdress = KDColor::blend(*currentPixelAdress, color, *currentMaskAddress);
83  //*currentPixelAdress = KDColorBlend(*currentPixelAdress, color, *currentMaskAddress);
84  }
85  }
86  pushRect(absoluteRect, workingBuffer);
87 }
88 
90  fillRect(KDRect(rect.origin(), rect.width(), 1), color);
91  fillRect(KDRect(KDPoint(rect.x(), rect.bottom()), rect.width(), 1), color);
92  fillRect(KDRect(rect.origin(), 1, rect.height()), color);
93  fillRect(KDRect(KDPoint(rect.right(), rect.y()), 1, rect.height()), color);
94 }
95 
KDRect translatedBy(KDPoint p) const
Definition: rect.cpp:108
void strokeRect(KDRect rect, KDColor color)
KDCoordinate x() const
Definition: rect.h:36
int16_t KDCoordinate
Definition: coordinate.h:6
void blendRectWithMask(KDRect rect, KDColor color, const uint8_t *mask, KDColor *workingBuffer)
bool isEmpty() const
Definition: rect.cpp:116
unsigned char uint8_t
Definition: stdint.h:4
Definition: point.h:6
KDCoordinate right() const
Definition: rect.h:43
virtual void pullRect(KDRect rect, KDColor *pixels)=0
virtual void pushRect(KDRect, const KDColor *pixels)=0
virtual void pushRectUniform(KDRect rect, KDColor color)=0
void fillRectWithPixels(KDRect rect, const KDColor *pixels, KDColor *workingBuffer)
KDCoordinate y() const
Definition: rect.h:37
Definition: rect.h:26
void fillRect(KDRect rect, KDColor color)
Definition: context_rect.cpp:8
Definition: color.h:6
KDPoint origin() const
Definition: rect.h:38
KDCoordinate width() const
Definition: rect.h:39
KDRect intersectedWith(const KDRect &other) const
Definition: rect.cpp:33
KDCoordinate height() const
Definition: rect.h:40
static KDColor blend(KDColor first, KDColor second, uint8_t alpha)
Definition: color.cpp:3
KDCoordinate bottom() const
Definition: rect.h:44