Levelauswahl auf Badge.
[hackover2013-badge-firmware.git] / badge / ui / sprite.c
1 #include "sprite.h"
2
3 //#include <assert.h>
4 #include <inttypes.h>
5 #include <limits.h>
6 #include <stdio.h>
7
8 typedef struct {
9 uint8_t const *data_ptr;
10 uint8_t left_in_byte;
11 } sprite_column_iterator;
12
13 static inline int8_t i8min( int8_t x, int8_t y) { return x < y ? x : y; }
14 static inline int8_t i8max( int8_t x, int8_t y) { return x < y ? y : x; }
15 static inline uint8_t u8min(uint8_t x, uint8_t y) { return x < y ? x : y; }
16 static inline uint8_t u8max(uint8_t x, uint8_t y) { return x < y ? y : x; }
17
18 static inline sprite_column_iterator sprite_column_iterator_init(badge_sprite const *sprite, uint8_t xskip) {
19 sprite_column_iterator result = { sprite->data, CHAR_BIT };
20
21 if(xskip != 0) {
22 int skip_bits = (xskip * sprite->height);
23
24 result.data_ptr += skip_bits / CHAR_BIT;
25 result.left_in_byte = CHAR_BIT - skip_bits % 8;
26 }
27
28 return result;
29 }
30
31 static inline uint32_t sprite_column_iterator_pop(sprite_column_iterator *iter, uint8_t height) {
32 uint32_t column = 0;
33
34 if(iter->left_in_byte > height) {
35 column = *iter->data_ptr >> (CHAR_BIT - iter->left_in_byte) & ((1 << height) - 1);
36 iter->left_in_byte -= height;
37 } else {
38 column = *iter->data_ptr >> (CHAR_BIT - iter->left_in_byte);
39
40 uint8_t shlen = iter->left_in_byte;
41 uint8_t n;
42
43 for(n = height - shlen; n >= CHAR_BIT; n -= CHAR_BIT) {
44 column |= *++iter->data_ptr << shlen;
45 shlen += CHAR_BIT;
46 }
47
48 column |= (*++iter->data_ptr & ((1 << n) - 1)) << shlen;
49 iter->left_in_byte = CHAR_BIT - n;
50 }
51
52 return column;
53 }
54
55 void badge_framebuffer_blt(badge_framebuffer *fb,
56 int8_t x,
57 int8_t y,
58 badge_sprite const *sprite,
59 unsigned flags)
60 {
61 if(y >= BADGE_DISPLAY_HEIGHT ||
62 x >= BADGE_DISPLAY_WIDTH ||
63 y <= -sprite->height ||
64 x <= -sprite->width) {
65 // Nichts zu tun.
66 return;
67 }
68
69 int8_t y_major = y / BADGE_DISPLAY_STRIPE_HEIGHT - (y < 0);
70 uint8_t y_minor = (uint8_t) (y - y_major * BADGE_DISPLAY_STRIPE_HEIGHT);
71
72 int8_t xmove;
73 int8_t xcursor;
74 int8_t xend;
75 uint8_t xskip;
76
77 if(flags & BADGE_BLT_MIRRORED) {
78 xmove = -1;
79 xcursor = i8min(x + sprite->width, BADGE_DISPLAY_WIDTH) - 1;
80 xend = i8max(x, 0) - 1;
81 xskip = x + sprite->width - xcursor - 1;
82 } else {
83 xmove = 1;
84 xcursor = i8max(x, 0);
85 xend = i8min(x + sprite->width, BADGE_DISPLAY_WIDTH);
86 xskip = xcursor - x;
87 }
88
89 sprite_column_iterator col_iter = sprite_column_iterator_init(sprite, xskip);
90
91 while(xcursor != xend) {
92 uint32_t column = sprite_column_iterator_pop(&col_iter, sprite->height);
93
94 /*
95 assert(xcursor >= 0);
96 assert(xcursor < BADGE_DISPLAY_WIDTH);
97 */
98
99 if(y_major >= 0) {
100 fb->data[y_major][xcursor] |= (uint8_t) column << y_minor;
101 }
102
103 uint8_t stripe_max = u8min((sprite->height + y_minor - 1) / BADGE_DISPLAY_STRIPE_HEIGHT,
104 BADGE_DISPLAY_STRIPE_COUNT - y_major - 1);
105
106 for(uint8_t stripe_ptr = i8max(1, -y_major); stripe_ptr <= stripe_max; ++stripe_ptr) {
107 /*
108 assert(y_major + stripe_ptr >= 0);
109 assert(y_major + stripe_ptr < BADGE_DISPLAY_STRIPE_COUNT);
110 */
111
112 fb->data[y_major + stripe_ptr][xcursor] |= (uint8_t) (column >> (stripe_ptr * BADGE_DISPLAY_STRIPE_HEIGHT - y_minor));
113 }
114
115 xcursor += xmove;
116 }
117 }
This page took 0.060631 seconds and 5 git commands to generate.