图像
设计
采用多window的方式实现显示,因为每个window可以独立的属性,比如刷新频率,也是我们最关注的
示例
/**********************************************
* Author: younger.liucn@hotmail.com
* File name: dfbFont.c
* Description: dfbFont
* Version, Desc
* 1.1 Created
* 1.2 add config
**********************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include <directfb.h>
#include "dfbFont.h"
/* config information */
#define DFB_LAYERID_USING 0
#define DFB_FONT_TYPE_1 "/home/younger/DFB/Font/data/decker.ttf"
/*********************************************************
* log flags and func of debug and error infor.[Begin]
********************************************************/
#ifdef _DFB_DEBUG_
#define DFB_DEBUG(format, ...) do { \
printf("[BootAnimation:%4dL]DEBUG: "format, __LINE__, ##__VA_ARGS__); \
} while (0)
#else
#define DFB_DEBUG(format, ...) do {} while (0)
#endif
#define DFB_NOTICE(format, ...) do { \
printf("[BootAnimation:%4dL]INFO: "format, __LINE__, ##__VA_ARGS__); \
} while (0)
#define DFB_ERROR(format, ...) do { \
printf("[BootAnimation:%4dL]ERROR: "format, __LINE__, ##__VA_ARGS__); \
} while (0)
/*********************************************************
* log flags and func of debug and error infor.[End]
********************************************************/
/*********************************************************
* Data structure and Global variants [Begin]
********************************************************/
/* 使用directFB画图所需的DFB资源 */
struct DfbResDsc {
IDirectFB *dfb;
IDirectFBDisplayLayer *layer;
};
static struct DfbResDsc badsc;
struct WinResDsc {
IDirectFBWindow *window;
IDirectFBSurface *surface;
};
static struct WinResDsc winText;
/* 如果位置值(OFFSET_X或OFFSET_Y)设置为-1,表示居中显示 */
#define WINDOW_TEXT_LEN_X (800)
#define WINDOW_TEXT_LEN_Y (100)
#define WINDOW_TEXT_OFFSET_X (-1)
#define WINDOW_TEXT_OFFSET_Y (500)
static char *testString = "Hello world! This is DirectFB!";
static struct WinResDsc winAnim;
/* 如果位置值(OFFSET_X或OFFSET_Y)设置为-1,表示居中显示 */
#define WINDOW_ANIM_LEN_X (200)
#define WINDOW_ANIM_LEN_Y (200)
#define WINDOW_ANIM_OFFSET_X (-1)
#define WINDOW_ANIM_OFFSET_Y (200)
/* config information */
#define ANIM_IMAGES_COUNT 48
/* support png, jpg */
#define ANIM_IMAGE_FORMAT "png"
#define ANIM_FILE_NAME_MAX_SIZE 255
#define ANIM_IMG_DEFAULT_WIDTH 186
#define ANIM_IMG_DEFAULT_HEIGHT 186
#define ANIM_IMG_DEFAULT_FPS 10
#define ANIM_MAX_RUNNING_MTIME (20000)
#define ANIM_DEFAULT_LOGO_PATH "/home/liuyiy/DFB/FontAnim/data/images"
static IDirectFBSurface *imgSfc[ANIM_IMAGES_COUNT];
/*********************************************************
* Data structure and Global variants [End]
********************************************************/
/* 初始化/释放资源dfb/layer [Begin] */
void freeResources()
{
/* Release the layer. */
if (badsc.layer)
badsc.layer->Release(badsc.layer);
badsc.dfb->Release(badsc.dfb);
return ;
}
static void initResources(int argc, char **argv)
{
DFBResult ret;
badsc.dfb = NULL;
IDirectFB *dfb = NULL;
/* 初始化DirectFB */
DirectFBInit(&argc, &argv);
DirectFBCreate(&dfb);
if (!dfb) {
DFB_ERROR("directfb interface is NULL\n");
return ;
}
badsc.dfb = dfb;
/* 初始化 display layer:其中DFB_LAYERID_USING设置为0.*/
ret = badsc.dfb->GetDisplayLayer(badsc.dfb, DFB_LAYERID_USING, &(badsc.layer));
if(ret != (DFBResult)DFB_OK) {
DFB_ERROR("Get layer(%d) failed!\n", DFB_LAYERID_USING);
goto fail;
} else {
DFB_DEBUG("Get layer(%d) independently.\n", DFB_LAYERID_USING);
}
return ;
fail:
freeResources();
return ;
}
/* 初始化/释放资源dfb/layer [End] */
/* 初始化/释放资源WinResDsc [Begin] */
static void deinitWinRes(struct WinResDsc *winres)
{
winres->surface->SetColor(winres->surface, 0, 0, 0, 0);
winres->surface->Clear(winres->surface, 0, 0, 0, 0);
winres->surface->Flip(winres->surface, NULL, DSFLIP_WAITFORSYNC);
/* Release the window's surface. */
if(winres->surface)
winres->surface->Release(winres->surface);
/* Release the window. */
if (winres->window)
winres->window->Release(winres->window);
return ;
}
static void initWinResPercent(struct WinResDsc *winres,
int window_offset_x,
int window_offset_y,
int window_len_x,
int window_len_y
)
{
DFBResult ret;
IDirectFBWindow *window = NULL;
IDirectFBSurface *surface = NULL;
DFBWindowDescription desc;
DFBDisplayLayerConfig config;
/* 获取display layer的配置,. */
badsc.layer->GetConfiguration(badsc.layer, &config);
/* 设置window参数,并创建Window */
desc.flags = (DFBWindowDescriptionFlags)(DWDESC_POSX | DWDESC_POSY | DWDESC_WIDTH | DWDESC_HEIGHT | DWDESC_CAPS | DWDESC_OPTIONS);
DFB_NOTICE("Layer Screen width %d, height %d !\n", config.width, config.height);
/* 固定window在layer的中位置 */
if (-1 == window_offset_x) {
desc.posx = (config.width - window_len_x) / 2;
} else {
desc.posx = window_offset_x;
}
if (-1 == window_offset_y) {
desc.posy = (config.height - window_len_y) / 2;
} else {
desc.posy = window_offset_y;
}
desc.width = window_len_x;
desc.height = window_len_y;
desc.caps = (DFBWindowCapabilities)(DWCAPS_NODECORATION);
desc.options = (DFBWindowOptions) (DWOP_GHOST);
ret = badsc.layer->CreateWindow(badsc.layer, &desc, &window);
if(ret != (DFBResult)DFB_OK) {
DFB_ERROR("Create window failed!\n");
return ;
}
/* 设置透明度 */
ret = window->SetOpacity(window, 0xFF);
if(ret != (DFBResult)DFB_OK) {
DFB_ERROR("SetOpacity failed!\n");
window->Release(window);
return ;
}
/* 获取window的surface. */
ret = window->GetSurface(window, &surface);
if(ret != (DFBResult)DFB_OK) {
DFB_ERROR("GetSurface failed!\n");
return ;
}
/*若不执行clear,则可能出现花屏*/
surface->SetColor(surface, 0, 0, 0, 0);
surface->Clear(surface, 0, 0, 0, 0);
surface->Flip(surface, NULL, DSFLIP_WAITFORSYNC);
winres->window = window;
winres->surface = surface;
return ;
}
/* 初始化/释放资源WinResDsc [End] */
/* 绘制字符串 */
static void flipText(char* str) {
int width = 0, height = 0;
IDirectFBFont* font = NULL;
DFBFontDescription font_desc;
IDirectFBSurface *surface = winText.surface;
surface->GetSize(surface, &width, &height);
/* font init */
font_desc.flags = DFDESC_HEIGHT;
font_desc.height = height / 2;
badsc.dfb->CreateFont(badsc.dfb, DFB_FONT_TYPE_1, &font_desc, &font);
surface->Clear(surface, 0x0, 0x0, 0x0, 0xff);
surface->SetFont(surface, font);
/* 设置前景颜色 */
surface->SetColor(surface, 0x00, 0xFF, 0x00, 0xFF);
surface->DrawString(surface, str, strlen(str), width / 2, height / 2, DSTF_CENTER);
/* 变换、更新surface buffer */
surface->Flip(surface, NULL, DSFLIP_WAITFORSYNC);
return ;
}
/* 绘制动画 [Begin] */
static inline int checkFileExist(const char *filename)
{
if((access(filename, R_OK)) != -1)
return 1;
return 0;
}
static int doLoadImg(const char *filename,
IDirectFBSurface **surface,
unsigned int *width,
unsigned int *height)
{
int ret;
IDirectFB *dfb = badsc.dfb;
DFBSurfaceDescription img_dsc;
IDirectFBImageProvider *provider = NULL;
if(NULL == surface || NULL == filename) {
DFB_ERROR("doLoadImg() failed for %d.\n", -EINVAL);
return -EINVAL;
}
DFB_DEBUG("doLoadImg() entry:%s .\n", filename);
/* 检查图片是否存在 */
if(!checkFileExist(filename)) {
DFB_ERROR("file %s does not exist.\n", filename);
return -EINVAL;
}
/* 将要显示的图片及其相关信息保存在一个image provider中 */
ret = dfb->CreateImageProvider(dfb, filename, &provider);
if(ret) {
DFB_ERROR("CreateImageProvider() for %s failed %d.\n", filename, ret);
return ret;
}
/* 将保存在provider中的图片信息提取出来,存于surface description中 */
ret = provider->GetSurfaceDescription(provider, &img_dsc);
if(ret) {
DFB_ERROR("GetSurfaceDescription() for %s failed %d.\n",
filename, ret);
provider->Release(provider);
return ret;
}
/* 根据surface description创建surface,尺寸与图片大小完全一致 */
ret = dfb->CreateSurface(dfb, &img_dsc, surface);
if(ret) {
DFB_ERROR("CreateSurface() for %s failed %d.\n", filename, ret);
provider->Release(provider);
return ret;
}
/* 将图片呈递给刚才建立的logo平面,如果大小不一致,则进行缩放 */
ret = provider->RenderTo(provider, *surface, NULL);
if(ret) {
DFB_ERROR("RenderTo() for %s failed %d.\n", filename, ret);
(*surface)->Release(*surface);
provider->Release(provider);
return ret;
}
/* Return width / height? */
if(width) {
*width = img_dsc.width;
}
if(height){
*height = img_dsc.height;
}
/* release provider */
provider->Release(provider);
DFB_DEBUG("doLoadImg() exit.\n");
return ret;
}
/* 释放图片资源 */
static void deinitImages()
{
int i = 0;
for (i = 0; i < ANIM_IMAGES_COUNT; i++) {
if (imgSfc[i]) {
imgSfc[i]->Release(imgSfc[i]);
} else {
break;
}
}
return ;
}
/* 初始化图片资源 */
static int initImages()
{
int ret = 0, i = 0;
char filename[ANIM_FILE_NAME_MAX_SIZE];
IDirectFBSurface *tmp_sfc = NULL;
for (i = 0; i < ANIM_IMAGES_COUNT; i++) {
imgSfc[i] = NULL;
}
for (i = 0; i < ANIM_IMAGES_COUNT; i++) {
tmp_sfc = NULL;
memset(filename, 0x0, sizeof(filename));
snprintf(filename, ANIM_FILE_NAME_MAX_SIZE,
"%s/%02d.%s", ANIM_DEFAULT_LOGO_PATH, i, ANIM_IMAGE_FORMAT);
ret = doLoadImg(filename, &tmp_sfc, NULL, NULL);
if (ret != 0) {
goto bail;
}
imgSfc[i] = tmp_sfc;
}
return 0;
bail:
deinitImages();
return -1;
}
static void fillDFBSurface(
IDirectFBSurface *primary_sfc,
IDirectFBSurface *img_sfc,
int x, int y)
{
primary_sfc->Clear(primary_sfc, 0, 0, 0, 255);
/*
* blit即将两张位图(即thiz和source)按拉操作的方法组合成一张图片。
* 在DirectFB中,其定义的动作也是合理的:将img_sfc blit到primary_sfc上去,
* 两个平面上的内容会产生叠加
*/
primary_sfc->Blit(primary_sfc, img_sfc, NULL, x, y);
/* 变换、更新surface buffer */
primary_sfc->Flip(primary_sfc, NULL, DSFLIP_WAITFORSYNC);
return ;
}
/* 获取b与a的时间差,单位:毫秒 */
static unsigned long deltaMsecs(struct timespec *a,
struct timespec *b)
{
long delta_secs = 0, delta_msecs = 0;
if(a->tv_sec < b->tv_sec ||
(a->tv_sec == b->tv_sec && a->tv_nsec < b->tv_nsec)) {
return 0;
}
delta_secs = a->tv_sec - b->tv_sec;
delta_msecs = (a->tv_nsec - b->tv_nsec) / 1000000;
while(delta_msecs < 0) {
delta_secs--;
delta_msecs += 1000;
}
return delta_secs * 1000 + delta_msecs;
}
static void doAnimation()
{
int ret, i;
struct timespec before_draw, after_draw;
unsigned long elapsed_msec, total_msec;
IDirectFBSurface *primary = winAnim.surface;
unsigned long interval = (1000 / ANIM_IMG_DEFAULT_FPS);
if (initImages()) {
DFB_ERROR("Init images failed!\n");
return ;
}
DFB_NOTICE("Animation start ...\n");
total_msec = 0;
i = 0;
do {
if(i >= ANIM_IMAGES_COUNT) {
i = 0;
}
clock_gettime(CLOCK_MONOTONIC, &before_draw);
fillDFBSurface(primary, imgSfc[i],
0,0);
clock_gettime(CLOCK_MONOTONIC, &after_draw);
/*
* 获取画图前后两次的时间差elapsed_msec
* 如果elapsed_msec>interval,则不再休眠
* 否则休眠interval-elapsed_msec
*/
elapsed_msec = deltaMsecs(&after_draw, &before_draw);
if(elapsed_msec < interval) {
usleep((interval - elapsed_msec) * 1000);
total_msec += interval;
} else {
total_msec += elapsed_msec;
}
DFB_DEBUG("elapsed %lu ms \n",
elapsed_msec < interval ? interval : elapsed_msec);
if(total_msec >= ANIM_MAX_RUNNING_MTIME) {
DFB_NOTICE("Stopped by Timeout(%lu).\n", total_msec);
break;
}
i++;
} while(1);
out:
DFB_NOTICE("Animation exit with black screen...\n");
deinitImages();
return ;
}
/* 绘制动画 [End] */
static void doShow()
{
DFB_NOTICE("Text start ...\n");
flipText(testString);
doAnimation();
return ;
}
int main(int argc, char **argv)
{
DFB_NOTICE("Animation entry.\n");
initResources(argc, argv);
initWinResPercent(&winText,
WINDOW_TEXT_OFFSET_X, WINDOW_TEXT_OFFSET_Y,
WINDOW_TEXT_LEN_X, WINDOW_TEXT_LEN_Y);
initWinResPercent(&winAnim,
WINDOW_ANIM_OFFSET_X, WINDOW_ANIM_OFFSET_Y,
WINDOW_ANIM_LEN_X, WINDOW_ANIM_LEN_Y);
doShow();
deinitWinRes(&winText);
deinitWinRes(&winAnim);
freeResources();
DFB_NOTICE("Animation exit.\n");
return 0;
}