동적 비트맵
이 섹션에서는 동적 비트맵을 사용하는 방법을 알아보겠습니다. 먼저 애플리케이션으로 컴파일되는 것은 표준 비트맵이기 때문에 컴파일할 때는 표준 비트맵을 사용해야 합니다. 비트맵은 PNG 파일 등에서 변환되어 크기 및 형식 정보와 함께 내부 형식으로 저장됩니다.
또한 런타임에서는 비트맵을 RAM에서 생성하는 것도 가능합니다. 이를 동적 비트맵이라고 합니다. 다만 동적 비트맵은 애플리케이션에 컴파일되는 정적 비트맵으로만 사용됩니다. 따라서 동적 비트맵을 Image 위젯과 Button 위젯에서 사용할 수 있습니다.
동적 비트맵 구성
동적 비트맵을 생성하면 비트맵 캐시에서 픽셀 메모리가 할당됩니다. 따라서 동적 비트맵을 생성하려면 먼저 비트맵 캐시를 구성해야 합니다. 비트맵 캐시는 TouchGFX Designer나 Generator에서 구성할 수 없기 때문에 직접 구성해야 합니다.
자세한 구성 방법은 비트맵 캐싱에서 해당 섹션을 참조하십시오.
애플리케이션에서 사용할 동적 비트맵의 최대 수를 정의해야 합니다. 이 최대 값은 비트맵 캐시 주소 및 크기와 함께 TouchGFX로 전달됩니다. 여기에서는 동적 비트맵의 최대 수를 4로 지정하여 비트맵 캐시를 구성합니다. 애플리케이션에 있는 모든 파일에서 이러한 구성을 수행할 수 있습니다. 단 한 번만 구성해야 한다면 FrontendApplication.cpp 파일이 좋습니다.
FrontendApplication.cpp (extract)
#include <gui/common/FrontendApplication.hpp>
#include <touchgfx/Bitmap.hpp>
FrontendApplication::FrontendApplication(Model& m, FrontendHeap& heap)
: FrontendApplicationBase(m, heap)
{
// Place cache start address in SDRAM at address 0xC0008000;
uint16_t* const cacheStartAddr = (uint16_t*)0xC0008000;
const uint32_t cacheSize = 0x300000; //3 MB, as example
Bitmap::setCache(cacheStartAddr, cacheSize, 4);
}
Windows 시뮬레이터를 사용하는 경우에도 여기에서 비트맵 캐시를 생성해야 합니다. Windows에서는 큰 배열을 선언하거나 malloc을 사용하는 것이 쉽습니다.
FrontendApplication.cpp (extract)
#include <gui/common/FrontendApplication.hpp>
#include <touchgfx/Bitmap.hpp>
FrontendApplication::FrontendApplication(Model& m, FrontendHeap& heap)
: FrontendApplicationBase(m, heap)
{
#ifdef SIMULATOR
const uint32_t cacheSize = 0x300000; //3 MB, as example
uint16_t* const cacheStartAddr = (uint16_t*)malloc(cacheSize);
Bitmap::setCache(cacheStartAddr, cacheSize, 4);
#else
// Place cache start address in SDRAM at address 0xC0008000;
uint16_t* const cacheStartAddr = (uint16_t*)0xC0008000;
const uint32_t cacheSize = 0x300000; //3 MB, as example
Bitmap::setCache(cacheStartAddr, cacheSize, 4);
#endif
}
동적 비트맵 사용 예
동적 비트맵을 사용하려면 표시할 위젯이 필요합니다. 따라서 다음과 같이 Image 위젯을 View에 삽입합니다(코드 또는 Designer에서).
#include <touchgfx/widgets/Image.hpp>
using namespace touchgfx;
class TemplateView : public View
{
private:
Image image;
}
동적 비트맵을 이 위젯에 사용하는 프로세스는 다음과 같이 3단계로 구성됩니다.
- 비트맵 캐시에서 동적 비트맵 생성
- 동적 비트맵에서 사용할 메모리 소거
- 비트맵을 위젯에 할당
setupScreen에서 동적 비트맵을 생성합니다. 여기에서는 16bpp RGB565 형식을 사용합니다. 만약 프레임버퍼가 24비트라면 RGB888 형식을 사용하고, 투명한 비트맵을 생성하려면 ARGB8888 형식을 사용합니다.
동적 비트맵의 픽셀 주소는 dynamicBitmapGetAddress 함수에서 반환됩니다.
#include <touchgfx/Bitmap.hpp>
void TemplateView::setupScreen()
{
BitmapId bmpId;
//Create (16bit) dynamic bitmap of size 100x150
const int width = 100;
const int height = 150;
bmpId = Bitmap::dynamicBitmapCreate(100, 150, Bitmap::RGB565);
//set all pixels white
if (bmpId != BITMAP_INVALID)
{
memset(Bitmap::dynamicBitmapGetAddress(bmpId), 0xFF, width*height*2);
}
//Make Image widget show the dynamic bitmap
image.setBitmap(Bitmap(bmpId));
//Position image and add to View
image.setXY(20, 20);
add(image);
...
}
비트맵 캐시에서 가져오는 픽셀 메모리는 소거되지 않기 때문에 바로 소거하거나 덮어쓰는 것이 좋습니다.
파일에서 이미지를 로드하고 싶다면 memset 호출을 로더 코드로 대체하면 됩니다. 자세한 내용은 런타임에서 이미지 로드를 참조하십시오.
동적 비트맵 연산
동적 비트맵 연산은 모두 비트맵 클래스에서 처리됩니다.
동적 비트맵 생성하기
다음 메소드는 지정된 가로, 세로 및 비트맵 형식으로 동적 비트맵을 생성합니다. 비트맵은 미사용 메모리가 충분한 경우에만 생성됩니다. 비트맵이 생성되지 않으면 메소드가 BITMAP_INVALID를 반환합니다.
static BitmapId Bitmap::dynamicBitmapCreate(const uint16_t width, const uint16_t height, BitmapFormat format, ClutFormat clutFormat)
동적 비트맵 삭제하기
아래 메소드는 동적 비트맵을 삭제합니다.
static bool Bitmap::dynamicBitmapDelete(BitmapId id)
동적 비트맵의 픽셀 주소 가져오기
아래 메소드는 동적 비트맵의 주소를 반환합니다. 이 메소드는 파일 로더에서 이미지 데이터를 비트맵으로 복사하는 데 사용됩니다.
static uint8_t* dynamicBitmapGetAddress(BitmapId id)
동적 비트맵의 불투명한 영역 설정하기
아래 메소드는 동적 비트맵의 불투명한 직사각형을 설정합니다.
static bool dynamicBitmapSetSolidRect(BitmapId id, const Rect& solidRect)
“불투명한 영역” 개념에 대한 자세한 내용은 커스텀 위젯 섹션을 참조하십시오.
기본적으로 불투명한 영역은 RGB565나 RGB888과 같이 투명하지 않은 형식일 때 전체 비트맵으로 설정됩니다. ARGB8888과 같이 투명한 형식일 때는 비어 있도록 설정됩니다.
세로 모드의 동적 비트맵
TouchGFX는 세로 모드에서도 실행됩니다. 세로 모드는 디스플레이가 기본 방향에서 90도 회전하여 장착되는 경우에 사용됩니다. 세로 모드에서 동적 비트맵을 사용할 때는 좀 더 주의가 필요합니다.
다음은 STM32F746 프로젝트 예입니다. 여기에서 디스플레이의 가로 픽셀은 480이고, 세로 픽셀은 272입니다. 프레임버퍼의 크기도 동일합니다.
image1 Image 위젯에는 어떠한 비트맵도 할당되지 않았습니다. 이 위젯을 사용해 동적 비트맵을 표시하겠습니다.
세로 모드를 사용하면 좌표계가 시계 반대 방향으로 90도 회전합니다. 이때 ‘D’와 가까운 왼쪽 상단 모퉁이가 (0, 0) 좌표에 해당합니다. 그리고 프레임버퍼의 (스크린에서 첫 번째 픽셀을 채색하는) 첫 번째 바이트는 오른쪽 상단 모퉁이가 됩니다.
따라서 프레임버퍼는 세로 모드로 실행해도 회전하지 않습니다. 이것은 동적 비트맵에서도 마찬가지입니다. 단, 장착된 디스플레이에서 첫 번째 줄에 표시하고 싶은 픽셀은 프레임버퍼에서 왼쪽 가장자리에 그려야 합니다.
아래 함수에서는 상단 행을 녹색으로, 오른쪽 가장자리를 빨간색으로 채색하여 동적 비트맵을 생성합니다.
Screen1View.cpp (extract)
void Screen1View::setupScreen()
{
Screen1ViewBase::setupScreen();
BitmapId bmpId;
bmpId = Bitmap::dynamicBitmapCreate(100, 100, Bitmap::RGB565);
if (bmpId != BITMAP_INVALID)
{
//set all pixels white
uint16_t* const bitmapPixels = (uint16_t*)Bitmap::dynamicBitmapGetAddress(bmpId);
memset(bitmapPixels, 0xFF, 100*100*2);
//first 200 pixels red, => two column on the right on display
for (int i = 0; i<200; i++) bitmapPixels[i] = 0xF800;
//first two pixels in all rows green in bitmap => top two rows on display
for (int i = 0; i<100; i++)
{
bitmapPixels[i*100] = 0x07E0;
bitmapPixels[i*100 + 1] = 0x07E0;
}
}
image1.setBitmap(bmpId);
}
디스플레이에 아래와 같은 동적 비트맵이 표시됩니다.