// https://github.com/dejwk/roo_display/blob/master/doc/programming_guide.md#text-alignment

#include "Arduino.h"
#include "roo_display.h"

using namespace roo_display;

// Select the driver to match your display device.
#include "roo_display/driver/ili9341.h"

// Set your configuration for the driver.
static constexpr int kCsPin = 5;
static constexpr int kDcPin = 2;
static constexpr int kRstPin = 4;
static constexpr int kBlPin = 16;

static constexpr int kSpiSck = -1;
static constexpr int kSpiMiso = -1;
static constexpr int kSpiMosi = -1;

// Uncomment if you have connected the BL pin to GPIO.

// #include "roo_display/backlit/esp32_ledc.h"
// LedcBacklit backlit(kBlPin);

Ili9341spi<kCsPin, kDcPin, kRstPin> device(Orientation().rotateLeft());
Display display(device);

static const int pinSdCs = 4;  // Or whatever yours is.
static const char* jpeg_file = "/roo.jpg";
static const char* png_file = "/penguin.png";

#include "SD.h"
#include "roo_display/core/raster.h"
#include "roo_display/driver/ili9341.h"
#include "roo_display/image/image.h"
#include "roo_display/image/jpeg/jpeg.h"
#include "roo_display/image/png/png.h"

void setup() {
  SPI.begin(kSpiSck, kSpiMiso, kSpiMosi);
  display.init(Graylevel(0xF0));

  pinMode(pinSdCs, OUTPUT);
  digitalWrite(pinSdCs, HIGH);
  SD.begin(pinSdCs);

  // Uncomment if using backlit.
  // backlit.begin();
}

void jpeg() {
  display.clear();

  JpegDecoder decoder;
  JpegFile img(decoder, SD, jpeg_file);
  DrawingContext dc(display);
  dc.draw(img, kCenter | kMiddle);

  delay(2000);
}

void jpeg_transformed() {
  display.clear();

  JpegDecoder decoder;
  JpegFile img(decoder, SD, jpeg_file);
  DrawingContext dc(display);
  dc.setTransformation(
      Transformation().translate(-100, -100).scale(3, 3).rotateRight());
  dc.setClipBox(120, 80, 359, 239);
  dc.draw(img, 240, 160);

  delay(2000);
}

void png() {
  display.clear();

  PngDecoder decoder;
  PngFile img(decoder, SD, png_file);
  DrawingContext dc(display);
  dc.draw(img, kCenter | kMiddle);

  delay(2000);
}

void builtin_gradient() {
  display.clear();

  static const uint8_t gradient[] PROGMEM = {0x01, 0x23, 0x45, 0x67,
                                             0x89, 0xAB, 0xCD, 0xEF};

  DrawingContext dc(display);
  dc.setTransformation(Transformation().scale(20, 200));
  dc.draw(ProgMemRaster<Grayscale4>(16, 1, gradient), kCenter | kMiddle);

  delay(2000);
}

void builtin_invader() {
  Color bg_backup = display.getBackgroundColor();
  display.setBackgroundColor(color::Black);
  display.clear();

  static const uint8_t invader[] PROGMEM = {
      0b00001000, 0b00100000, 0b00000100, 0b01000000, 0b00001111, 0b11100000,
      0b00011011, 0b10110000, 0b00111111, 0b11111000, 0b00101111, 0b11101000,
      0b00101000, 0b00101000, 0b00000110, 0b11000000,
  };

  static Color colors[] PROGMEM = {color::Transparent, color::Green};

  static Palette palette = Palette::ReadOnly(colors, 2);

  DrawingContext dc(display);
  dc.setTransformation(Transformation().scale(20, 20));
  dc.draw(ProgMemRaster<Indexed1>(16, 8, invader, &palette), kCenter | kMiddle);

  delay(2000);
  display.setBackgroundColor(bg_backup);
}

static const Color penguin_palette[] PROGMEM = {
    Color(0x00000000), Color(0xfffcfefb), Color(0xff000000), Color(0xfff8c200),
    Color(0xffdcdfdb), Color(0xffcfd1ce), Color(0xff595a57), Color(0xffa8aaa7),
    Color(0xff1e1a16), Color(0xffeaca5f), Color(0xff2f2f29), Color(0xff888a86),
    Color(0xffe9ba14), Color(0xfff6e6a4), Color(0xffeed994), Color(0xffffface),
};

// See https://github.com/dejwk/roo_display_image_importer.

// Image file penguin 60x45, Indexed, 4-bit (16-color) palette,  RLE, 547 bytes.
static const uint8_t penguin_data[] PROGMEM = {
    0x88, 0x00, 0x83, 0x22, 0x8F, 0x00, 0x02, 0x02, 0x26, 0x6A, 0x83, 0x22,
    0x00, 0x20, 0x8D, 0x00, 0x07, 0x2A, 0x51, 0x11, 0xB2, 0x22, 0x28, 0xA2,
    0x22, 0x8C, 0x00, 0x01, 0x22, 0x85, 0x81, 0x11, 0x05, 0x1B, 0x26, 0x51,
    0x11, 0x56, 0x22, 0x8A, 0x00, 0x02, 0x02, 0x22, 0x61, 0x81, 0x11, 0x01,
    0x15, 0xB1, 0x81, 0x11, 0x02, 0x14, 0x62, 0x20, 0x89, 0x00, 0x81, 0x22,
    0x00, 0x71, 0x81, 0x11, 0x01, 0x44, 0x41, 0x82, 0x11, 0x01, 0x58, 0x22,
    0x88, 0x00, 0x07, 0x02, 0x22, 0x28, 0x51, 0x11, 0x14, 0xA5, 0x57, 0x82,
    0x11, 0x02, 0x58, 0x22, 0x20, 0x87, 0x00, 0x00, 0x02, 0x81, 0x22, 0x04,
    0x71, 0x11, 0x14, 0x65, 0x75, 0x82, 0x11, 0x02, 0x72, 0x22, 0x20, 0x87,
    0x00, 0x82, 0x22, 0x00, 0xB1, 0x81, 0x11, 0x01, 0x14, 0x64, 0x81, 0x11,
    0x01, 0x14, 0x62, 0x81, 0x22, 0x87, 0x00, 0x82, 0x22, 0x00, 0xA4, 0x81,
    0x11, 0x04, 0x1B, 0x2A, 0x74, 0x44, 0x7A, 0x82, 0x22, 0x86, 0x00, 0x00,
    0x02, 0x82, 0x22, 0x05, 0x26, 0x41, 0x1F, 0x9C, 0xCC, 0x00, 0x84, 0x22,
    0x00, 0x20, 0x85, 0x00, 0x00, 0x02, 0x83, 0x22, 0x01, 0x8B, 0x79, 0x81,
    0x33, 0x01, 0xC7, 0x6A, 0x83, 0x22, 0x00, 0x20, 0x85, 0x00, 0x00, 0x02,
    0x82, 0x22, 0x07, 0x26, 0x74, 0x11, 0x93, 0x33, 0xD1, 0x14, 0x76, 0x82,
    0x22, 0x00, 0x20, 0x85, 0x00, 0x82, 0x22, 0x01, 0x2A, 0x74, 0x81, 0x11,
    0x01, 0xDC, 0x39, 0x81, 0x11, 0x01, 0x14, 0x76, 0x82, 0x22, 0x85, 0x00,
    0x82, 0x22, 0x01, 0x65, 0x41, 0x81, 0x11, 0x01, 0x1E, 0xCF, 0x82, 0x11,
    0x01, 0x45, 0xB8, 0x81, 0x22, 0x85, 0x00, 0x81, 0x22, 0x01, 0x2B, 0x54,
    0x82, 0x11, 0x01, 0x1F, 0xD1, 0x82, 0x11, 0x04, 0x14, 0x4B, 0x82, 0x22,
    0x20, 0x83, 0x00, 0x82, 0x22, 0x01, 0x65, 0x41, 0x87, 0x11, 0x02, 0x14,
    0x44, 0xB2, 0x81, 0x22, 0x82, 0x00, 0x00, 0x02, 0x81, 0x22, 0x02, 0x2A,
    0x54, 0x41, 0x88, 0x11, 0x01, 0x44, 0x56, 0x82, 0x22, 0x81, 0x00, 0x82,
    0x22, 0x01, 0x27, 0x44, 0x89, 0x11, 0x02, 0x44, 0x47, 0x82, 0x81, 0x22,
    0x00, 0x20, 0x83, 0x22, 0x01, 0xA5, 0x44, 0x89, 0x11, 0x02, 0x14, 0x44,
    0x62, 0x82, 0x22, 0x81, 0x00, 0x81, 0x22, 0x01, 0xB4, 0x41, 0x89, 0x11,
    0x03, 0x14, 0x44, 0x78, 0x20, 0x84, 0x00, 0x02, 0x28, 0x74, 0x41, 0x8A,
    0x11, 0x01, 0x44, 0x58, 0x85, 0x00, 0x02, 0x28, 0x54, 0x41, 0x8A, 0x11,
    0x01, 0x44, 0x5A, 0x85, 0x00, 0x02, 0x2A, 0x54, 0x41, 0x8A, 0x11, 0x01,
    0x44, 0x5A, 0x85, 0x00, 0x02, 0x08, 0x54, 0x41, 0x8A, 0x11, 0x01, 0x44,
    0x50, 0x85, 0x00, 0x02, 0x08, 0x74, 0x41, 0x8A, 0x11, 0x01, 0x44, 0x50,
    0x85, 0x00, 0x02, 0x02, 0x74, 0x41, 0x89, 0x11, 0x02, 0x14, 0x44, 0x50,
    0x86, 0x00, 0x01, 0x64, 0x41, 0x89, 0x11, 0x01, 0x14, 0x44, 0x87, 0x00,
    0x01, 0x85, 0x44, 0x89, 0x11, 0x01, 0x14, 0x44, 0x87, 0x00, 0x01, 0x0B,
    0x44, 0x89, 0x11, 0x01, 0x44, 0x40, 0x87, 0x00, 0x02, 0x08, 0x74, 0x41,
    0x88, 0x11, 0x01, 0x44, 0x40, 0x88, 0x00, 0x03, 0xC9, 0x99, 0xED, 0xF1,
    0x83, 0x11, 0x03, 0x1F, 0xDE, 0x99, 0x9E, 0x87, 0x00, 0x00, 0x03, 0x83,
    0x33, 0x01, 0x39, 0xD1, 0x81, 0x11, 0x01, 0x1D, 0x93, 0x83, 0x33, 0x00,
    0x30, 0x85, 0x00, 0x85, 0x33, 0x03, 0x39, 0xF1, 0x11, 0x93, 0x85, 0x33,
    0x00, 0xC0, 0x83, 0x00, 0x00, 0x03, 0x86, 0x33, 0x01, 0xE1, 0x1E, 0x86,
    0x33, 0x00, 0x30, 0x83, 0x00, 0x00, 0x03, 0x86, 0x33, 0x01, 0x91, 0x1E,
    0x87, 0x33, 0x83, 0x00, 0x00, 0x03, 0x86, 0x33, 0x01, 0xC6, 0x6B, 0x86,
    0x33, 0x00, 0x30, 0x84, 0x00, 0x85, 0x33, 0x00, 0x30, 0x81, 0x00, 0x00,
    0x03, 0x85, 0x33, 0x86, 0x00, 0x00, 0x03, 0x82, 0x33, 0x00, 0x30, 0x84,
    0x00, 0x82, 0x33, 0x00, 0x30, 0x83, 0x00,
};

const RleImage<Indexed4, ProgMemPtr>& penguin() {
  static Palette palette = Palette::ReadOnly(penguin_palette, 16);
  static RleImage<Indexed4, ProgMemPtr> value(
      Box(8, 3, 51, 41), Box(0, 0, 59, 44), penguin_data, Indexed4(&palette));
  return value;
}

void builtin_penguin() {
  display.clear();

  DrawingContext dc(display);
  dc.draw(penguin(), kCenter | kMiddle);

  delay(2000);
}

void loop() {
  jpeg();
  jpeg_transformed();
  png();
  builtin_gradient();
  builtin_invader();
  builtin_penguin();
}