mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-19 00:37:25 +01:00
108 lines
4.1 KiB
C++
108 lines
4.1 KiB
C++
#include <kandinsky/context.h>
|
|
#include <assert.h>
|
|
|
|
KDRect KDContext::absoluteFillRect(KDRect rect) {
|
|
return rect.translatedBy(m_origin).intersectedWith(m_clippingRect);
|
|
}
|
|
|
|
void KDContext::fillRect(KDRect rect, KDColor color) {
|
|
KDRect absoluteRect = absoluteFillRect(rect);
|
|
if (absoluteRect.isEmpty()) {
|
|
return;
|
|
}
|
|
pushRectUniform(absoluteRect, color);
|
|
}
|
|
|
|
/* Note: we support the case where workingBuffer IS equal to pixels */
|
|
void KDContext::fillRectWithPixels(KDRect rect, const KDColor * pixels, KDColor * workingBuffer) {
|
|
KDRect absoluteRect = absoluteFillRect(rect);
|
|
|
|
if (absoluteRect.isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
/* Caution:
|
|
* The absoluteRect may have a SMALLER size than the original rect because it
|
|
* has been clipped. Therefore we cannot assume that the mask can be read as a
|
|
* continuous area. */
|
|
|
|
if (absoluteRect.width() == rect.width() && absoluteRect.height() == rect.height()) {
|
|
pushRect(absoluteRect, pixels);
|
|
return;
|
|
}
|
|
|
|
KDCoordinate startingI = m_clippingRect.x() - rect.translatedBy(m_origin).x();
|
|
KDCoordinate startingJ = m_clippingRect.y() - rect.translatedBy(m_origin).y();
|
|
startingI = startingI > 0 ? startingI : 0;
|
|
startingJ = startingJ > 0 ? startingJ : 0;
|
|
|
|
/* If the rect has indeed been clipped, we only want to push the correct
|
|
* discontinuous extract of pixels. We want also to minimize calls to pushRect
|
|
* (time consuming). If a working buffer is available, we can fill it by
|
|
* concatenating extracted rows of 'pixels' to call pushRect only once on the
|
|
* absoluteRect. However, if we do not have a working buffer, we push row by
|
|
* row extracts of 'pixels' calling pushRect multiple times. */
|
|
|
|
if (workingBuffer == nullptr) {
|
|
for (KDCoordinate j=0; j<absoluteRect.height(); j++) {
|
|
KDRect absoluteRow = KDRect(absoluteRect.x(), absoluteRect.y()+j, absoluteRect.width(), 1);
|
|
KDColor * rowPixels = (KDColor *)pixels+startingI+rect.width()*(startingJ+j);
|
|
pushRect(absoluteRow, rowPixels);
|
|
}
|
|
} else {
|
|
for (KDCoordinate j=0; j<absoluteRect.height(); j++) {
|
|
for (KDCoordinate i=0; i<absoluteRect.width(); i++) {
|
|
workingBuffer[i+absoluteRect.width()*j] = pixels[startingI+i+rect.width()*(startingJ+j)];
|
|
}
|
|
}
|
|
pushRect(absoluteRect, workingBuffer);
|
|
}
|
|
}
|
|
|
|
// Mask's size must be rect.size
|
|
// WorkingBuffer, same deal
|
|
// TODO: should we avoid pullRect by giving a 'memory' working buffer?
|
|
void KDContext::blendRectWithMask(KDRect rect, KDColor color, const uint8_t * mask, KDColor * workingBuffer) {
|
|
KDRect absoluteRect = absoluteFillRect(rect);
|
|
|
|
/* Caution:
|
|
* The absoluteRect may have a SMALLER size than the original rect because it
|
|
* has been clipped. Therefore we cannot assume that the mask can be read as a
|
|
* continuous area. */
|
|
|
|
pullRect(absoluteRect, workingBuffer);
|
|
KDCoordinate startingI = m_clippingRect.x() - rect.translatedBy(m_origin).x();
|
|
KDCoordinate startingJ = m_clippingRect.y() - rect.translatedBy(m_origin).y();
|
|
startingI = startingI > 0 ? startingI : 0;
|
|
startingJ = startingJ > 0 ? startingJ : 0;
|
|
for (KDCoordinate j=0; j<absoluteRect.height(); j++) {
|
|
for (KDCoordinate i=0; i<absoluteRect.width(); i++) {
|
|
KDColor * currentPixelAdress = workingBuffer + i + absoluteRect.width()*j;
|
|
const uint8_t * currentMaskAddress = mask + i + startingI + rect.width()*(j + startingJ);
|
|
*currentPixelAdress = KDColor::blend(*currentPixelAdress, color, *currentMaskAddress);
|
|
//*currentPixelAdress = KDColorBlend(*currentPixelAdress, color, *currentMaskAddress);
|
|
}
|
|
}
|
|
pushRect(absoluteRect, workingBuffer);
|
|
}
|
|
|
|
void KDContext::strokeRect(KDRect rect, KDColor color) {
|
|
KDPoint p1 = rect.origin();
|
|
KDPoint p2 = KDPoint(rect.x(), rect.bottom());
|
|
for (int i = 0; i<rect.width(); i++) {
|
|
setPixel(p1, color);
|
|
setPixel(p2, color);
|
|
p1 = p1.translatedBy(KDPoint(1,0));
|
|
p2 = p2.translatedBy(KDPoint(1,0));
|
|
}
|
|
p1 = rect.origin();
|
|
p2 = KDPoint(rect.right(), rect.y());
|
|
for (int i = 0; i<rect.height(); i++) {
|
|
setPixel(p1, color);
|
|
setPixel(p2, color);
|
|
p1 = p1.translatedBy(KDPoint(0,1));
|
|
p2 = p2.translatedBy(KDPoint(0,1));
|
|
}
|
|
}
|
|
|