Arduboy2 Library  6.0.0
SpritesB.cpp
Go to the documentation of this file.
1 
8 #include "SpritesB.h"
9 
10 void SpritesB::drawExternalMask(int16_t x, int16_t y, const uint8_t *bitmap,
11  const uint8_t *mask, uint8_t frame, uint8_t mask_frame)
12 {
13  draw(x, y, bitmap, frame, mask, mask_frame, SPRITE_MASKED);
14 }
15 
16 void SpritesB::drawOverwrite(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame)
17 {
18  draw(x, y, bitmap, frame, NULL, 0, SPRITE_OVERWRITE);
19 }
20 
21 void SpritesB::drawErase(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame)
22 {
23  draw(x, y, bitmap, frame, NULL, 0, SPRITE_IS_MASK_ERASE);
24 }
25 
26 void SpritesB::drawSelfMasked(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame)
27 {
28  draw(x, y, bitmap, frame, NULL, 0, SPRITE_IS_MASK);
29 }
30 
31 void SpritesB::drawPlusMask(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame)
32 {
33  draw(x, y, bitmap, frame, NULL, 0, SPRITE_PLUS_MASK);
34 }
35 
36 
37 //common functions
38 void SpritesB::draw(int16_t x, int16_t y,
39  const uint8_t *bitmap, uint8_t frame,
40  const uint8_t *mask, uint8_t sprite_frame,
41  uint8_t drawMode)
42 {
43  unsigned int frame_offset;
44 
45  if (bitmap == NULL)
46  return;
47 
48  uint8_t width = pgm_read_byte(bitmap);
49  uint8_t height = pgm_read_byte(++bitmap);
50  bitmap++;
51  if (frame > 0 || sprite_frame > 0) {
52  frame_offset = (width * ( height / 8 + ( height % 8 == 0 ? 0 : 1)));
53  // sprite plus mask uses twice as much space for each frame
54  if (drawMode == SPRITE_PLUS_MASK) {
55  frame_offset *= 2;
56  } else if (mask != NULL) {
57  mask += sprite_frame * frame_offset;
58  }
59  bitmap += frame * frame_offset;
60  }
61 
62  // if we're detecting the draw mode then base it on whether a mask
63  // was passed as a separate object
64  if (drawMode == SPRITE_AUTO_MODE) {
65  drawMode = mask == NULL ? SPRITE_UNMASKED : SPRITE_MASKED;
66  }
67 
68  drawBitmap(x, y, bitmap, mask, width, height, drawMode);
69 }
70 
71 void SpritesB::drawBitmap(int16_t x, int16_t y,
72  const uint8_t *bitmap, const uint8_t *mask,
73  uint8_t w, uint8_t h, uint8_t draw_mode)
74 {
75  // no need to draw at all of we're offscreen
76  if (x + w <= 0 || x > WIDTH - 1 || y + h <= 0 || y > HEIGHT - 1)
77  return;
78 
79  if (bitmap == NULL)
80  return;
81 
82  // xOffset technically doesn't need to be 16 bit but the math operations
83  // are measurably faster if it is
84  uint16_t xOffset, ofs;
85  int8_t yOffset = y & 7;
86  int8_t sRow = y / 8;
87  uint8_t loop_h, start_h, rendered_width;
88 
89  if (y < 0 && yOffset > 0) {
90  sRow--;
91  }
92 
93  // if the left side of the render is offscreen skip those loops
94  if (x < 0) {
95  xOffset = abs(x);
96  } else {
97  xOffset = 0;
98  }
99 
100  // if the right side of the render is offscreen skip those loops
101  if (x + w > WIDTH - 1) {
102  rendered_width = ((WIDTH - x) - xOffset);
103  } else {
104  rendered_width = (w - xOffset);
105  }
106 
107  // if the top side of the render is offscreen skip those loops
108  if (sRow < -1) {
109  start_h = abs(sRow) - 1;
110  } else {
111  start_h = 0;
112  }
113 
114  loop_h = h / 8 + (h % 8 > 0 ? 1 : 0); // divide, then round up
115 
116  // if (sRow + loop_h - 1 > (HEIGHT/8)-1)
117  if (sRow + loop_h > (HEIGHT / 8)) {
118  loop_h = (HEIGHT / 8) - sRow;
119  }
120 
121  // prepare variables for loops later so we can compare with 0
122  // instead of comparing two variables
123  loop_h -= start_h;
124 
125  sRow += start_h;
126  ofs = (sRow * WIDTH) + x + xOffset;
127 
128  uint8_t mul_amt = 1 << yOffset;
129  uint16_t mask_data;
130  uint16_t bitmap_data;
131 
132  const uint8_t ofs_step = draw_mode == SPRITE_PLUS_MASK ? 2 : 1;
133  const uint8_t ofs_stride = (w - rendered_width)*ofs_step;
134  const uint16_t initial_bofs = ((start_h * w) + xOffset)*ofs_step;
135 
136  const uint8_t *bofs = bitmap + initial_bofs;
137  const uint8_t *mask_ofs = !mask ? bitmap : mask;
138  mask_ofs += initial_bofs + ofs_step - 1;
139 
140  for (uint8_t a = 0; a < loop_h; a++) {
141  for (uint8_t iCol = 0; iCol < rendered_width; iCol++) {
142  uint8_t data;
143 
144  bitmap_data = pgm_read_byte(bofs) * mul_amt;
145  mask_data = ~bitmap_data;
146 
147  if (draw_mode == SPRITE_UNMASKED) {
148  mask_data = ~(0xFF * mul_amt);
149  } else if (draw_mode == SPRITE_IS_MASK_ERASE) {
150  bitmap_data = 0;
151  } else {
152  mask_data = ~(pgm_read_byte(mask_ofs) * mul_amt);
153  }
154 
155  if (sRow >= 0) {
156  data = Arduboy2Base::sBuffer[ofs];
157  data &= (uint8_t)(mask_data);
158  data |= (uint8_t)(bitmap_data);
159  Arduboy2Base::sBuffer[ofs] = data;
160  }
161  if (yOffset != 0 && sRow < 7) {
162  const size_t index = static_cast<uint16_t>(ofs + WIDTH);
163  data = Arduboy2Base::sBuffer[index];
164  data &= (uint8_t)(mask_data >> 8);
165  data |= (uint8_t)(bitmap_data >> 8);
166  Arduboy2Base::sBuffer[index] = data;
167  }
168  ofs++;
169  mask_ofs += ofs_step;
170  bofs += ofs_step;
171  }
172  sRow++;
173  bofs += ofs_stride;
174  mask_ofs += ofs_stride;
175  ofs += WIDTH - rendered_width;
176  }
177 }
SpritesB::drawErase
static void drawErase(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame)
"Erase" a sprite.
Definition: SpritesB.cpp:21
SpritesB::drawPlusMask
static void drawPlusMask(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame)
Draw a sprite using an array containing both image and mask values.
Definition: SpritesB.cpp:31
Arduboy2Base::sBuffer
static uint8_t sBuffer[(HEIGHT *WIDTH)/8]
The display buffer array in RAM.
Definition: Arduboy2.h:1465
WIDTH
#define WIDTH
Definition: Arduboy2Core.h:242
SpritesB.h
A class for drawing animated sprites from image and mask bitmaps. Optimized for small code size.
SpritesB::drawExternalMask
static void drawExternalMask(int16_t x, int16_t y, const uint8_t *bitmap, const uint8_t *mask, uint8_t frame, uint8_t mask_frame)
Draw a sprite using a separate image and mask array.
Definition: SpritesB.cpp:10
SpritesB::drawSelfMasked
static void drawSelfMasked(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame)
Draw a sprite using only the bits set to 1.
Definition: SpritesB.cpp:26
HEIGHT
#define HEIGHT
Definition: Arduboy2Core.h:243
SpritesB::drawOverwrite
static void drawOverwrite(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame)
Draw a sprite by replacing the existing content completely.
Definition: SpritesB.cpp:16