#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"

#define TFT_DC 9
#define TFT_CS 10

Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);

uint16_t colors[] = {ILI9341_YELLOW, ILI9341_GREEN, ILI9341_BLACK, ILI9341_WHITE, ILI9341_BLUE, ILI9341_RED, ILI9341_CYAN, ILI9341_PINK, ILI9341_MAGENTA};

const int textX = 10;
const int textY = 180;
const int textSize = 2;
const int delayTime = 500;

void setup() {
  Serial.begin(9600);
  Serial.println("ILI9341 Test!");

  tft.begin();

  Serial.println(F("Benchmark                Time (microseconds)"));
  delay(10);

  Serial.print(F("Screen fill              "));
  Serial.println(testFillScreen());
  delay(500);

  Serial.print(F("Text                     "));
  Serial.println(testText());
  delay(3000);

  Serial.print(F("Lines                    "));
  Serial.println(testLines());
  delay(500);

  Serial.print(F("Horiz/Vert Lines         "));
  Serial.println(testFastLines());
  delay(500);

  Serial.print(F("Rectangles (outline)     "));
  Serial.println(testRects());
  delay(500);

  Serial.print(F("Rectangles (filled)      "));
  Serial.println(testFilledRects());
  delay(500);

  Serial.print(F("Circles (filled)         "));
  Serial.println(testFilledCircles(10));
  delay(500);

  Serial.print(F("Circles (outline)        "));
  Serial.println(testCircles(10));
  delay(500);

  Serial.print(F("Triangles (outline)      "));
  Serial.println(testTriangles());
  delay(500);

  Serial.print(F("Triangles (filled)       "));
  Serial.println(testFilledTriangles());
  delay(500);

  Serial.print(F("Rounded rects (outline)  "));
  Serial.println(testRoundRects());
  delay(500);

  Serial.print(F("Rounded rects (filled)   "));
  Serial.println(testFilledRoundRects());
  delay(500);

  Serial.println(F("Done!"));
}

void loop() {
  showTextAnimation();
  // Your loop code here
}

void showTextAnimation() {
  tft.setTextSize(textSize);
  tft.setTextColor(ILI9341_BLACK);

  for (int i = 0; i < sizeof(colors) / sizeof(colors[0]); ++i) {
    tft.fillScreen(colors[i]);
    yield();

    tft.setCursor(textX, textY);
    tft.println("Nama: Vicky Januar P.P");
    delay(delayTime);

    tft.setCursor(textX, textY + 20);
    tft.println("NIM: 04122002");
    delay(delayTime);

    tft.setCursor(textX, textY + 40);
    tft.println("Prodi: Sistem Komputer");
    delay(delayTime);

    tft.setCursor(textX, textY + 60);
    tft.println("UTS: MICROCONTROLLER");
    delay(delayTime);
  }
}

unsigned long testFillScreen() {
  unsigned long start = micros();

  for (int i = 0; i < sizeof(colors) / sizeof(colors[0]); ++i) {
    tft.fillScreen(colors[i]);
    delay(1000);
  }

  return micros() - start;
}

unsigned long testText() {
  tft.fillScreen(ILI9341_BLACK);
  unsigned long start = micros();
  tft.setCursor(0, 0);
  tft.setTextColor(ILI9341_WHITE);
  tft.setTextSize(2);
  tft.println("UTS MICROCONTROLLER");
  delay(100);

  tft.setTextColor(ILI9341_WHITE);
  tft.setTextSize(2);
  tft.println(1311.23);
  tft.println();
  tft.setTextColor(ILI9341_RED);
  tft.setTextSize(5);
  tft.println("WHO?");
  delay(200);
  tft.setTextSize(2);
  tft.println("DO YOU SEE THAT?");
  delay(200);
  tft.setTextSize(2);
  tft.println("WHO YOU REALLY ARE?");
  delay(200);
  tft.println("WHAT ARE YOU DOING?");
  delay(200);
  tft.println("YOU'RE NOTHING");
  delay(200);
  tft.println("EXCEPT THE VOID");
  delay(200);
  tft.setTextSize(1);
  tft.println("THERE'S NOTHING YOU CAN TRUST");
  delay(200);
  tft.println("EVERYONE CAN BETRAY YOU");
  delay(200);
  tft.println("DO U UNDERSTAND?");
  delay(200);

  return micros() - start;
}

unsigned long testLines() {
  unsigned long start;
  int           w = tft.width(), h = tft.height();

  for (int i = 0; i < sizeof(colors) / sizeof(colors[0]); ++i) {
    tft.fillScreen(colors[i]);
    yield();

    start = micros();
    for (int x = 0; x < w; x += 16)
      tft.drawLine(x, 0, w - x - 1, h - 1, randomColor());

    for (int y = 0; y < h; y += 16)
      tft.drawLine(0, y, w - 1, h - y - 1, randomColor());

    delay(1000);
  }

  return micros() - start;
}

unsigned long testFastLines() {
  unsigned long start;
  int           x, y, w = tft.width(), h = tft.height();

  for (int i = 0; i < sizeof(colors) / sizeof(colors[0]); ++i) {
    tft.fillScreen(colors[i]);
    yield();

    start = micros();
    for (y = 0; y < h; y += 20)
      tft.drawFastHLine(0, y, w, randomColor());

    for (x = 0; x < w; x += 20)
      tft.drawFastVLine(x, 0, h, randomColor());

    delay(1000);
  }

  return micros() - start;
}

unsigned long testRects() {
  unsigned long start;
  int           n, i, i2,
                cx = tft.width() / 2,
                cy = tft.height() / 2;

  for (int j = 0; j < sizeof(colors) / sizeof(colors[0]); ++j) {
    tft.fillScreen(colors[j]);
    yield();

    n     = min(tft.width(), tft.height());
    start = micros();
    for (i = 4; i < n; i += 16) {
      i2 = i / 2;
      tft.drawRect(cx - i2, cy - i2, i, i, randomColor());
    }

    delay(1000);
  }

  return micros() - start;
}

unsigned long testFilledRects() {
  unsigned long start, t = 0;
  int           n, i, i2,
                cx = tft.width() / 2 - 1,
                cy = tft.height() / 2 - 1;

  for (int j = 0; j < sizeof(colors) / sizeof(colors[0]); ++j) {
    tft.fillScreen(colors[j]);
    yield();

    n = min(tft.width(), tft.height());
    for (i = n; i > 0; i -= 16) {
      i2    = i / 2;
      start = micros();
      tft.fillRect(cx - i2, cy - i2, i, i, randomColor());
      t    += micros() - start;
      // Outlines are not included in timing results
      tft.drawRect(cx - i2, cy - i2, i, i, randomColor());
      yield();
    }

    delay(1000);
  }

  return t;
}

unsigned long testFilledCircles(uint8_t radius) {
  unsigned long start;
  int           x, y, r2 = radius * 2,
                w = tft.width() + radius,
                h = tft.height() + radius;

  for (int k = 0; k < sizeof(colors) / sizeof(colors[0]); ++k) {
    tft.fillScreen(colors[k]);
    yield();

    start = micros();
    for (x = radius; x < w; x += r2) {
      for (y = radius; y < h; y += r2) {
        tft.fillCircle(x, y, radius, randomColor());
      }
    }

    delay(1000);
  }

  return micros() - start;
}

unsigned long testCircles(uint8_t radius) {
  unsigned long start;
  int           x, y, r2 = radius * 2,
                w = tft.width() + radius,
                h = tft.height() + radius;

  for (int k = 0; k < sizeof(colors) / sizeof(colors[0]); ++k) {
    tft.fillScreen(colors[k]);
    yield();

    start = micros();
    for (x = 0; x < w; x += r2) {
      for (y = 0; y < h; y += r2) {
        tft.drawCircle(x, y, radius, randomColor());
      }
    }

    delay(1000);
  }

  return micros() - start;
}

unsigned long testTriangles() {
  unsigned long start;
  int           n, i, cx = tft.width() / 2 - 1,
                      cy = tft.height() / 2 - 1;

  for (int k = 0; k < sizeof(colors) / sizeof(colors[0]); ++k) {
    tft.fillScreen(colors[k]);
    yield();

    n     = min(cx, cy);
    start = micros();
    for (i = 0; i < n; i += 16) {
      tft.drawTriangle(
        cx    , cy - i,
        cx - i, cy + i,
        cx + i, cy + i,
        randomColor()
      );
    }

    delay(1000);
  }

  return micros() - start;
}

unsigned long testFilledTriangles() {
  unsigned long start, t = 0;
  int           i, cx = tft.width() / 2 - 1,
                   cy = tft.height() / 2 - 1;

  for (int k = 0; k < sizeof(colors) / sizeof(colors[0]); ++k) {
    tft.fillScreen(colors[k]);
    yield();

    start = micros();
    for (i = min(cx, cy); i > 0; i -= 16) {
      start = micros();
      tft.fillTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i,
        randomColor());
      t += micros() - start;
      tft.drawTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i,
        randomColor());
      yield();
    }

    delay(1000);
  }

  return t;
}

unsigned long testRoundRects() {
  unsigned long start;
  int           w, i, i2,
                cx = tft.width() / 2 - 1,
                cy = tft.height() / 2 - 1;

  for (int k = 0; k < sizeof(colors) / sizeof(colors[0]); ++k) {
    tft.fillScreen(colors[k]);
    yield();

    w     = min(tft.width(), tft.height());
    start = micros();
    for (i = 0; i < w; i += 16) {
      i2 = i / 2;
      tft.drawRoundRect(cx - i2, cy - i2, i, i, i / 8, randomColor());
    }

    delay(1000);
  }

  return micros() - start;
}

unsigned long testFilledRoundRects() {
  unsigned long start;
  int           i, i2,
                cx = tft.width() / 2 - 1,
                cy = tft.height() / 2 - 1;

  for (int k = 0; k < sizeof(colors) / sizeof(colors[0]); ++k) {
    tft.fillScreen(colors[k]);
    yield();

    start = micros();
    for (i = min(tft.width(), tft.height()); i > 0; i -= 16) {
      i2 = i / 2;
      tft.fillRoundRect(cx - i2, cy - i2, i, i, i / 8, randomColor());
      yield();
    }

    delay(1000);
  }

  return micros() - start;
}

uint16_t randomColor() {
  return tft.color565(random(0, 256), random(0, 256), random(0, 256));
}