Compare commits

..

No commits in common. "3619601efaf242d9df99922894082d8cd6d79af9" and "0e9f37832b9e37309a86bfae054dd81b8d1a2995" have entirely different histories.

6 changed files with 3 additions and 2825 deletions

View File

@ -4,8 +4,8 @@ pipeline:
image: python
commands:
- pip install -U platformio
- pio run -e esp32 -e esp32_wifi -e esp32_wifi_display
- pio run -e esp32 -e esp32_wifi -e esp32_wifi_display --target buildfs
- pio run -e esp32 -e esp32_wifi -e esp32_bluetooth -e esp32_wifi_display
- pio run -e esp32 -e esp32_wifi -e esp32_bluetooth -e esp32_wifi_display --target buildfs
build_esp8266:
group: build
image: python

2656
Doxygen

File diff suppressed because it is too large Load Diff

View File

@ -3,38 +3,13 @@
#include "Geometry.h"
/**
* Generic interface for converting between virtual and physical coordinates
*/
struct CoordinateMapping {
/**
* Maps physical coordinates to virtual coordinates.
* Virtual coordinates range from 0 to 255. Physical coordinates are
* hardware-dependent.
*/
virtual VirtualCoordinates physicalToVirtualCoords(const PhysicalCoordinates localCoords) const = 0;
/**
* Maps virtual coordinates to physical (aka, hardware) coordinates.
* Virtual coordinates range from 0 to 255. Physical coordinates are
* hardware-dependent.
*/
virtual PhysicalCoordinates virtualToPhysicalCoords(const VirtualCoordinates virtualCoords) const = 0;
/**
* Returns the index of the underlying FastLED array, i.e., the physical
* hardware pixel.
*/
virtual int physicalCoordsToIndex(const PhysicalCoordinates localCoords) const = 0;
virtual unsigned int physicalPixelCount() const = 0;
};
/**
* Basic mapping for a contiguous 1-d linear display, eg, an LED strip.
*
* X value ranges from 0 to 255; all Y values are flattened to Y=0
*/
struct LinearCoordinateMapping: CoordinateMapping {
unsigned int pixelCount = 1;
unsigned int startPixel = 0;
@ -57,51 +32,22 @@ struct LinearCoordinateMapping: CoordinateMapping {
}
};
/**
* The connection between the rendering engine and the physical hardware.
* Provides direct access to the underlying FastLED array.
*/
class Display {
public:
Display(CRGB* pixels, int pixelCount, const CoordinateMapping* map)
: m_pixels(pixels), m_pixelCount(pixelCount), m_coordMap(map) {}
/**
* Returns the physical pixel at the given physical coordinates
*/
CRGB& pixelAt(const PhysicalCoordinates coords);
/**
* Returns the physical pixel at the given virtual coordinates
*/
CRGB& pixelAt(const VirtualCoordinates coords);
/**
* Returns the physical pixel in the underlying FastLED array
*/
CRGB& pixelAt(int idx);
/**
* Returns how many pixels are in this display
*/
int pixelCount() const;
/**
* Returns the raw underlying FastLED array
*/
CRGB* pixelBacking() const;
const CoordinateMapping* coordinateMapping() const;
/**
* Sets every pixel to (0, 0, 0)
*/
void clear();
/**
* Sets every pixel to the given display
*/
void clear(const CRGB& color);
void clear(VirtualCoordinates& start, VirtualCoordinates& end, const CRGB& color);
private:
CRGB* m_pixels;

View File

@ -10,36 +10,13 @@ class Display;
class InputEvent;
class InputSource;
/**
* A generic interface for anything that can be executed and respond to events.
*/
struct Loopable {
/**
* Called by the MainLoop to process events
*/
virtual void handleEvent(const InputEvent& event) {}
/**
* Called on every MainLoop tick
*/
virtual void loop() = 0;
};
/**
* A Loopable that can be named and may be started or stopped in a MainLoop.
*/
struct Task : public virtual Loopable {
/**
* Implement in a subclass to run when the task is started
* The default implementation does nothing.
*/
virtual void onStart() {};
/**
* Implement in a subclass to run when the task is stopped.
* The default implementation does nothing.
*/
virtual void onStop() {};
enum State {
@ -50,52 +27,27 @@ struct Task : public virtual Loopable {
Task() {}
explicit Task(const char* name) : name(name) {}
/**
* Starts the task and makes it schedulable
*/
void start() { state = Running; onStart(); }
/**
* Stops the task and makes it unschedulable
*/
void stop() { onStop(); state = Stopped; }
/**
* A hacky way to determine if a task is a Figment subclass or not, without
* having to resort to RTTI
*/
virtual bool isFigment() const { return false; }
const char* name = "";
State state = Stopped;
};
/**
* Functional lambda interface for creating Tasks
*/
struct TaskFunc: public Task {
TaskFunc(std::function<void()> func) : Task("lambda"), func(func) {}
void loop() override {func();}
std::function<void()> func;
};
/**
* A Task with a graphical output
*/
struct Figment: public Task {
Figment() : Task() {}
explicit Figment(const char* name) : Task(name) {}
/**
* Called when the Figment should render its output to a display
*/
virtual void render(Display* dpy) const = 0;
bool isFigment() const override { return true; }
};
/**
* Functional lambda interface for creating Figments
*/
struct FigmentFunc: public Figment {
FigmentFunc(std::function<void(Display*)> func) : Figment("lambda"), func(func) {}
void loop() override {}

View File

@ -1,34 +1,20 @@
#pragma once
#include <array>
/**
* A simple ring buffer structure
*/
template<typename T, int Size>
struct Ringbuf {
Ringbuf() : m_head(0), m_tail(0) {}
/**
* Clears the buffer's contents
*/
void clear() {
m_head = 0;
m_tail = 0;
}
/**
* Returns the value of the next available item, if available
*/
T peek(int offset) const {
const int nextHead = (m_head + offset) % Size;
return m_items[nextHead];
}
/**
* Removes and returns the next available item, if any.
*
* @return false if no data is available, true otherwise
*/
bool take(T& dest) {
if (m_head == m_tail) {
return false;
@ -40,10 +26,6 @@ struct Ringbuf {
return true;
}
/**
* Inserts an item into the buffer. If the buffer is full, the oldest item
* is overwritten.
*/
void insert(const T& src) {
const int cur = m_tail;
const int nextTail = (m_tail + 1) % Size;
@ -55,9 +37,6 @@ struct Ringbuf {
m_items[cur] = src;
}
/**
* Consumes the entire buffer and writes it to the given array.
*/
size_t write(T(&dest)[Size]) {
int i = 0;
size_t ret = 0;
@ -68,9 +47,6 @@ struct Ringbuf {
return ret;
}
/**
* Consumes the entire buffer and writes it to the given output
*/
size_t write(Print& stream) {
T val;
size_t ret = 0;
@ -80,9 +56,6 @@ struct Ringbuf {
return ret;
}
/**
* Returns how many items are available in the buffer
*/
size_t size() {
if (m_tail > m_head) {
return m_tail - m_head;

View File

@ -6,34 +6,13 @@
class Display;
/**
* A high performance and hardware-independent rendering surface which
* represents a full 2d display ranging from (0,0) to (255, 255), that may be
* rotated.
*
* Simple brushes and complex shaders may be applied to a Surface using
* @paintWith and @paintShader. The Surface will only execute each shader or
* brush once for each physical pixel in the display, allowing you to design
* display-independent graphics.
*/
class Surface {
public:
Surface(Display* dpy, const VirtualCoordinates& start, const VirtualCoordinates& end);
Surface(Display* dpy, const VirtualCoordinates& start, const VirtualCoordinates& end, uint8_t rotation);
/**
* Sets the entire surface to one solid color
*/
Surface& operator=(const CRGB& color);
/**
* Adds the given color to every pixel on the surface
*/
Surface& operator+=(const CRGB& color);
/**
* OR operation that applies the given color to every pixel on the surface
*/
template<typename T>
Surface& operator|=(const T& val) {
paintWith([&](CRGB& pixel) {
@ -42,26 +21,10 @@ public:
return *this;
}
/**
* A lambda function that maps coordinates to colors.
*/
using Shader = std::function<void(CRGB&, const VirtualCoordinates& virtPos, const PhysicalCoordinates& realPos, const VirtualCoordinates& surfacePos)>;
/**
* A simple lambda that is called for every pixel in a surface. Commonly
* used for solid fills; if you want to map pixel coordinates to colors or
* textures, you probably want to use a Shader instead.
*/
using BrushFunc = std::function<void(CRGB&)>;
/**
* Applies the given BrushFunc to every physical pixel in the surface
*/
void paintWith(BrushFunc func);
/**
* Applies the given Shader to every physical pixel in the surface
*/
void paintShader(Shader shader);
const PhysicalCoordinates start;