

/*
red   D2
green D3
blue  D4
hsync D9
vsync D8  

*/



#include <Arduino.h>
#include <VGA.h>
#include "Font8x8.h"   // load font8x8_basic[96][8]
#include "bitmap.h"

// resolution
static const int SCREEN_W = 400;
static const int SCREEN_H = 300;


VGA vga;

// colors (RGB565, only 1-bit per chanel → 8 colors)
#define COL_BLACK   0x0000
#define COL_RED     0xF800
#define COL_GREEN   0x07E0
#define COL_BLUE    0x001F
#define COL_CYAN    0x07FF
#define COL_MAGENTA 0xF81F
#define COL_YELLOW  0xFFE0
#define COL_WHITE   0xFFFF


// 8x8-characters draw
void drawChar(uint8_t ch, int x, int y, uint16_t fg, uint16_t bg)
{
  if (ch < 32 || ch > 127) return;
  const uint8_t* glyph = font8x8_basic[ch - 32];
  for (int row = 0; row < 8; ++row)
  {
    uint8_t bits = glyph[row];
    for (int col = 0; col < 8; ++col)
    {
      bool on = (bits >> col) & 0x01;
      vga.dotFast(x + col, y + row, on ? fg : bg);
    }
  }
}

void fillScreen(uint16_t c)
{
  for (int y = 0; y < SCREEN_H; ++y)
    for (int x = 0; x < SCREEN_W; ++x)
      vga.dotFast(x, y, c);
}

void setup()
{
  // *** PinConfig for XIAO ESP32-S3 with only 1 bit per chanel ***
  const PinConfig pins(
    -1, -1, -1, -1, 5,        // R (1 bit on GPIO3)
    -1, -1, -1, -1, -1, 4,    // G (1 bit on GPIO4)
    -1, -1, -1, -1, 3,        // B (1 bit on GPIO5)
    8, 7                      // HSync=GPIO8, VSync=GPIO7
  );

  // 400x300@60Hz, 16 bpp Framebuffer, 2 Buffers
  vga.init(pins, Mode::MODE_400x300x60, 16, 2);
  vga.start();

  // clear background
  fillScreen(COL_BLACK);
  //fillScreen(COL_MAGENTA);

  // write all 96 ASCII-characters in a 8x8-pattern
  const int cellW = 8, cellH = 8;
  const int cols = SCREEN_W / cellW;   // 50 Spalten
  int idx = 0;
  for (int code = 32; code <= 127; ++code)
  {
    int cx = (idx % cols) * cellW;
    int cy = (idx / cols) * cellH;
    // every line another color
    uint16_t fg = (idx / cols) % 8; 
    switch(fg) {
      case 0: fg = COL_WHITE; break;
      case 1: fg = COL_RED; break;
      case 2: fg = COL_GREEN; break;
      case 3: fg = COL_BLUE; break;
      case 4: fg = COL_CYAN; break;
      case 5: fg = COL_MAGENTA; break;
      case 6: fg = COL_YELLOW; break;
      case 7: fg = COL_WHITE; break;
    }
    drawChar((uint8_t)code, cx, cy, fg, COL_BLACK);
    idx++;
  }

  // headline
  const char *title = "XIAO ESP32-S3 VGA (8 colors)";
  int tx = 4, ty = 8 * 3; // 
  for (const char* p = title; *p; ++p, tx += 8)
    drawChar(*p, tx, ty, COL_YELLOW, COL_BLACK);

vga.circle(200, 150, 50, COL_RED);
vga.fillEllipse(100, 190, 60, 30, COL_YELLOW);
delay(2000);

}

void loop()
{
  // here is the action

  arrowLeft(); delay(2000);
  arrowRight(); delay(2000);

  fillScreen(COL_BLACK);
  drawCenteredText("This is a centered VGA text line!", COL_YELLOW); delay(3000);
  //allDemo();
  //smiley();
}

// ********** predefined tasks **********

void arrowLeft() {
  fillScreen(COL_BLACK);
  vga.fillTri(20, 150, 120, 70, 120, 230, COL_GREEN);
  vga.fillRect(120, 100, 250, 100, COL_GREEN);
  delay(10);
}

void arrowRight() {
  fillScreen(COL_BLACK);
  vga.fillTri(380, 150, 280, 70, 280, 230, COL_WHITE);
  vga.fillRect(30, 100, 250, 100, COL_WHITE);
  delay(10);
}

void drawBitmap8x8(int x, int y, const uint8_t bmp[8][8]) {
  fillScreen(COL_WHITE);
  for (int row = 0; row < 8; row++) {
    for (int col = 0; col < 8; col++) {
      uint16_t color = bmp[row][col]; // 3-Bit-Farbe
      vga.dotFast(x + col, y + row, color);
    }
  }
}

void drawBitmap16x16(int x, int y, const uint8_t bmp[16][16]) {
  for (int row = 0; row < 16; row++) {
    for (int col = 0; col < 16; col++) {
      vga.dotFast(x + col, y + row, bmp[row][col]);
    }
  }
}

void drawCenteredText(const char *text, uint8_t color) {
  int len = strlen(text);
  int textWidth = len * FONT_W;
  int startX = (SCREEN_W - textWidth) / 2;
  int startY = (SCREEN_H - FONT_H) / 2;
  drawText(startX, startY, text, color);
}

void drawText(int x, int y, const char *text, uint8_t color) {
  while (*text) {
    drawChar(x, y, *text, color, COL_BLACK);
    x += FONT_W;
    text++;
  }
}


void allDemo() {
  // Linien
  fillScreen(COL_BLACK);
  vga.xLineFast(10, 20, 300, COL_WHITE);
  vga.line(20, 30, 150, 80, COL_RED);
  delay(2000);

  // Dreiecke
  fillScreen(COL_BLACK);
  vga.tri(30, 50, 100, 220, 110, 90, COL_GREEN);
  vga.fillTri(190, 160, 200, 290, 300, 90, COL_BLUE);
  delay(2000);

  // Rechtecke
  fillScreen(COL_BLACK);
  vga.rect(20, 10, 220, 90, COL_CYAN);
  vga.fillRect(80, 190, 190, 160, COL_RED);
  delay(2000);


  // Kreise
  fillScreen(COL_BLACK);
  vga.circle(30, 150, 140, COL_MAGENTA);
  vga.fillCircle(280, 280, 110, COL_YELLOW);
  delay(2000);

  // Ellipsen
  fillScreen(COL_BLACK);
  vga.ellipse(90, 140, 80, 60, COL_WHITE);
  vga.fillEllipse(220, 200, 120, 40, COL_BLUE);
  delay(2000);


  // smiley
  fillScreen(COL_BLACK);
  vga.fillCircle(200, 150, 140, COL_YELLOW);    //head
  vga.fillCircle(130, 120, 15, COL_BLACK);vga.fillCircle(270, 120, 15, COL_BLACK); //eyes
  vga.ellipse(200, 190, 100, 50, COL_BLACK);    //smile
  vga.fillEllipse(200, 180, 105, 50, COL_YELLOW);
  delay(3000);

  // Am Ende Bildschirm leeren
  fillScreen(COL_BLACK);
}

void smiley() { 
  fillScreen(COL_BLACK);
  vga.fillCircle(200, 150, 140, COL_YELLOW);    //head
  vga.fillCircle(130, 120, 15, COL_BLACK);vga.fillCircle(270, 120, 15, COL_BLACK); //eyes
  vga.ellipse(200, 190, 100, 50, COL_BLACK);    //smile
  vga.fillEllipse(200, 180, 105, 50, COL_YELLOW);
  delay(3000);
}


/*
VGA COMMANDS
=============

	void xLineFast(int x0, int x1, int y, int rgb);
	void line(int x1, int y1, int x2, int y2, int rgb);
	void tri(int x1, int y1, int x2, int y2, int x3, int y3, int rgb);
	void fillTri(int x1, int y1, int x2, int y2, int x3, int y3, int rgb);
	void squircle(int center_x, int center_y, int a, int b, float n, int rgb);
	void fillSquircle(int center_x, int center_y, int a, int b, float n, int rgb);
	void fillRect(int x, int y, int w, int h, int rgb);
	void rect(int x, int y, int w, int h, int rgb);
	void circle(int x, int y, int r, int rgb);
	void fillCircle(int x, int y, int r, int rgb);
	void ellipse(int x, int y, int rx, int ry, int rgb);
	void fillEllipse(int x, int y, int rx, int ry, int rgb);
	void mouse(int x1, int y1);
	
	void scrollText(int dy);
	void get(int x, int y);
	void dotAdd(int x, int y, int rgb);
	void scrollWindow(int x, int y, int w, int h, int dx, int dy);	
	void scrollFastWindow(int dx, int dy);

  */