From 4c3d4b5a62c2196abc7b5cd04d089a559924b24b Mon Sep 17 00:00:00 2001
From: Micah Elizabeth Scott <micah@scanlime.org>
Date: Thu, 18 Jul 2013 19:50:51 -0700
Subject: [PATCH] Initial rough dithering code, imported from Wavebucket

---
 LICENSE                     |   2 +-
 README.md                   |   6 ++
 fc_firmware/fc_firmware.ino |  33 ++++++++++
 fc_firmware/hcolor.h        | 120 ++++++++++++++++++++++++++++++++++++
 4 files changed, 160 insertions(+), 1 deletion(-)
 create mode 100644 fc_firmware/fc_firmware.ino
 create mode 100644 fc_firmware/hcolor.h

diff --git a/LICENSE b/LICENSE
index cd16d8e..d356020 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
 The MIT License (MIT)
 
-Copyright (c) 2013 M. Elizabeth Scott
+Copyright (c) 2013 Micah Elizabeth Scott
 
 Permission is hereby granted, free of charge, to any person obtaining a copy of
 this software and associated documentation files (the "Software"), to deal in
diff --git a/README.md b/README.md
index 97c2456..53b1237 100644
--- a/README.md
+++ b/README.md
@@ -23,3 +23,9 @@ This is a work in progress! Things I don't know yet:
 * How many LEDs will be supported per Teensy board
 * Maximum frame rates
 * Specific documentation for the USB protocol
+
+Prerequisites
+-------------
+
+* The recommended ARM toolchain, from <https://code.launchpad.net/gcc-arm-embedded>
+* The Teensy Loader: <http://www.pjrc.com/teensy/loader.html>
diff --git a/fc_firmware/fc_firmware.ino b/fc_firmware/fc_firmware.ino
new file mode 100644
index 0000000..f52b033
--- /dev/null
+++ b/fc_firmware/fc_firmware.ino
@@ -0,0 +1,33 @@
+/*
+ * Fadecandy Firmware
+ * For Arduino with Teensyduino and OctoWS2811.
+ *
+ * Copyright <c> 2013 Micah Elizabeth Scott. <micah@scanlime.org>
+ */
+
+#include <OctoWS2811.h>
+#include "hcolor.h"
+
+static const int ledsPerStrip = 64;
+static const int ledsTotal = ledsPerStrip * 8;
+
+DMAMEM int displayMemory[ledsPerStrip * 6];
+int drawingMemory[ledsPerStrip * 6];
+OctoWS2811 leds(ledsPerStrip, displayMemory, drawingMemory, WS2811_GRB | WS2811_800kHz);
+HPixelBuffer<ledsTotal> pixbuf;
+
+void setup()
+{
+    leds.begin();
+
+    for (unsigned i = 0; i < ledsTotal; ++i) {
+        pixbuf.pixels[i].color = HColor16(0x1080, 0x0080, 0x0080);
+    }
+}
+
+void loop()
+{
+    pixbuf.pixels[0].color.r = millis() & 0xffff;
+
+    pixbuf.show(leds);
+}
diff --git a/fc_firmware/hcolor.h b/fc_firmware/hcolor.h
new file mode 100644
index 0000000..3534da4
--- /dev/null
+++ b/fc_firmware/hcolor.h
@@ -0,0 +1,120 @@
+/*
+ * High dynamic range color library.
+ *
+ * Copyright <c> 2013 Micah Elizabeth Scott. <micah@scanlime.org>
+ *
+ * This is a high dynamic range (48-bit) color data type,
+ * and a temporal dithering implementation that's compatible
+ * with the OctoWS2811 LED driver.
+ */
+
+#pragma once
+#include <stdint.h>
+#include <algorithm>
+
+class OctoWS2811;
+
+/// Basic data type for a high-dynamic-range color.
+struct HColor {
+    uint16_t r, g, b;
+};
+
+/// Constructor for 16-bit colors
+static inline HColor HColor16(uint16_t r, uint16_t g, uint16_t b) {
+    HColor c = { r, g, b };
+    return c;
+}
+
+/// Constructor for 8-bit colors
+static inline HColor HColor8(uint8_t r, uint8_t g, uint8_t b) {
+    HColor c = {
+        r | (unsigned(r) << 8),
+        g | (unsigned(g) << 8),
+        b | (unsigned(b) << 8),
+    };
+    return c;
+}
+
+/// Constructor for 8-bit colors packed into a 24-bit word
+static inline HColor HColor8(uint32_t rgb) {
+    return HColor8( (rgb & 0xFF0000) >> 16, (rgb & 0x00FF00) >> 8, rgb & 0x0000FF );
+}
+
+/// Constructor for float colors, with clamping.
+static inline HColor HColorF(float r, float g, float b) {
+    HColor c = {
+        std::min<int>(0xffff, std::max<int>(0, r * 65535.0f + 0.5f)),
+        std::min<int>(0xffff, std::max<int>(0, g * 65535.0f + 0.5f)),
+        std::min<int>(0xffff, std::max<int>(0, b * 65535.0f + 0.5f)),
+    };
+    return c;
+}
+
+/// Add two colors, with saturation
+static inline HColor operator + (HColor a, HColor b) {
+    HColor c = {
+        std::min<int>(0xffff, unsigned(a.r) + unsigned(b.r)),
+        std::min<int>(0xffff, unsigned(a.g) + unsigned(b.g)),
+        std::min<int>(0xffff, unsigned(a.b) + unsigned(b.b)),
+    };
+    return c;
+}
+
+/**
+ * Linear interpolation between two colors. "Alpha" is in 8-bit fixed point.
+ * Returns c1 if alpha==0, or c2 if alpha==0x100. Values outside this range will extrapolate.
+ */
+static inline HColor lerp8(HColor c1, HColor c2, int alpha) {
+  int invA = 0x100 - alpha;
+  HColor c = {
+    (c1.r * invA + c2.r * alpha) >> 8,
+    (c1.g * invA + c2.g * alpha) >> 8,
+    (c1.b * invA + c2.b * alpha) >> 8,
+  };
+  return c;
+}
+
+/// Floating point linear interpolation, with clamping.
+static inline HColor lerp(HColor c1, HColor c2, float alpha) {
+  float invA = 1.0f - alpha;
+  HColor c = {
+    std::min<int>(0xffff, std::max<int>(0, c1.r * invA + c2.r * alpha)),
+    std::min<int>(0xffff, std::max<int>(0, c1.g * invA + c2.g * alpha)),
+    std::min<int>(0xffff, std::max<int>(0, c1.b * invA + c2.b * alpha)),
+  };
+  return c;
+}
+
+/// Data type for one display pixel
+struct HPixel {
+    HColor color;
+    int16_t residual[3];
+
+    /// Temporal dithering algorithm. Returns a 24-bit RGB color.
+    uint32_t dither() {
+        int r16 = color.r + residual[0];
+        int g16 = color.g + residual[1];
+        int b16 = color.b + residual[2];
+        int r8 = std::min<int>(0xff, std::max<int>(0, (r16 + 0x80) >> 8));
+        int g8 = std::min<int>(0xff, std::max<int>(0, (g16 + 0x80) >> 8));
+        int b8 = std::min<int>(0xff, std::max<int>(0, (b16 + 0x80) >> 8));
+        residual[0] = r16 - (r8 | (r8 << 8));
+        residual[1] = g16 - (g8 | (g8 << 8));
+        residual[2] = b16 - (b8 | (b8 << 8));
+        return (r8 << 16) | (g8 << 8) | b8;
+    }
+};
+
+/// Data type for a framebuffer of pixels
+template <unsigned tCount>
+struct HPixelBuffer {
+    HPixel pixels[tCount];
+
+    /// Update the entire frame
+    void show(OctoWS2811 &leds) {
+        for (unsigned i = 0; i < tCount; ++i) {
+            leds.setPixel(i, pixels[i].dither());
+        }
+        leds.show();
+    }
+};
-- 
GitLab