-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgraphics.c
290 lines (245 loc) · 9.1 KB
/
graphics.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
#include <directfb.h>
#include <signal.h>
#include <time.h>
#include "graphics.h"
#define VOLUME_X_COOR 50
#define VOLUME_Y_COOR 50
#define INFO_BAR_RED 0
#define INFO_BAR_GREEN 166
#define INFO_BAR_BLUE 81
#define TEXT_RED 255
#define TEXT_GREEN 255
#define TEXT_BLUE 255
#define VOLUME_TIME 3
#define INFO_TIME 3
// Helper macro for error checking.
#define DFBCHECK(x...) \
{ \
DFBResult err = x; \
\
if (err != DFB_OK) \
{ \
fprintf( stderr, "%s <%d>:\n\t", __FILE__, __LINE__ ); \
DirectFBErrorFatal( #x, err ); \
} \
}
typedef struct _info_bar_t
{
uint8_t channelNumber;
uint8_t teletextExist;
uint8_t audioPID;
uint8_t videoPID;
char date[11];
uint8_t visible;
} info_bar_t;
typedef struct _volume_bar_t
{
uint8_t volume;
uint8_t visible;
} volume_bar_t;
static info_bar_t infoBar;
static volume_bar_t volumeBar;
static IDirectFBSurface *primary = NULL;
static IDirectFB *dfbInterface = NULL;
static int screenWidth;
static int screenHeight;
static DFBSurfaceDescription surfaceDesc;
static timer_t volumeTimerId;
static timer_t infoTimerId;
static struct itimerspec volumeTimerSpec;
static struct itimerspec volumeTimerSpecOld;
static struct itimerspec infoTimerSpec;
static struct itimerspec infoTimerSpecOld;
t_Error initGraphic()
{
struct sigevent volumeSignalEvent;
struct sigevent infoSignalEvent;
// Initialize DirectFB.
DFBCHECK(DirectFBInit(NULL, NULL));
DFBCHECK(DirectFBCreate(&dfbInterface));
DFBCHECK(dfbInterface->SetCooperativeLevel(dfbInterface, DFSCL_FULLSCREEN));
// Create primary surface, with enabled double buffering and fetch size.
surfaceDesc.flags = DSDESC_CAPS;
surfaceDesc.caps = DSCAPS_PRIMARY | DSCAPS_FLIPPING;
DFBCHECK (dfbInterface->CreateSurface(dfbInterface,
&surfaceDesc, &primary));
DFBCHECK (primary->GetSize(primary, &screenWidth, &screenHeight));
// Set both elements to not visible.
infoBar.visible = 0;
volumeBar.visible = 0;
// Prepare volume timer specification.
memset(&volumeTimerSpec, 0, sizeof(volumeTimerSpec));
volumeTimerSpec.it_value.tv_sec = VOLUME_TIME;
volumeTimerSpec.it_value.tv_nsec = 0;
// Prepare volume signal event specification.
volumeSignalEvent.sigev_notify = SIGEV_THREAD;
volumeSignalEvent.sigev_notify_function = removeVolume;
volumeSignalEvent.sigev_value.sival_ptr = NULL;
volumeSignalEvent.sigev_notify_attributes = NULL;
// Create volume timer and check if there was error while creating.
if (-1 == timer_create(CLOCK_REALTIME, &volumeSignalEvent, &volumeTimerId))
{
printf("ERROR: %s failed to create volume timer.\n", __func__);
primary->Release(primary);
dfbInterface->Release(dfbInterface);
return ERROR;
}
// Prepare info timer specification.
memset(&infoTimerSpec, 0, sizeof(infoTimerSpec));
infoTimerSpec.it_value.tv_sec = VOLUME_TIME;
infoTimerSpec.it_value.tv_nsec = 0;
// Prepare info signal event specification.
infoSignalEvent.sigev_notify = SIGEV_THREAD;
infoSignalEvent.sigev_notify_function = removeInfoBar;
infoSignalEvent.sigev_value.sival_ptr = NULL;
infoSignalEvent.sigev_notify_attributes = NULL;
// Create info timer and check if there was error while creating.
if(-1 == timer_create(CLOCK_REALTIME, &infoSignalEvent, &infoTimerId))
{
printf("ERROR: %s failed to create info timer.\n", __func__);
primary->Release(primary);
dfbInterface->Release(dfbInterface);
return ERROR;
}
return NO_ERROR;
}
void render()
{
IDirectFBImageProvider *provider;
IDirectFBSurface *logoSurface;
IDirectFBFont *fontInterface;
DFBFontDescription fontDesc;
char imageName[15];
int32_t logoHeight;
int32_t logoWidth;
char prog[32];
char date[32];
char telxt[32];
char audio[32];
char video[32];
// Fetch the screen size and clear screen.
DFBCHECK(primary->SetColor(primary, 0x00, 0x00, 0x00, 0x00));
DFBCHECK(primary->FillRectangle(primary, 0, 0, screenWidth, screenHeight));
if (volumeBar.visible)
{
// Make a new name.
sprintf(imageName, "volume_%hu.png", volumeBar.volume);
// Read image, prepare surface descriptor and render image to given surface.
DFBCHECK(dfbInterface->CreateImageProvider(dfbInterface, imageName, &provider));
DFBCHECK(provider->GetSurfaceDescription(provider, &surfaceDesc));
DFBCHECK(dfbInterface->CreateSurface(dfbInterface, &surfaceDesc, &logoSurface));
DFBCHECK(provider->RenderTo(provider, logoSurface, NULL));
provider->Release(provider);
// Fetch the logo size and add it to the screen buffer.
DFBCHECK(logoSurface->GetSize(logoSurface, &logoWidth, &logoHeight));
DFBCHECK(primary->Blit(primary, logoSurface,
NULL, VOLUME_X_COOR, VOLUME_Y_COOR));
}
if (infoBar.visible)
{
// Prepare strings for info bar.
sprintf(prog, "Program %hu", infoBar.channelNumber);
sprintf(date, "Naziv dana u nedelji %s", infoBar.date);
sprintf(audio, "Audio PID %hu", infoBar.audioPID);
sprintf(video, "Video PID %hu", infoBar.videoPID);
if (infoBar.teletextExist)
{
sprintf(telxt, "Teletekst postoji");
}
else
{
sprintf(telxt, "Teletekst ne postoji");
}
// Prepare text font, color and size. Then create font and draw it.
fontDesc.flags = DFDESC_HEIGHT;
fontDesc.height = 40;
DFBCHECK(dfbInterface->CreateFont(dfbInterface,
"/home/galois/fonts/DejaVuSans.ttf", &fontDesc, &fontInterface));
DFBCHECK(primary->SetFont(primary, fontInterface));
// Draw a rectangle representing info bar.
DFBCHECK(primary->SetColor(primary, INFO_BAR_RED,
INFO_BAR_GREEN, INFO_BAR_BLUE, 0xff));
DFBCHECK(primary->FillRectangle(primary, screenWidth/6, 4*screenHeight/5,
4*screenWidth/6, screenHeight/6));
// Write program number, date and teletext to info bar.
DFBCHECK(primary->SetColor(primary, TEXT_RED, TEXT_GREEN, TEXT_BLUE, 0xff));
DFBCHECK(primary->DrawString(primary, prog, -1, screenWidth/5,
17*screenHeight/20, DSTF_LEFT));
DFBCHECK(primary->DrawString(primary, audio, -1, screenWidth/5,
18*screenHeight/20, DSTF_LEFT));
DFBCHECK(primary->DrawString(primary, video, -1, screenWidth/5,
19*screenHeight/20, DSTF_LEFT));
DFBCHECK(primary->DrawString(primary, date, -1, 4*screenWidth/9,
19*screenHeight/20, DSTF_LEFT));
DFBCHECK(primary->DrawString(primary, telxt, -1, 4*screenWidth/9,
17*screenHeight/20, DSTF_LEFT));
}
// Switch buffers.
DFBCHECK(primary->Flip(primary, NULL, 0));
}
t_Error drawVolume(uint8_t volume)
{
volumeBar.volume = volume;
volumeBar.visible = 1;
render();
// Specify the timer timeout time and set it, saving the old specifications.
volumeTimerSpec.it_value.tv_sec = VOLUME_TIME;
volumeTimerSpec.it_value.tv_nsec = 0;
if (-1 == timer_settime(volumeTimerId, 0,
&volumeTimerSpec, &volumeTimerSpecOld))
{
printf("ERROR: %s failed while setting timer.\n", __func__);
return ERROR;
}
return NO_ERROR;
}
t_Error drawInfoBar(info_data_t data)
{
infoBar.channelNumber = data.channelNumber;
infoBar.teletextExist = data.teletextExist;
infoBar.audioPID = data.audioPID;
infoBar.videoPID = data.videoPID;
strcpy(infoBar.date, data.date);
infoBar.visible = 1;
render();
// Specify the timer timeout time and set new timer.
infoTimerSpec.it_value.tv_sec = INFO_TIME;
infoTimerSpec.it_value.tv_nsec = 0;
if (-1 == timer_settime(infoTimerId, 0, &infoTimerSpec, &infoTimerSpecOld))
{
printf("ERROR: %s failed while creating timer.\n", __func__);
return ERROR;
}
return NO_ERROR;
}
void removeInfoBar()
{
infoBar.visible = 0;
render();
// Stop timer.
memset(&infoTimerSpec, 0, sizeof(infoTimerSpec));
if (-1 == timer_settime(infoTimerId, 0, &infoTimerSpec, &infoTimerSpecOld))
{
printf("ERROR: %s failed while stoping timer.\n", __func__);
}
}
void removeVolume(union sigval signalArg)
{
volumeBar.visible = 0;
render();
// Stop timer.
memset(&volumeTimerSpec, 0, sizeof(volumeTimerSpec));
if (-1 == timer_settime(volumeTimerId, 0, &volumeTimerSpec,
&volumeTimerSpecOld))
{
printf("ERROR: %s failed while stoping timer.\n", __func__);
}
}
void deinitGraphic()
{
timer_delete(volumeTimerId);
timer_delete(infoTimerId);
primary->Release(primary);
dfbInterface->Release(dfbInterface);
return;
}