1 #if ! defined(PROG_DISABLE_GUI) && ! defined(PROG_DISABLE_BOB)
2 
3 #include "declarations.h"
4 #include "widget_shr.h"
5 #include "bob.h"
6 
7 
8 
9 /**
10  * @brief Get bob current altitude in pixels.
11  *
12  * @param[in] d Bob container id returned by bob_create_container()
13  * @param[in] e Bob id returned by bob_create()
14  *
15  * @retval Bob altitude in pixels
16  *
17  */
18 
bob_get_altitude(unsigned int d,unsigned int e)19 unsigned int bob_get_altitude(unsigned int d, unsigned int e) {
20 	struct b_bob *b;
21 
22 	if((b = bob_get_bob_by_id(d, e)) == NULL) return(0);
23 
24 	return(b->a);
25 }
26 
27 /**
28  * @brief Set bob altitude in pixels.
29  *
30  * @param[in] d Bob container id returned by bob_create_container()
31  * @param[in] e Bob id returned by bob_create()
32  * @param[in] a Bob altitude in pixels
33  *
34  */
35 
bob_set_altitude(unsigned int d,unsigned int e,unsigned int a)36 void bob_set_altitude(unsigned int d, unsigned int e, unsigned int a) {
37 	struct b_bob *b;
38 
39 	if((b = bob_get_bob_by_id(d, e)) == NULL) return;
40 
41 	b->a = a;
42 }
43 
44 /**
45  * @brief Add offset to bob altitude.
46  *
47  * @param[in] d Bob container id returned by bob_create_container()
48  * @param[in] e Bob id returned by bob_create()
49  * @param[in] a Pixels to add to current altitude
50  *
51  */
52 
bob_add_altitude(unsigned int d,unsigned int e,int a)53 void bob_add_altitude(unsigned int d, unsigned int e, int a) {
54 	struct b_bob *b;
55 
56 	if((b = bob_get_bob_by_id(d, e)) == NULL) return;
57 
58 	b->a += a;
59 }
60 
61 /**
62  * @brief Subtract offset from bob altitude.
63  *
64  * @param[in] d Bob container id returned by bob_create_container()
65  * @param[in] e Bob id returned by bob_create()
66  * @param[in] a Pixels to subtract from current altitude
67  *
68  */
69 
bob_sub_altitude(unsigned int d,unsigned int e,int a)70 void bob_sub_altitude(unsigned int d, unsigned int e, int a) {
71 	struct b_bob *b;
72 
73 	if((b = bob_get_bob_by_id(d, e)) == NULL) return;
74 
75 	b->a -= a;
76 }
77 
78 /**
79  * @brief Get bob current x position in pixels.
80  *
81  * @param[in] d Bob container id returned by bob_create_container()
82  * @param[in] e Bob id returned by bob_create()
83  *
84  * @retval Bob position in x axis
85  *
86  */
87 
bob_get_x_position(unsigned int d,unsigned int e)88 int bob_get_x_position(unsigned int d, unsigned int e) {
89 	struct b_bob *b;
90 
91 	if((b = bob_get_bob_by_id(d, e)) == NULL) return(0);
92 
93 	return(b->x);
94 }
95 
96 /**
97  * @brief Get bob current y position in pixels.
98  *
99  * @param[in] d Bob container id returned by bob_create_container()
100  * @param[in] e Bob id returned by bob_create()
101  *
102  * @retval Bob position in y axis
103  *
104  */
105 
bob_get_y_position(unsigned int d,unsigned int e)106 int bob_get_y_position(unsigned int d, unsigned int e) {
107 	struct b_bob *b;
108 
109 	if((b = bob_get_bob_by_id(d, e)) == NULL) return(0);
110 
111 	return(b->y);
112 }
113 
114 /**
115  * @brief Set bob position in pixels.
116  *
117  * @param[in] d Bob container id returned by bob_create_container()
118  * @param[in] e Bob id returned by bob_create()
119  * @param[in] x Bob position in x axis
120  * @param[in] y Bob position in y axis
121  *
122  */
123 
bob_set_position(unsigned int d,unsigned int e,int x,int y)124 void bob_set_position(unsigned int d, unsigned int e, int x, int y) {
125 	struct b_bob *b;
126 
127 	if((b = bob_get_bob_by_id(d, e)) == NULL) return;
128 
129 	b->x = x;
130 	b->y = y;
131 }
132 
133 /**
134  * @brief Set bob x position in pixels.
135  *
136  * @param[in] d Bob container id returned by bob_create_container()
137  * @param[in] e Bob id returned by bob_create()
138  * @param[in] x Bob position in x axis
139  *
140  */
141 
bob_set_x_position(unsigned int d,unsigned int e,int x)142 void bob_set_x_position(unsigned int d, unsigned int e, int x) {
143 	struct b_bob *b;
144 
145 	if((b = bob_get_bob_by_id(d, e)) == NULL) return;
146 
147 	b->x = x;
148 }
149 
150 /**
151  * @brief Set bob y position in pixels.
152  *
153  * @param[in] d Bob container id returned by bob_create_container()
154  * @param[in] e Bob id returned by bob_create()
155  * @param[in] y Bob position in y axis
156  *
157  */
158 
bob_set_y_position(unsigned int d,unsigned int e,int y)159 void bob_set_y_position(unsigned int d, unsigned int e, int y) {
160 	struct b_bob *b;
161 
162 	if((b = bob_get_bob_by_id(d, e)) == NULL) return;
163 
164 	b->y = y;
165 }
166 
167 /**
168  * @brief Add offset to bob x position.
169  *
170  * @param[in] d Bob container id returned by bob_create_container()
171  * @param[in] e Bob id returned by bob_create()
172  * @param[in] x Pixels to add to current x position
173  *
174  */
175 
bob_add_x_position(unsigned int d,unsigned int e,int x)176 void bob_add_x_position(unsigned int d, unsigned int e, int x) {
177 	struct b_bob *b;
178 
179 	if((b = bob_get_bob_by_id(d, e)) == NULL) return;
180 
181 	b->x += x;
182 }
183 
184 /**
185  * @brief Add offset to bob y position.
186  *
187  * @param[in] d Bob container id returned by bob_create_container()
188  * @param[in] e Bob id returned by bob_create()
189  * @param[in] y Pixels to add to current y position
190  *
191  */
192 
bob_add_y_position(unsigned int d,unsigned int e,int y)193 void bob_add_y_position(unsigned int d, unsigned int e, int y) {
194 	struct b_bob *b;
195 
196 	if((b = bob_get_bob_by_id(d, e)) == NULL) return;
197 
198 	b->y += y;
199 }
200 
201 /**
202  * @brief Subtract offset from bob x position.
203  *
204  * @param[in] d Bob container id returned by bob_create_container()
205  * @param[in] e Bob id returned by bob_create()
206  * @param[in] x Pixels to subtract from current x position
207  *
208  */
209 
bob_sub_x_position(unsigned int d,unsigned int e,int x)210 void bob_sub_x_position(unsigned int d, unsigned int e, int x) {
211 	struct b_bob *b;
212 
213 	if((b = bob_get_bob_by_id(d, e)) == NULL) return;
214 
215 	b->x -= x;
216 }
217 
218 /**
219  * @brief Subtract offset from bob y position.
220  *
221  * @param[in] d Bob container id returned by bob_create_container()
222  * @param[in] e Bob id returned by bob_create()
223  * @param[in] y Pixels to subtract from current y position
224  *
225  */
226 
bob_sub_y_position(unsigned int d,unsigned int e,int y)227 void bob_sub_y_position(unsigned int d, unsigned int e, int y) {
228 	struct b_bob *b;
229 
230 	if((b = bob_get_bob_by_id(d, e)) == NULL) return;
231 
232 	b->y -= y;
233 }
234 
235 /**
236  * @brief Get bob position angle.
237  *
238  * @param[in] d Bob container id returned by bob_create_container()
239  * @param[in] e Bob id returned by bob_create()
240  *
241  * @retval Bob position angle in degrees
242  *
243  */
244 
bob_get_angle(unsigned int d,unsigned int e)245 double bob_get_angle(unsigned int d, unsigned int e) {
246 	struct b_bob *b;
247 
248 	struct position a;
249 
250 	if((b = bob_get_bob_by_id(d, e)) == NULL) return(0.0);
251 
252 	a.x = b->x;
253 	a.y = b->y;
254 	a.z = 0.0;
255 
256 	return(coords_position_to_angle(&a));
257 }
258 
259 /**
260  * @brief Set bob position in pixels by given angle and distance.
261  *
262  * @param[in] d Bob container id returned by bob_create_container()
263  * @param[in] e Bob id returned by bob_create()
264  * @param[in] a Angle in degrees
265  * @param[in] n Distance in pixels
266  *
267  */
268 
bob_set_angle_position(unsigned int d,unsigned int e,double a,double n)269 void bob_set_angle_position(unsigned int d, unsigned int e, double a, double n) {
270 	struct b_bob *b;
271 
272 	struct position p;
273 
274 	if((b = bob_get_bob_by_id(d, e)) == NULL) return;
275 
276 	(void) coords_angle_distance_to_position(a, n, &p);
277 
278 	b->x = (int) round(p.x);
279 	b->y = (int) round(p.y);
280 }
281 
282 /**
283  * @brief Get bob current depth in its container, aka drawing order.
284  *
285  * @param[in] d Bob container id returned by bob_create_container()
286  * @param[in] e Bob id returned by bob_create()
287  *
288  * @retval Bob drawing order in its container
289  *
290  */
291 
bob_get_depth(unsigned int d,unsigned int e)292 int bob_get_depth(unsigned int d, unsigned int e) {
293 	struct b_bob *b;
294 
295 	if((b = bob_get_bob_by_id(d, e)) == NULL) return(0);
296 
297 	return(b->z);
298 }
299 
300 /**
301  * @brief Set bob depth in its container, aka drawing order.
302  *
303  * Bobs are drawn by starting from the lowest number to highest, ie. highest depth is the topmost.
304  *
305  * @param[in] d Bob container id returned by bob_create_container()
306  * @param[in] e Bob id returned by bob_create()
307  * @param[in] z Bob drawing order in its container
308  *
309  */
310 
bob_set_depth(unsigned int d,unsigned int e,int z)311 void bob_set_depth(unsigned int d, unsigned int e, int z) {
312 	struct b_bob *b;
313 	struct b_bob_c *c;
314 
315 	if((b = bob_get_bob_by_id(d, e)) == NULL) return;
316 	if((c = bob_get_container_by_id(d)) == NULL) return;
317 
318 	if(b->z == z) return;
319 
320 	/* Hold on a while if bobs are currently being processed */
321 	while(b_lck == IS_YES) {
322 		(void) timer_wait(0, TIMER_RESOLUTION_VERYFAST);
323 	}
324 
325 	b_lck = IS_MAYBE;
326 
327 	b->z = z;
328 
329 	/* Sort bob array */
330 	if(c->c > 1) {
331 		(void) qsort((void *) c->b, (size_t) c->c, sizeof(struct b_bob *), bob_create_cmp);
332 	}
333 
334 	b_lck = IS_NO;
335 }
336 
337 /**
338  * @brief Get distance in pixels between two bobs.
339  *
340  * @param[in] d First bob container id returned by bob_create_container()
341  * @param[in] e First bob id returned by bob_create()
342  * @param[in] o Second bob container id returned by bob_create_container()
343  * @param[in] p Second bob id returned by bob_create()
344  *
345  * @retval Distance in pixels
346  *
347  */
348 
bob_get_distance(unsigned int d,unsigned int e,unsigned int o,unsigned int p)349 unsigned int bob_get_distance(unsigned int d, unsigned int e, unsigned int o, unsigned int p) {
350 	struct b_bob *b, *c;
351 
352 	struct position x, y;
353 
354 	if((b = bob_get_bob_by_id(d, e)) == NULL) return(0);
355 	if((c = bob_get_bob_by_id(o, p)) == NULL) return(0);
356 
357 	x.x = (double) b->x;
358 	x.y = (double) b->y;
359 	x.z = 0.0;
360 
361 	y.x = (double) c->x;
362 	y.y = (double) c->y;
363 	y.z = 0.0;
364 
365 	return((unsigned int) round(coords_difference_2d(&x, &y)));
366 }
367 
368 /**
369  * @brief Get distance in pixels between bob and given point.
370  *
371  * @param[in] d Bob container id returned by bob_create_container()
372  * @param[in] e Bob id returned by bob_create()
373  * @param[in] x Point x position in pixels
374  * @param[in] y Point y position in pixels
375  *
376  * @retval Distance in pixels
377  *
378  */
379 
bob_get_measure(unsigned int d,unsigned int e,int x,int y)380 unsigned int bob_get_measure(unsigned int d, unsigned int e, int x, int y) {
381 	struct b_bob *b;
382 
383 	struct position o, p;
384 
385 	if((b = bob_get_bob_by_id(d, e)) == NULL) return(0);
386 
387 	o.x = (double) x;
388 	o.y = (double) y;
389 	o.z = 0.0;
390 
391 	p.x = (double) b->x;
392 	p.y = (double) b->y;
393 	p.z = 0.0;
394 
395 	return((unsigned int) round(coords_difference_2d(&o, &p)));
396 }
397 
398 /**
399  * @brief Get bob current mapping, aka visibility, state.
400  *
401  * @param[in] d Bob container id returned by bob_create_container()
402  * @param[in] e Bob id returned by bob_create()
403  *
404  * @retval Bob mapping state (IS_YES or IS_NO)
405  *
406  */
407 
bob_get_map(unsigned int d,unsigned int e)408 unsigned int bob_get_map(unsigned int d, unsigned int e) {
409 	struct b_bob *b;
410 
411 	if((b = bob_get_bob_by_id(d, e)) == NULL) return(0);
412 
413 	return(b->m);
414 }
415 
416 /**
417  * @brief Set bob mapping, aka visibility, state.
418  *
419  * @param[in] d Bob container id returned by bob_create_container()
420  * @param[in] e Bob id returned by bob_create()
421  * @param[in] m Bob mapping state (IS_YES or IS_NO)
422  *
423  */
424 
bob_set_map(unsigned int d,unsigned int e,unsigned int m)425 void bob_set_map(unsigned int d, unsigned int e, unsigned int m) {
426 	struct b_bob *b;
427 
428 	if((b = bob_get_bob_by_id(d, e)) == NULL) return;
429 
430 	b->play.u = clock_get_ticks();
431 
432 	b->m = m;
433 }
434 
435 /**
436  * @brief Get bob current play direction.
437  *
438  * @param[in] d Bob container id returned by bob_create_container()
439  * @param[in] e Bob id returned by bob_create()
440  *
441  * @retval Bob play direction (BOB_PLAY_DIRECTION_*)
442  *
443  */
444 
bob_get_playdirection(unsigned int d,unsigned int e)445 unsigned int bob_get_playdirection(unsigned int d, unsigned int e) {
446 	struct b_bob *b;
447 
448 	if((b = bob_get_bob_by_id(d, e)) == NULL) return(0);
449 
450 	return(b->play.n);
451 }
452 
453 /**
454  * @brief Set bob play direction.
455  *
456  * @param[in] d Bob container id returned by bob_create_container()
457  * @param[in] e Bob id returned by bob_create()
458  * @param[in] n Bob play direction (BOB_PLAY_DIRECTION_*)
459  *
460  */
461 
bob_set_playdirection(unsigned int d,unsigned int e,unsigned int n)462 void bob_set_playdirection(unsigned int d, unsigned int e, unsigned int n) {
463 	struct b_bob *b;
464 
465 	if((b = bob_get_bob_by_id(d, e)) == NULL) return;
466 
467 	b->play.n = n;
468 }
469 
470 /**
471  * @brief Get bob current play mode.
472  *
473  * @param[in] d Bob container id returned by bob_create_container()
474  * @param[in] e Bob id returned by bob_create()
475  *
476  * @retval Bob play mode (BOB_PLAY_MODE_*)
477  *
478  */
479 
bob_get_playmode(unsigned int d,unsigned int e)480 unsigned int bob_get_playmode(unsigned int d, unsigned int e) {
481 	struct b_bob *b;
482 
483 	if((b = bob_get_bob_by_id(d, e)) == NULL) return(0);
484 
485 	return(b->play.m);
486 }
487 
488 /**
489  * @brief Set bob play mode.
490  *
491  * @param[in] d Bob container id returned by bob_create_container()
492  * @param[in] e Bob id returned by bob_create()
493  * @param[in] m Bob play mode (BOB_PLAY_MODE_*)
494  *
495  */
496 
bob_set_playmode(unsigned int d,unsigned int e,unsigned int m)497 void bob_set_playmode(unsigned int d, unsigned int e, unsigned int m) {
498 	struct b_bob *b;
499 
500 	if((b = bob_get_bob_by_id(d, e)) == NULL) return;
501 
502 	b->play.m = m;
503 }
504 
505 /**
506  * @brief Get bob current frame skip in frames.
507  *
508  * @param[in] d Bob container id returned by bob_create_container()
509  * @param[in] e Bob id returned by bob_create()
510  *
511  * @retval Bob frame skip in frames
512  *
513  */
514 
bob_get_playskip(unsigned int d,unsigned int e)515 unsigned int bob_get_playskip(unsigned int d, unsigned int e) {
516 	struct b_bob *b;
517 
518 	if((b = bob_get_bob_by_id(d, e)) == NULL) return(0);
519 
520 	return(b->play.s);
521 }
522 
523 /**
524  * @brief Set bob frame skip in frames.
525  *
526  * @param[in] d Bob container id returned by bob_create_container()
527  * @param[in] e Bob id returned by bob_create()
528  * @param[in] s Bob frame skip in frames
529  *
530  */
531 
bob_set_playskip(unsigned int d,unsigned int e,unsigned int s)532 void bob_set_playskip(unsigned int d, unsigned int e, unsigned int s) {
533 	struct b_bob *b;
534 
535 	if((b = bob_get_bob_by_id(d, e)) == NULL) return;
536 
537 	b->play.s = s;
538 }
539 
540 /**
541  * @brief Get bob current play speed.
542  *
543  * @param[in] d Bob container id returned by bob_create_container()
544  * @param[in] e Bob id returned by bob_create()
545  *
546  * @retval Bob play speed as multiplier to one second
547  *
548  */
549 
bob_get_playspeed(unsigned int d,unsigned int e)550 double bob_get_playspeed(unsigned int d, unsigned int e) {
551 	struct b_bob *b;
552 
553 	if((b = bob_get_bob_by_id(d, e)) == NULL) return(0.0);
554 
555 	return(b->play.r);
556 }
557 
558 /**
559  * @brief Set bob play speed.
560  *
561  * @param[in] d Bob container id returned by bob_create_container()
562  * @param[in] e Bob id returned by bob_create()
563  * @param[in] r Bob play speed as multiplier to one second
564  *
565  */
566 
bob_set_playspeed(unsigned int d,unsigned int e,double r)567 void bob_set_playspeed(unsigned int d, unsigned int e, double r) {
568 	struct b_bob *b;
569 
570 	if((b = bob_get_bob_by_id(d, e)) == NULL) return;
571 
572 	b->play.r = r;
573 }
574 
575 /**
576  * @brief Set bob current frame to display.
577  *
578  * @param[in] d Bob container id returned by bob_create_container()
579  * @param[in] e Bob id returned by bob_create()
580  * @param[in] c Bob frame number to display
581  *
582  */
583 
bob_set_frame(unsigned int d,unsigned int e,unsigned int c)584 void bob_set_frame(unsigned int d, unsigned int e, unsigned int c) {
585 	struct b_bob *b;
586 
587 	if((b = bob_get_bob_by_id(d, e)) == NULL) return;
588 
589 	b->c = c;
590 
591 	(void) bob_set_frame_op(b);
592 }
593 
594 /**
595  * @brief Add offset to bob frame to display.
596  *
597  * @param[in] d Bob container id returned by bob_create_container()
598  * @param[in] e Bob id returned by bob_create()
599  * @param[in] c Frames to add to current frame
600  *
601  */
602 
bob_add_frame(unsigned int d,unsigned int e,int c)603 void bob_add_frame(unsigned int d, unsigned int e, int c) {
604 	struct b_bob *b;
605 
606 	if((b = bob_get_bob_by_id(d, e)) == NULL) return;
607 
608 	b->c += c;
609 
610 	(void) bob_set_frame_op(b);
611 }
612 
613 /**
614  * @brief Subtract offset from bob frame to display.
615  *
616  * @param[in] d Bob container id returned by bob_create_container()
617  * @param[in] e Bob id returned by bob_create()
618  * @param[in] c Frames to subtract from current frame
619  *
620  */
621 
bob_sub_frame(unsigned int d,unsigned int e,int c)622 void bob_sub_frame(unsigned int d, unsigned int e, int c) {
623 	struct b_bob *b;
624 
625 	if((b = bob_get_bob_by_id(d, e)) == NULL) return;
626 
627 	b->c -= c;
628 
629 	(void) bob_set_frame_op(b);
630 }
631 
bob_set_frame_op(struct b_bob * b)632 static void bob_set_frame_op(struct b_bob *b) {
633 	switch(b->play.m) {
634 		case BOB_PLAY_MODE_MANUAL:
635 			b->play.u = clock_get_ticks();
636 
637 			/* Handle possible frame overflow */
638 			if(b->c >= b->data->c) b->c %= b->data->c;
639 
640 			break;
641 		default:
642 			break;
643 	}
644 }
645 
646 /**
647  * @brief Get bob container depth, aka drawing order.
648  *
649  * @param[in] d Bob container id returned by bob_create_container()
650  *
651  * @retval Bob container drawing order
652  *
653  */
654 
bob_get_container_depth(unsigned int d)655 int bob_get_container_depth(unsigned int d) {
656 	struct b_bob_c *c;
657 
658 	if((c = bob_get_container_by_id(d)) == NULL) return(0);
659 
660 	return(c->z);
661 }
662 
663 /**
664  * @brief Set bob container depth, aka drawing order.
665  *
666  * Bob containers are drawn by starting from the lowest number to highest, ie. highest depth is the topmost.
667  *
668  * @param[in] d Bob container id returned by bob_create_container()
669  * @param[in] z Bob container drawing order
670  *
671  */
672 
bob_set_container_depth(unsigned int d,int z)673 void bob_set_container_depth(unsigned int d, int z) {
674 	struct b_bob_c *c;
675 
676 	if((c = bob_get_container_by_id(d)) == NULL) return;
677 
678 	if(c->z == z) return;
679 
680 	/* Hold on a while if bobs are currently being processed */
681 	while(b_lck == IS_YES) {
682 		(void) timer_wait(0, TIMER_RESOLUTION_VERYFAST);
683 	}
684 
685 	b_lck = IS_MAYBE;
686 
687 	c->z = z;
688 
689 	/* Sort bob container array */
690 	if(c_bob > 1) {
691 		(void) qsort((void *) a_bob, (size_t) c_bob, sizeof(struct b_bob_c *), bob_create_container_cmp);
692 	}
693 
694 	b_lck = IS_NO;
695 }
696 
697 /**
698  * @brief Create new bob in given container.
699  *
700  * Initial visibility, aka mapping, for new bob is hidden. Use bob_set_map() to change visibility.
701  * Use positive value for drawing order to get bob on top of background.
702  *
703  * @param[in] f Bob file id returned by bob_init_[file|image]()
704  * @param[in] n Bob container id returned by bob_create_container()
705  * @param[in] a Bob initial altitude in pixels
706  * @param[in] x Bob initial position in x axis
707  * @param[in] y Bob initial position in y axis
708  * @param[in] z Bob initial depth in its container, aka drawing order
709  *
710  * @retval Bob id on success
711  * @retval Zero on failure
712  *
713  */
714 
bob_create(unsigned int f,unsigned int n,unsigned int a,int x,int y,int z)715 unsigned int bob_create(unsigned int f, unsigned int n, unsigned int a, int x, int y, int z) {
716 	struct b_bob_c *c;
717 	struct b_bob **t;
718 
719 	if((c = bob_get_container_by_id(n)) == NULL) return(0);
720 
721 	APP_REALLOC_RET_VALUE(t, c->b, sizeof(struct b_bob *) * (c->c + 1), 0);
722 	APP_MALLOC_RET_VALUE(c->b[c->c], sizeof(struct b_bob), 0);
723 
724 	(void) memset((void *) c->b[c->c], 0, sizeof(struct b_bob));
725 
726 	/* Hold on a while if bobs are currently being processed */
727 	while(b_lck == IS_YES) {
728 		(void) timer_wait(0, TIMER_RESOLUTION_VERYFAST);
729 	}
730 
731 	b_lck = IS_MAYBE;
732 
733 	if(bob_create_op(f, c->b[c->c]) != 0) {
734 		(void) free(c->b[c->c]);
735 
736 		c->b[c->c] = NULL;
737 
738 		b_lck = IS_NO;
739 
740 		return(0);
741 	}
742 
743 	c->b[c->c]->d = ++c->p;
744 
745 	c->b[c->c]->m = IS_NO;
746 
747 	c->b[c->c]->o = 0;
748 
749 	c->b[c->c]->c = 0;
750 
751 	c->b[c->c]->a = a;
752 	c->b[c->c]->x = x;
753 	c->b[c->c]->y = y;
754 	c->b[c->c]->z = z;
755 
756 	c->b[c->c]->play.n = BOB_PLAY_DIRECTION_NONE;
757 	c->b[c->c]->play.m = BOB_PLAY_MODE_MANUAL;
758 	c->b[c->c]->play.s = 0;
759 
760 	c->b[c->c]->play.r = BOB_UPDATE_RATE_DEFAULT;
761 	c->b[c->c]->play.u = 0.0;
762 
763 	/* Sort bob array */
764 	if(++c->c > 1) {
765 		(void) qsort((void *) c->b, (size_t) c->c, sizeof(struct b_bob *), bob_create_cmp);
766 	}
767 
768 	b_lck = IS_NO;
769 
770 	return(c->p);
771 }
772 
bob_create_cmp(const void * a,const void * b)773 static int bob_create_cmp(const void *a, const void *b) {
774 	const struct b_bob *c, *d;
775 
776 	c = *(const struct b_bob **) a;
777 	d = *(const struct b_bob **) b;
778 
779 	return(c->z - d->z);
780 }
781 
bob_create_op(unsigned int d,struct b_bob * b)782 static int bob_create_op(unsigned int d, struct b_bob *b) {
783 	struct a_bob *a;
784 
785 	if((a = bob_get_file_by_id(d)) == NULL) return(-1);
786 
787 	b->data = a;
788 
789 	return(0);
790 }
791 
792 /**
793  * @brief Create new background in given container.
794  *
795  * Initial visibility, aka mapping, for new background is hidden. Use bob_set_map() to change visibility.
796  * Use negative value for drawing order to get bobs on top of background.
797  *
798  * @param[in] f Bob file id returned by bob_init_[file|image]()
799  * @param[in] n Bob container id returned by bob_create_container()
800  * @param[in] o Background mode, non-zero for opaque or zero for translucent where alpha channel takes effect
801  * @param[in] z Background initial depth in its container, aka drawing order
802  *
803  * @retval Bob id on success
804  * @retval Zero on failure
805  *
806  */
807 
bob_create_background(unsigned int f,unsigned int n,unsigned int o,int z)808 unsigned int bob_create_background(unsigned int f, unsigned int n, unsigned int o, int z) {
809 	unsigned int d, w, h;
810 
811 	struct a_bob *a, *b;
812 	struct b_bob_c *c;
813 	struct b_bob **t;
814 
815 	if((c = bob_get_container_by_id(n)) == NULL) return(0);
816 
817 	if((w = window_get_active_width(c->h)) == 0 || (h = window_get_active_height(c->h)) == 0) {
818 		return(0);
819 	}
820 
821 	if((a = bob_get_file_by_id(f)) == NULL) return(0);
822 
823 	APP_REALLOC_RET_VALUE(t, c->b, sizeof(struct b_bob *) * (c->c + 1), 0);
824 	APP_MALLOC_RET_VALUE(c->b[c->c], sizeof(struct b_bob), 0);
825 
826 	(void) memset((void *) c->b[c->c], 0, sizeof(struct b_bob));
827 
828 	/* Hold on a while if bobs are currently being processed */
829 	while(b_lck == IS_YES) {
830 		(void) timer_wait(0, TIMER_RESOLUTION_VERYFAST);
831 	}
832 
833 	b_lck = IS_MAYBE;
834 
835 	if((d = bob_init_image(w, h)) == 0) return(0);
836 
837 	if((b = bob_create_background_at(c->b[c->c], d)) == NULL) {
838 		(void) bob_free_image(d);
839 		(void) free(c->b[c->c]);
840 
841 		c->b[c->c] = NULL;
842 
843 		b_lck = IS_NO;
844 
845 		return(0);
846 	}
847 
848 	/* Fill background source image */
849 	(void) bob_create_background_op(b->t_a.p, a->t_a.p,
850 		h / a->t_a.h, w / a->t_a.w, h % a->t_a.h, w % a->t_a.w,
851 		(unsigned int) a->t_a.w, (unsigned int) a->t_a.h, w);
852 
853 	c->b[c->c]->d = ++c->p;
854 
855 	c->b[c->c]->m = IS_NO;
856 
857 	c->b[c->c]->o = o;
858 
859 	c->b[c->c]->c = 0;
860 
861 	c->b[c->c]->a = 0;
862 	c->b[c->c]->x = 0;
863 	c->b[c->c]->y = 0;
864 	c->b[c->c]->z = z;
865 
866 	c->b[c->c]->play.n = BOB_PLAY_DIRECTION_NONE;
867 	c->b[c->c]->play.m = BOB_PLAY_MODE_MANUAL;
868 	c->b[c->c]->play.s = 0;
869 
870 	c->b[c->c]->play.r = 0.0;
871 	c->b[c->c]->play.u = 0.0;
872 
873 	/* Sort bob array */
874 	if(++c->c > 1) {
875 		(void) qsort((void *) c->b, (size_t) c->c, sizeof(struct b_bob *), bob_create_cmp);
876 	}
877 
878 	b_lck = IS_NO;
879 
880 	return(c->p);
881 }
882 
bob_create_background_at(struct b_bob * b,unsigned int d)883 static struct a_bob *bob_create_background_at(struct b_bob *b, unsigned int d) {
884 	struct a_bob *a;
885 
886 	if((a = bob_get_file_by_id(d)) == NULL) return(NULL);
887 
888 	b->data = a;
889 	b->data->i = d;
890 
891 	return(a);
892 }
893 
bob_create_background_op(struct pixel_rgba_8 * p,struct pixel_rgba_8 * r,unsigned int a,unsigned int b,unsigned int e,unsigned int f,unsigned int w,unsigned int h,unsigned int q)894 static void bob_create_background_op(struct pixel_rgba_8 *p, struct pixel_rgba_8 *r, unsigned int a, unsigned int b, unsigned int e, unsigned int f, unsigned int w, unsigned int h, unsigned int q) {
895 	unsigned int i, j;
896 
897 	for(i = 0; i < a; i++) {
898 		/* Copy row of bobs to background if needed */
899 		for(j = 0; j < b; j++) {
900 			(void) bob_create_background_op_full(p, r, j, i, w, h, q);
901 		}
902 
903 		/* Copy also partial bob at the end of the row if needed */
904 		if(f != 0) (void) bob_create_background_op_part(p, r, j, i, f, h, w, h, q);
905 	}
906 
907 	if(e != 0) {
908 		/* Copy last partial line of bobs if needed */
909 		for(j = 0; j < b; j++) {
910 			(void) bob_create_background_op_part(p, r, j, a, w, e, w, h, q);
911 		}
912 
913 		/* Copy also partial bob at the end of the last row if needed */
914 		if(f != 0) (void) bob_create_background_op_part(p, r, j, a, f, e, w, h, q);
915 	}
916 }
917 
bob_create_background_op_full(struct pixel_rgba_8 * a,struct pixel_rgba_8 * r,unsigned int x,unsigned int y,unsigned int e,unsigned int f,unsigned int q)918 static void bob_create_background_op_full(struct pixel_rgba_8 *a, struct pixel_rgba_8 *r, unsigned int x, unsigned int y, unsigned int e, unsigned int f, unsigned int q) {
919 	unsigned int i, j, k;
920 
921 	struct pixel_rgba_8 *b;
922 
923 	/* Adjust destination coordinate for tiling */
924 	a += (y * f) * q;
925 	a += (x * e);
926 
927 	for(i = 0; i < f; i++) {
928 		b = a + (i * q);
929 		k = i * e;
930 
931 		for(j = 0; j < e; j++) b[j].pixel.p = r[k + j].pixel.p;
932 	}
933 }
934 
bob_create_background_op_part(struct pixel_rgba_8 * a,struct pixel_rgba_8 * r,unsigned int x,unsigned int y,unsigned int w,unsigned int h,unsigned int e,unsigned int f,unsigned int q)935 static void bob_create_background_op_part(struct pixel_rgba_8 *a, struct pixel_rgba_8 *r, unsigned int x, unsigned int y, unsigned int w, unsigned int h, unsigned int e, unsigned int f, unsigned int q) {
936 	unsigned int i, j, k;
937 
938 	struct pixel_rgba_8 *b;
939 
940 	/* Adjust destination coordinate for tiling */
941 	a += (y * f) * q;
942 	a += (x * e);
943 
944 	for(i = 0; i < h; i++) {
945 		b = a + (i * q);
946 		k = i * e;
947 
948 		for(j = 0; j < w; j++) b[j].pixel.p = r[k + j].pixel.p;
949 	}
950 }
951 
952 /**
953  * @brief Create new bob container to host bobs.
954  *
955  * @param[in] h Window handle where to draw bobs created in this container
956  * @param[in] z Container initial depth, aka drawing order
957  *
958  * @retval Bob container id on success
959  * @retval Zero on failure
960  *
961  */
962 
bob_create_container(unsigned int h,int z)963 unsigned int bob_create_container(unsigned int h, int z) {
964 	if(c_bob >= BOB_CONTAINERS_MAX) {
965 		(void) flush_error();
966 
967 		LOGWARN(
968 			ERROR_SLIGHT, SUBSYSTEM,
969 			_("Failed to create new container, pool has reached its maximum limit of %u entries"),
970 			(unsigned int) BOB_CONTAINERS_MAX
971 		);
972 
973 		return(0);
974 	}
975 
976 	APP_MALLOC_RET_VALUE(a_bob[c_bob], sizeof(struct b_bob_c), 0);
977 
978 	(void) memset((void *) a_bob[c_bob], 0, sizeof(struct b_bob_c));
979 
980 	/* Hold on a while if bobs are currently being processed */
981 	while(b_lck == IS_YES) {
982 		(void) timer_wait(0, TIMER_RESOLUTION_VERYFAST);
983 	}
984 
985 	b_lck = IS_MAYBE;
986 
987 	a_bob[c_bob]->d = ++d_bob;
988 	a_bob[c_bob]->c = 0;
989 	a_bob[c_bob]->p = 0;
990 
991 	a_bob[c_bob]->h = h;
992 	a_bob[c_bob]->z = z;
993 
994 	a_bob[c_bob]->b = NULL;
995 
996 	/* Sort bob container array */
997 	if(++c_bob > 1) {
998 		(void) qsort((void *) a_bob, (size_t) c_bob, sizeof(struct b_bob_c *), bob_create_container_cmp);
999 	}
1000 
1001 	b_lck = IS_NO;
1002 
1003 	/* Request drawing if this is first container */
1004 	if(c_bob == 1) (void) bob_create_container_op();
1005 
1006 	return(d_bob);
1007 }
1008 
bob_create_container_cmp(const void * a,const void * b)1009 static int bob_create_container_cmp(const void *a, const void *b) {
1010 	const struct b_bob_c *c, *d;
1011 
1012 	c = *(const struct b_bob_c **) a;
1013 	d = *(const struct b_bob_c **) b;
1014 
1015 	return(c->z - d->z);
1016 }
1017 
bob_create_container_op(void)1018 static void bob_create_container_op(void) {
1019 	struct w_cmd c;
1020 
1021 	c.c = WINDOW_COMMAND_BOBS;
1022 	c.e = IS_YES;
1023 	c.h = 0;
1024 	c.p = (void *) a_bob;
1025 	c.t = sizeof(c.p);
1026 
1027 	(void) window_cmd_push(&c);
1028 }
1029 
1030 /**
1031  * @brief Delete bob from its container.
1032  *
1033  * When bob_delete() is called, bob is gone for good and cannot be used anymore.
1034  *
1035  * @param[in] d Bob container id returned by bob_create_container()
1036  * @param[in] e Bob id returned by bob_create()
1037  *
1038  */
1039 
bob_delete(unsigned int d,unsigned int e)1040 void bob_delete(unsigned int d, unsigned int e) {
1041 	unsigned int i;
1042 
1043 	size_t t;
1044 
1045 	struct b_bob *b;
1046 	struct b_bob_c *c;
1047 
1048 	if((c = bob_get_container_by_id(d)) == NULL) return;
1049 
1050 	for(i = 0; i < c->c; i++) {
1051 		if(c->b[i] == NULL || c->b[i]->d != e) continue;
1052 
1053 		/* Hold on a while if bobs are currently being processed */
1054 		while(b_lck == IS_YES) {
1055 			(void) timer_wait(0, TIMER_RESOLUTION_VERYFAST);
1056 		}
1057 
1058 		b_lck = IS_MAYBE;
1059 
1060 		if((b = bob_get_bob_by_id(d, e)) != NULL) {
1061 			/* Free also allocated image frame if this bob has one */
1062 			if(b->data->i != 0) (void) bob_free_image(b->data->i);
1063 
1064 			(void) free(b);
1065 		}
1066 
1067 		/* Compress bob array to get rid of deleted slot */
1068 		if((t = (c->c - (i + 1)) * sizeof(struct b_bob *)) != 0) {
1069 			(void) memmove(c->b + i, c->b + (i + 1), t);
1070 		}
1071 
1072 		--c->c;
1073 
1074 		b_lck = IS_NO;
1075 
1076 		return;
1077 	}
1078 }
1079 
1080 /**
1081  * @brief Delete bob container and all bobs in it.
1082  *
1083  * When bob_delete_container() is called, container and all bobs in it are gone for good and cannot be used anymore.
1084  *
1085  * @param[in] d Bob container id returned by bob_create_container()
1086  *
1087  */
1088 
bob_delete_container(unsigned int d)1089 void bob_delete_container(unsigned int d) {
1090 	unsigned int i, j;
1091 
1092 	size_t t;
1093 
1094 	struct b_bob_c *c;
1095 
1096 	for(i = 0; i < c_bob; i++) {
1097 		if(a_bob[i] == NULL || a_bob[i]->d != d) continue;
1098 
1099 		/* Hold on a while if bobs are currently being processed */
1100 		while(b_lck == IS_YES) {
1101 			(void) timer_wait(0, TIMER_RESOLUTION_VERYFAST);
1102 		}
1103 
1104 		b_lck = IS_MAYBE;
1105 
1106 		c = a_bob[i];
1107 
1108 		if(c->b != NULL) {
1109 			/* Free bobs in this container */
1110 			for(j = 0; j < c->c; j++) {
1111 				if(c->b[j] != NULL) (void) free(c->b[j]);
1112 			}
1113 
1114 			(void) free(c->b);
1115 		}
1116 
1117 		(void) free(c);
1118 
1119 		/* Compress bob container array to get rid of deleted slot */
1120 		if(c_bob > 1) {
1121 			if((t = (c_bob - (i + 1)) * sizeof(struct b_bob_c *)) != 0) {
1122 				(void) memmove(a_bob + i, a_bob + (i + 1), t);
1123 			}
1124 		}
1125 
1126 		/* Remove permanent command from command pool if last container was deleted */
1127 		if(--c_bob == 0) {
1128 			(void) window_cmd_cancel_permanent(WINDOW_COMMAND_BOBS);
1129 
1130 			d_bob = 0;
1131 		}
1132 
1133 		b_lck = IS_NO;
1134 
1135 		return;
1136 	}
1137 }
1138 
1139 /**
1140  * @brief Initialize bob image data from file.
1141  *
1142  * @param[in] a Bob image data file name
1143  *
1144  * @retval Bob file id on success
1145  * @retval Zero on failure
1146  *
1147  */
1148 
bob_init_file(char * a)1149 unsigned int bob_init_file(char *a) {
1150 	unsigned int i, d;
1151 
1152 	struct a_bob **t;
1153 
1154 	if(a == NULL) return(0);
1155 
1156 	/* Check if some slot can be reused */
1157 	d = 0;
1158 
1159 	for(i = 0; i < c_fle; i++) {
1160 		if(a_fle[i] == NULL) {
1161 			d = i + 1;
1162 
1163 			break;
1164 		}
1165 	}
1166 
1167 	if(d == 0) {
1168 		/* No free slot found, allocate one */
1169 		APP_REALLOC_RET_VALUE(t, a_fle, sizeof(struct a_bob *) * (c_fle + 1), 0);
1170 		APP_MALLOC_RET_VALUE(a_fle[c_fle], sizeof(struct a_bob), 0);
1171 
1172 		(void) memset((void *) a_fle[c_fle], 0, sizeof(struct a_bob));
1173 
1174 		d = ++c_fle;
1175 	}
1176 	else {
1177 		/* Reuse existing slot */
1178 		APP_MALLOC_RET_VALUE(a_fle[d - 1], sizeof(struct a_bob), 0);
1179 
1180 		(void) memset((void *) a_fle[d - 1], 0, sizeof(struct a_bob));
1181 	}
1182 
1183 	a_fle[d - 1]->d = d;
1184 	a_fle[d - 1]->i = 0;
1185 
1186 	/* Try to read and initialize the file */
1187 	if((a_fle[d - 1]->f = bob_init_file_op(a, a_fle[d - 1], &a_fle[d - 1]->t_a, &a_fle[d - 1]->t_b)) == 0) {
1188 		(void) free(a_fle[d - 1]);
1189 
1190 		a_fle[d - 1] = NULL;
1191 
1192 		return(0);
1193 	}
1194 
1195 	return(d);
1196 }
1197 
bob_init_file_op(char * a,struct a_bob * b,struct t_img * t_a,struct t_img * t_b)1198 static unsigned int bob_init_file_op(char *a, struct a_bob *b, struct t_img *t_a, struct t_img *t_b) {
1199 	unsigned int i, f;
1200 
1201 	char *s;
1202 
1203 	size_t t;
1204 
1205 	struct widget_header *h;
1206 
1207 	t = CONFIG_PATH_LENGTH;
1208 
1209 	APP_MALLOC_RET_VALUE(s, t + sizeof(char), 0);
1210 
1211 	for(i = 0; ; i++) {
1212 		if(c_d_t[i] == NULL) {
1213 			(void) flush_error();
1214 
1215 			LOGWARN(
1216 				ERROR_SLIGHT, SUBSYSTEM,
1217 				_("Failed to find %s from any of the bob directories, please check the installation"),
1218 				a
1219 			);
1220 
1221 			(void) free(s);
1222 
1223 			return(0);
1224 		}
1225 
1226 		if(conf_read_try(c_d_t[i], a, s, t) != 0) continue;
1227 
1228 		if((f = files_open(s, FILE_FLAG_SILENT, FILE_MODE_READ)) != 0) {
1229 			if((t = files_get_file_size(f)) == 0) {
1230 				(void) bob_init_file_op_c(s, f);
1231 
1232 				return(0);
1233 			}
1234 
1235 			if(files_read(f, t) != 0) {
1236 				(void) bob_init_file_op_c(s, f);
1237 
1238 				return(0);
1239 			}
1240 
1241 			break;
1242 		}
1243 	}
1244 
1245 	/* Check and initialize bob image data */
1246 	if((t_a->c = files_get_content(f)) == NULL) {
1247 		(void) bob_init_file_op_c(s, f);
1248 
1249 		return(0);
1250 	}
1251 
1252 	t_a->t = files_get_content_size(f);
1253 
1254 	h = (struct widget_header *) t_a->c;
1255 
1256 	for(i = 0; i < WIDGET_FILE_TAG_SIZE; i++) {
1257 		if(t_a->t < sizeof(struct widget_header) || h->id[i] != endian_le_uint32(widget_header_tag[i])) {
1258 			(void) flush_error();
1259 
1260 			LOGWARN(
1261 				ERROR_SLIGHT, SUBSYSTEM,
1262 				_("Failed to identify bob file %s, please check the installation"),
1263 				s
1264 			);
1265 
1266 			(void) bob_init_file_op_c(s, f);
1267 
1268 			return(0);
1269 		}
1270 	}
1271 
1272 	(void) free(s);
1273 
1274 	(void) bob_init_file_at(b, h, t_a, t_b);
1275 
1276 	return(f);
1277 }
1278 
bob_init_file_op_c(char * s,unsigned int f)1279 static void bob_init_file_op_c(char *s, unsigned int f) {
1280 	(void) files_close(f);
1281 	(void) free(s);
1282 }
1283 
bob_init_file_at(struct a_bob * b,struct widget_header * h,struct t_img * t_a,struct t_img * t_b)1284 static void bob_init_file_at(struct a_bob *b, struct widget_header *h, struct t_img *t_a, struct t_img *t_b) {
1285 	char *p;
1286 
1287 	/* Initialize bob image frames */
1288 	b->c = (unsigned int) endian_be_uint32(h->frames);
1289 
1290 	b->ox = (int) endian_be_int32(h->offset_x);
1291 	b->oy = (int) endian_be_int32(h->offset_y);
1292 
1293 	t_a->w = (int32_t) endian_be_uint32(h->widget_width);
1294 	t_a->h = (int32_t) endian_be_uint32(h->widget_height);
1295 
1296 	t_a->b = sizeof(struct pixel_rgba_8) * 8;
1297 
1298 	p = (char *) t_a->c;
1299 	p += sizeof(struct widget_header) + endian_be_uint32(h->widget_data);
1300 
1301 	t_a->p = (struct pixel_rgba_8 *) p;
1302 
1303 	/* Correct endianess in image data if needed */
1304 	(void) bob_init_file_en(t_a->p, b->c, (unsigned int) t_a->w, (unsigned int) t_a->h);
1305 
1306 	/* Initialize bob shadow frames */
1307 	t_b->c = t_a->c;
1308 	t_b->t = t_a->t;
1309 
1310 	t_b->w = (int32_t) endian_be_uint32(h->shadow_width);
1311 	t_b->h = (int32_t) endian_be_uint32(h->shadow_height);
1312 
1313 	if(t_b->w == 0 || t_b->h == 0) {
1314 		t_b->b = 0;
1315 
1316 		t_b->p = NULL;
1317 	}
1318 	else {
1319 		t_b->b = sizeof(struct pixel_rgba_8) * 8;
1320 
1321 		p = (char *) t_b->c;
1322 		p += sizeof(struct widget_header) + endian_be_uint32(h->shadow_data);
1323 
1324 		t_b->p = (struct pixel_rgba_8 *) p;
1325 
1326 		/* Correct endianess in shadow data if needed */
1327 		(void) bob_init_file_en(t_b->p, b->c, (unsigned int) t_b->w, (unsigned int) t_b->h);
1328 	}
1329 }
1330 
bob_init_file_en(struct pixel_rgba_8 * p,unsigned int e,unsigned int w,unsigned int h)1331 static void bob_init_file_en(struct pixel_rgba_8 *p, unsigned int e, unsigned int w, unsigned int h) {
1332 #if defined(IS_BIGENDIAN)
1333 	unsigned int i, j, k, l, n;
1334 
1335 	/* Big-endian machine needs bytes reversed */
1336 	for(l = 0; l < e; l++) {
1337 		n = w * h * l;
1338 
1339 		for(i = 0; i < h; i++) {
1340 			k = n + (i * w);
1341 
1342 			for(j = 0; j < w; j++) {
1343 				p[k + j].pixel.p = endian_le_uint32(p[k + j].pixel.p);
1344 			}
1345 		}
1346 	}
1347 #else
1348 	(void) p;
1349 	(void) e;
1350 	(void) w;
1351 	(void) h;
1352 #endif
1353 }
1354 
1355 /**
1356  * @brief Initialize one-frame bob with empty image buffer.
1357  *
1358  * @param[in] w Bob image data width in pixels
1359  * @param[in] h Bob image data height in pixels
1360  *
1361  * @retval Bob image id on success
1362  * @retval Zero on failure
1363  *
1364  */
1365 
bob_init_image(unsigned int w,unsigned int h)1366 unsigned int bob_init_image(unsigned int w, unsigned int h) {
1367 	unsigned int i, d;
1368 
1369 	struct a_bob **t;
1370 
1371 	if(w == 0 || h == 0) return(0);
1372 
1373 	/* Check if some slot can be reused */
1374 	d = 0;
1375 
1376 	for(i = 0; i < c_fle; i++) {
1377 		if(a_fle[i] == NULL) {
1378 			d = i + 1;
1379 
1380 			break;
1381 		}
1382 	}
1383 
1384 	if(d == 0) {
1385 		/* No free slot found, allocate one */
1386 		APP_REALLOC_RET_VALUE(t, a_fle, sizeof(struct a_bob *) * (c_fle + 1), 0);
1387 		APP_MALLOC_RET_VALUE(a_fle[c_fle], sizeof(struct a_bob), 0);
1388 
1389 		(void) memset((void *) a_fle[c_fle], 0, sizeof(struct a_bob));
1390 
1391 		d = ++c_fle;
1392 	}
1393 	else {
1394 		/* Reuse existing slot */
1395 		APP_MALLOC_RET_VALUE(a_fle[d - 1], sizeof(struct a_bob), 0);
1396 
1397 		(void) memset((void *) a_fle[d - 1], 0, sizeof(struct a_bob));
1398 	}
1399 
1400 	a_fle[d - 1]->d = d;
1401 	a_fle[d - 1]->f = 0;
1402 	a_fle[d - 1]->i = 0;
1403 
1404 	a_fle[d - 1]->c = 1;
1405 
1406 	a_fle[d - 1]->ox = 0;
1407 	a_fle[d - 1]->oy = 0;
1408 
1409 	/* Try to initialize empty image buffer */
1410 	if(bob_init_image_op(w, h, &a_fle[d - 1]->t_a, &a_fle[d - 1]->t_b) != 0) {
1411 		(void) free(a_fle[d - 1]);
1412 
1413 		a_fle[d - 1] = NULL;
1414 
1415 		return(0);
1416 	}
1417 
1418 	return(d);
1419 }
1420 
bob_init_image_op(unsigned int w,unsigned int h,struct t_img * t_a,struct t_img * t_b)1421 static int bob_init_image_op(unsigned int w, unsigned int h, struct t_img *t_a, struct t_img *t_b) {
1422 	char *p;
1423 
1424 	size_t t;
1425 
1426 	t = (w * h) * sizeof(struct pixel_rgba_8);
1427 
1428 	APP_MALLOC_RET_VALUE(p, t, -1);
1429 
1430 	/* Initialize bob image frame */
1431 	t_a->w = (int32_t) w;
1432 	t_a->h = (int32_t) h;
1433 
1434 	t_a->b = sizeof(struct pixel_rgba_8) * 8;
1435 
1436 	t_a->c = (void *) p;
1437 	t_a->p = (struct pixel_rgba_8 *) t_a->c;
1438 	t_a->t = t;
1439 
1440 	(void) memset((void *) t_a->c, 0, t);
1441 
1442 	/* Initialize empty shadow frame */
1443 	t_b->w = 0;
1444 	t_b->h = 0;
1445 
1446 	t_b->b = 0;
1447 
1448 	t_b->c = NULL;
1449 	t_b->p = (struct pixel_rgba_8 *) t_b->c;
1450 	t_b->t = 0;
1451 
1452 	return(0);
1453 }
1454 
1455 /**
1456  * @brief Free bob file.
1457  *
1458  * When bob_free_file() is called, file is freed for good and cannot be accessed anymore.
1459  * All bobs using this file must be deleted before calling this function.
1460  *
1461  * @param[in] d Bob file id returned by bob_init_file()
1462  *
1463  */
1464 
bob_free_file(unsigned int d)1465 void bob_free_file(unsigned int d) {
1466 	unsigned int i;
1467 
1468 	for(i = 0; i < c_fle; i++) {
1469 		if(a_fle[i] != NULL && a_fle[i]->d == d) {
1470 			(void) files_close(a_fle[i]->f);
1471 			(void) free(a_fle[i]);
1472 
1473 			a_fle[i] = NULL;
1474 
1475 			break;
1476 		}
1477 	}
1478 }
1479 
1480 /**
1481  * @brief Free bob image.
1482  *
1483  * When bob_free_image() is called, image is freed for good and cannot be accessed anymore.
1484  * All bobs using this image must be deleted before calling this function.
1485  *
1486  * @param[in] d Bob image id returned by bob_init_image()
1487  *
1488  */
1489 
bob_free_image(unsigned int d)1490 void bob_free_image(unsigned int d) {
1491 	unsigned int i;
1492 
1493 	for(i = 0; i < c_fle; i++) {
1494 		if(a_fle[i] != NULL && a_fle[i]->d == d) {
1495 			(void) free(a_fle[i]->t_a.c);
1496 			(void) free(a_fle[i]);
1497 
1498 			a_fle[i] = NULL;
1499 
1500 			break;
1501 		}
1502 	}
1503 }
1504 
bob_get_frame(unsigned int d,unsigned int e,struct w_bob * b,struct w_bob * s)1505 int bob_get_frame(unsigned int d, unsigned int e, struct w_bob *b, struct w_bob *s) {
1506 	struct b_bob *c;
1507 	struct pixel_rgba_8 *p;
1508 
1509 	c = a_bob[d]->b[e];
1510 
1511 	/* Return error to caller if bob is not mapped */
1512 	if(c->m != IS_YES) return(-1);
1513 
1514 	/* Pass bob image frame to the caller */
1515 	b->x = c->x;
1516 	b->y = c->y - c->a;
1517 
1518 	b->width = c->data->t_a.w;
1519 	b->height = c->data->t_a.h;
1520 	b->opaque = c->o;
1521 
1522 	p = c->data->t_a.p;
1523 	p += (c->data->t_a.w * c->data->t_a.h) * c->c;
1524 
1525 	b->frame = p;
1526 
1527 	/* Pass bob shadow frame to the caller */
1528 	s->x = c->x + c->data->ox;
1529 	s->y = c->y + c->data->oy;
1530 
1531 	s->width = c->data->t_b.w;
1532 	s->height = c->data->t_b.h;
1533 	s->opaque = c->o;
1534 
1535 	if(c->data->t_b.p != NULL) {
1536 		p = c->data->t_b.p;
1537 		p += (c->data->t_b.w * c->data->t_b.h) * c->c;
1538 
1539 		s->frame = p;
1540 	}
1541 	else s->frame = NULL;
1542 
1543 	/* Pass container's window handle to the caller */
1544 	b->hnd = a_bob[d]->h;
1545 
1546 	/* Prepare new frame for next iteration */
1547 	(void) bob_get_frame_op(c);
1548 
1549 	return(0);
1550 }
1551 
bob_get_frame_op(struct b_bob * c)1552 static void bob_get_frame_op(struct b_bob *c) {
1553 	if(c->data->c < 2 || c->play.m == BOB_PLAY_MODE_MANUAL) return;
1554 
1555 	/* If this frame's visible timeslice exceeded, update frame */
1556 	if(clock_get_ticks() - c->play.u >= c->play.r) {
1557 		switch(c->play.n) {
1558 			case BOB_PLAY_DIRECTION_FORWARD:
1559 				c->c = c->c + (1 + c->play.s);
1560 
1561 				break;
1562 			case BOB_PLAY_DIRECTION_BACKWARDS:
1563 				c->c = c->c - (1 + c->play.s);
1564 
1565 				break;
1566 			default:
1567 				break;
1568 		}
1569 
1570 		/* Bob play mode says what happens if new frame is off limits */
1571 		if(c->c >= c->data->c) {
1572 			switch(c->play.m) {
1573 				case BOB_PLAY_MODE_ONCE:
1574 					c->c = 0;
1575 					c->m = IS_NO;
1576 
1577 					break;
1578 				default:
1579 					c->c %= c->data->c;
1580 
1581 					break;
1582 			}
1583 		}
1584 
1585 		c->play.u += c->play.r;
1586 	}
1587 }
1588 
bob_count(unsigned int d)1589 unsigned int bob_count(unsigned int d) {
1590 	return(a_bob[d]->c);
1591 }
1592 
bob_begin(void)1593 unsigned int bob_begin(void) {
1594 	b_lck = IS_YES;
1595 
1596 	return(c_bob);
1597 }
1598 
bob_end(void)1599 void bob_end(void) {
1600 	b_lck = IS_NO;
1601 }
1602 
bob_locked(void)1603 void bob_locked(void) {
1604 	while(b_lck == IS_MAYBE) {
1605 		(void) timer_wait(0, TIMER_RESOLUTION_VERYFAST);
1606 	}
1607 }
1608 
bob_get_file_by_id(unsigned int d)1609 static struct a_bob *bob_get_file_by_id(unsigned int d) {
1610 	unsigned int i;
1611 
1612 	for(i = 0; i < c_fle; i++) {
1613 		if(a_fle[i] != NULL && a_fle[i]->d == d) return(a_fle[i]);
1614 	}
1615 
1616 	return(NULL);
1617 }
1618 
bob_get_bob_by_id(unsigned int d,unsigned int b)1619 static struct b_bob *bob_get_bob_by_id(unsigned int d, unsigned int b) {
1620 	unsigned int i;
1621 
1622 	struct b_bob_c *c;
1623 
1624 	if((c = bob_get_container_by_id(d)) == NULL) return(NULL);
1625 
1626 	for(i = 0; i < c->c; i++) {
1627 		if(c->b[i] != NULL && c->b[i]->d == b) return(c->b[i]);
1628 	}
1629 
1630 	return(NULL);
1631 }
1632 
bob_get_container_by_id(unsigned int d)1633 static struct b_bob_c *bob_get_container_by_id(unsigned int d) {
1634 	unsigned int i;
1635 
1636 	for(i = 0; i < c_bob; i++) {
1637 		if(a_bob[i] != NULL && a_bob[i]->d == d) return(a_bob[i]);
1638 	}
1639 
1640 	return(NULL);
1641 }
1642 
bob_get_default_bob_path(unsigned int i)1643 const char *bob_get_default_bob_path(unsigned int i) {
1644 	return(c_d_t[i]);
1645 }
1646 #endif
1647