ダイナミックL8画像の作成
このセクションでは、ダイナミックL8画像の使用方法、特にパレットの作成方法について説明します。
ダイナミック・ビットマップの概要についてはこちら、L8画像フォーマットの概要についてはこちらをお読みください。
ダイナミックL8画像
ダイナミックL8ビットマップは、他のダイナミック・ビットマップと同じように作成されますが、ビットマップ用に作成するパレットのタイプを指定する必要がある点が異なります。
TouchGFXは、以下の3つのタイプのパレットをサポートしています。
パレット | 説明 |
---|---|
CLUT_FORMAT_L8_ARGB8888 | 32ビット、赤色、緑色、青色、ピクセル・アルファチャンネルそれぞれに8ビット |
CLUT_FORMAT_L8_RGB888 | 24ビット、赤色、緑色、青色それぞれに8ビットで、ピクセル・アルファチャンネルなし |
CLUT_FORMAT_L8_RGB565 | 16ビット、赤色には5ビット、緑色には6ビット、青色には5ビットで、ピクセル・アルファチャンネルなし |
24ビット・パレットによるダイナミックL8画像の作成
ここでは、24ビット・パレットで100x100ピクセルのL8ビットマップを作成します。
Screen1View.cpp
BitmapId dynamicBitmap1 = Bitmap::dynamicBitmapCreateL8(100, 100, Bitmap::CLUT_FORMAT_L8_RGB888, 256);
この呼び出しで、100x100 L8ビットマップと24ビット・パレットが、ビットマップ・キャッシュ内に割り当てられました。 パレットにはダイナミック・ビットマップ用に256色が保持されていますが、この色数はメモリ消費を抑えるために目的のサイズに調整できます。
パレットへのアクセス
(最初の32ビットが割り当てられたアドレスの)ピクセルのすぐ後の2バイトには、L8パレット・フォーマットが(リトル・エンディアンで)格納され、その後の2バイトには、パレット内のエントリ数が(リトル・エンディアンで)格納されます。その後には実際のパレットの色が続きます。 つまり、パレットの色はピクセル(32ビット割当て)の4バイト後ろに配置されます。
パレットのポインタ(現時点で未初期化)は次のようにして取得できます。
Screen1View.cpp
//Get a pointer to the bitmap data (pixels and palette)
uint8_t* data = Bitmap::dynamicBitmapGetAddress(dynamicBitmap1);
//1 byte pr pixel, round up to 32-bit
uint32_t byteSize = 100*100;
byteSize = ((byteSize + 3) & ~3);
//Palette size is saved in byte 2 and 3
int palSize = (data[3] << 8) | data[2];
//Palette starts four bytes after the pixels
uint8_t* pal = (data + byteSize + 4);
ダイナミックL8ビットマップの例
ここからは、ダイナミックL8ビットマップの作成方法とパレットの操作方法について、例を通して見ていきます。 パレットの操作は、一般的なアプリケーションでは通常は行いません。 以下の例は、パレットにアクセスして生成する方法の実例を示します。
まず、TouchGFX Designerでスクリーンを作成し、バックグラウンドに白いボックスを挿入し、たとえばx=140, y=8の位置に画像を挿入します。
次にコードを生成して、Screen1View.cppファイルを開きます。 ビットマップ・キャッシュを初期化してダイナミック・ビットマップを作成するためのコードを、setupScreenに挿入する必要があります。
200x256ピクセルのビットマップを作成します。 L8ビットマップ内の各ピクセルは1バイトであることを覚えておいてください。 画像の各行に異なる色を付けます。 最初の行はカラー0、最後の行はカラー255です。
次にパレット内の色を初期化します。 パレットの開始アドレスを計算し、256色のRGB値を設定します。 ここでは、緑色から赤色へ移り、再び緑色に戻る色を作成します。
Screen1View.cpp
#ifdef SIMULATOR
uint32_t cacheBuffer[320*1024/4]; //simulate PSRAM
uint16_t* psram = (uint16_t*)cacheBuffer;
#else
uint16_t* psram = (uint16_t*)(0xd0000000 + 480*272*2*2); //Address after two 16bit framebuffers
#endif
Screen1View::Screen1View()
{
}
void Screen1View::setupScreen()
{
Screen1ViewBase::setupScreen();
//Create one dynamic bitmap
Bitmap::setCache(psram, 320*1024, 1); //320Kb cache
const uint16_t palSize = 256;
BitmapId dynamicBitmap1 = Bitmap::dynamicBitmapCreateL8(200, 256, Bitmap::CLUT_FORMAT_L8_RGB888, palSize);
imageDynamic.setBitmap(Bitmap(dynamicBitmap1));
if (dynamicBitmap1 == BITMAP_INVALID)
{
touchgfx_printf("Unable to create dynamic bitmap\n");
}
else
{
uint8_t* data = Bitmap::dynamicBitmapGetAddress(dynamicBitmap1);
uint8_t* pixel = data;
//make colored rows
for (int y = 0; y<256; y++)
{
for (int x = 0; x<200; x++)
{
*pixel++ = y;
}
}
uint32_t byteSize = 200*256;
byteSize = ((byteSize + 3) & ~3);
//Palette starts four bytes after the pixels
uint8_t* pal = (data + byteSize + 4);
//Make palette with 256 colors from green to red to green
for (int i = 0; i < palSize; i++)
{
//BGR
pal[i * 3 + 0] = 0x00;
pal[i * 3 + 1] = 127 * (1 + cosf(i * 6.28f / (palSize - 1)));
pal[i * 3 + 2] = 255 * (sinf(i * 3.14f / (palSize - 1)));
}
}
}
これによって、スクリーンは次のような表示になります。
パレットの操作
ダイナミックL8ビットマップに使用するパレットにアクセスできれば、簡単にパレットを操作できます。
ここでは、1インデックスずつ下に色を循環させ、すべてのフレームの画像を強制的に再描画します。
Screen1View.cpp
...
void Screen1View::handleTickEvent()
{
//get palette address
uint8_t* data = Bitmap::dynamicBitmapGetAddress(imageDynamic.getBitmap());
uint32_t byteSize = 200*256;
byteSize = ((byteSize + 3) & ~3);
const int palSize = (data[3] << 8) | data[2];
uint8_t* pal = (data + byteSize + 4);
//Cycle palette, copy color 0
int8_t blue = pal[0], green = pal[1], red = pal[2];
//Move palette down, 1->0, 2->1, ...
for (int i = 3; i < palSize * 3; i++)
{
pal[i - 3] = pal[i];
}
//Insert color 0 as color 255
pal[(palSize - 1) * 3 + 0] = blue;
pal[(palSize - 1) * 3 + 1] = green;
pal[(palSize - 1) * 3 + 2] = red;
//Force redraw by invalidating
imageDynamic.invalidate();
}
これによって、ダイナミック・ビットマップ内の色が「上方に」移動します。