GPiCASE にアナログ時計を表示する
フレームバッファを使えば、GPiCASE の RetroPie で画面に表示させることが出来るとわかりました。SDL で開発すれば、GPiCASE のフレームバッファに出してくれることもわかりました。
そこで、試しに GPiCASE に表示する時計を作りました。デジタル時計ではなく、アナログ時計を作ります。
320 x 240 のサイズで時計の文字盤をビットマップで作り、それを表示するだけのプログラムを作ってみました。テストは普通のRaspberry Pi のデスクトップで確認します。
#include <SDL/SDL.h>
int main(int argc, char* argv[]){
SDL_Surface* image;
SDL_Rect rect, scr_rect;
SDL_Init(SDL_INIT_EVERYTHING);
SDL_SetVideoMode(320, 240, 32, SDL_HWSURFACE);
/* 画像読み込み */
image = SDL_LoadBMP("clock.bmp");
/* 画像の矩形情報設定 */
rect.x = 0;
rect.y = 0;
rect.w = image->w;
rect.h = image->h;
/* 画像配置位置情報の設定 */
scr_rect.x = 0;
scr_rect.y = 0;
/* サーフェスの複写 */
SDL_BlitSurface(image, &rect, SDL_GetVideoSurface(), &scr_rect);
/* サーフェスフリップ */
SDL_Flip(SDL_GetVideoSurface());
SDL_Delay(3000);
SDL_FreeSurface(image);
SDL_Quit();
return 0;
}
3 秒だけ時計の文字盤が表示されます。GPiCASE の Raspberry Pi Zero へコピーして実行すると、GPiCASE に文字盤が表示されました。大丈夫です。
さて、現在時刻を取得して、時計の針を表示しなければなりません。現在時刻の取得は普通の C で取得できますが、秒針の描画をどうしましょうか。
方法としては、いくつか考えられます。
- 全ての状態の秒針、分針、時針の画像を準備して重ね合わせる。
- 針の画像を準備して回転させる。
- ラインで描画する。
どれが簡単でしょう。針の画像を回転させて表示するのがいいと思いましたが、SDL + OPENGL で作るか、SDL2 あたりを使うかになるでしょう。SDL だけでは無理です。
針の描画は後にして、SDL2 に変更してタイマーを使い、デジタルで時刻を表示してみることにしました。
#include <stdio.h>
#include <time.h>
#include <SDL.h>
#include <SDL_ttf.h>
static SDL_Surface* image = NULL;
static SDL_Window *window = NULL;
static TTF_Font *font = NULL;
static SDL_Color gray = {0x60, 0x60, 0x60};
char *get_time(int *h, int *m, int *s) {
time_t timer;
struct tm *local;
static char result[20];
int ts;
timer = time(NULL);
local = localtime(&timer);
*h = local->tm_hour;
*m = local->tm_min;
*s = local->tm_sec;
sprintf(result, "%02d:%02d:%02d", *h, *m, *s);
return result;
}
void *redraw(void *param) {
SDL_Rect rect;
SDL_Surface *text;
int h, m, s;
/* 文字盤の表示 */
SDL_BlitSurface(image, NULL, SDL_GetWindowSurface(window), NULL);
/* 時刻の表示 */
text = TTF_RenderUTF8_Blended(font, get_time(&h, &m, &s), gray);
rect.x = 87;
rect.y = 200;
rect.w = text->w;
rect.h = text->h;
SDL_BlitSurface(text, NULL, SDL_GetWindowSurface(window), &rect);
SDL_FreeSurface(text);
rect.x = rect.y = 0;
rect.w = image->w, rect.h = image->w;
SDL_UpdateWindowSurfaceRects(window, &rect, 1);
}
Uint32 callbackfunc(Uint32 interval, void *param)
{
SDL_Event event;
SDL_UserEvent userevent;
/* コールバックでSDL_USEREVENTイベントをキューに入れる。
このコールバック関数は一定の周期で再び呼ばれる */
userevent.type = SDL_USEREVENT;
userevent.code = 0;
userevent.data1 = &redraw;
userevent.data2 = param;
event.type = SDL_USEREVENT;
event.user = userevent;
SDL_PushEvent(&event);
return(interval);
}
int main(int argc, char* argv[]){
SDL_Event event;
SDL_TimerID my_timer_id;
/* 初期化 */
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0) {
fprintf(stderr, "SDL_Init(): %s\n", SDL_GetError());
exit(1);
}
if (SDL_Init(SDL_INIT_JOYSTICK) >= 0 ) {
if( SDL_JoystickOpen(0) != NULL )
SDL_ShowCursor(SDL_DISABLE);
}
TTF_Init();
/* フォント取得 */
font = TTF_OpenFont("/usr/share/fonts/truetype/fonts-japanese-gothic.ttf", 24);
if( font == NULL ) {
printf("Can not open font\n");
exit(1);
}
/* 画像読み込み */
image = SDL_LoadBMP("clock.bmp");
if( image == NULL ) {
printf("Can not load image\n");
exit(1);
}
/* タイマーを作る */
my_timer_id = SDL_AddTimer(1000, callbackfunc, NULL);
/* ウィンドウ作成 */
window = SDL_CreateWindow("SDL clock", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 320, 240, SDL_WINDOW_OPENGL);
if( window == NULL ) {
printf("Can not create window\n");
exit(1);
}
/* イベントループ */
while(1) {
if( SDL_PollEvent(&event) ) {
switch (event.type) {
case SDL_WINDOWEVENT:
switch (event.window.event) {
case SDL_WINDOWEVENT_EXPOSED:
SDL_UpdateWindowSurface(window);
break;
}
break;
case SDL_USEREVENT: {
void (*p) (void*) = event.user.data1;
p(event.user.data2);
break;
}
case SDL_JOYBUTTONDOWN:
if( event.jbutton.button != 7 ) break;
case SDL_QUIT:
SDL_Quit();
exit(0);
break;
}
} else
SDL_Delay(500);
}
/* ここにはこない */
SDL_Quit();
return 0;
}
デジタルでの時計表示はできました。GPiCASE では、スタートボタンで終了します。後はアナログ時計の針の描画です。
SDL2 の回転は、renderer を使うようです。renderer は初めて使いましたが、画像の表示も renderer を使って表示します。
針は、矩形にしました。文字盤の画像の左上のピクセルを使って、矩形にコピーして回転する、SDL_RenderCopyEx を使うことにしました。
また、ただ単純に時計を表示するだけではつまらないので、タイマー機能も追加しました。ソースは整理していません。あとで、別ページでダウンロードできるようにします。
(2021.09.24 追記)
SDL でアナログ時計を作り、GPiCASE で動かす からソースのダウンロードができます。

ディスカッション
コメント一覧
まだ、コメントがありません