@@ -154,8 +154,8 @@ bool displayio_tilegrid_get_area(displayio_tilegrid_t *self, displayio_buffer_tr
154154 displayio_area_t scaled_area = {
155155 .x1 = self -> area .x1 * transform -> scale ,
156156 .y1 = self -> area .y1 * transform -> scale ,
157- .x2 = ( self -> area .x2 + 1 ) * transform -> scale - 1 , // Second point is inclusive.
158- .y2 = ( self -> area .y2 + 1 ) * transform -> scale - 1
157+ .x2 = self -> area .x2 * transform -> scale ,
158+ .y2 = self -> area .y2 * transform -> scale
159159 };
160160 if (!displayio_area_compute_overlap (area , & scaled_area , & overlap )) {
161161 return false;
@@ -169,19 +169,20 @@ bool displayio_tilegrid_get_area(displayio_tilegrid_t *self, displayio_buffer_tr
169169 }
170170 uint16_t start = 0 ;
171171 if (transform -> mirror_x ) {
172- start += (area -> x2 - area -> x1 ) * x_stride ;
172+ start += (area -> x2 - area -> x1 - 1 ) * x_stride ;
173173 x_stride *= -1 ;
174174 }
175175 if (transform -> mirror_y ) {
176- start += (area -> y2 - area -> y1 ) * y_stride ;
176+ start += (area -> y2 - area -> y1 - 1 ) * y_stride ;
177177 y_stride *= -1 ;
178178 }
179179
180+ // Track if this layer finishes filling in the given area. We can ignore any remaining
181+ // layers at that point.
180182 bool full_coverage = displayio_area_equal (area , & overlap );
181183
182- // TODO(tannewt): Set full coverage to true if all pixels outside the overlap have already been
183- // set as well.
184- bool always_full_coverage = false;
184+ // TODO(tannewt): Skip coverage tracking if all pixels outside the overlap have already been
185+ // set and our palette is all opaque.
185186
186187 // TODO(tannewt): Check to see if the pixel_shader has any transparency. If it doesn't then we
187188 // can either return full coverage or bulk update the mask.
@@ -191,17 +192,22 @@ bool displayio_tilegrid_get_area(displayio_tilegrid_t *self, displayio_buffer_tr
191192 }
192193 int16_t x_shift = area -> x1 - scaled_area .x1 ;
193194 int16_t y_shift = area -> y1 - scaled_area .y1 ;
194- for (; y <= overlap .y2 - scaled_area .y1 ; y ++ ) {
195+ for (; y < overlap .y2 - scaled_area .y1 ; y ++ ) {
195196 int16_t x = overlap .x1 - scaled_area .x1 ;
196197 if (x < 0 ) {
197198 x = 0 ;
198199 }
199200 int16_t row_start = start + (y - y_shift ) * y_stride ;
200201 int16_t local_y = y / transform -> scale ;
201- for (; x <= overlap .x2 - scaled_area .x1 ; x ++ ) {
202+ for (; x < overlap .x2 - scaled_area .x1 ; x ++ ) {
202203 // Compute the destination pixel in the buffer and mask based on the transformations.
203204 uint16_t offset = row_start + (x - x_shift ) * x_stride ;
204205
206+ // This is super useful for debugging out range accesses. Uncomment to use.
207+ // if (offset < 0 || offset >= displayio_area_size(area)) {
208+ // asm("bkpt");
209+ // }
210+
205211 // Check the mask first to see if the pixel has already been set.
206212 if ((mask [offset / 32 ] & (1 << (offset % 32 ))) != 0 ) {
207213 continue ;
@@ -229,22 +235,21 @@ bool displayio_tilegrid_get_area(displayio_tilegrid_t *self, displayio_buffer_tr
229235 return true;
230236 } else if (MP_OBJ_IS_TYPE (self -> pixel_shader , & displayio_palette_type )) {
231237 if (!displayio_palette_get_color (self -> pixel_shader , value , pixel )) {
232- // mark the pixel as transparent
238+ // A pixel is transparent so we haven't fully covered the area ourselves.
233239 full_coverage = false;
234- } else if (! always_full_coverage ) {
240+ } else {
235241 mask [offset / 32 ] |= 1 << (offset % 32 );
236242 }
237243 } else if (MP_OBJ_IS_TYPE (self -> pixel_shader , & displayio_colorconverter_type )) {
238244 if (!common_hal_displayio_colorconverter_convert (self -> pixel_shader , value , pixel )) {
239- // mark the pixel as transparent
245+ // A pixel is transparent so we haven't fully covered the area ourselves.
240246 full_coverage = false;
241- } else if (! always_full_coverage ) {
247+ } else {
242248 mask [offset / 32 ] |= 1 << (offset % 32 );
243249 }
244250 }
245251 }
246252 }
247-
248253 return full_coverage ;
249254}
250255
0 commit comments