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 で動かす からソースのダウンロードができます。
ディスカッション
コメント一覧
まだ、コメントがありません