#include <Arduino.h>

#include <LovyanGFX.hpp>

// ESP32でLovyanGFXを独自設定で利用する場合の設定例

/// 独自の設定を行うクラスを、LGFX_Deviceから派生して作成します。
class LGFX : public lgfx::LGFX_Device
{
  /*
   クラス名は"LGFX"から別の名前に変更しても構いません。
   AUTODETECTと併用する場合は"LGFX"は使用されているため、LGFX以外の名前に変更してください。
   また、複数枚のパネルを同時使用する場合もそれぞれに異なる名前を付けてください。
   ※ クラス名を変更する場合はコンストラクタの名前も併せて同じ名前に変更が必要です。

   名前の付け方は自由に決めて構いませんが、設定が増えた場合を想定し、
   例えばESP32 DevKit-CでSPI接続のILI9341の設定を行った場合、
    LGFX_DevKitC_SPI_ILI9341
   のような名前にし、ファイル名とクラス名を一致させておくことで、利用時に迷いにくくなります。
  //*/

  // 接続するパネルの型にあったインスタンスを用意します。
  // lgfx::Panel_GC9A01      _panel_instance;
  // lgfx::Panel_GDEW0154M09 _panel_instance;
  // lgfx::Panel_HX8357B     _panel_instance;
  // lgfx::Panel_HX8357D     _panel_instance;
  // lgfx::Panel_ILI9163     _panel_instance;
  // lgfx::Panel_ILI9341     _panel_instance;
  // lgfx::Panel_ILI9342     _panel_instance;
  // lgfx::Panel_ILI9481     _panel_instance;
  // lgfx::Panel_ILI9486     _panel_instance;
  // lgfx::Panel_ILI9488     _panel_instance;
  // lgfx::Panel_IT8951      _panel_instance;
  // lgfx::Panel_RA8875      _panel_instance;
  // lgfx::Panel_SH110x      _panel_instance; // SH1106, SH1107
  // lgfx::Panel_SSD1306     _panel_instance;
  // lgfx::Panel_SSD1327     _panel_instance;
  // lgfx::Panel_SSD1331     _panel_instance;
  // lgfx::Panel_SSD1351     _panel_instance; // SSD1351, SSD1357
  // lgfx::Panel_SSD1963     _panel_instance;
  // lgfx::Panel_ST7735      _panel_instance;
  // lgfx::Panel_ST7735S     _panel_instance;
  lgfx::Panel_ST7789 _panel_instance;
  // lgfx::Panel_ST7796      _panel_instance;

  // パネルを接続するバスの種類にあったインスタンスを用意します。
  lgfx::Bus_SPI _bus_instance; // SPIバスのインスタンス
  // lgfx::Bus_I2C        _bus_instance;   // I2Cバスのインスタンス
  // lgfx::Bus_Parallel8  _bus_instance;   // 8ビットパラレルバスのインスタンス

  // バックライト制御が可能な場合はインスタンスを用意します。(必要なければ削除)
  // lgfx::Light_PWM     _light_instance;

  // タッチスクリーンの型にあったインスタンスを用意します。(必要なければ削除)
  // lgfx::Touch_CST816S          _touch_instance;
  // lgfx::Touch_FT5x06           _touch_instance; // FT5206, FT5306, FT5406, FT6206, FT6236, FT6336, FT6436
  // lgfx::Touch_GSL1680E_800x480 _touch_instance; // GSL_1680E, 1688E, 2681B, 2682B
  // lgfx::Touch_GSL1680F_800x480 _touch_instance;
  // lgfx::Touch_GSL1680F_480x272 _touch_instance;
  // lgfx::Touch_GSLx680_320x320  _touch_instance;
  // lgfx::Touch_GT911            _touch_instance;
  // lgfx::Touch_STMPE610         _touch_instance;
  // lgfx::Touch_TT21xxx          _touch_instance; // TT21100
  // lgfx::Touch_XPT2046          _touch_instance;

public:
  // コンストラクタを作成し、ここで各種設定を行います。
  // クラス名を変更した場合はコンストラクタも同じ名前を指定してください。
  LGFX(void)
  {
    {                                    // バス制御の設定を行います。
      auto cfg = _bus_instance.config(); // バス設定用の構造体を取得します。

      // SPIバスの設定
      cfg.spi_host = SPI2_HOST; // 使用するSPIを選択  ESP32-S2,C3 : SPI2_HOST or SPI3_HOST / ESP32 : VSPI_HOST or HSPI_HOST
      // ※ ESP-IDFバージョンアップに伴い、VSPI_HOST , HSPI_HOSTの記述は非推奨になるため、エラーが出る場合は代わりにSPI2_HOST , SPI3_HOSTを使用してください。
      cfg.spi_mode = 0;                  // SPI通信モードを設定 (0 ~ 3)
      cfg.freq_write = 40000000;         // 送信時のSPIクロック (最大80MHz, 80MHzを整数で割った値に丸められます)
      cfg.freq_read = 16000000;          // 受信時のSPIクロック
      cfg.spi_3wire = true;              // 受信をMOSIピンで行う場合はtrueを設定
      cfg.use_lock = true;               // トランザクションロックを使用する場合はtrueを設定
      cfg.dma_channel = SPI_DMA_CH_AUTO; // 使用するDMAチャンネルを設定 (0=DMA不使用 / 1=1ch / 2=ch / SPI_DMA_CH_AUTO=自動設定)
      // ※ ESP-IDFバージョンアップに伴い、DMAチャンネルはSPI_DMA_CH_AUTO(自動設定)が推奨になりました。1ch,2chの指定は非推奨になります。
      cfg.pin_sclk = 2;  // SPIのSCLKピン番号を設定
      cfg.pin_mosi = 3;  // SPIのMOSIピン番号を設定
      cfg.pin_miso = -1; // SPIのMISOピン番号を設定 (-1 = disable)
      cfg.pin_dc = 8;    // SPIのD/Cピン番号を設定  (-1 = disable)
                         // SDカードと共通のSPIバスを使う場合、MISOは省略せず必ず設定してください。
                         //*/
                         /*
                         // I2Cバスの設定
                               cfg.i2c_port    = 0;          // 使用するI2Cポートを選択 (0 or 1)
                               cfg.freq_write  = 400000;     // 送信時のクロック
                               cfg.freq_read   = 400000;     // 受信時のクロック
                               cfg.pin_sda     = 21;         // SDAを接続しているピン番号
                               cfg.pin_scl     = 22;         // SCLを接続しているピン番号
                               cfg.i2c_addr    = 0x3C;       // I2Cデバイスのアドレス
                         //*/
                         /*
                         // 8ビットパラレルバスの設定
                               cfg.i2s_port = I2S_NUM_0;     // 使用するI2Sポートを選択 (I2S_NUM_0 or I2S_NUM_1) (ESP32のI2S LCDモードを使用します)
                               cfg.freq_write = 20000000;    // 送信クロック (最大20MHz, 80MHzを整数で割った値に丸められます)
                               cfg.pin_wr =  4;              // WR を接続しているピン番号
                               cfg.pin_rd =  2;              // RD を接続しているピン番号
                               cfg.pin_rs = 15;              // RS(D/C)を接続しているピン番号
                               cfg.pin_d0 = 12;              // D0を接続しているピン番号
                               cfg.pin_d1 = 13;              // D1を接続しているピン番号
                               cfg.pin_d2 = 26;              // D2を接続しているピン番号
                               cfg.pin_d3 = 25;              // D3を接続しているピン番号
                               cfg.pin_d4 = 17;              // D4を接続しているピン番号
                               cfg.pin_d5 = 16;              // D5を接続しているピン番号
                               cfg.pin_d6 = 27;              // D6を接続しているピン番号
                               cfg.pin_d7 = 14;              // D7を接続しているピン番号
                         //*/

      _bus_instance.config(cfg);              // 設定値をバスに反映します。
      _panel_instance.setBus(&_bus_instance); // バスをパネルにセットします。
    }

    {                                      // 表示パネル制御の設定を行います。
      auto cfg = _panel_instance.config(); // 表示パネル設定用の構造体を取得します。

      cfg.pin_cs = 5;    // CSが接続されているピン番号   (-1 = disable)
      cfg.pin_rst = 7;   // RSTが接続されているピン番号  (-1 = disable)
      cfg.pin_busy = -1; // BUSYが接続されているピン番号 (-1 = disable)

      // ※ 以下の設定値はパネル毎に一般的な初期値が設定されていますので、不明な項目はコメントアウトして試してみてください。

      cfg.panel_width = 135;    // 実際に表示可能な幅
      cfg.panel_height = 240;   // 実際に表示可能な高さ
      cfg.offset_x = 53;         // パネルのX方向オフセット量
      cfg.offset_y = 40;         // パネルのY方向オフセット量
      cfg.offset_rotation = 0;  // 回転方向の値のオフセット 0~7 (4~7は上下反転)
      cfg.dummy_read_pixel = 8; // ピクセル読出し前のダミーリードのビット数
      cfg.dummy_read_bits = 1;  // ピクセル以外のデータ読出し前のダミーリードのビット数
      cfg.readable = true;      // データ読出しが可能な場合 trueに設定
      cfg.invert = false;       // パネルの明暗が反転してしまう場合 trueに設定
      cfg.rgb_order = false;    // パネルの赤と青が入れ替わってしまう場合 trueに設定
      cfg.dlen_16bit = false;   // 16bitパラレルやSPIでデータ長を16bit単位で送信するパネルの場合 trueに設定
      cfg.bus_shared = true;    // SDカードとバスを共有している場合 trueに設定(drawJpgFile等でバス制御を行います)

      // 以下はST7735やILI9163のようにピクセル数が可変のドライバで表示がずれる場合にのみ設定してください。
      //    cfg.memory_width     =   240;  // ドライバICがサポートしている最大の幅
      //    cfg.memory_height    =   320;  // ドライバICがサポートしている最大の高さ

      _panel_instance.config(cfg);
    }

    // //*
    //     { // バックライト制御の設定を行います。(必要なければ削除)
    //       auto cfg = _light_instance.config();    // バックライト設定用の構造体を取得します。

    //       cfg.pin_bl = 32;              // バックライトが接続されているピン番号
    //       cfg.invert = false;           // バックライトの輝度を反転させる場合 true
    //       cfg.freq   = 44100;           // バックライトのPWM周波数
    //       cfg.pwm_channel = 7;          // 使用するPWMのチャンネル番号

    //       _light_instance.config(cfg);
    //       _panel_instance.setLight(&_light_instance);  // バックライトをパネルにセットします。
    //     }
    // //*/

    // //*
    //     { // タッチスクリーン制御の設定を行います。(必要なければ削除)
    //       auto cfg = _touch_instance.config();

    //       cfg.x_min      = 0;    // タッチスクリーンから得られる最小のX値(生の値)
    //       cfg.x_max      = 239;  // タッチスクリーンから得られる最大のX値(生の値)
    //       cfg.y_min      = 0;    // タッチスクリーンから得られる最小のY値(生の値)
    //       cfg.y_max      = 319;  // タッチスクリーンから得られる最大のY値(生の値)
    //       cfg.pin_int    = 38;   // INTが接続されているピン番号
    //       cfg.bus_shared = true; // 画面と共通のバスを使用している場合 trueを設定
    //       cfg.offset_rotation = 0;// 表示とタッチの向きのが一致しない場合の調整 0~7の値で設定

    // // SPI接続の場合
    //       cfg.spi_host = VSPI_HOST;// 使用するSPIを選択 (HSPI_HOST or VSPI_HOST)
    //       cfg.freq = 1000000;     // SPIクロックを設定
    //       cfg.pin_sclk = 18;     // SCLKが接続されているピン番号
    //       cfg.pin_mosi = 23;     // MOSIが接続されているピン番号
    //       cfg.pin_miso = 19;     // MISOが接続されているピン番号
    //       cfg.pin_cs   =  5;     //   CSが接続されているピン番号

    // // I2C接続の場合
    //       cfg.i2c_port = 1;      // 使用するI2Cを選択 (0 or 1)
    //       cfg.i2c_addr = 0x38;   // I2Cデバイスアドレス番号
    //       cfg.pin_sda  = 23;     // SDAが接続されているピン番号
    //       cfg.pin_scl  = 32;     // SCLが接続されているピン番号
    //       cfg.freq = 400000;     // I2Cクロックを設定

    //       _touch_instance.config(cfg);
    //       _panel_instance.setTouch(&_touch_instance);  // タッチスクリーンをパネルにセットします。
    //     }
    // //*/

    setPanel(&_panel_instance); // 使用するパネルをセットします。
  }
};

// 準備したクラスのインスタンスを作成します。
static LGFX lcd;
static LGFX_Sprite sprite(&lcd);
// void setup(void)
// {
//   // SPIバスとパネルの初期化を実行すると使用可能になります。
//   display.init();

//   display.setTextSize((std::max(display.width(), display.height()) + 255) >> 8);

//   // タッチが使用可能な場合のキャリブレーションを行います。(省略可)
//   if (display.touch())
//   {
//     if (display.width() < display.height())
//       display.setRotation(display.getRotation() ^ 1);

//     // 画面に案内文章を描画します。
//     display.setTextDatum(textdatum_t::middle_center);
//     display.drawString("touch the arrow marker.", display.width() >> 1, display.height() >> 1);
//     display.setTextDatum(textdatum_t::top_left);

//     // タッチを使用する場合、キャリブレーションを行います。画面の四隅に表示される矢印の先端を順にタッチしてください。
//     std::uint16_t fg = TFT_WHITE;
//     std::uint16_t bg = TFT_BLACK;
//     if (display.isEPD())
//       std::swap(fg, bg);
//     display.calibrateTouch(nullptr, fg, bg, std::max(display.width(), display.height()) >> 3);
//   }

//   display.fillScreen(TFT_BLACK);
// }

// uint32_t count = ~0;
// void loop(void)
// {
//   display.startWrite();
//   display.setRotation(++count & 7);
//   display.setColorDepth((count & 8) ? 16 : 24);

//   display.setTextColor(TFT_WHITE);
//   display.drawNumber(display.getRotation(), 16, 0);

//   display.setTextColor(0xFF0000U);
//   display.drawString("R", 30, 16);
//   display.setTextColor(0x00FF00U);
//   display.drawString("G", 40, 16);
//   display.setTextColor(0x0000FFU);
//   display.drawString("B", 50, 16);

//   display.drawRect(30, 30, display.width() - 60, display.height() - 60, count * 7);
//   display.drawFastHLine(0, 0, 10);

//   display.endWrite();

//   int32_t x, y;
//   if (display.getTouch(&x, &y))
//   {
//     display.fillRect(x - 2, y - 2, 5, 5, count * 7);
//   }
// }

void setup(void)
{
// 最初に初期化関数を呼び出します。
  lcd.init();


// 回転方向を 0~3 の4方向から設定します。(4~7を使用すると上下反転になります。)
  lcd.setRotation(1);


// バックライトの輝度を 0~255 の範囲で設定します。
  lcd.setBrightness(128);


// 必要に応じてカラーモードを設定します。(初期値は16)
// 16の方がSPI通信量が少なく高速に動作しますが、赤と青の諧調が5bitになります。
// 24の方がSPI通信量が多くなりますが、諧調表現が綺麗になります。
//lcd.setColorDepth(16);  // RGB565の16ビットに設定
  lcd.setColorDepth(24);  // RGB888の24ビットに設定(表示される色数はパネル性能によりRGB666の18ビットになります)


// 基本的な図形の描画関数は以下の通りです。
/*
  fillScreen    (                color);  // 画面全体の塗り潰し
  drawPixel     ( x, y         , color);  // 点
  drawFastVLine ( x, y   , h   , color);  // 垂直線
  drawFastHLine ( x, y, w      , color);  // 水平線
  drawRect      ( x, y, w, h   , color);  // 矩形の外周
  fillRect      ( x, y, w, h   , color);  // 矩形の塗り
  drawRoundRect ( x, y, w, h, r, color);  // 角丸の矩形の外周
  fillRoundRect ( x, y, w, h, r, color);  // 角丸の矩形の塗り
  drawCircle    ( x, y      , r, color);  // 円の外周
  fillCircle    ( x, y      , r, color);  // 円の塗り
  drawEllipse   ( x, y, rx, ry , color);  // 楕円の外周
  fillEllipse   ( x, y, rx, ry , color);  // 楕円の塗り
  drawLine      ( x0, y0, x1, y1        , color); // 2点間の直線
  drawTriangle  ( x0, y0, x1, y1, x2, y2, color); // 3点間の三角形の外周
  fillTriangle  ( x0, y0, x1, y1, x2, y2, color); // 3点間の三角形の塗り
  drawBezier    ( x0, y0, x1, y1, x2, y2, color); // 3点間のベジエ曲線
  drawBezier    ( x0, y0, x1, y1, x2, y2, x3, y3, color); // 4点間のベジエ曲線
  drawArc       ( x, y, r0, r1, angle0, angle1, color);   // 円弧の外周
  fillArc       ( x, y, r0, r1, angle0, angle1, color);   // 円弧の塗り
*/


// 例えばdrawPixelで点を書く場合は、引数は X座標,Y座標,色 の3つ。
  lcd.drawPixel(0, 0, 0xFFFF); // 座標0:0に白の点を描画


// カラーコードを生成する関数が用意されており、色の指定に使用できます。
// 引数は、赤,緑,青をそれぞれ 0~255で指定します。
// 色情報の欠落を防ぐため、color888を使う事を推奨します。
  lcd.drawFastVLine(2, 0, 100, lcd.color888(255,   0,   0)); // 赤で垂直の線を描画
  lcd.drawFastVLine(4, 0, 100, lcd.color565(  0, 255,   0)); // 緑で垂直の線を描画
  lcd.drawFastVLine(6, 0, 100, lcd.color332(  0,   0, 255)); // 青で垂直の線を描画


// カラーコード生成関数を使用しない場合は以下のようになります。
// RGB888 24ビットで指定 uint32_t型
// RGB565 16ビットで指定 uint16_t型、int32_t型
// RGB332  8ビットで指定 uint8_t型

// uint32_t型を使用すると、RGB888の24ビットとして扱われます。
// 16進数2桁で赤緑青の順に記述できます。
// uint32_t型の変数を使うか、末尾にUを付けるか、uint32_t型にキャストして使用します。
  uint32_t red = 0xFF0000;
  lcd.drawFastHLine(0, 2, 100, red);            // 赤で水平の線を描画
  lcd.drawFastHLine(0, 4, 100, 0x00FF00U);      // 緑で水平の線を描画
  lcd.drawFastHLine(0, 6, 100, (uint32_t)0xFF); // 青で水平の線を描画


// uint16_t型およびint32_t型を使用すると、RGB565の16ビットとして扱われます。
// 特別な書き方をしない場合はint32_t型として扱われるので、この方式になります。
// (AdafruitGFX や TFT_eSPI との互換性のために、このようにしています。)
  uint16_t green = 0x07E0;
  lcd.drawRect(10, 10, 50, 50, 0xF800);         // 赤で矩形の外周を描画
  lcd.drawRect(12, 12, 50, 50, green);          // 緑で矩形の外周を描画
  lcd.drawRect(14, 14, 50, 50, (uint16_t)0x1F); // 青で矩形の外周を描画


// int8_t型、uint8_t型を使用すると、RGB332の8ビットとして扱われます。
  uint8_t blue = 0x03;
  lcd.fillRect(20, 20, 20, 20, (uint8_t)0xE0);  // 赤で矩形の塗りを描画
  lcd.fillRect(30, 30, 20, 20, (uint8_t)0x1C);  // 緑で矩形の塗りを描画
  lcd.fillRect(40, 40, 20, 20, blue);           // 青で矩形の塗りを描画


// 描画関数の引数の色は省略できます。
// 省略した場合、setColor関数で設定した色 または最後に使用した色を描画色として使用します。
// 同じ色で繰り返し描画する場合は、省略した方がわずかに速く動作します。
  lcd.setColor(0xFF0000U);                        // 描画色に赤色を指定
  lcd.fillCircle ( 40, 80, 20    );               // 赤色で円の塗り
  lcd.fillEllipse( 80, 40, 10, 20);               // 赤色で楕円の塗り
  lcd.fillArc    ( 80, 80, 20, 10, 0, 90);        // 赤色で円弧の塗り
  lcd.fillTriangle(80, 80, 60, 80, 80, 60);       // 赤色で三角の塗り
  lcd.setColor(0x0000FFU);                        // 描画色に青色を指定
  lcd.drawCircle ( 40, 80, 20    );               // 青色で円の外周
  lcd.drawEllipse( 80, 40, 10, 20);               // 青色で楕円の外周
  lcd.drawArc    ( 80, 80, 20, 10, 0, 90);        // 青色で円弧の外周
  lcd.drawTriangle(60, 80, 80, 80, 80, 60);       // 青色で三角の外周
  lcd.setColor(0x00FF00U);                        // 描画色に緑色を指定
  lcd.drawBezier( 60, 80, 80, 80, 80, 60);        // 緑色で二次ベジエ曲線
  lcd.drawBezier( 60, 80, 80, 20, 20, 80, 80, 60);// 緑色で三次ベジエ曲線

// グラデーションの線を描画するdrawGradientLine は色の指定を省略できません。
  lcd.drawGradientLine( 0, 80, 80, 0, 0xFF0000U, 0x0000FFU);// 赤から青へのグラデーション直線

  delay(1000);

// clearまたはfillScreenで画面全体を塗り潰せます。
// fillScreenはfillRectの画面全体を指定したのと同じで、色の指定は描画色の扱いになります。
  lcd.fillScreen(0xFFFFFFu);  // 白で塗り潰し
  lcd.setColor(0x00FF00u);    // 描画色に緑色を指定
  lcd.fillScreen();           // 緑で塗り潰し

// clearは描画系の関数とは別で背景色という扱いで色を保持しています。
// 背景色は出番が少ないですが、スクロール機能使用時の隙間を塗る色としても使用されます。
  lcd.clear(0xFFFFFFu);       // 背景色に白を指定して塗り潰し
  lcd.setBaseColor(0x000000u);// 背景色に黒を指定
  lcd.clear();                // 黒で塗り潰し


// SPIバスの確保と解放は描画関数を呼び出した時に自動的に行われますが、
// 描画スピードを重視する場合は、描画処理の前後に startWriteとendWriteを使用します。
// SPIバスの確保と解放が抑制され、速度が向上します。
// 電子ペーパー(EPD)の場合、startWrite()以降の描画は、endWrite()を呼ぶ事で画面に反映されます。
  lcd.drawLine(0, 1, 39, 40, red);       // SPIバス確保、線を描画、SPIバス解放
  lcd.drawLine(1, 0, 40, 39, blue);      // SPIバス確保、線を描画、SPIバス解放
  lcd.startWrite();                      // SPIバス確保
  lcd.drawLine(38, 0, 0, 38, 0xFFFF00U); // 線を描画
  lcd.drawLine(39, 1, 1, 39, 0xFF00FFU); // 線を描画
  lcd.drawLine(40, 2, 2, 40, 0x00FFFFU); // 線を描画
  lcd.endWrite();                        // SPIバス解放


// startWriteとendWriteは呼出し回数を内部でカウントしており、
// 繰り返し呼び出した場合は最初と最後のみ動作します。
// startWriteとendWriteは必ず対になるように使用してください。
// (SPIバスを占有して構わない場合は、最初にstartWriteを一度呼び、endWriteしない使い方も可能です。)
  lcd.startWrite();     // カウント+1、SPIバス確保
  lcd.startWrite();     // カウント+1
  lcd.startWrite();     // カウント+1
  lcd.endWrite();       // カウント-1
  lcd.endWrite();       // カウント-1
  lcd.endWrite();       // カウント-1、SPIバス解放
  lcd.endWrite();       // 何もしない
// なお過剰にendWriteを呼び出した場合は何も行わず、カウントがマイナスになることもありません。


// startWriteのカウントの状態に依らず、強制的にSPIバスを解放・確保したい場合は、
// endTransaction・beginTransactionを使用します。
// カウントはクリアされないので、辻褄が合わなくならないよう注意してください。
  lcd.startWrite();       // カウント+1、SPIバス確保
  lcd.startWrite();       // カウント+1
  lcd.drawPixel(0, 0);    // 描画
  lcd.endTransaction();   // SPIバス解放
  // ここで他のSPIデバイスの使用が可能
  // 同じSPIバスの別のデバイス(SDカード等)を使う場合、
  // 必ずSPIバスが解放された状態で行ってください。
  lcd.beginTransaction(); // SPIバスの確保
  lcd.drawPixel(0, 0);    // 描画
  lcd.endWrite();         // カウント-1
  lcd.endWrite();         // カウント-1、SPIバス解放



// drawPixelとは別に、writePixelという点を描画する関数があります。
// drawPixelは必要に応じてSPIバスの確保を行うのに対し、
// writePixelはSPIバスの状態をチェックしません。
  lcd.startWrite();  // SPIバス確保
  for (uint32_t x = 0; x < 128; ++x) {
    for (uint32_t y = 0; y < 128; ++y) {
      lcd.writePixel(x, y, lcd.color888( x*2, x + y, y*2));
    }
  }
  lcd.endWrite();    // SPIバス解放
// 名前が write~ で始まる関数は全て明示的にstartWriteを呼び出しておく必要があります。
// writePixel、writeFastVLine、writeFastHLine、writeFillRect が該当します。

  delay(1000);

// スプライト(オフスクリーン)への描画も同様の描画関数が使えます。
// 最初にスプライトの色深度をsetColorDepthで指定します。(省略した場合は16として扱われます。)
//sprite.setColorDepth(1);   // 1ビット( 2色)パレットモードに設定
//sprite.setColorDepth(2);   // 2ビット( 4色)パレットモードに設定
//sprite.setColorDepth(4);   // 4ビット(16色)パレットモードに設定
//sprite.setColorDepth(8);   // RGB332の8ビットに設定
//sprite.setColorDepth(16);  // RGB565の16ビットに設定
  sprite.setColorDepth(24);  // RGB888の24ビットに設定


// ※ setColorDepth(8);を設定後に createPalette()を呼ぶ事で、256色パレットモードになります
// sprite.createPalette();


// createSpriteで幅と高さを指定してメモリを確保します。
// 消費するメモリは色深度と面積に比例します。大きすぎるとメモリ確保に失敗しますので注意してください。
  sprite.createSprite(65, 65); // 幅65、高さ65でスプライトを作成。

  for (uint32_t x = 0; x < 64; ++x) {
    for (uint32_t y = 0; y < 64; ++y) {
      sprite.drawPixel(x, y, lcd.color888(3 + x*4, (x + y)*2, 3 + y*4));  // スプライトに描画
    }
  }
  sprite.drawRect(0, 0, 65, 65, 0xFFFF);

// 作成したスプライトはpushSpriteで任意の座標に出力できます。
// 出力先はインスタンス作成時に引数で渡したLGFXになります。
  sprite.pushSprite(64, 0);        // lcdの座標64,0にスプライトを描画

// spriteのインスタンス作成時に描画先のポインタを渡していない場合や、
// 複数のLGFXがある場合などは、出力先を第一引数に指定してpushSpriteすることもできます。
  sprite.pushSprite(&lcd, 0, 64);  // lcdの座標0,64にスプライトを描画

  delay(1000);

  // pushRotateZoomでスプライトを回転拡大縮小して描画できます。
  // setPivotで設定した座標が回転中心として扱われ、描画先の座標に回転中心が位置するように描画されます。
  sprite.setPivot(32, 32);    // 座標32,32を中心として扱う
  int32_t center_x = lcd.width()/2;
  int32_t center_y = lcd.height()/2;
  lcd.startWrite();
  for (int angle = 0; angle <= 360; ++angle) {
    sprite.pushRotateZoom(center_x, center_y, angle, 2.5, 3); // 画面中心に角度angle、幅2.5倍、高さ3倍で描画

    if ((angle % 36) == 0) lcd.display(); // 電子ペーパーの場合の表示更新を 36回に一度行う
  }
  lcd.endWrite();

  delay(1000);

  // 使用しなくなったスプライトのメモリを解放するには deleteSprite を使用します。
  sprite.deleteSprite();

  // deleteSprite の後でも、同じインスタンスの再利用が可能です。
  sprite.setColorDepth(4);     // 4ビット(16色)パレットモードに設定
  sprite.createSprite(65, 65);

  // パレットモードのスプライトでは、描画関数の引数の色をパレット番号として扱います。
  // pushSprite等で描画する際に、パレットを参照して実際の描画色が決まります。

  // 4ビット(16色)パレットモードの場合、パレット番号は0~15が使用可能です。
  // パレットの初期色は、0が黒,末尾のパレットが白で、0から末尾にかけてグラデーションになっています。
  // パレットの色を設定するには setPaletteColor を使用します。
  sprite.setPaletteColor(1, 0x0000FFU);    // パレット1番を青に設定
  sprite.setPaletteColor(2, 0x00FF00U);    // パレット2番を緑に設定
  sprite.setPaletteColor(3, 0xFF0000U);    // パレット3番を赤に設定

  sprite.fillRect(10, 10, 45, 45, 1);             // パレット1番で矩形の塗り
  sprite.fillCircle(32, 32, 22, 2);               // パレット2番で円の塗り
  sprite.fillTriangle(32, 12, 15, 43, 49, 43, 3); // パレット3番で三角の塗り

  // pushSpriteの最後の引数で、描画しない色を指定することができます。
  sprite.pushSprite( 0,  0, 0);  // パレット0を透過扱いでスプライトを描画
  sprite.pushSprite(65,  0, 1);  // パレット1を透過扱いでスプライトを描画
  sprite.pushSprite( 0, 65, 2);  // パレット2を透過扱いでスプライトを描画
  sprite.pushSprite(65, 65, 3);  // パレット3を透過扱いでスプライトを描画

  delay(5000);

  lcd.startWrite(); // ここでstartWrite()することで、SPIバスを占有したままにする。
}

void loop(void)
{
  static int count = 0;
  static int a = 0;
  static int x = 0;
  static int y = 0;
  static float zoom = 3;
  ++count;
  if ((a += 1) >= 360) a -= 360;
  if ((x += 2) >= lcd.width()) x -= lcd.width();
  if ((y += 1) >= lcd.height()) y -= lcd.height();
  sprite.setPaletteColor(1, lcd.color888( 0, 0, count & 0xFF));
  sprite.setPaletteColor(2, lcd.color888( 0,~count & 0xFF, 0));
  sprite.setPaletteColor(3, lcd.color888( count & 0xFF, 0, 0));

  sprite.pushRotateZoom(x, y, a, zoom, zoom, 0);

  if ((count % 100) == 0) lcd.display(); // 電子ペーパーの場合の表示更新を 100回に一度行う
}