mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-18 16:27:34 +01:00
Migrate Kandinsky to C++
Change-Id: I2752a8db84ad0bb817119cf6c2993c1622621150
This commit is contained in:
4
Makefile
4
Makefile
@@ -25,7 +25,7 @@ endif
|
||||
|
||||
# Language-specific flags
|
||||
CFLAGS = -std=c99
|
||||
CXXFLAGS = -std=c++11 -fno-exceptions -fno-rtti
|
||||
CXXFLAGS = -std=c++11 -fno-exceptions -fno-rtti -fno-threadsafe-statics
|
||||
|
||||
products := boot.elf boot.hex boot.bin test.elf test.hex test.bin
|
||||
|
||||
@@ -58,7 +58,7 @@ include libaxx/Makefile
|
||||
endif
|
||||
include ion/Makefile
|
||||
include kandinsky/Makefile
|
||||
include poincare/Makefile
|
||||
#include poincare/Makefile
|
||||
include escher/Makefile
|
||||
include apps/Makefile
|
||||
include quiz/Makefile # Quiz should be included at the end
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "cursor_view.h"
|
||||
|
||||
void CursorView::drawRect(KDRect rect) const {
|
||||
KDFillRect(rect, KDColorRed);
|
||||
void CursorView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
ctx->fillRect(rect, KDColorRed);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
class CursorView : public ChildlessView {
|
||||
public:
|
||||
using ChildlessView::ChildlessView;
|
||||
void drawRect(KDRect rect) const override;
|
||||
void drawRect(KDContext * ctx, KDRect rect) const override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#include "graph_view.h"
|
||||
#include <assert.h>
|
||||
|
||||
constexpr KDColor kAxisColor = KDColorGray(0x0);
|
||||
constexpr KDColor kMainGridColor = KDColorGray(0xCC);
|
||||
constexpr KDColor kSecondaryGridColor = KDColorGray(0xEE);
|
||||
constexpr KDColor kAxisColor = KDColor(0x000000);
|
||||
constexpr KDColor kMainGridColor = KDColor(0xCCCCCC);
|
||||
constexpr KDColor kSecondaryGridColor = KDColor(0xEEEEEE);
|
||||
constexpr int kNumberOfMainGridLines = 5;
|
||||
constexpr int kNumberOfSecondaryGridLines = 4;
|
||||
|
||||
@@ -31,15 +31,13 @@ View * GraphView::subviewAtIndex(int index) {
|
||||
}
|
||||
|
||||
void GraphView::moveCursorRight() {
|
||||
m_cursorPosition.x = m_cursorPosition.x + 2;
|
||||
KDPoint offset = KDPoint(2,0);
|
||||
m_cursorPosition = m_cursorPosition.translatedBy(offset);
|
||||
layoutSubviews();
|
||||
}
|
||||
|
||||
void GraphView::layoutSubviews() {
|
||||
KDRect cursorFrame;
|
||||
cursorFrame.origin = m_cursorPosition;
|
||||
cursorFrame.width = 10;
|
||||
cursorFrame.height = 10;
|
||||
KDRect cursorFrame(m_cursorPosition, 10, 10);
|
||||
m_cursorView.setFrame(cursorFrame);
|
||||
}
|
||||
|
||||
@@ -52,14 +50,14 @@ KDSize GraphView::tileSize() const {
|
||||
return {kTileWidth, kTileHeight};
|
||||
}
|
||||
|
||||
void GraphView::drawTile(KDRect rect) const {
|
||||
void GraphView::drawTile(KDContext * ctx, KDRect rect) const {
|
||||
#else
|
||||
void GraphView::drawRect(KDRect rect) const {
|
||||
void GraphView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
#endif
|
||||
KDFillRect(rect, KDColorWhite);
|
||||
drawGrid(rect);
|
||||
drawAxes(rect);
|
||||
drawFunction(rect);
|
||||
ctx->fillRect(rect, KDColorWhite);
|
||||
drawGrid(ctx, rect);
|
||||
drawAxes(ctx, rect);
|
||||
drawFunction(ctx, rect);
|
||||
/*
|
||||
|
||||
constexpr int maskLength = 3;
|
||||
@@ -80,46 +78,46 @@ void GraphView::drawRect(KDRect rect) const {
|
||||
*/
|
||||
}
|
||||
|
||||
void GraphView::drawLine(KDRect rect, Axis axis, float coordinate, KDColor color, KDCoordinate thickness) const {
|
||||
KDRect lineRect;
|
||||
void GraphView::drawLine(KDContext * ctx, KDRect rect, Axis axis, float coordinate, KDColor color, KDCoordinate thickness) const {
|
||||
KDRect lineRect = KDRectZero;
|
||||
switch(axis) {
|
||||
case Axis::Horizontal:
|
||||
lineRect.x = rect.x;
|
||||
lineRect.y = floatToPixel(Axis::Vertical, coordinate);
|
||||
lineRect.width = rect.width;
|
||||
lineRect.height = thickness;
|
||||
lineRect = KDRect(
|
||||
rect.x(), floatToPixel(Axis::Vertical, coordinate),
|
||||
rect.width(), thickness
|
||||
);
|
||||
break;
|
||||
case Axis::Vertical:
|
||||
lineRect.x = floatToPixel(Axis::Horizontal, coordinate);
|
||||
lineRect.y = rect.y;
|
||||
lineRect.width = thickness;
|
||||
lineRect.height = rect.height;
|
||||
lineRect = KDRect(
|
||||
floatToPixel(Axis::Horizontal, coordinate), rect.y(),
|
||||
thickness, rect.height()
|
||||
);
|
||||
break;
|
||||
}
|
||||
KDFillRect(lineRect, color);
|
||||
ctx->fillRect(lineRect, color);
|
||||
}
|
||||
|
||||
void GraphView::drawAxes(KDRect rect) const {
|
||||
drawLine(rect, Axis::Horizontal, 0.0f, kAxisColor, 2);
|
||||
drawLine(rect, Axis::Vertical, 0.0f, kAxisColor, 2);
|
||||
void GraphView::drawAxes(KDContext * ctx, KDRect rect) const {
|
||||
drawLine(ctx, rect, Axis::Horizontal, 0.0f, kAxisColor, 2);
|
||||
drawLine(ctx, rect, Axis::Vertical, 0.0f, kAxisColor, 2);
|
||||
}
|
||||
|
||||
void GraphView::drawGridLines(KDRect rect, Axis axis, int count, KDColor color) const {
|
||||
void GraphView::drawGridLines(KDContext * ctx, KDRect rect, Axis axis, int count, KDColor color) const {
|
||||
float range = max(axis)-min(axis);
|
||||
float step = range/count;
|
||||
float start = step*((int)(min(axis)/step));
|
||||
for (int i=0; i<count; i++) {
|
||||
Axis otherAxis = (axis == Axis::Horizontal) ? Axis::Vertical : Axis::Horizontal;
|
||||
drawLine(rect, otherAxis, start+i*step, color);
|
||||
drawLine(ctx, rect, otherAxis, start+i*step, color);
|
||||
}
|
||||
}
|
||||
|
||||
void GraphView::drawGrid(KDRect rect) const {
|
||||
drawGridLines(rect, Axis::Horizontal, kNumberOfMainGridLines*kNumberOfSecondaryGridLines, kSecondaryGridColor);
|
||||
drawGridLines(rect, Axis::Vertical, kNumberOfMainGridLines*kNumberOfSecondaryGridLines, kSecondaryGridColor);
|
||||
void GraphView::drawGrid(KDContext * ctx, KDRect rect) const {
|
||||
drawGridLines(ctx, rect, Axis::Horizontal, kNumberOfMainGridLines*kNumberOfSecondaryGridLines, kSecondaryGridColor);
|
||||
drawGridLines(ctx, rect, Axis::Vertical, kNumberOfMainGridLines*kNumberOfSecondaryGridLines, kSecondaryGridColor);
|
||||
|
||||
drawGridLines(rect, Axis::Horizontal, kNumberOfMainGridLines, kMainGridColor);
|
||||
drawGridLines(rect, Axis::Vertical, kNumberOfMainGridLines, kMainGridColor);
|
||||
drawGridLines(ctx, rect, Axis::Horizontal, kNumberOfMainGridLines, kMainGridColor);
|
||||
drawGridLines(ctx, rect, Axis::Vertical, kNumberOfMainGridLines, kMainGridColor);
|
||||
}
|
||||
|
||||
float GraphView::min(Axis axis) const {
|
||||
@@ -134,7 +132,7 @@ float GraphView::max(Axis axis) const {
|
||||
|
||||
KDCoordinate GraphView::pixelLength(Axis axis) const {
|
||||
assert(axis == Axis::Horizontal || axis == Axis::Vertical);
|
||||
return (axis == Axis::Horizontal ? m_frame.width : m_frame.height);
|
||||
return (axis == Axis::Horizontal ? m_frame.width() : m_frame.height());
|
||||
}
|
||||
|
||||
float GraphView::pixelToFloat(Axis axis, KDCoordinate p) const {
|
||||
@@ -145,8 +143,7 @@ KDCoordinate GraphView::floatToPixel(Axis axis, float f) const {
|
||||
return pixelLength(axis)*(max(axis)-f)/(max(axis)-min(axis));
|
||||
}
|
||||
|
||||
void GraphView::drawFunction(KDRect rect) const {
|
||||
KDPoint p;
|
||||
void GraphView::drawFunction(KDContext * ctx, KDRect rect) const {
|
||||
|
||||
constexpr KDCoordinate stampSize = 5;
|
||||
|
||||
@@ -160,16 +157,13 @@ void GraphView::drawFunction(KDRect rect) const {
|
||||
|
||||
KDColor workingBuffer[stampSize*stampSize];
|
||||
|
||||
for (p.x=rect.x-stampSize; p.x<(rect.x+rect.width); p.x++) {
|
||||
float x = pixelToFloat(Axis::Horizontal, p.x);
|
||||
for (KDCoordinate px = rect.x()-stampSize; px<rect.right(); px++) {
|
||||
float x = pixelToFloat(Axis::Horizontal, px);
|
||||
float y = (x-1)*(x+1)*x;
|
||||
p.y = floatToPixel(Axis::Vertical, y);
|
||||
KDRect stampRect;
|
||||
stampRect.origin = p;
|
||||
stampRect.width = stampSize;
|
||||
stampRect.height = stampSize;
|
||||
KDCoordinate py = floatToPixel(Axis::Vertical, y);
|
||||
KDRect stampRect(px, py, stampSize, stampSize);
|
||||
//KDColor red = KDColorRed;
|
||||
KDFillRectWithMask(stampRect, KDColorRed, mask, workingBuffer);
|
||||
ctx->fillRectWithMask(stampRect, KDColorRed, mask, workingBuffer);
|
||||
//KDBlitRect(stampRect, &red, {1,1}, mask, {stampSize,stampSize});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,9 +19,9 @@ public:
|
||||
#if GRAPH_VIEW_IS_TILED
|
||||
KDColor * tile() const override;
|
||||
KDSize tileSize() const override;
|
||||
void drawTile(KDRect rect) const override;
|
||||
void drawTile(KDContext * ctx, KDRect rect) const override;
|
||||
#else
|
||||
void drawRect(KDRect rect) const override;
|
||||
void drawRect(KDContext * ctx, KDRect rect) const override;
|
||||
#endif
|
||||
|
||||
// void drawRect(KDRect rect) const override;
|
||||
@@ -43,13 +43,13 @@ private:
|
||||
float pixelToFloat(Axis axis, KDCoordinate p) const;
|
||||
KDCoordinate floatToPixel(Axis axis, float f) const;
|
||||
|
||||
void drawLine(KDRect rect, Axis axis,
|
||||
void drawLine(KDContext * ctx, KDRect rect, Axis axis,
|
||||
float coordinate, KDColor color, KDCoordinate thickness = 1) const;
|
||||
|
||||
void drawAxes(KDRect rect) const;
|
||||
void drawGrid(KDRect rect) const;
|
||||
void drawGridLines(KDRect rect, Axis axis, int count, KDColor color) const;
|
||||
void drawFunction(KDRect rect) const;
|
||||
void drawAxes(KDContext * ctx, KDRect rect) const;
|
||||
void drawGrid(KDContext * ctx, KDRect rect) const;
|
||||
void drawGridLines(KDContext * ctx, KDRect rect, Axis axis, int count, KDColor color) const;
|
||||
void drawFunction(KDContext * ctx, KDRect rect) const;
|
||||
|
||||
static constexpr KDCoordinate kTileWidth = 32;
|
||||
static constexpr KDCoordinate kTileHeight = 32;
|
||||
|
||||
@@ -8,10 +8,10 @@ FunctionCell::FunctionCell() :
|
||||
m_message = "NULL";
|
||||
}
|
||||
|
||||
void FunctionCell::drawRect(KDRect rect) const {
|
||||
KDColor background = m_even ? KDColorRGB(0xEE, 0xEE, 0xEE) : KDColorRGB(0x77,0x77,0x77);
|
||||
KDFillRect(rect, background);
|
||||
KDDrawString(m_message, KDPointZero, m_focused);
|
||||
void FunctionCell::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
KDColor background = m_even ? KDColor(0xEEEEEE) : KDColor(0x777777);
|
||||
ctx->fillRect(rect, background);
|
||||
ctx->drawString(m_message, KDPointZero, m_focused);
|
||||
}
|
||||
|
||||
void FunctionCell::setMessage(const char * message) {
|
||||
|
||||
@@ -9,7 +9,7 @@ public:
|
||||
void setMessage(const char * message);
|
||||
void setEven(bool even);
|
||||
|
||||
void drawRect(KDRect rect) const override;
|
||||
void drawRect(KDContext * ctx, KDRect rect) const override;
|
||||
void setFocused(bool focused) override;
|
||||
private:
|
||||
const char * m_message;
|
||||
|
||||
@@ -10,7 +10,7 @@ public:
|
||||
Vertical
|
||||
};
|
||||
ScrollViewIndicator(Direction direction);
|
||||
void drawRect(KDRect rect) const override;
|
||||
void drawRect(KDContext * ctx, KDRect rect) const override;
|
||||
|
||||
void setStart(float start);
|
||||
void setEnd(float end);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
class SolidColorView : public ChildlessView {
|
||||
public:
|
||||
SolidColorView(KDColor color);
|
||||
void drawRect(KDRect rect) const override;
|
||||
void drawRect(KDContext * ctx, KDRect rect) const override;
|
||||
protected:
|
||||
#if ESCHER_VIEW_LOGGING
|
||||
const char * className() const override;
|
||||
|
||||
@@ -10,7 +10,7 @@ class TabView : public View {
|
||||
public:
|
||||
TabView();
|
||||
|
||||
void drawRect(KDRect rect) const override;
|
||||
void drawRect(KDContext * ctx, KDRect rect) const override;
|
||||
|
||||
void addTabNamed(const char * name);
|
||||
//TODO: void removeLastTab();
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
class TabViewCell : public ChildlessView {
|
||||
public:
|
||||
TabViewCell();
|
||||
void drawRect(KDRect rect) const override;
|
||||
void drawRect(KDContext * ctx, KDRect rect) const override;
|
||||
void setName(const char * name);
|
||||
void setActive(bool active);
|
||||
protected:
|
||||
|
||||
@@ -9,7 +9,7 @@ class TextField : public ChildlessView, public Responder {
|
||||
public:
|
||||
TextField(char * textBuffer, size_t textBufferSize);
|
||||
// View
|
||||
void drawRect(KDRect rect) const override;
|
||||
void drawRect(KDContext * ctx, KDRect rect) const override;
|
||||
// Responder
|
||||
bool handleEvent(ion_event_t event) override;
|
||||
protected:
|
||||
|
||||
@@ -12,7 +12,7 @@ public:
|
||||
TextView(const char * text,
|
||||
float horizontalAlignment,
|
||||
float verticalAlignment);
|
||||
void drawRect(KDRect rect) const override;
|
||||
void drawRect(KDContext * ctx, KDRect rect) const override;
|
||||
void setText(const char * text);
|
||||
protected:
|
||||
#if ESCHER_VIEW_LOGGING
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
class TiledView : public View {
|
||||
using View::View;
|
||||
protected:
|
||||
void drawRect(KDRect rect) const override;
|
||||
virtual void drawTile(KDRect rect) const = 0;
|
||||
void drawRect(KDContext * ctx, KDRect rect) const override;
|
||||
virtual void drawTile(KDContext * ctx, KDRect rect) const = 0;
|
||||
|
||||
virtual KDColor * tile() const = 0;
|
||||
virtual KDSize tileSize() const = 0;
|
||||
|
||||
@@ -28,8 +28,8 @@ public:
|
||||
|
||||
/* The drawRect method should be implemented by each View subclass. In a
|
||||
* typical drawRect implementation, a subclass will make drawing calls to the
|
||||
* Kandinsky library. */
|
||||
virtual void drawRect(KDRect rect) const;
|
||||
* Kandinsky library using the provided context. */
|
||||
virtual void drawRect(KDContext * ctx, KDRect rect) const;
|
||||
|
||||
void setFrame(KDRect frame);
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ void App::run() {
|
||||
sRunningApp = this;
|
||||
|
||||
Window window;
|
||||
window.setFrame({{{0,0}}, {{ION_SCREEN_WIDTH, ION_SCREEN_HEIGHT}}});
|
||||
window.setFrame(KDRect(0, 0, ION_SCREEN_WIDTH, ION_SCREEN_HEIGHT));
|
||||
View * rootView = rootViewController()->view();
|
||||
|
||||
focus(rootViewController());
|
||||
|
||||
@@ -32,28 +32,24 @@ View * ScrollView::subviewAtIndex(int index) {
|
||||
|
||||
void ScrollView::layoutSubviews() {
|
||||
// Layout indicators
|
||||
KDRect verticalIndicatorFrame;
|
||||
verticalIndicatorFrame.x = m_frame.width - k_indicatorThickness;
|
||||
verticalIndicatorFrame.y = 0;
|
||||
verticalIndicatorFrame.width = k_indicatorThickness;
|
||||
verticalIndicatorFrame.height = m_frame.height;
|
||||
KDRect verticalIndicatorFrame = KDRect(
|
||||
m_frame.width() - k_indicatorThickness, 0,
|
||||
k_indicatorThickness, m_frame.height()
|
||||
);
|
||||
m_verticalScrollIndicator.setFrame(verticalIndicatorFrame);
|
||||
|
||||
// Layout contentView
|
||||
// We're only re-positionning the contentView, not modifying its size.
|
||||
KDRect contentFrame;
|
||||
contentFrame.x = -m_offset.x;
|
||||
contentFrame.y = -m_offset.y;
|
||||
contentFrame.size = m_contentView->bounds().size;
|
||||
KDRect contentFrame = KDRect(m_offset.opposite(), m_contentView->bounds().size());
|
||||
m_contentView->setFrame(contentFrame);
|
||||
}
|
||||
|
||||
void ScrollView::setContentOffset(KDPoint offset) {
|
||||
m_offset = offset;
|
||||
|
||||
float contentHeight = m_contentView->bounds().height;
|
||||
float start = offset.y;
|
||||
float end = offset.y + m_frame.height;
|
||||
float contentHeight = m_contentView->bounds().height();
|
||||
float start = offset.y();
|
||||
float end = offset.y() + m_frame.height();
|
||||
|
||||
m_verticalScrollIndicator.setStart(start/contentHeight);
|
||||
m_verticalScrollIndicator.setEnd(end/contentHeight);
|
||||
@@ -62,7 +58,7 @@ void ScrollView::setContentOffset(KDPoint offset) {
|
||||
}
|
||||
|
||||
KDCoordinate ScrollView::maxContentWidth() {
|
||||
return m_frame.width - k_indicatorThickness;
|
||||
return m_frame.width() - k_indicatorThickness;
|
||||
}
|
||||
|
||||
#if ESCHER_VIEW_LOGGING
|
||||
|
||||
@@ -14,22 +14,22 @@ ScrollViewIndicator::ScrollViewIndicator(ScrollViewIndicator::Direction directio
|
||||
{
|
||||
}
|
||||
|
||||
void ScrollViewIndicator::drawRect(KDRect rect) const {
|
||||
KDFillRect(bounds(), k_backgroundColor);
|
||||
KDRect indicatorFrame;
|
||||
void ScrollViewIndicator::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
ctx->fillRect(bounds(), k_backgroundColor);
|
||||
KDRect indicatorFrame = KDRectZero;
|
||||
if (m_direction == Direction::Horizontal) {
|
||||
indicatorFrame.x = m_start*m_frame.width;
|
||||
indicatorFrame.y = 0;
|
||||
indicatorFrame.width = (m_end-m_start)*m_frame.width;
|
||||
indicatorFrame.height = m_frame.height;
|
||||
indicatorFrame = KDRect(
|
||||
m_start*m_frame.width(), 0,
|
||||
(m_end-m_start)*m_frame.width(), m_frame.height()
|
||||
);
|
||||
} else {
|
||||
assert(m_direction == Direction::Vertical);
|
||||
indicatorFrame.x = 0;
|
||||
indicatorFrame.y = m_start*m_frame.height;
|
||||
indicatorFrame.width = m_frame.width;
|
||||
indicatorFrame.height = (m_end-m_start)*m_frame.height;
|
||||
indicatorFrame = KDRect(
|
||||
0, m_start*m_frame.height(),
|
||||
m_frame.width(), (m_end-m_start)*m_frame.height()
|
||||
);
|
||||
}
|
||||
KDFillRect(indicatorFrame, k_indicatorColor);
|
||||
ctx->fillRect(indicatorFrame, k_indicatorColor);
|
||||
}
|
||||
|
||||
void ScrollViewIndicator::setStart(float start) {
|
||||
|
||||
@@ -6,8 +6,8 @@ SolidColorView::SolidColorView(KDColor color) :
|
||||
{
|
||||
}
|
||||
|
||||
void SolidColorView::drawRect(KDRect rect) const {
|
||||
KDFillRect(rect, m_color);
|
||||
void SolidColorView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
ctx->fillRect(rect, m_color);
|
||||
}
|
||||
|
||||
#if ESCHER_VIEW_LOGGING
|
||||
|
||||
@@ -11,9 +11,9 @@ TabView::TabView() :
|
||||
{
|
||||
}
|
||||
|
||||
void TabView::drawRect(KDRect rect) const {
|
||||
KDColor backgroundColor = KDColorRGB(0xb5, 0x1d, 0xab);
|
||||
KDFillRect(rect, backgroundColor);
|
||||
void TabView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
KDColor backgroundColor = KDColor(0xB51DAB);
|
||||
ctx->fillRect(rect, backgroundColor);
|
||||
}
|
||||
|
||||
void TabView::addTabNamed(const char * name) {
|
||||
@@ -46,13 +46,12 @@ View * TabView::subviewAtIndex(int index) {
|
||||
|
||||
void TabView::layoutSubviews() {
|
||||
// Simple layout: all tabs have the same length
|
||||
KDCoordinate tabLength = m_frame.width/m_numberOfTabs;
|
||||
KDCoordinate tabLength = m_frame.width()/m_numberOfTabs;
|
||||
for (int i=0; i<m_numberOfTabs; i++) {
|
||||
KDRect cellFrame;
|
||||
cellFrame.x = i*tabLength;
|
||||
cellFrame.y = 0;
|
||||
cellFrame.width = tabLength;
|
||||
cellFrame.height = m_frame.height;
|
||||
KDRect cellFrame = KDRect(
|
||||
i*tabLength, 0,
|
||||
tabLength, m_frame.height()
|
||||
);
|
||||
m_cells[i].setFrame(cellFrame);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,8 +20,8 @@ void TabViewCell::setActive(bool active) {
|
||||
markRectAsDirty(bounds());
|
||||
}
|
||||
|
||||
void TabViewCell::drawRect(KDRect rect) const {
|
||||
KDDrawString(m_name, {0,0}, m_active);
|
||||
void TabViewCell::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
ctx->drawString(m_name, {0,0}, m_active);
|
||||
}
|
||||
|
||||
#if ESCHER_VIEW_LOGGING
|
||||
|
||||
@@ -19,17 +19,17 @@ void TabViewController::ContentView::setActiveView(View * view) {
|
||||
void TabViewController::ContentView::layoutSubviews() {
|
||||
KDCoordinate tabHeight = 20;
|
||||
|
||||
KDRect tabViewFrame;
|
||||
tabViewFrame.origin = KDPointZero;
|
||||
tabViewFrame.width = m_frame.width,
|
||||
tabViewFrame.height = tabHeight;
|
||||
KDRect tabViewFrame = KDRect(
|
||||
0, 0,
|
||||
m_frame.width(), tabHeight
|
||||
);
|
||||
m_tabView.setFrame(tabViewFrame);
|
||||
if (m_activeView) {
|
||||
KDRect activeViewFrame;
|
||||
activeViewFrame.x = 0;
|
||||
activeViewFrame.y = tabHeight;
|
||||
activeViewFrame.width = m_frame.width;
|
||||
activeViewFrame.height = m_frame.height - tabHeight;
|
||||
KDRect activeViewFrame = KDRect(
|
||||
0, tabHeight,
|
||||
m_frame.width(),
|
||||
m_frame.height() - tabHeight
|
||||
);
|
||||
m_activeView->setFrame(activeViewFrame);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,10 +31,7 @@ void TableView::layoutSubviews() {
|
||||
// We only have to layout our contentView.
|
||||
// We will size it here, and ScrollView::layoutSubviews will position it.
|
||||
|
||||
KDRect contentViewFrame;
|
||||
contentViewFrame.origin = KDPointZero; // Will be overriden by ScrollView::layoutSubviews
|
||||
contentViewFrame.width = maxContentWidth();
|
||||
contentViewFrame.height = m_contentView.height();
|
||||
KDRect contentViewFrame(0, 0, maxContentWidth(), m_contentView.height());
|
||||
m_contentView.setFrame(contentViewFrame);
|
||||
|
||||
ScrollView::layoutSubviews();
|
||||
@@ -56,17 +53,14 @@ KDCoordinate TableView::ContentView::height() const {
|
||||
void TableView::ContentView::scrollToRow(int index) const {
|
||||
if (cellAtIndexIsBeforeFullyVisibleRange(index)) {
|
||||
// Let's scroll the tableView to put that cell on the top
|
||||
KDPoint contentOffset;
|
||||
contentOffset.x = 0;
|
||||
contentOffset.y = index*m_dataSource->cellHeight();
|
||||
KDPoint contentOffset(0, index*m_dataSource->cellHeight());
|
||||
m_tableView->setContentOffset(contentOffset);
|
||||
return;
|
||||
}
|
||||
if (cellAtIndexIsAfterFullyVisibleRange(index)) {
|
||||
// Let's scroll the tableView to put that cell on the bottom
|
||||
KDPoint contentOffset;
|
||||
contentOffset.x = 0;
|
||||
contentOffset.y = (index+1)*m_dataSource->cellHeight() - m_tableView->bounds().height;
|
||||
KDPoint contentOffset(0,
|
||||
(index+1)*m_dataSource->cellHeight() - m_tableView->bounds().height());
|
||||
m_tableView->setContentOffset(contentOffset);
|
||||
return;
|
||||
}
|
||||
@@ -99,12 +93,8 @@ void TableView::ContentView::layoutSubviews() {
|
||||
for (int i=0; i<numberOfSubviews(); i++) {
|
||||
View * cell = subview(i);
|
||||
|
||||
KDRect cellFrame;
|
||||
KDCoordinate cellHeight = m_dataSource->cellHeight();
|
||||
cellFrame.x = 0;
|
||||
cellFrame.y = (cellOffset+i)*cellHeight;
|
||||
cellFrame.width = m_frame.width;
|
||||
cellFrame.height = cellHeight;
|
||||
KDRect cellFrame(0, (cellOffset+i)*cellHeight, m_frame.width(), cellHeight);
|
||||
|
||||
cell->setFrame(cellFrame);
|
||||
|
||||
@@ -113,7 +103,7 @@ void TableView::ContentView::layoutSubviews() {
|
||||
}
|
||||
|
||||
int TableView::ContentView::numberOfDisplayableCells() const {
|
||||
int result = m_tableView->bounds().height / m_dataSource->cellHeight() + 1;
|
||||
int result = m_tableView->bounds().height() / m_dataSource->cellHeight() + 1;
|
||||
assert(result <= m_dataSource->reusableCellCount());
|
||||
return result;
|
||||
}
|
||||
@@ -121,7 +111,7 @@ int TableView::ContentView::numberOfDisplayableCells() const {
|
||||
int TableView::ContentView::cellScrollingOffset() const {
|
||||
/* Here, we want to translate the offset at which our tableView is displaying
|
||||
* us into an integer offset we can use to ask cells to our data source. */
|
||||
KDCoordinate pixelScrollingOffset = -m_frame.y;
|
||||
KDCoordinate pixelScrollingOffset = -m_frame.y();
|
||||
return pixelScrollingOffset / m_dataSource->cellHeight();
|
||||
}
|
||||
|
||||
|
||||
@@ -10,9 +10,9 @@ TextField::TextField(char * textBuffer, size_t textBufferSize) :
|
||||
|
||||
/* View */
|
||||
|
||||
void TextField::drawRect(KDRect rect) const {
|
||||
void TextField::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
m_textBuffer[m_currentTextLength] = 0;
|
||||
KDDrawString(m_textBuffer, KDPointZero, 0);
|
||||
ctx->drawString(m_textBuffer, KDPointZero, 0);
|
||||
}
|
||||
|
||||
#if ESCHER_VIEW_LOGGING
|
||||
|
||||
@@ -16,13 +16,13 @@ void TextView::setText(const char * text) {
|
||||
m_text = text;
|
||||
}
|
||||
|
||||
void TextView::drawRect(KDRect rect) const {
|
||||
KDSize textSize = KDStringSize(m_text);
|
||||
void TextView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
KDSize textSize = ctx->stringSize(m_text);
|
||||
KDPoint origin = {
|
||||
(KDCoordinate)(m_horizontalAlignment*(m_frame.width - textSize.width)),
|
||||
(KDCoordinate)(m_verticalAlignment*(m_frame.height - textSize.height))
|
||||
(KDCoordinate)(m_horizontalAlignment*(m_frame.width() - textSize.width())),
|
||||
(KDCoordinate)(m_verticalAlignment*(m_frame.height() - textSize.height()))
|
||||
};
|
||||
KDDrawString(m_text, origin, 0);
|
||||
ctx->drawString(m_text, origin, 0);
|
||||
}
|
||||
|
||||
#if ESCHER_VIEW_LOGGING
|
||||
|
||||
@@ -1,53 +1,26 @@
|
||||
#include <escher/tiled_view.h>
|
||||
#include <assert.h>
|
||||
|
||||
static KDFrameBuffer sCurrentTile;
|
||||
void TiledView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
KDColor * pixels = tile();
|
||||
KDSize size = tileSize();
|
||||
KDFrameBuffer tileBuffer(pixels, size);
|
||||
|
||||
void tilePushRect(KDRect rect, const KDColor * pixels) {
|
||||
KDFramePushRect(&sCurrentTile, rect, pixels);
|
||||
}
|
||||
void tilePushRectUniform(KDRect rect, KDColor color) {
|
||||
KDFramePushRectUniform(&sCurrentTile, rect, color);
|
||||
}
|
||||
|
||||
void tilePullRect(KDRect rect, KDColor * pixels) {
|
||||
KDFramePullRect(&sCurrentTile, rect, pixels);
|
||||
}
|
||||
|
||||
static KDContext sTileContext = {
|
||||
{
|
||||
&tilePushRect,
|
||||
&tilePushRectUniform,
|
||||
&tilePullRect
|
||||
},
|
||||
{0, 0},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
void TiledView::drawRect(KDRect rect) const {
|
||||
sCurrentTile.pixels = tile();
|
||||
sCurrentTile.size = tileSize();
|
||||
|
||||
sTileContext.clippingRect.origin = KDPointZero; // Useless
|
||||
sTileContext.clippingRect.size = sCurrentTile.size;
|
||||
|
||||
KDRect tileRect;
|
||||
for (int i=0; i<(rect.width/sCurrentTile.size.width+1); i++) {
|
||||
for (int j=0; j<(rect.height/sCurrentTile.size.height+1); j++) {
|
||||
tileRect.x = rect.x + i*sCurrentTile.size.width;
|
||||
tileRect.y = rect.y + j*sCurrentTile.size.height;
|
||||
tileRect.size = sCurrentTile.size;
|
||||
for (int i=0; i<(rect.width()/size.width()+1); i++) {
|
||||
for (int j=0; j<(rect.height()/size.height()+1); j++) {
|
||||
KDRect tileRect(
|
||||
rect.x() + i*size.width(),
|
||||
rect.y() + j*size.height(),
|
||||
size.width(), size.height()
|
||||
);
|
||||
//tileRect = KDRectIntersection(tileRect, rect); // Optional
|
||||
KDContext * previousContext = KDCurrentContext;
|
||||
sTileContext.origin.x = -tileRect.x;
|
||||
sTileContext.origin.y = -tileRect.y;
|
||||
KDFrameBufferContext tileContext = KDFrameBufferContext(&tileBuffer);
|
||||
KDPoint origin = tileRect.origin().opposite();
|
||||
tileContext.setOrigin(origin);
|
||||
|
||||
KDCurrentContext = &sTileContext;
|
||||
drawTile(tileRect);
|
||||
KDCurrentContext = previousContext;
|
||||
KDSize zero = {0,0};
|
||||
drawTile(&tileContext, tileRect);
|
||||
|
||||
KDFillRectWithPixels(tileRect, sCurrentTile.pixels, sCurrentTile.pixels);
|
||||
ctx->fillRectWithPixels(tileRect, pixels, pixels);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ View::View() :
|
||||
{
|
||||
}
|
||||
|
||||
void View::drawRect(KDRect rect) const {
|
||||
void View::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
// By default, a view doesn't do anything
|
||||
// It's transparent!
|
||||
}
|
||||
@@ -24,7 +24,7 @@ const Window * View::window() const {
|
||||
}
|
||||
|
||||
void View::markRectAsDirty(KDRect rect) {
|
||||
m_dirtyRect = KDRectUnion(m_dirtyRect, rect);
|
||||
m_dirtyRect = m_dirtyRect.unionedWith(rect);
|
||||
}
|
||||
|
||||
void View::redraw(KDRect rect) {
|
||||
@@ -35,14 +35,15 @@ void View::redraw(KDRect rect) {
|
||||
}
|
||||
|
||||
// First, let's draw our own content by calling drawRect
|
||||
KDRect rectNeedingRedraw = KDRectIntersection(rect, m_dirtyRect);
|
||||
if (rectNeedingRedraw.width > 0 && rectNeedingRedraw.height > 0) {
|
||||
KDRect rectNeedingRedraw = rect.intersectedWith(m_dirtyRect);
|
||||
if (!rectNeedingRedraw.isEmpty()) {
|
||||
KDPoint absOrigin = absoluteOrigin();
|
||||
KDRect absRect = KDRectTranslate(rectNeedingRedraw, absOrigin);
|
||||
KDRect absClippingRect = KDRectIntersection(absoluteVisibleFrame(), absRect);
|
||||
KDCurrentContext->origin = absOrigin;
|
||||
KDCurrentContext->clippingRect = absClippingRect;
|
||||
this->drawRect(rectNeedingRedraw);
|
||||
KDRect absRect = rectNeedingRedraw.translatedBy(absOrigin);
|
||||
KDRect absClippingRect = absoluteVisibleFrame().intersectedWith(absRect);
|
||||
KDContext * ctx = KDIonContext::sharedContext();
|
||||
ctx->setOrigin(absOrigin);
|
||||
ctx->setClippingRect(absClippingRect);
|
||||
this->drawRect(ctx, rectNeedingRedraw);
|
||||
}
|
||||
|
||||
// Then, let's recursively draw our children over ourself
|
||||
@@ -53,11 +54,10 @@ void View::redraw(KDRect rect) {
|
||||
}
|
||||
assert(subview->m_superview == this);
|
||||
|
||||
if (KDRectIntersect(rect, subview->m_frame)) {
|
||||
KDRect intersection = KDRectIntersection(rect, subview->m_frame);
|
||||
if (rect.intersects(subview->m_frame)) {
|
||||
KDRect intersection = rect.intersectedWith(subview->m_frame);
|
||||
// Let's express intersection in subview's coordinates
|
||||
intersection.x -= subview->m_frame.x;
|
||||
intersection.y -= subview->m_frame.y;
|
||||
intersection = intersection.translatedBy(subview->m_frame.origin().opposite());
|
||||
subview->redraw(intersection);
|
||||
}
|
||||
}
|
||||
@@ -100,18 +100,15 @@ void View::setFrame(KDRect frame) {
|
||||
}
|
||||
|
||||
KDRect View::bounds() const {
|
||||
KDRect bounds = m_frame;
|
||||
bounds.x = 0;
|
||||
bounds.y = 0;
|
||||
return bounds;
|
||||
return m_frame.movedTo(KDPointZero);
|
||||
}
|
||||
|
||||
KDPoint View::absoluteOrigin() const {
|
||||
if (m_superview == nullptr) {
|
||||
assert(this == (View *)window());
|
||||
return m_frame.origin;
|
||||
return m_frame.origin();
|
||||
} else {
|
||||
return KDPointTranslate(m_frame.origin, m_superview->absoluteOrigin());
|
||||
return m_frame.origin().translatedBy(m_superview->absoluteOrigin());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,10 +119,9 @@ KDRect View::absoluteVisibleFrame() const {
|
||||
} else {
|
||||
KDRect parentDrawingArea = m_superview->absoluteVisibleFrame();
|
||||
|
||||
KDRect absoluteFrame = m_frame;
|
||||
absoluteFrame.origin = absoluteOrigin();
|
||||
KDRect absoluteFrame = m_frame.movedTo(absoluteOrigin());
|
||||
|
||||
return KDRectIntersection(absoluteFrame, parentDrawingArea);
|
||||
return absoluteFrame.intersectedWith(parentDrawingArea);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,11 +11,13 @@
|
||||
* pixel coordinates every time. We're therefore leveraging this capability
|
||||
* which results in a very consequent speedup (up to ~10x faster). */
|
||||
|
||||
#include <kandinsky.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void ion_screen_push_rect(KDRect rect, const KDColor * pixels);
|
||||
void ion_screen_push_rect_uniform(KDRect rect, KDColor color);
|
||||
void ion_screen_pull_rect(KDRect rect, KDColor * pixels);
|
||||
typedef uint16_t ion_color_t;
|
||||
|
||||
void ion_screen_push_rect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, const ion_color_t * pixels);
|
||||
void ion_screen_push_rect_uniform(uint16_t x, uint16_t y, uint16_t width, uint16_t height, ion_color_t color);
|
||||
void ion_screen_pull_rect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, ion_color_t * pixels);
|
||||
/*
|
||||
void ion_screen_set_working_area(KDRect area);
|
||||
void ion_screen_push_pixels(const KDColor * pixels, size_t count);
|
||||
|
||||
@@ -40,19 +40,19 @@ void ion_display_off() {
|
||||
// Turn off panel
|
||||
}
|
||||
|
||||
void ion_screen_push_rect(KDRect rect, const KDColor * pixels) {
|
||||
st7789_set_drawing_area(&sDisplayController, rect);
|
||||
st7789_push_pixels(&sDisplayController, pixels, rect.width*rect.height);
|
||||
void ion_screen_push_rect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, const ion_color_t * pixels) {
|
||||
st7789_set_drawing_area(&sDisplayController, x, y, width, height);
|
||||
st7789_push_pixels(&sDisplayController, pixels, width*height);
|
||||
}
|
||||
|
||||
void ion_screen_push_rect_uniform(KDRect rect, KDColor color) {
|
||||
st7789_set_drawing_area(&sDisplayController, rect);
|
||||
for (size_t i=0; i<rect.width*rect.height; i++) {
|
||||
void ion_screen_push_rect_uniform(uint16_t x, uint16_t y, uint16_t width, uint16_t height, ion_color_t color) {
|
||||
st7789_set_drawing_area(&sDisplayController, x, y, width, height);
|
||||
for (size_t i=0; i<width*height; i++) {
|
||||
st7789_push_pixels(&sDisplayController, &color, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void ion_screen_pull_rect(KDRect rect, KDColor * pixels) {
|
||||
void ion_screen_pull_rect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, ion_color_t * pixels) {
|
||||
assert(0); // Unimplemented
|
||||
}
|
||||
|
||||
|
||||
@@ -155,12 +155,11 @@ void st7789_initialize(st7789_t * c) {
|
||||
perform_instructions(c, init_sequence, sizeof(init_sequence)/sizeof(init_sequence[0]));
|
||||
}
|
||||
|
||||
void st7789_set_drawing_area(st7789_t * controller, KDRect area) {
|
||||
assert(sizeof(KDCoordinate) == 2); // We expect 16-bit values
|
||||
uint16_t x_start = area.x;
|
||||
uint16_t x_end = area.x + area.width - 1;
|
||||
uint16_t y_start = area.y;
|
||||
uint16_t y_end = area.y + area.height - 1;
|
||||
void st7789_set_drawing_area(st7789_t * controller, uint16_t x, uint16_t y, uint16_t width, uint16_t height) {
|
||||
uint16_t x_start = x;
|
||||
uint16_t x_end = x + width - 1;
|
||||
uint16_t y_start = y;
|
||||
uint16_t y_end = y + height - 1;
|
||||
|
||||
const instruction_t sequence[] = {
|
||||
COMMAND(CASET),
|
||||
@@ -183,8 +182,8 @@ void st7789_set_drawing_area(st7789_t * controller, KDRect area) {
|
||||
|
||||
|
||||
void st7789_push_pixels(st7789_t * controller,
|
||||
const KDColor * pixels, size_t numberOfPixels) {
|
||||
assert(sizeof(KDColor) == 2); // We expect KDColor to be RGB565
|
||||
const ion_color_t * pixels, size_t numberOfPixels) {
|
||||
assert(sizeof(ion_color_t) == 2); // We expect KDColor to be RGB565
|
||||
for (size_t i=0; i<numberOfPixels; i++) {
|
||||
perform_instruction(controller, DATA(pixels[i] >> 8));
|
||||
perform_instruction(controller, DATA(pixels[i] & 0xFF));
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <ion/screen.h>
|
||||
#include <kandinsky.h>
|
||||
|
||||
#define ST7789_USE_9BIT_SPI 1
|
||||
|
||||
@@ -23,8 +22,8 @@ typedef struct {
|
||||
|
||||
void st7789_initialize(st7789_t * controller);
|
||||
|
||||
void st7789_set_drawing_area(st7789_t * controller, KDRect area);
|
||||
void st7789_set_drawing_area(st7789_t * controller, uint16_t x, uint16_t y, uint16_t width, uint16_t height);
|
||||
|
||||
void st7789_push_pixels(st7789_t * controller,
|
||||
const KDColor * pixels, size_t numberOfPixels);
|
||||
const ion_color_t * pixels, size_t numberOfPixels);
|
||||
#endif
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <FL/fl_draw.H>
|
||||
|
||||
FltkLCD::FltkLCD(int x, int y, int w, int h, uint16_t * rgb565FrameBuffer) :
|
||||
FltkLCD::FltkLCD(int x, int y, int w, int h, KDColor * rgb565FrameBuffer) :
|
||||
Fl_Widget(x, y, w, h, nullptr),
|
||||
m_rgb565frameBufferStart(rgb565FrameBuffer),
|
||||
m_rgb565frameBufferEnd(rgb565FrameBuffer+w*h)
|
||||
@@ -21,9 +21,9 @@ void FltkLCD::draw() {
|
||||
|
||||
while(rgb565Pixel < m_rgb565frameBufferEnd) {
|
||||
KDColor color = *rgb565Pixel++;
|
||||
*rgb888Component++ = KDColorRedComponent(color);
|
||||
*rgb888Component++ = KDColorGreenComponent(color);
|
||||
*rgb888Component++ = KDColorBlueComponent(color);
|
||||
*rgb888Component++ = color.red();
|
||||
*rgb888Component++ = color.green();
|
||||
*rgb888Component++ = color.blue();
|
||||
}
|
||||
|
||||
// 2/ Draw the 888 framebuffer
|
||||
|
||||
@@ -15,7 +15,7 @@ extern "C" {
|
||||
|
||||
static FltkLCD * sDisplay;
|
||||
static FltkKbd * sKeyboard;
|
||||
static KDFrameBuffer sFrameBuffer;
|
||||
static KDFrameBuffer * sFrameBuffer;
|
||||
|
||||
#define FRAMEBUFFER_ADDRESS (sDisplay->m_framebuffer)
|
||||
|
||||
@@ -29,16 +29,15 @@ void init_platform() {
|
||||
|
||||
Fl_Window * window = new Fl_Window(screen_width+2*margin, margin+screen_height+margin+keyboard_height+margin);
|
||||
|
||||
sFrameBuffer.pixels = (KDColor *)malloc(ION_SCREEN_WIDTH*ION_SCREEN_HEIGHT*2);
|
||||
sFrameBuffer.size.width = ION_SCREEN_WIDTH;
|
||||
sFrameBuffer.size.height = ION_SCREEN_HEIGHT;
|
||||
KDColor * pixels = (KDColor *)malloc(ION_SCREEN_WIDTH*ION_SCREEN_HEIGHT*sizeof(KDColor));
|
||||
sFrameBuffer = new KDFrameBuffer(pixels, KDSize(ION_SCREEN_WIDTH, ION_SCREEN_HEIGHT));
|
||||
/*
|
||||
sFrameBuffer.drawingArea.origin = KDPointZero;
|
||||
sFrameBuffer.drawingArea.size = sFrameBuffer.size;
|
||||
sFrameBuffer.drawingCursor = KDPointZero;
|
||||
*/
|
||||
|
||||
sDisplay = new FltkLCD(margin, margin, screen_width, screen_height, sFrameBuffer.pixels);
|
||||
sDisplay = new FltkLCD(margin, margin, screen_width, screen_height, pixels);
|
||||
sKeyboard = new FltkKbd(margin, margin+screen_height+margin, screen_width, keyboard_height);
|
||||
|
||||
window->end();
|
||||
@@ -47,16 +46,33 @@ void init_platform() {
|
||||
//KDCurrentContext->fillRect = NULL;
|
||||
}
|
||||
|
||||
void ion_screen_push_rect(KDRect rect, const KDColor * pixels) {
|
||||
KDFramePushRect(&sFrameBuffer, rect, pixels);
|
||||
void ion_screen_push_rect(uint16_t x, uint16_t y,
|
||||
uint16_t width, uint16_t height,
|
||||
const ion_color_t * pixels)
|
||||
{
|
||||
// FIXME: Boy those casts are fugly
|
||||
const void * foo = static_cast<const void *>(pixels);
|
||||
const KDColor * pouet = static_cast<const KDColor *>(foo);
|
||||
sFrameBuffer->pushRect(KDRect(x,y,width,height), pouet);
|
||||
}
|
||||
|
||||
void ion_screen_push_rect_uniform(KDRect rect, KDColor color) {
|
||||
KDFramePushRectUniform(&sFrameBuffer, rect, color);
|
||||
void ion_screen_push_rect_uniform(uint16_t x, uint16_t y,
|
||||
uint16_t width, uint16_t height,
|
||||
ion_color_t color)
|
||||
{
|
||||
ion_color_t * foo = &color;
|
||||
const void * bar = static_cast<const void *>(foo);
|
||||
const KDColor * baz = static_cast<const KDColor *>(bar);
|
||||
sFrameBuffer->pushRectUniform(KDRect(x,y,width,height), *baz);
|
||||
}
|
||||
|
||||
void ion_screen_pull_rect(KDRect rect, KDColor * pixels) {
|
||||
KDFramePullRect(&sFrameBuffer, rect, pixels);
|
||||
void ion_screen_pull_rect(uint16_t x, uint16_t y,
|
||||
uint16_t width, uint16_t height,
|
||||
ion_color_t * pixels)
|
||||
{
|
||||
void * foo = static_cast<void *>(pixels);
|
||||
KDColor * pouet = static_cast<KDColor *>(foo);
|
||||
sFrameBuffer->pullRect(KDRect(x,y,width,height), pouet);
|
||||
}
|
||||
|
||||
bool ion_key_down(ion_key_t key) {
|
||||
|
||||
@@ -2,18 +2,21 @@ SFLAGS += -Ikandinsky/include
|
||||
objs += $(addprefix kandinsky/src/,\
|
||||
color.o\
|
||||
context.o\
|
||||
context_line.o\
|
||||
context_pixel.o\
|
||||
context_rect.o\
|
||||
context_text.o\
|
||||
font.o\
|
||||
framebuffer.o\
|
||||
line.o\
|
||||
pixel.o\
|
||||
framebuffer_context.o\
|
||||
ion_context.o\
|
||||
point.o\
|
||||
rect.o\
|
||||
text.o\
|
||||
types.o\
|
||||
size.o\
|
||||
)
|
||||
tests += $(addprefix kandinsky/test/,\
|
||||
color.c\
|
||||
rect.c\
|
||||
set_pixel.c\
|
||||
color.cpp\
|
||||
rect.cpp\
|
||||
)
|
||||
|
||||
FREETYPE_PATH := /usr/local/Cellar/freetype/2.6.3
|
||||
@@ -21,7 +24,7 @@ FREETYPE_PATH := /usr/local/Cellar/freetype/2.6.3
|
||||
# built w/o PNG support and simply won't output an image of the rasterization
|
||||
#LIBPNG_PATH := /usr/local/Cellar/libpng/1.6.21
|
||||
|
||||
kandinsky/src/text.c: kandinsky/src/font.h
|
||||
kandinsky/src/context_text.cpp: kandinsky/src/font.h
|
||||
|
||||
font_files = $(addprefix kandinsky/src/, font.h font.c)
|
||||
|
||||
|
||||
@@ -2,12 +2,13 @@
|
||||
#define KANDINSKY_KANDINSKY_H
|
||||
|
||||
#include <kandinsky/color.h>
|
||||
#include <kandinsky/coordinate.h>
|
||||
#include <kandinsky/context.h>
|
||||
#include <kandinsky/framebuffer.h>
|
||||
#include <kandinsky/line.h>
|
||||
#include <kandinsky/pixel.h>
|
||||
#include <kandinsky/framebuffer_context.h>
|
||||
#include <kandinsky/ion_context.h>
|
||||
#include <kandinsky/point.h>
|
||||
#include <kandinsky/rect.h>
|
||||
#include <kandinsky/text.h>
|
||||
#include <kandinsky/types.h>
|
||||
#include <kandinsky/size.h>
|
||||
|
||||
#endif
|
||||
|
||||
@@ -3,32 +3,24 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// Kandinsky uses RGB565
|
||||
class KDColor {
|
||||
public:
|
||||
constexpr KDColor() : m_value(0) {}
|
||||
// FIXME: This should not be needed, and is probably wasting CPU cycles
|
||||
|
||||
typedef uint16_t KDColor;
|
||||
constexpr KDColor(uint32_t rgb)
|
||||
: m_value(((rgb&0xF80000)>>8)|((rgb&0x00FC00)>>5)|((rgb&0x0000F8)>>3)) {}
|
||||
uint8_t red();
|
||||
uint8_t green();
|
||||
uint8_t blue();
|
||||
KDColor blend(KDColor other, uint8_t alpha);
|
||||
operator uint16_t() { return m_value; }
|
||||
private:
|
||||
uint16_t m_value;
|
||||
};
|
||||
|
||||
/* KDColorRGB takes a 32-bits RGB color and builds a KDColor from it.
|
||||
* Given KDColor is RGB565 and that we take 8-bit values for R, G, and B,
|
||||
* some shifting has to happen. */
|
||||
|
||||
// FIXME: KDColorRGB(rgb), as a single 32-bits value
|
||||
#define KDColorRGB(r,g,b) ((KDColor)((((((uint16_t)(r))>>3)&0x1F)<<11)|(((((uint16_t)(g))>>2)&0x3F)<<5)|((((uint16_t)(b))>>3)&0x1F)))
|
||||
|
||||
#define KDColorRedComponent(color) ((uint8_t)(((color)>>11)<<3))
|
||||
#define KDColorGreenComponent(color) ((uint8_t)((((color)>>5)&0x3F)<<2))
|
||||
#define KDColorBlueComponent(color) ((uint8_t)(((color)&0x1F)<<3))
|
||||
|
||||
#define KDColorGray(i) KDColorRGB(i,i,i)
|
||||
|
||||
#define KDColorBlack KDColorRGB(0x00, 0x00, 0x00)
|
||||
#define KDColorWhite KDColorRGB(0xFF, 0xFF, 0xFF)
|
||||
|
||||
#define KDColorRed KDColorRGB(0xFF, 0x00, 0x00)
|
||||
#define KDColorGreen KDColorRGB(0x00, 0xFF, 0x00)
|
||||
#define KDColorBlue KDColorRGB(0x00, 0x00, 0xFF)
|
||||
|
||||
// alpha = 0 -> only a
|
||||
// alpha = 0xFF -> only b
|
||||
KDColor KDColorBlend(KDColor background, KDColor foreground, uint8_t alpha);
|
||||
constexpr KDColor KDColorBlack = KDColor(0x000000);
|
||||
constexpr KDColor KDColorWhite = KDColor(0xFFFFFF);
|
||||
constexpr KDColor KDColorRed = KDColor(0xFF0000);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,19 +1,40 @@
|
||||
#ifndef KANDINSKY_CONTEXT_H
|
||||
#define KANDINSKY_CONTEXT_H
|
||||
|
||||
#include "types.h"
|
||||
#include "rect.h"
|
||||
#include <kandinsky/color.h>
|
||||
#include <kandinsky/rect.h>
|
||||
|
||||
typedef struct {
|
||||
struct {
|
||||
void (*pushRect)(KDRect rect, const KDColor * pixels);
|
||||
void (*pushRectUniform)(KDRect rect, KDColor color);
|
||||
void (*pullRect)(KDRect rect, KDColor * pixels);
|
||||
} io;
|
||||
KDPoint origin;
|
||||
KDRect clippingRect;
|
||||
} KDContext;
|
||||
class KDContext {
|
||||
public:
|
||||
void setOrigin(KDPoint origin);
|
||||
void setClippingRect(KDRect clippingRect);
|
||||
|
||||
extern KDContext * KDCurrentContext;
|
||||
// Pixel manipulation
|
||||
void setPixel(KDPoint p, KDColor c);
|
||||
KDColor getPixel(KDPoint p);
|
||||
|
||||
// Text
|
||||
void drawChar(char character, KDPoint p, uint8_t inverse);
|
||||
void drawString(const char * text, KDPoint p, uint8_t inverse);
|
||||
KDSize stringSize(const char * text);
|
||||
|
||||
// Line. Not anti-aliased.
|
||||
void drawLine(KDPoint p1, KDPoint p2, KDColor c);
|
||||
|
||||
// Rect
|
||||
void fillRect(KDRect rect, KDColor color);
|
||||
void fillRectWithPixels(KDRect rect, const KDColor * pixels, KDColor * workingBuffer);
|
||||
void fillRectWithMask(KDRect rect, KDColor color, const uint8_t * mask, KDColor * workingBuffer);
|
||||
void drawRect(KDRect rect, KDColor color);
|
||||
protected:
|
||||
KDContext(KDPoint origin, KDRect clippingRect);
|
||||
virtual void pushRect(KDRect, const KDColor * pixels) = 0;
|
||||
virtual void pushRectUniform(KDRect rect, KDColor color) = 0;
|
||||
virtual void pullRect(KDRect rect, KDColor * pixels) = 0;
|
||||
private:
|
||||
KDRect absoluteFillRect(KDRect rect);
|
||||
KDPoint m_origin;
|
||||
KDRect m_clippingRect;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
8
kandinsky/include/kandinsky/coordinate.h
Normal file
8
kandinsky/include/kandinsky/coordinate.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef KANDINSKY_COORDINATE_H
|
||||
#define KANDINSKY_COORDINATE_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef int16_t KDCoordinate;
|
||||
|
||||
#endif
|
||||
@@ -2,16 +2,19 @@
|
||||
#define KANDINSKY_FRAMEBUFFER_H
|
||||
|
||||
#include <kandinsky/color.h>
|
||||
#include <kandinsky/types.h>
|
||||
#include <kandinsky/rect.h>
|
||||
|
||||
typedef struct {
|
||||
KDColor * pixels;
|
||||
KDSize size;
|
||||
} KDFrameBuffer;
|
||||
|
||||
void KDFramePushRect(KDFrameBuffer * frameBuffer, KDRect rect, const KDColor * pixels);
|
||||
void KDFramePushRectUniform(KDFrameBuffer * frameBuffer, KDRect rect, KDColor color);
|
||||
void KDFramePullRect(KDFrameBuffer * frameBuffer, KDRect rect, KDColor * pixels);
|
||||
class KDFrameBuffer {
|
||||
public:
|
||||
KDFrameBuffer(KDColor * pixels, KDSize size);
|
||||
void pushRect(KDRect rect, const KDColor * pixels);
|
||||
void pushRectUniform(KDRect rect, KDColor color);
|
||||
void pullRect(KDRect rect, KDColor * pixels);
|
||||
KDRect bounds();
|
||||
private:
|
||||
KDColor * pixelAddress(KDPoint p) const;
|
||||
KDColor * m_pixels;
|
||||
KDSize m_size;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
18
kandinsky/include/kandinsky/framebuffer_context.h
Normal file
18
kandinsky/include/kandinsky/framebuffer_context.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef KANDINSKY_FRAMEBUFFER_CONTEXT_H
|
||||
#define KANDINSKY_FRAMEBUFFER_CONTEXT_H
|
||||
|
||||
#include <kandinsky/context.h>
|
||||
#include <kandinsky/framebuffer.h>
|
||||
|
||||
class KDFrameBufferContext : public KDContext {
|
||||
public:
|
||||
KDFrameBufferContext(KDFrameBuffer * frameBuffer);
|
||||
protected:
|
||||
void pushRect(KDRect, const KDColor * pixels) override;
|
||||
void pushRectUniform(KDRect rect, KDColor color) override;
|
||||
void pullRect(KDRect rect, KDColor * pixels) override;
|
||||
private:
|
||||
KDFrameBuffer * m_frameBuffer;
|
||||
};
|
||||
|
||||
#endif
|
||||
16
kandinsky/include/kandinsky/ion_context.h
Normal file
16
kandinsky/include/kandinsky/ion_context.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef KANDINSKY_ION_CONTEXT_H
|
||||
#define KANDINSKY_ION_CONTEXT_H
|
||||
|
||||
#include <kandinsky/context.h>
|
||||
|
||||
class KDIonContext : public KDContext {
|
||||
public:
|
||||
static KDIonContext * sharedContext();
|
||||
private:
|
||||
KDIonContext();
|
||||
void pushRect(KDRect rect, const KDColor * pixels) override;
|
||||
void pushRectUniform(KDRect rect, KDColor color) override;
|
||||
void pullRect(KDRect rect, KDColor * pixels) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,11 +0,0 @@
|
||||
#ifndef KANDINSKY_LINE_H
|
||||
#define KANDINSKY_LINE_H
|
||||
|
||||
#include <kandinsky/color.h>
|
||||
#include <kandinsky/types.h>
|
||||
|
||||
void KDDrawLine(KDPoint p1, KDPoint p2, KDColor c);
|
||||
|
||||
void KDDrawAntiAliasedLine(KDPoint p1, KDPoint p2, KDCoordinate width, KDColor frontColor, KDColor backColor);
|
||||
|
||||
#endif
|
||||
@@ -1,10 +0,0 @@
|
||||
#ifndef KANDINSKY_REFERENTIAL_H
|
||||
#define KANDINSKY_REFERENTIAL_H
|
||||
|
||||
#include <kandinsky/types.h>
|
||||
#include <kandinsky/color.h>
|
||||
|
||||
void KDSetPixel(KDPoint p, KDColor c);
|
||||
KDColor KDGetPixel(KDPoint p);
|
||||
|
||||
#endif
|
||||
20
kandinsky/include/kandinsky/point.h
Normal file
20
kandinsky/include/kandinsky/point.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef KANDINSKY_POINT_H
|
||||
#define KANDINSKY_POINT_H
|
||||
|
||||
#include <kandinsky/coordinate.h>
|
||||
|
||||
struct KDPoint {
|
||||
constexpr KDPoint(KDCoordinate x, KDCoordinate y) :
|
||||
m_x(x), m_y(y) {}
|
||||
KDCoordinate x() const;
|
||||
KDCoordinate y() const;
|
||||
KDPoint translatedBy(KDPoint other) const;
|
||||
KDPoint opposite() const;
|
||||
private:
|
||||
KDCoordinate m_x;
|
||||
KDCoordinate m_y;
|
||||
};
|
||||
|
||||
constexpr KDPoint KDPointZero = KDPoint(0,0);
|
||||
|
||||
#endif
|
||||
@@ -1,42 +1,43 @@
|
||||
#ifndef KANDINSKY_RECT_H
|
||||
#define KANDINSKY_RECT_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <kandinsky/color.h>
|
||||
#include <kandinsky/types.h>
|
||||
#include <kandinsky/coordinate.h>
|
||||
#include <kandinsky/point.h>
|
||||
#include <kandinsky/size.h>
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
struct {
|
||||
KDCoordinate x;
|
||||
KDCoordinate y;
|
||||
};
|
||||
KDPoint origin;
|
||||
};
|
||||
union {
|
||||
struct {
|
||||
KDCoordinate width;
|
||||
KDCoordinate height;
|
||||
};
|
||||
KDSize size;
|
||||
};
|
||||
} KDRect;
|
||||
class KDRect {
|
||||
public:
|
||||
constexpr KDRect(KDCoordinate x, KDCoordinate y,
|
||||
KDCoordinate width, KDCoordinate height) :
|
||||
m_x(x), m_y(y), m_width(width), m_height(height) {}
|
||||
|
||||
extern KDRect KDRectZero;
|
||||
KDRect(KDPoint p, KDSize s);
|
||||
KDRect(KDCoordinate x, KDCoordinate y, KDSize s);
|
||||
KDRect(KDPoint p, KDCoordinate width, KDCoordinate height);
|
||||
|
||||
bool KDRectIntersect(KDRect r1, KDRect r2);
|
||||
KDRect KDRectIntersection(KDRect r1, KDRect r2);
|
||||
KDCoordinate x() const;
|
||||
KDCoordinate y() const;
|
||||
KDPoint origin() const;
|
||||
KDCoordinate width() const;
|
||||
KDCoordinate height() const;
|
||||
KDSize size() const;
|
||||
KDCoordinate left() const;
|
||||
KDCoordinate right() const;
|
||||
KDCoordinate top() const;
|
||||
KDCoordinate bottom() const;
|
||||
|
||||
// Returns the smallest rectangle containing r1 and r2
|
||||
KDRect KDRectUnion(KDRect r1, KDRect r2);
|
||||
KDRect translatedBy(KDPoint p) const;
|
||||
KDRect movedTo(KDPoint p) const;
|
||||
bool intersects(const KDRect & other) const;
|
||||
KDRect intersectedWith(const KDRect & other) const;
|
||||
KDRect unionedWith(const KDRect & other) const; // Returns the smallest rectangle containing r1 and r2
|
||||
bool contains(KDPoint p) const;
|
||||
bool isEmpty() const;
|
||||
|
||||
bool KDRectContains(KDRect r, KDPoint p);
|
||||
KDRect KDRectTranslate(KDRect r, KDPoint p);
|
||||
private:
|
||||
KDCoordinate m_x, m_y, m_width, m_height;
|
||||
};
|
||||
|
||||
void KDFillRect(KDRect rect, KDColor color);
|
||||
void KDFillRectWithPixels(KDRect rect, const KDColor * pixels, KDColor * workingBuffer);
|
||||
void KDFillRectWithMask(KDRect rect, KDColor color, const uint8_t * mask, KDColor * workingBuffer);
|
||||
void KDDrawRect(KDRect rect, KDColor color);
|
||||
constexpr KDRect KDRectZero = KDRect(0,0,0,0);
|
||||
|
||||
#endif
|
||||
|
||||
18
kandinsky/include/kandinsky/size.h
Normal file
18
kandinsky/include/kandinsky/size.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef KANDINSKY_SIZE_H
|
||||
#define KANDINSKY_SIZE_H
|
||||
|
||||
#include <kandinsky/coordinate.h>
|
||||
|
||||
struct KDSize {
|
||||
constexpr KDSize(KDCoordinate width, KDCoordinate height) :
|
||||
m_width(width), m_height(height) {}
|
||||
KDCoordinate width() const;
|
||||
KDCoordinate height() const;
|
||||
private:
|
||||
KDCoordinate m_width;
|
||||
KDCoordinate m_height;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,10 +0,0 @@
|
||||
#ifndef KANDINSKY_TEXT_H
|
||||
#define KANDINSKY_TEXT_H
|
||||
|
||||
#include <kandinsky/types.h>
|
||||
|
||||
void KDDrawChar(char character, KDPoint p, uint8_t inverse);
|
||||
void KDDrawString(const char * text, KDPoint p, uint8_t inverse);
|
||||
KDSize KDStringSize(const char * text);
|
||||
|
||||
#endif
|
||||
@@ -1,34 +0,0 @@
|
||||
#ifndef KANDINSKY_TYPES_H
|
||||
#define KANDINSKY_TYPES_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef int16_t KDCoordinate;
|
||||
|
||||
typedef struct {
|
||||
KDCoordinate x;
|
||||
KDCoordinate y;
|
||||
} KDPoint;
|
||||
|
||||
extern KDPoint KDPointZero;
|
||||
|
||||
static inline KDPoint KDPointMake(KDCoordinate x, KDCoordinate y) {
|
||||
KDPoint p;
|
||||
p.x = x;
|
||||
p.y = y;
|
||||
return p;
|
||||
}
|
||||
|
||||
static inline KDPoint KDPointTranslate(KDPoint p1, KDPoint p2) {
|
||||
KDPoint p;
|
||||
p.x = p1.x+p2.x;
|
||||
p.y = p1.y+p2.y;
|
||||
return p;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
KDCoordinate width;
|
||||
KDCoordinate height;
|
||||
} KDSize;
|
||||
|
||||
#endif
|
||||
@@ -1,11 +0,0 @@
|
||||
#include <kandinsky/color.h>
|
||||
|
||||
#define KDAlphaBlend(c1,c2,a) ((uint8_t)((((uint16_t)c1*(0xFF-a))+((uint16_t)c2*a))/0xFF))
|
||||
|
||||
KDColor KDColorBlend(KDColor a, KDColor b, uint8_t alpha) {
|
||||
return KDColorRGB(
|
||||
KDAlphaBlend(KDColorRedComponent(a), KDColorRedComponent(b), alpha),
|
||||
KDAlphaBlend(KDColorGreenComponent(a), KDColorGreenComponent(b), alpha),
|
||||
KDAlphaBlend(KDColorBlueComponent(a), KDColorBlueComponent(b), alpha)
|
||||
);
|
||||
}
|
||||
20
kandinsky/src/color.cpp
Normal file
20
kandinsky/src/color.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#include <kandinsky/color.h>
|
||||
|
||||
KDColor KDColor::blend(KDColor other, uint8_t alpha) {
|
||||
return other; // FIXME
|
||||
}
|
||||
|
||||
uint8_t KDColor::red() {
|
||||
uint8_t r5 = (m_value>>11)&0x1F;
|
||||
return r5 << 3;
|
||||
}
|
||||
|
||||
uint8_t KDColor::green() {
|
||||
uint8_t g6 = (m_value>>5)&0x3F;
|
||||
return g6 << 2;
|
||||
}
|
||||
|
||||
uint8_t KDColor::blue() {
|
||||
uint8_t b5 = m_value&0x1F;
|
||||
return b5 << 3;
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
#include <kandinsky/context.h>
|
||||
#include <ion.h>
|
||||
|
||||
KDContext KDIonContext = {
|
||||
.io = {
|
||||
.pushRect = &ion_screen_push_rect,
|
||||
.pushRectUniform = &ion_screen_push_rect_uniform,
|
||||
.pullRect = &ion_screen_pull_rect
|
||||
},
|
||||
.origin = {
|
||||
.x = 0,
|
||||
.y = 0
|
||||
},
|
||||
.clippingRect = {
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.width = ION_SCREEN_WIDTH,
|
||||
.height = ION_SCREEN_HEIGHT
|
||||
}
|
||||
};
|
||||
|
||||
KDContext * KDCurrentContext = &KDIonContext;
|
||||
16
kandinsky/src/context.cpp
Normal file
16
kandinsky/src/context.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
#include <kandinsky/context.h>
|
||||
#include <assert.h>
|
||||
|
||||
KDContext::KDContext(KDPoint origin, KDRect clippingRect) :
|
||||
m_origin(origin),
|
||||
m_clippingRect(clippingRect)
|
||||
{
|
||||
}
|
||||
|
||||
void KDContext::setOrigin(KDPoint origin) {
|
||||
m_origin = origin;
|
||||
}
|
||||
|
||||
void KDContext::setClippingRect(KDRect clippingRect) {
|
||||
m_clippingRect = clippingRect;
|
||||
}
|
||||
59
kandinsky/src/context_line.cpp
Normal file
59
kandinsky/src/context_line.cpp
Normal file
@@ -0,0 +1,59 @@
|
||||
#include <kandinsky/context.h>
|
||||
#include <assert.h>
|
||||
|
||||
void KDContext::drawLine(KDPoint p1, KDPoint p2, KDColor c) {
|
||||
// Find the largest gap
|
||||
KDPoint left = KDPointZero, right = KDPointZero;
|
||||
if (p2.x() > p1.x()) {
|
||||
left = p1;
|
||||
right = p2;
|
||||
} else {
|
||||
left = p2;
|
||||
right = p1;
|
||||
}
|
||||
KDPoint top = KDPointZero, bottom = KDPointZero;
|
||||
if (p2.y() > p1.y()) {
|
||||
top = p1;
|
||||
bottom = p2;
|
||||
} else {
|
||||
top = p2;
|
||||
bottom = p1;
|
||||
}
|
||||
assert(right.x() >= left.x());
|
||||
assert(bottom.y() >= top.y());
|
||||
|
||||
KDCoordinate deltaX = 2*(right.x() - left.x());
|
||||
KDCoordinate deltaY = 2*(bottom.y() - top.y());
|
||||
|
||||
KDPoint p = KDPointZero, alwaysTranslate = KDPointZero, conditionalTranslate = KDPointZero;
|
||||
KDCoordinate scanLength, error, minusError, plusError;
|
||||
|
||||
if (deltaX >= deltaY) {
|
||||
p = left;
|
||||
scanLength = right.x() - left.x();
|
||||
error = right.x() - left.x();
|
||||
minusError = deltaY;
|
||||
plusError = deltaX;
|
||||
alwaysTranslate = KDPoint(1,0);
|
||||
conditionalTranslate = KDPoint(0, (right.y() >= left.y() ? 1 : -1));
|
||||
} else {
|
||||
p = top;
|
||||
scanLength = bottom.y() - top.y();
|
||||
error = bottom.y() - top.y();
|
||||
minusError = deltaX;
|
||||
plusError = deltaY;
|
||||
alwaysTranslate = KDPoint(0,1);
|
||||
conditionalTranslate = KDPoint((bottom.x() >= top.x() ? 1 : -1), 0);
|
||||
}
|
||||
|
||||
KDCoordinate scanCounter = 0;
|
||||
while (scanCounter++ < scanLength) {
|
||||
setPixel(p, c);
|
||||
p = p.translatedBy(alwaysTranslate);
|
||||
error = error - minusError;
|
||||
if (error <= 0) {
|
||||
p = p.translatedBy(conditionalTranslate);
|
||||
error = error + plusError;
|
||||
}
|
||||
}
|
||||
}
|
||||
18
kandinsky/src/context_pixel.cpp
Normal file
18
kandinsky/src/context_pixel.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#include <kandinsky/context.h>
|
||||
|
||||
void KDContext::setPixel(KDPoint p, KDColor c) {
|
||||
KDPoint absolutePoint = p.translatedBy(m_origin);
|
||||
if (m_clippingRect.contains(absolutePoint)) {
|
||||
pushRect(KDRect(absolutePoint, 1, 1), &c);
|
||||
}
|
||||
}
|
||||
|
||||
KDColor KDContext::getPixel(KDPoint p) {
|
||||
KDPoint absolutePoint = p.translatedBy(m_origin);
|
||||
if (m_clippingRect.contains(absolutePoint)) {
|
||||
KDColor result = KDColorBlack;
|
||||
pullRect(KDRect(absolutePoint, 1, 1), &result);
|
||||
return result;
|
||||
}
|
||||
return KDColorBlack;
|
||||
}
|
||||
84
kandinsky/src/context_rect.cpp
Normal file
84
kandinsky/src/context_rect.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
/* At this point we need the working buffer */
|
||||
assert(workingBuffer != nullptr);
|
||||
for (KDCoordinate j=0; j<absoluteRect.height(); j++) {
|
||||
for (KDCoordinate i=0; i<absoluteRect.width(); i++) {
|
||||
workingBuffer[i+absoluteRect.width()*j] = pixels[i+rect.width()*j];
|
||||
}
|
||||
}
|
||||
pushRect(absoluteRect, workingBuffer);
|
||||
}
|
||||
|
||||
// Mask's size must be rect.size
|
||||
// WorkingBuffer, same deal
|
||||
void KDContext::fillRectWithMask(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);
|
||||
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 + rect.width()*j;
|
||||
*currentPixelAdress = currentPixelAdress->blend(color, *currentMaskAddress);
|
||||
//*currentPixelAdress = KDColorBlend(*currentPixelAdress, color, *currentMaskAddress);
|
||||
}
|
||||
}
|
||||
pushRect(absoluteRect, workingBuffer);
|
||||
}
|
||||
|
||||
void KDContext::drawRect(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));
|
||||
}
|
||||
}
|
||||
|
||||
29
kandinsky/src/context_text.cpp
Normal file
29
kandinsky/src/context_text.cpp
Normal file
@@ -0,0 +1,29 @@
|
||||
#include <kandinsky/context.h>
|
||||
#include <string.h>
|
||||
#include "font.h"
|
||||
|
||||
void KDContext::drawChar(char character, KDPoint p, uint8_t inverse) {
|
||||
for (int j=0; j<BITMAP_FONT_CHARACTER_HEIGHT;j++) {
|
||||
for (int i=0; i<BITMAP_FONT_CHARACTER_WIDTH;i++) {
|
||||
uint8_t intensity = inverse ?
|
||||
bitmapFont[character-BITMAP_FONT_FIRST_CHARACTER][j][i] :
|
||||
(0xFF-bitmapFont[character-BITMAP_FONT_FIRST_CHARACTER][j][i]);
|
||||
KDPoint offset = KDPoint(i,j);
|
||||
setPixel(p.translatedBy(offset), intensity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KDContext::drawString(const char * text, KDPoint p, uint8_t inverse) {
|
||||
KDPoint position = p;
|
||||
KDPoint characterSize(BITMAP_FONT_CHARACTER_WIDTH, 0);
|
||||
while(*text != 0) {
|
||||
drawChar(*text, position, inverse);
|
||||
text++;
|
||||
position = position.translatedBy(characterSize);
|
||||
}
|
||||
}
|
||||
|
||||
KDSize KDContext::stringSize(const char * text) {
|
||||
return KDSize(BITMAP_FONT_CHARACTER_WIDTH*strlen(text), BITMAP_FONT_CHARACTER_HEIGHT);
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
#include <kandinsky/framebuffer.h>
|
||||
#include <string.h>
|
||||
|
||||
static inline KDColor * frameBufferPixelAddress(KDFrameBuffer * frameBuffer, KDCoordinate x, KDCoordinate y) {
|
||||
return frameBuffer->pixels + x + y*frameBuffer->size.width;
|
||||
}
|
||||
|
||||
void KDFramePushRect(KDFrameBuffer * frameBuffer, KDRect rect, const KDColor * pixels) {
|
||||
const KDColor * line = pixels;
|
||||
for (int j=0; j<rect.height; j++) {
|
||||
memcpy(frameBufferPixelAddress(frameBuffer, rect.x, rect.y+j),
|
||||
line,
|
||||
rect.width*sizeof(KDColor));
|
||||
line += rect.width;
|
||||
}
|
||||
}
|
||||
|
||||
void KDFramePushRectUniform(KDFrameBuffer * frameBuffer, KDRect rect, KDColor color) {
|
||||
for (int j=0; j<rect.height; j++) {
|
||||
for (int i=0; i<rect.width; i++) {
|
||||
*frameBufferPixelAddress(frameBuffer, rect.x+i, rect.y+j) = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KDFramePullRect(KDFrameBuffer * frameBuffer, KDRect rect, KDColor * pixels) {
|
||||
KDColor * line = pixels;
|
||||
for (int j=0; j<rect.height; j++) {
|
||||
memcpy(line,
|
||||
frameBufferPixelAddress(frameBuffer, rect.x, rect.y+j),
|
||||
rect.width*sizeof(KDColor));
|
||||
line += rect.width;
|
||||
}
|
||||
}
|
||||
46
kandinsky/src/framebuffer.cpp
Normal file
46
kandinsky/src/framebuffer.cpp
Normal file
@@ -0,0 +1,46 @@
|
||||
#include <kandinsky/framebuffer.h>
|
||||
#include <string.h>
|
||||
|
||||
KDFrameBuffer::KDFrameBuffer(KDColor * pixels, KDSize size) :
|
||||
m_pixels(pixels),
|
||||
m_size(size)
|
||||
{
|
||||
}
|
||||
|
||||
KDRect KDFrameBuffer::bounds() {
|
||||
return KDRect(KDPointZero, m_size);
|
||||
}
|
||||
|
||||
KDColor * KDFrameBuffer::pixelAddress(KDPoint p) const {
|
||||
return m_pixels + p.x() + p.y()*m_size.width();
|
||||
}
|
||||
|
||||
void KDFrameBuffer::pushRect(KDRect rect, const KDColor * pixels) {
|
||||
const KDColor * line = pixels;
|
||||
for (KDCoordinate j=0; j<rect.height(); j++) {
|
||||
KDPoint lineOffset = KDPoint(0, j);
|
||||
memcpy(pixelAddress(rect.origin().translatedBy(lineOffset)),
|
||||
line,
|
||||
rect.width()*sizeof(KDColor));
|
||||
line += rect.width();
|
||||
}
|
||||
}
|
||||
|
||||
void KDFrameBuffer::pushRectUniform(KDRect rect, KDColor color) {
|
||||
for (KDCoordinate i=0; i<rect.width(); i++) {
|
||||
for (KDCoordinate j=0; j<rect.height(); j++) {
|
||||
*pixelAddress(rect.origin().translatedBy(KDPoint(i,j))) = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KDFrameBuffer::pullRect(KDRect rect, KDColor * pixels) {
|
||||
KDColor * line = pixels;
|
||||
for (KDCoordinate j=0; j<rect.height(); j++) {
|
||||
KDPoint lineOffset = KDPoint(0, j);
|
||||
memcpy(line,
|
||||
pixelAddress(rect.origin().translatedBy(lineOffset)),
|
||||
rect.width()*sizeof(KDColor));
|
||||
line += rect.width();
|
||||
}
|
||||
}
|
||||
19
kandinsky/src/framebuffer_context.cpp
Normal file
19
kandinsky/src/framebuffer_context.cpp
Normal file
@@ -0,0 +1,19 @@
|
||||
#include <kandinsky/framebuffer_context.h>
|
||||
|
||||
KDFrameBufferContext::KDFrameBufferContext(KDFrameBuffer * frameBuffer) :
|
||||
KDContext(KDPointZero, frameBuffer->bounds()),
|
||||
m_frameBuffer(frameBuffer)
|
||||
{
|
||||
}
|
||||
|
||||
void KDFrameBufferContext::pushRect(KDRect rect, const KDColor * pixels) {
|
||||
m_frameBuffer->pushRect(rect, pixels);
|
||||
}
|
||||
|
||||
void KDFrameBufferContext::pushRectUniform(KDRect rect, KDColor color) {
|
||||
m_frameBuffer->pushRectUniform(rect, color);
|
||||
}
|
||||
|
||||
void KDFrameBufferContext::pullRect(KDRect rect, KDColor * pixels) {
|
||||
m_frameBuffer->pullRect(rect, pixels);
|
||||
}
|
||||
27
kandinsky/src/ion_context.cpp
Normal file
27
kandinsky/src/ion_context.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
#include <kandinsky/ion_context.h>
|
||||
extern "C" {
|
||||
#include <ion.h>
|
||||
}
|
||||
|
||||
KDIonContext * KDIonContext::sharedContext() {
|
||||
static KDIonContext context;
|
||||
return &context;
|
||||
}
|
||||
|
||||
KDIonContext::KDIonContext() :
|
||||
KDContext(KDPointZero,
|
||||
KDRect(0, 0, ION_SCREEN_WIDTH, ION_SCREEN_HEIGHT))
|
||||
{
|
||||
}
|
||||
|
||||
void KDIonContext::pushRect(KDRect rect, const KDColor * pixels) {
|
||||
ion_screen_push_rect(rect.x(), rect.y(), rect.width(), rect.height(), (const ion_color_t *)pixels);
|
||||
}
|
||||
|
||||
void KDIonContext::pushRectUniform(KDRect rect, KDColor color) {
|
||||
ion_screen_push_rect_uniform(rect.x(), rect.y(), rect.width(), rect.height(), color);
|
||||
}
|
||||
|
||||
void KDIonContext::pullRect(KDRect rect, KDColor * pixels) {
|
||||
ion_screen_pull_rect(rect.x(), rect.y(), rect.width(), rect.height(), (ion_color_t *)pixels);
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
#include <kandinsky/pixel.h>
|
||||
#include <kandinsky/rect.h>
|
||||
#include <kandinsky/context.h>
|
||||
#include <assert.h>
|
||||
#include <ion.h>
|
||||
|
||||
void KDSetPixel(KDPoint p, KDColor c) {
|
||||
KDPoint absolutePoint = KDPointTranslate(p, KDCurrentContext->origin);
|
||||
if (KDRectContains(KDCurrentContext->clippingRect, absolutePoint)) {
|
||||
KDCurrentContext->io.pushRect((KDRect){.origin = absolutePoint, .width = 1, .height = 1}, &c);
|
||||
}
|
||||
}
|
||||
|
||||
KDColor KDGetPixel(KDPoint p) {
|
||||
KDPoint absolutePoint = KDPointTranslate(p, KDCurrentContext->origin);
|
||||
if (KDRectContains(KDCurrentContext->clippingRect, absolutePoint)) {
|
||||
KDColor result;
|
||||
KDCurrentContext->io.pullRect((KDRect){.origin = absolutePoint, .width = 1, .height = 1}, &result);
|
||||
return result;
|
||||
}
|
||||
return KDColorBlack;
|
||||
}
|
||||
/*
|
||||
void KDSetAbsolutePixelDirect(KDPoint p, KDColor c) {
|
||||
KDCurrentContext->io.setWorkingArea((KDRect){.origin = p, .width = 1, .height = 1});
|
||||
KDCurrentContext->io.pushPixels(&c, 1);
|
||||
}
|
||||
|
||||
KDColor KDGetAbsolutePixelDirect(KDPoint p) {
|
||||
KDColor result;
|
||||
KDCurrentContext->io.setWorkingArea((KDRect){.origin = p, .width = 1, .height = 1});
|
||||
KDCurrentContext->io.pullPixels(&result, 1);
|
||||
return result;
|
||||
}
|
||||
*/
|
||||
12
kandinsky/src/point.cpp
Normal file
12
kandinsky/src/point.cpp
Normal file
@@ -0,0 +1,12 @@
|
||||
#include <kandinsky/point.h>
|
||||
|
||||
KDCoordinate KDPoint::x() const { return m_x; }
|
||||
KDCoordinate KDPoint::y() const { return m_y; }
|
||||
|
||||
KDPoint KDPoint::translatedBy(KDPoint other) const {
|
||||
return KDPoint(m_x+other.x(), m_y+other.y());
|
||||
}
|
||||
|
||||
KDPoint KDPoint::opposite() const {
|
||||
return KDPoint(-m_x, -m_y);
|
||||
}
|
||||
@@ -1,271 +0,0 @@
|
||||
#include <kandinsky/rect.h>
|
||||
#include <kandinsky/pixel.h>
|
||||
#include <kandinsky/context.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
KDRect KDRectZero = {.x = 0, .y = 0, .width = 0, .height = 0};
|
||||
|
||||
static inline KDCoordinate left(KDRect r) { return r.x; }
|
||||
static inline KDCoordinate right(KDRect r) { return r.x+r.width; }
|
||||
static inline KDCoordinate top(KDRect r) { return r.y; }
|
||||
static inline KDCoordinate bottom(KDRect r) { return r.y+r.height; }
|
||||
static inline KDCoordinate min(KDCoordinate x, KDCoordinate y) { return (x<y ? x : y); }
|
||||
static inline KDCoordinate max(KDCoordinate x, KDCoordinate y) { return (x>y ? x : y); }
|
||||
|
||||
bool KDRectIntersect(KDRect r1, KDRect r2) {
|
||||
return !(right(r2) < left(r1)
|
||||
||
|
||||
left(r2) > right(r1)
|
||||
||
|
||||
top(r2) > bottom(r1)
|
||||
||
|
||||
bottom(r2) < top(r1)
|
||||
);
|
||||
}
|
||||
|
||||
KDRect KDRectIntersection(KDRect r1, KDRect r2) {
|
||||
if (!KDRectIntersect(r1, r2)) {
|
||||
return KDRectZero;
|
||||
}
|
||||
|
||||
KDCoordinate intersectionLeft = max(left(r1), left(r2));
|
||||
KDCoordinate intersectionRight = min(right(r1), right(r2));
|
||||
KDCoordinate intersectionTop = max(top(r1), top(r2));
|
||||
KDCoordinate intersectionBottom = min(bottom(r1), bottom(r2));
|
||||
|
||||
KDRect intersection;
|
||||
intersection.x = intersectionLeft;
|
||||
intersection.width = intersectionRight-intersectionLeft;
|
||||
intersection.y = intersectionTop;
|
||||
intersection.height = intersectionBottom-intersectionTop;
|
||||
return intersection;
|
||||
}
|
||||
|
||||
static void KDRectComputeUnionBound(KDCoordinate size1, KDCoordinate size2,
|
||||
KDCoordinate * outputMin, KDCoordinate * outputMax,
|
||||
KDCoordinate min1, KDCoordinate min2,
|
||||
KDCoordinate max1, KDCoordinate max2)
|
||||
{
|
||||
if (size1 != 0) {
|
||||
if (size2 != 0) {
|
||||
*outputMin = min(min1, min2);
|
||||
*outputMax = max(max1, max2);
|
||||
} else {
|
||||
*outputMin = min1;
|
||||
*outputMax = max1;
|
||||
}
|
||||
} else {
|
||||
if (size2 != 0) {
|
||||
*outputMin = min2;
|
||||
*outputMax = max2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
KDRect KDRectUnion(KDRect r1, KDRect r2) {
|
||||
/* We should ignore coordinate whose size is zero
|
||||
* For example, if r1.height is zero, just ignore r1.y and r1.height. */
|
||||
|
||||
KDCoordinate resultLeft = 0;
|
||||
KDCoordinate resultTop = 0;
|
||||
KDCoordinate resultRight = 0;
|
||||
KDCoordinate resultBottom = 0;
|
||||
|
||||
KDRectComputeUnionBound(r1.width, r2.width,
|
||||
&resultLeft, &resultRight,
|
||||
left(r1), left(r2),
|
||||
right(r1), right(r2));
|
||||
|
||||
KDRectComputeUnionBound(r1.height, r2.height,
|
||||
&resultTop, &resultBottom,
|
||||
top(r1), top(r2),
|
||||
bottom(r1), bottom(r2));
|
||||
|
||||
return (KDRect){
|
||||
.x = resultLeft,
|
||||
.y = resultTop,
|
||||
.width = resultRight-resultLeft,
|
||||
.height = resultBottom-resultTop
|
||||
};
|
||||
}
|
||||
|
||||
bool KDRectContains(KDRect r, KDPoint p) {
|
||||
return (p.x >= r.x && p.x < (r.x+r.width) && p.y >= r.y && p.y < (r.y+r.height));
|
||||
}
|
||||
|
||||
KDRect KDRectTranslate(KDRect r, KDPoint p) {
|
||||
return (KDRect){
|
||||
.origin = KDPointTranslate(r.origin, p),
|
||||
.size = r.size
|
||||
};
|
||||
}
|
||||
|
||||
KDRect absoluteFillRect(KDRect rect) {
|
||||
KDRect absolutRect = rect;
|
||||
absolutRect.origin = KDPointTranslate(absolutRect.origin, KDCurrentContext->origin);
|
||||
|
||||
KDRect rectToBeFilled = KDRectIntersection(absolutRect, KDCurrentContext->clippingRect);
|
||||
return rectToBeFilled;
|
||||
}
|
||||
|
||||
void KDFillRect(KDRect rect, KDColor color) {
|
||||
KDRect absoluteRect = absoluteFillRect(rect);
|
||||
if (absoluteRect.width > 0 && absoluteRect.height > 0) {
|
||||
KDCurrentContext->io.pushRectUniform(absoluteRect, color);
|
||||
}
|
||||
}
|
||||
|
||||
/* Note: we support the case where workingBuffer IS equal to pixels */
|
||||
void KDFillRectWithPixels(KDRect rect, const KDColor * pixels, KDColor * workingBuffer) {
|
||||
KDRect absoluteRect = absoluteFillRect(rect);
|
||||
|
||||
if (absoluteRect.width == 0 || absoluteRect.height == 0) {
|
||||
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) {
|
||||
KDCurrentContext->io.pushRect(absoluteRect, pixels);
|
||||
return;
|
||||
}
|
||||
|
||||
/* At this point we need the working buffer */
|
||||
assert(workingBuffer != NULL);
|
||||
for (KDCoordinate j=0; j<absoluteRect.height; j++) {
|
||||
for (KDCoordinate i=0; i<absoluteRect.width; i++) {
|
||||
workingBuffer[i+absoluteRect.width*j] = pixels[i+rect.width*j];
|
||||
}
|
||||
}
|
||||
KDCurrentContext->io.pushRect(absoluteRect, workingBuffer);
|
||||
}
|
||||
|
||||
// Mask's size must be rect.size
|
||||
// WorkingBuffer, same deal
|
||||
void KDFillRectWithMask(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. */
|
||||
|
||||
KDCurrentContext->io.pullRect(absoluteRect, workingBuffer);
|
||||
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 + rect.width*j;
|
||||
*currentPixelAdress = KDColorBlend(*currentPixelAdress, color, *currentMaskAddress);
|
||||
}
|
||||
}
|
||||
KDCurrentContext->io.pushRect(absoluteRect, workingBuffer);
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
/* Takes an absolute rect and pushes the pixels */
|
||||
/* Does the pattern-to-continuous-memory conversion */
|
||||
void pushRect(KDRect rect, const KDColor * pattern, KDSize patternSize) {
|
||||
KDCurrentContext->io.setWorkingArea(rect);
|
||||
//#define ION_DEVICE_FILL_RECT_FAST_PATH 1
|
||||
#if ION_DEVICE_FILL_RECT_FAST_PATH
|
||||
/* If the pattern width matches the target rect width, we can easily push
|
||||
* mutliple lines at once since those will be contiguous in memory. */
|
||||
if (patternSize.width == rect.width) {
|
||||
size_t remainingPixelCount = rect.width*rect.height;
|
||||
size_t patternPixelCount = patternSize.width*patternSize.height;
|
||||
while (remainingPixelCount > 0) {
|
||||
int32_t blockSize = remainingPixelCount < patternPixelCount ? remainingPixelCount : patternPixelCount;
|
||||
KDCurrentContext->io.pushPixels(pattern, blockSize);
|
||||
remainingPixelCount -= blockSize;
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
uint16_t remainingHeight = rect.height;
|
||||
uint16_t patternLine = 0;
|
||||
while (remainingHeight-- > 0) {
|
||||
uint16_t remainingWidth = rect.width;
|
||||
while (remainingWidth > 0) {
|
||||
int32_t blockSize = remainingWidth < patternSize.width ? remainingWidth : patternSize.width;
|
||||
KDCurrentContext->io.pushPixels(pattern + patternLine*patternSize.width, blockSize);
|
||||
remainingWidth -= blockSize;
|
||||
}
|
||||
if (++patternLine >= patternSize.height) {
|
||||
patternLine = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KDBlitRect(KDRect rect, const KDColor * pattern, KDSize patternSize, const uint8_t * mask, KDSize maskSize) {
|
||||
assert(pattern != NULL && patternSize.width > 0 && patternSize.height > 0);
|
||||
KDRect absolutRect = rect;
|
||||
absolutRect.origin = KDPointTranslate(absolutRect.origin, KDCurrentContext->origin);
|
||||
|
||||
KDRect rectToBeFilled = KDRectIntersection(absolutRect, KDCurrentContext->clippingRect);
|
||||
|
||||
bool useBlending = (mask != NULL && maskSize.width > 0 && maskSize.height > 0);
|
||||
|
||||
if (!useBlending) {
|
||||
pushRect(rectToBeFilled, pattern, patternSize);
|
||||
return;
|
||||
}
|
||||
|
||||
assert(KDCurrentContext->io.pullPixels != NULL);
|
||||
|
||||
KDCoordinate patternX = 0, patternY = 0, maskX = 0, maskY = 0;
|
||||
for (KDCoordinate j=0; j<rectToBeFilled.height; j++) {
|
||||
for (KDCoordinate i=0; i<rectToBeFilled.width; i++) {
|
||||
KDColor foregroundColor = pattern[patternX+patternSize.width*patternY];
|
||||
KDPoint p = {
|
||||
.x = rectToBeFilled.x + i,
|
||||
.y = rectToBeFilled.y + j
|
||||
};
|
||||
KDColor backgroundColor = KDGetAbsolutePixelDirect(p);
|
||||
uint8_t alpha = mask[maskX+maskSize.width*maskY];
|
||||
KDColor newColor = KDColorBlend(backgroundColor, foregroundColor, alpha);
|
||||
KDSetAbsolutePixelDirect(p, newColor);
|
||||
if (++patternX >= patternSize.width) {
|
||||
patternX = 0;
|
||||
}
|
||||
if (++maskX >= maskSize.width) {
|
||||
maskX = 0;
|
||||
}
|
||||
}
|
||||
if (++patternY >= patternSize.height) {
|
||||
patternY = 0;
|
||||
}
|
||||
if (++maskY >= maskSize.height) {
|
||||
maskY = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void KDDrawRect(KDRect rect, KDColor color) {
|
||||
KDPoint p1, p2;
|
||||
p1.x = rect.x;
|
||||
p1.y = rect.y;
|
||||
p2.x = rect.x;
|
||||
p2.y = rect.y + rect.height;
|
||||
for (int i = 0; i<rect.width; i++) {
|
||||
KDSetPixel(p1, color);
|
||||
KDSetPixel(p2, color);
|
||||
p1.x++;
|
||||
p2.x++;
|
||||
}
|
||||
p1.x = rect.x;
|
||||
p1.y = rect.y;
|
||||
p2.x = rect.x + rect.width;
|
||||
p2.y = rect.y;
|
||||
for (int i = 0; i<rect.height; i++) {
|
||||
KDSetPixel(p1, color);
|
||||
KDSetPixel(p2, color);
|
||||
p1.y++;
|
||||
p2.y++;
|
||||
}
|
||||
}
|
||||
124
kandinsky/src/rect.cpp
Normal file
124
kandinsky/src/rect.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
#include <kandinsky/rect.h>
|
||||
|
||||
KDRect::KDRect(KDPoint p, KDSize s) :
|
||||
m_x(p.x()), m_y(p.y()),
|
||||
m_width(s.width()), m_height(s.height())
|
||||
{
|
||||
}
|
||||
|
||||
KDRect::KDRect(KDCoordinate x, KDCoordinate y, KDSize s) :
|
||||
m_x(x), m_y(y),
|
||||
m_width(s.width()), m_height(s.height())
|
||||
{
|
||||
}
|
||||
|
||||
KDRect::KDRect(KDPoint p, KDCoordinate width, KDCoordinate height) :
|
||||
m_x(p.x()), m_y(p.y()),
|
||||
m_width(width), m_height(height)
|
||||
{
|
||||
}
|
||||
|
||||
KDCoordinate KDRect::x() const { return m_x; }
|
||||
KDCoordinate KDRect::y() const { return m_y; }
|
||||
KDPoint KDRect::origin() const { return KDPoint(m_x, m_y); }
|
||||
KDCoordinate KDRect::width() const { return m_width; }
|
||||
KDCoordinate KDRect::height() const { return m_height; }
|
||||
KDSize KDRect::size() const { return KDSize(m_width, m_height); }
|
||||
|
||||
KDCoordinate KDRect::top() const { return m_y; }
|
||||
KDCoordinate KDRect::right() const { return m_x+m_width; }
|
||||
KDCoordinate KDRect::bottom() const { return m_y+m_height; }
|
||||
KDCoordinate KDRect::left() const { return m_x; }
|
||||
|
||||
static inline KDCoordinate min(KDCoordinate x, KDCoordinate y) { return (x<y ? x : y); }
|
||||
static inline KDCoordinate max(KDCoordinate x, KDCoordinate y) { return (x>y ? x : y); }
|
||||
|
||||
bool KDRect::intersects(const KDRect & other) const {
|
||||
return (
|
||||
other.right() >= left() &&
|
||||
other.left() <= right() &&
|
||||
other.top() <= bottom() &&
|
||||
other.bottom() >= top()
|
||||
);
|
||||
}
|
||||
|
||||
KDRect KDRect::intersectedWith(const KDRect & other) const {
|
||||
if (!intersects(other)) {
|
||||
return KDRectZero;
|
||||
}
|
||||
|
||||
KDCoordinate intersectionLeft = max(left(), other.left());
|
||||
KDCoordinate intersectionRight = min(right(), other.right());
|
||||
KDCoordinate intersectionTop = max(top(), other.top());
|
||||
KDCoordinate intersectionBottom = min(bottom(), other.bottom());
|
||||
|
||||
return KDRect(
|
||||
intersectionLeft,
|
||||
intersectionTop,
|
||||
intersectionRight-intersectionLeft,
|
||||
intersectionBottom-intersectionTop);
|
||||
}
|
||||
|
||||
void computeUnionBound(KDCoordinate size1, KDCoordinate size2,
|
||||
KDCoordinate * outputMin, KDCoordinate * outputMax,
|
||||
KDCoordinate min1, KDCoordinate min2,
|
||||
KDCoordinate max1, KDCoordinate max2)
|
||||
{
|
||||
if (size1 != 0) {
|
||||
if (size2 != 0) {
|
||||
*outputMin = min(min1, min2);
|
||||
*outputMax = max(max1, max2);
|
||||
} else {
|
||||
*outputMin = min1;
|
||||
*outputMax = max1;
|
||||
}
|
||||
} else {
|
||||
if (size2 != 0) {
|
||||
*outputMin = min2;
|
||||
*outputMax = max2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
KDRect KDRect::unionedWith(const KDRect & other) const {
|
||||
/* We should ignore coordinate whose size is zero
|
||||
* For example, if r1.height is zero, just ignore r1.y and r1.height. */
|
||||
|
||||
KDCoordinate resultLeft = 0;
|
||||
KDCoordinate resultTop = 0;
|
||||
KDCoordinate resultRight = 0;
|
||||
KDCoordinate resultBottom = 0;
|
||||
|
||||
computeUnionBound(width(), other.width(),
|
||||
&resultLeft, &resultRight,
|
||||
left(), other.left(),
|
||||
right(), other.right());
|
||||
|
||||
computeUnionBound(height(), other.height(),
|
||||
&resultTop, &resultBottom,
|
||||
top(), other.top(),
|
||||
bottom(), other.bottom());
|
||||
|
||||
return KDRect(
|
||||
resultLeft,
|
||||
resultTop,
|
||||
resultRight-resultLeft,
|
||||
resultBottom-resultTop
|
||||
);
|
||||
}
|
||||
|
||||
bool KDRect::contains(KDPoint p) const {
|
||||
return (p.x() >= x() && p.x() < right() && p.y() >= y() && p.y() < bottom());
|
||||
}
|
||||
|
||||
KDRect KDRect::translatedBy(KDPoint p) const {
|
||||
return KDRect(x() + p.x(), y() + p.y(), width(), height());
|
||||
}
|
||||
|
||||
KDRect KDRect::movedTo(KDPoint p) const {
|
||||
return KDRect(p.x(), p.y(), width(), height());
|
||||
}
|
||||
|
||||
bool KDRect::isEmpty() const {
|
||||
return (width() == 0 || height() == 0);
|
||||
}
|
||||
4
kandinsky/src/size.cpp
Normal file
4
kandinsky/src/size.cpp
Normal file
@@ -0,0 +1,4 @@
|
||||
#include <kandinsky/size.h>
|
||||
|
||||
KDCoordinate KDSize::width() const { return m_width; }
|
||||
KDCoordinate KDSize::height() const { return m_height; }
|
||||
@@ -1,3 +0,0 @@
|
||||
#include <kandinsky/types.h>
|
||||
|
||||
KDPoint KDPointZero = {.x = 0, .y = 0};
|
||||
@@ -3,15 +3,17 @@
|
||||
#include <assert.h>
|
||||
|
||||
QUIZ_CASE(kandinsky_color_rgb) {
|
||||
assert(KDColorRGB(0xFF, 0, 0) == 0xF800);
|
||||
assert(KDColorRGB(0, 0xFF, 0) == 0x07E0);
|
||||
assert(KDColorRGB(0, 0, 0xFF) == 0x1F);
|
||||
assert(sizeof(KDColor) == 2); // We really want KDColor to be packed
|
||||
|
||||
assert(KDColor(0xFF0000) == 0xF800);
|
||||
assert(KDColor(0x00FF00) == 0x07E0);
|
||||
assert(KDColor(0x0000FF) == 0x1F);
|
||||
/* R = 0x12 = 0b 0001 0010. 5 most important bits are 00010.
|
||||
* G = 0x34 = 0b 0011 0100. 6 most important bits are 001101.
|
||||
* B = 0x56 = 0b 0101 0110. 5 most important bits are 01010.
|
||||
* KDColor = 0b 00010 001101 01010
|
||||
* = 0b 0001 0001 1010 1010
|
||||
* = 0x 1 1 A A */
|
||||
assert(KDColorRGB(0x12, 0x34, 0x56) == 0x11AA);
|
||||
assert(KDColor(0x123456) == 0x11AA);
|
||||
}
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
#include <quiz.h>
|
||||
#include <kandinsky.h>
|
||||
#include <assert.h>
|
||||
|
||||
QUIZ_CASE(kandinsky_rect_intersect) {
|
||||
KDRect a = {
|
||||
.x = -5, .y = -5,
|
||||
.width = 10, .height = 10
|
||||
};
|
||||
KDRect b = {
|
||||
.x = 0, .y = 0,
|
||||
.width = 10, .height = 10
|
||||
};
|
||||
assert(KDRectIntersect(a,b));
|
||||
assert(KDRectIntersect(b,a));
|
||||
KDRect c = KDRectIntersection(a,b);
|
||||
assert(c.x == 0);
|
||||
assert(c.y == 0);
|
||||
assert(c.width == 5);
|
||||
assert(c.height == 5);
|
||||
c = KDRectIntersection(b,a);
|
||||
assert(c.x == 0);
|
||||
assert(c.y == 0);
|
||||
assert(c.width == 5);
|
||||
assert(c.height == 5);
|
||||
}
|
||||
|
||||
QUIZ_CASE(kandinsky_rect_union) {
|
||||
KDRect a = {
|
||||
.x = -5, .y = -5,
|
||||
.width = 10, .height = 10
|
||||
};
|
||||
KDRect b = {
|
||||
.x = 0, .y = 0,
|
||||
.width = 10, .height = 10
|
||||
};
|
||||
|
||||
KDRect c = KDRectUnion(a,b);
|
||||
assert(c.x == -5);
|
||||
assert(c.y == -5);
|
||||
assert(c.width == 15);
|
||||
assert(c.height == 15);
|
||||
|
||||
c = KDRectUnion(a,b);
|
||||
assert(c.x == -5);
|
||||
assert(c.y == -5);
|
||||
assert(c.width == 15);
|
||||
assert(c.height == 15);
|
||||
}
|
||||
|
||||
QUIZ_CASE(kandinsky_rect_empty_union) {
|
||||
KDRect a = {
|
||||
.x = 1, .y = 2,
|
||||
.width = 3, .height = 4
|
||||
};
|
||||
KDRect b = {
|
||||
.x = 5, .y = 6,
|
||||
.width = 0, .height = 0
|
||||
};
|
||||
KDRect c = {
|
||||
.x = -2, .y = -1,
|
||||
.width = 0, .height = 1
|
||||
};
|
||||
|
||||
KDRect t = KDRectUnion(a,b);
|
||||
assert(t.x == a.x);
|
||||
assert(t.y == a.y);
|
||||
assert(t.width == a.width);
|
||||
assert(t.height == a.height);
|
||||
|
||||
t = KDRectUnion(b,a);
|
||||
assert(t.x == a.x);
|
||||
assert(t.y == a.y);
|
||||
assert(t.width == a.width);
|
||||
assert(t.height == a.height);
|
||||
|
||||
t = KDRectUnion(a,c);
|
||||
assert(t.x == a.x);
|
||||
assert(t.y == c.y);
|
||||
assert(t.width == a.width);
|
||||
assert(t.height == 7);
|
||||
}
|
||||
60
kandinsky/test/rect.cpp
Normal file
60
kandinsky/test/rect.cpp
Normal file
@@ -0,0 +1,60 @@
|
||||
#include <quiz.h>
|
||||
#include <kandinsky.h>
|
||||
#include <assert.h>
|
||||
|
||||
QUIZ_CASE(kandinsky_rect_intersect) {
|
||||
KDRect a(-5,-5, 10, 10);
|
||||
KDRect b(0, 0, 10, 10);
|
||||
assert(a.intersects(b));
|
||||
assert(b.intersects(a));
|
||||
KDRect c = a.intersectedWith(b);
|
||||
assert(c.x() == 0);
|
||||
assert(c.y() == 0);
|
||||
assert(c.width() == 5);
|
||||
assert(c.height() == 5);
|
||||
c = b.intersectedWith(a);
|
||||
assert(c.x() == 0);
|
||||
assert(c.y() == 0);
|
||||
assert(c.width() == 5);
|
||||
assert(c.height() == 5);
|
||||
}
|
||||
|
||||
QUIZ_CASE(kandinsky_rect_union) {
|
||||
KDRect a(-5, -5, 10, 10);
|
||||
KDRect b(0, 0, 10, 10);
|
||||
KDRect c = a.unionedWith(b);
|
||||
assert(c.x() == -5);
|
||||
assert(c.y() == -5);
|
||||
assert(c.width() == 15);
|
||||
assert(c.height() == 15);
|
||||
|
||||
c = a.unionedWith(b);
|
||||
assert(c.x() == -5);
|
||||
assert(c.y() == -5);
|
||||
assert(c.width() == 15);
|
||||
assert(c.height() == 15);
|
||||
}
|
||||
|
||||
QUIZ_CASE(kandinsky_rect_empty_union) {
|
||||
KDRect a(1, 2, 3, 4);
|
||||
KDRect b(5, 6, 0, 0);
|
||||
KDRect c(-2, -1, 0, 1);
|
||||
|
||||
KDRect t = a.unionedWith(b);
|
||||
assert(t.x() == a.x());
|
||||
assert(t.y() == a.y());
|
||||
assert(t.width() == a.width());
|
||||
assert(t.height() == a.height());
|
||||
|
||||
t = b.unionedWith(a);
|
||||
assert(t.x() == a.x());
|
||||
assert(t.y() == a.y());
|
||||
assert(t.width() == a.width());
|
||||
assert(t.height() == a.height());
|
||||
|
||||
t = a.unionedWith(c);
|
||||
assert(t.x() == a.x());
|
||||
assert(t.y() == c.y());
|
||||
assert(t.width() == a.width());
|
||||
assert(t.height() == 7);
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
#include <quiz.h>
|
||||
#include <kandinsky.h>
|
||||
|
||||
QUIZ_CASE(setpixel) {
|
||||
}
|
||||
@@ -1,12 +1,15 @@
|
||||
#include "symbols.h"
|
||||
#include <string.h>
|
||||
#include <kandinsky.h>
|
||||
extern "C" {
|
||||
#include <ion.h>
|
||||
}
|
||||
|
||||
void print(char * message) {
|
||||
void print(const char * message) {
|
||||
static int line_y = 0;
|
||||
int line_height = KDStringSize("M").height;
|
||||
KDDrawString(message, (KDPoint){.x = 0, .y = line_y}, 0);
|
||||
KDContext * ctx = KDIonContext::sharedContext();
|
||||
int line_height = ctx->stringSize("M").height();
|
||||
ctx->drawString(message, KDPoint(0, line_y), 0);
|
||||
line_y += line_height;
|
||||
if (line_y > ION_SCREEN_HEIGHT) {
|
||||
line_y = 0;
|
||||
Reference in New Issue
Block a user