roo_display
API Documentation for roo_display
Loading...
Searching...
No Matches
offscreen.h
Go to the documentation of this file.
1#pragma once
2
3/// Support for drawing to in-memory buffers, using various color modes.
4
5#include <cstring>
6#include <utility>
7
13#include "roo_io/memory/fill.h"
14#include "roo_io/memory/store.h"
15
16namespace roo_display {
17
18namespace internal {
19
20// Helper class used by the Offscreen to transform point or rect coordinates
21// received in the write and fill requests, in order to apply the offscreen's
22// orientation.
23// The orientation applies to how content is _written_ to the buffer. Reading
24// the buffer is following its 'native' orientation. This allows the buffer
25// to be used as a streamable, and have its content drawn to another canvas
26// in the standardized order (left-to-right, top-to-bottom), regardless of
27// the orientation.
28class Orienter {
29 public:
35
36 Orientation orientation() const { return orientation_; }
37
39
40 void orientPixels(int16_t*& x, int16_t*& y, int16_t count);
41 void orientRects(int16_t*& x0, int16_t*& y0, int16_t*& x1, int16_t*& y1,
42 int16_t count);
43
44 void orientRect(int16_t& x0, int16_t& y0, int16_t& x1, int16_t& y1);
45
46 private:
47 inline void revertX(int16_t* x, uint16_t count);
48 inline void revertY(int16_t* y, uint16_t count);
49
50 Orientation orientation_;
51 int16_t xMax_;
52 int16_t yMax_;
53};
54
55// Helper class used by Offscreen to implement setAddress() and then
56// write()/fill() under different orientations. Internally, the class
57// stores two (signed) integer offsets, specifying the amount of pixel
58// index increment (or decrement, if negative) along the x and y axis,
59// respectively. This representation yields a very efficient and simple
60// implementation of advance(), regardless of the orientation.
62 public:
64
65 void setAddress(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1,
66 int16_t raw_width, int16_t raw_height,
68
69 int16_t x() const { return cursor_x_; }
70 int16_t y() const { return cursor_y_; }
71
72 const uint32_t offset() const { return offset_; }
73 Orientation orientation() const { return orientation_; }
74 int16_t advance_x() const { return advance_x_; }
75 int32_t advance_y() const { return advance_y_; }
76
77 void advance();
78 void advance(uint32_t count);
79
80 bool eof() const { return cursor_y_ > y1_; }
81 uint16_t remaining_in_row() const { return x1_ - cursor_x_ + 1; }
82 uint16_t remaining_rows() const { return y1_ - cursor_y_ + 1; }
83 int16_t width() const { return x1_ - x0_ + 1; }
84 int16_t height() const { return y1_ - y0_ + 1; }
85
86 private:
87 Orientation orientation_;
88 uint32_t offset_;
89 uint16_t x0_, x1_, y0_, y1_;
90 int16_t advance_x_;
91 int32_t advance_y_;
92 uint16_t cursor_x_, cursor_y_;
93};
94
95} // namespace internal
96
97// It implements both Drawable and Streamable contracts,
98// which allows to be easily drawn to other display devices.
99// For example, to draw a sub-rectangle of the Offscreen, simply use
100// CreateClippedStream(offscreen, rect).
101
102// If you draw to/from the offscreen using its public methods only, the choice
103// of these two parameters does not really matter; use defaults. But, if you're
104// importing or exporting raw data from/to some existing format or device, you
105// may need to set these parameters to match that format. For example, XBitmap
106// uses LSB_FIRST.
107//
108
109// Bounding rectangle, specified during construction, determines how the
110// Offscreen behaves when it is drawn to another display device. As any other
111// Drawable, Offscreen can have a bounding rectangle that does not start at
112// (0,0).
113
114//
115// Note: to use the content of the offscreen as Stremable, e.g. to super-impose
116// the content over / under another streamable, use raster().
117
118/// In-memory `DisplayDevice` backed by a pixel buffer.
119///
120/// Supports arbitrary color modes, byte orders, and pixel orders via template
121/// parameters:
122/// - `pixel_order` applies to sub-byte modes (MSB/LSB first).
123/// - `byte_order` applies to multi-byte modes (big/little endian).
124///
125/// Orientation affects how content is written to the buffer. Existing content
126/// is not rotated when orientation changes, but subsequent writes are. For
127/// example, `Orientation::Default().rotateLeft()` renders content rotated
128/// 90 degrees counter-clockwise.
129template <typename ColorMode,
131 ByteOrder byte_order = roo_io::kBigEndian,
132 int8_t pixels_per_byte = ColorTraits<ColorMode>::pixels_per_byte,
133 typename storage_type = ColorStorageType<ColorMode>>
135 public:
136 /// Create an offscreen device with the given geometry and buffer.
137 ///
138 /// The buffer must have capacity
139 /// $(width * height * ColorMode::bits_per_pixel + 7) / 8$ bytes. The buffer
140 /// is not modified on construction.
141 OffscreenDevice(int16_t width, int16_t height, roo::byte* buffer,
142 ColorMode color_mode)
143 : DisplayDevice(width, height),
144 color_mode_(color_mode),
145 color_format_(color_mode_),
146 buffer_(buffer),
147 orienter_(width, height, Orientation::Default()) {
149 }
150
152 : DisplayDevice(other.orientation(), other.raw_width(),
153 other.raw_height()),
154 color_mode_(std::move(other.color_mode_)),
155 color_format_(color_mode_),
156 buffer_(other.buffer_),
157 orienter_(other.orienter_),
158 window_(other.window_),
159 blending_mode_(other.blending_mode_) {
160 other.buffer_ = nullptr;
161 }
162
163 /// Update orientation-dependent state.
165
167 BlendingMode mode) override;
168
169 void write(Color* color, uint32_t pixel_count) override;
170
171 void writePixels(BlendingMode mode, Color* color, int16_t* x, int16_t* y,
172 uint16_t pixel_count) override;
173
174 void fillPixels(BlendingMode mode, Color color, int16_t* x, int16_t* y,
175 uint16_t pixel_count) override;
176
177 void writeRects(BlendingMode mode, Color* color, int16_t* x0, int16_t* y0,
178 int16_t* x1, int16_t* y1, uint16_t count) override;
179
180 void fillRects(BlendingMode mode, Color color, int16_t* x0, int16_t* y0,
181 int16_t* x1, int16_t* y1, uint16_t count) override;
182
183 void end() override { awaitAsyncBlit(); }
184
185 void drawDirectRect(const roo::byte* data, size_t row_width_bytes,
188 awaitAsyncBlit();
189 if (src_x1 < src_x0 || src_y1 < src_y0) return;
190 int16_t width = src_x1 - src_x0 + 1;
191 int16_t height = src_y1 - src_y0 + 1;
192
193 // Fast paths for default orientation: memcpy rows (or the whole block if
194 // the source is already tightly packed).
196 if constexpr (ColorTraits<ColorMode>::pixels_per_byte == 1) {
197 constexpr size_t kBytesPerPixel =
199 size_t copy_row_bytes = static_cast<size_t>(width) * kBytesPerPixel;
200 size_t dst_row_bytes =
201 static_cast<size_t>(raw_width()) * kBytesPerPixel;
202
203 const roo::byte* src_row =
204 data + static_cast<size_t>(src_y0) * row_width_bytes +
205 static_cast<size_t>(src_x0) * kBytesPerPixel;
206 roo::byte* dst_row = buffer_ +
207 static_cast<size_t>(dst_y0) * dst_row_bytes +
208 static_cast<size_t>(dst_x0) * kBytesPerPixel;
209
211 static_cast<size_t>(height));
212 return;
213 } else {
215 // Sub-byte fast path only if rows and x offsets are byte-aligned.
216 if (kPixelsPerByte > 1 && (raw_width() % kPixelsPerByte) == 0 &&
217 (src_x0 % kPixelsPerByte) == 0 && (dst_x0 % kPixelsPerByte) == 0 &&
218 (width % kPixelsPerByte) == 0) {
219 size_t copy_row_bytes = static_cast<size_t>(width) / kPixelsPerByte;
220 size_t dst_row_bytes =
221 static_cast<size_t>(raw_width()) / kPixelsPerByte;
222
223 const roo::byte* src_row =
224 data + static_cast<size_t>(src_y0) * row_width_bytes +
225 static_cast<size_t>(src_x0 / kPixelsPerByte);
226 roo::byte* dst_row = buffer_ +
227 static_cast<size_t>(dst_y0) * dst_row_bytes +
228 static_cast<size_t>(dst_x0 / kPixelsPerByte);
229
231 static_cast<size_t>(height));
232 return;
233 }
234 }
235 }
236
237 // Fallback: iterate AddressWindow order and write pixel-by-pixel.
238 setAddress(dst_x0, dst_y0, dst_x0 + width - 1, dst_y0 + height - 1,
240 uint32_t pixel_count = static_cast<uint32_t>(width) * height;
241
242 if constexpr (ColorTraits<ColorMode>::pixels_per_byte == 1) {
243 constexpr size_t kBytesPerPixel = ColorTraits<ColorMode>::bytes_per_pixel;
244
245 // Reads a source row-major rect and writes each pixel into the window.
246 class DirectRectWriter {
247 public:
248 DirectRectWriter(const roo::byte* data, size_t row_width_bytes,
250 : src_row_(data + static_cast<size_t>(src_y0) * row_width_bytes +
251 static_cast<size_t>(src_x0) * kBytesPerPixel),
253 static_cast<size_t>(width) * kBytesPerPixel),
254 remaining_in_row_(width),
255 width_(width) {}
256
257 void operator()(roo::byte* p, uint32_t offset) {
258 roo::byte* dst = p + offset * kBytesPerPixel;
259 std::memcpy(dst, src_row_, kBytesPerPixel);
260 advance();
261 }
262
263 private:
264 void advance() {
265 src_row_ += kBytesPerPixel;
266 if (--remaining_in_row_ == 0) {
269 }
270 }
271
272 const roo::byte* src_row_;
273 size_t row_advance_;
276 };
277
279 writeToWindow(writer, pixel_count);
280 return;
281 } else {
283 // Sub-byte variant: load/store packed pixels with correct bit ordering.
284 class SubByteWriter {
285 public:
286 SubByteWriter(const roo::byte* data, size_t row_width_bytes,
288 : src_row_start_(data +
289 static_cast<size_t>(src_y0) * row_width_bytes +
290 static_cast<size_t>(src_x0 / kPixelsPerByte)),
295 width_(width),
296 remaining_in_row_(width) {}
297
298 void operator()(roo::byte* p, uint32_t offset) {
300 roo::byte* dst = p + offset / kPixelsPerByte;
301 int dst_index = offset % kPixelsPerByte;
302 uint8_t raw = io.loadRaw(*src_row_, src_index_);
303 io.storeRaw(raw, dst, dst_index);
304 advance();
305 }
306
307 private:
308 void advance() {
309 if (++src_index_ == kPixelsPerByte) {
310 src_index_ = 0;
311 ++src_row_;
312 }
313 if (--remaining_in_row_ == 0) {
318 }
319 }
320
321 const roo::byte* src_row_start_;
322 const roo::byte* src_row_;
324 int src_index_;
325 size_t row_width_bytes_;
328 };
329
331 writeToWindow(writer, pixel_count);
332 }
333 }
334
335 void drawDirectRectAsync(const roo::byte* data, size_t row_width_bytes,
338 int16_t dst_y0) override {
339 awaitAsyncBlit();
340 if (src_x1 < src_x0 || src_y1 < src_y0) {
341 return;
342 }
343
344 int16_t width = src_x1 - src_x0 + 1;
345 int16_t height = src_y1 - src_y0 + 1;
346
348 if constexpr (ColorTraits<ColorMode>::pixels_per_byte == 1) {
349 constexpr size_t kBytesPerPixel =
351 size_t copy_row_bytes = static_cast<size_t>(width) * kBytesPerPixel;
352 size_t dst_row_bytes =
353 static_cast<size_t>(raw_width()) * kBytesPerPixel;
354
355 const roo::byte* src_row =
356 data + static_cast<size_t>(src_y0) * row_width_bytes +
357 static_cast<size_t>(src_x0) * kBytesPerPixel;
358 roo::byte* dst_row = buffer_ +
359 static_cast<size_t>(dst_y0) * dst_row_bytes +
360 static_cast<size_t>(dst_x0) * kBytesPerPixel;
362 copy_row_bytes, static_cast<size_t>(height));
363 return;
364 } else {
366 if (kPixelsPerByte > 1 && (raw_width() % kPixelsPerByte) == 0 &&
367 (src_x0 % kPixelsPerByte) == 0 && (dst_x0 % kPixelsPerByte) == 0 &&
368 (width % kPixelsPerByte) == 0) {
369 size_t copy_row_bytes = static_cast<size_t>(width) / kPixelsPerByte;
370 size_t dst_row_bytes =
371 static_cast<size_t>(raw_width()) / kPixelsPerByte;
372
373 const roo::byte* src_row =
374 data + static_cast<size_t>(src_y0) * row_width_bytes +
375 static_cast<size_t>(src_x0 / kPixelsPerByte);
376 roo::byte* dst_row = buffer_ +
377 static_cast<size_t>(dst_y0) * dst_row_bytes +
378 static_cast<size_t>(dst_x0 / kPixelsPerByte);
379
381 copy_row_bytes, static_cast<size_t>(height));
382 return;
383 }
384 }
385 }
386
388 dst_x0, dst_y0);
389 }
390
391 void flush() override { awaitAsyncBlit(); }
392
393 /// Access color mode.
394 ColorMode& color_mode() { return color_mode_; }
395 /// Access color mode (const).
396 const ColorMode& color_mode() const { return color_mode_; }
397
398 const ColorFormat& getColorFormat() const override { return color_format_; }
399
400 // const Raster<const roo::byte *, ColorMode, pixel_order, byte_order>
401 // &raster()
402 // const {
403 // return raster_;
404 // }
405
406 /// Return a raster view of the full buffer.
410
411 /// Return a raster view of the buffer with an offset.
413 int16_t dx, int16_t dy) const {
415 Box(dx, dy, dx + raw_width() - 1, dy + raw_height() - 1), buffer_,
416 color_mode_);
417 }
418
419 // std::unique_ptr<PixelStream> createStream() const override {
420 // return raster().createStream();
421 // }
422
423 // TransparencyMode getTransparencyMode() const override {
424 // return color_mode().transparency();
425 // }
426
427 // virtual void readColors(const int16_t *x, const int16_t *y, uint32_t count,
428 // Color *result) const override {
429 // raster().readColors(x, y, count, result);
430 // }
431
432 /// Direct access to the underlying buffer.
433 roo::byte* buffer() { return buffer_; }
434 /// Direct access to the underlying buffer (const).
435 const roo::byte* buffer() const { return buffer_; }
436
437 /// Current address window x cursor.
438 int16_t window_x() const { return window_.x(); }
439 /// Current address window y cursor.
440 int16_t window_y() const { return window_.y(); }
441
442 private:
443 template <typename, typename, ColorPixelOrder, ByteOrder>
444 friend struct WriteOp;
445
446 template <typename Writer>
447 void writeToWindow(Writer& write, uint32_t count) {
448 while (count-- > 0) {
449 write(buffer_, window_.offset());
450 window_.advance();
451 }
452 }
453
454 inline void awaitAsyncBlit() { async_blit_await(); }
455
456 void fillRectsAbsolute(BlendingMode mode, Color color, int16_t* x0,
457 int16_t* y0, int16_t* x1, int16_t* y1, uint16_t count);
458
459 void fillHlinesAbsolute(BlendingMode mode, Color color, int16_t* x0,
460 int16_t* y0, int16_t* x1, uint16_t count);
461
462 void fillVlinesAbsolute(BlendingMode mode, Color color, int16_t* x0,
463 int16_t* y0, int16_t* y1, uint16_t count);
464
465 ColorMode color_mode_;
466 internal::ColorFormatImpl<ColorMode, byte_order, pixel_order> color_format_;
467
468 roo::byte* buffer_;
469
470 // bool owns_buffer_;
471 internal::Orienter orienter_;
472 // // Streaming read acess.
473 // Raster<const roo::byte *, ColorMode, pixel_order, byte_order> raster_;
474 internal::AddressWindow window_;
475 BlendingMode blending_mode_;
476};
477
478/// Offscreen rasterizable that writes into a pixel buffer.
479///
480/// Example:
481/// ```
482/// Offscreen<Rgb565> offscreen;
483/// DrawingContext dc(offscreen);
484/// dc.draw(...);
485/// ```
486template <typename ColorMode,
488 ByteOrder byte_order = roo_io::kBigEndian,
489 int8_t pixels_per_byte = ColorTraits<ColorMode>::pixels_per_byte,
490 typename storage_type = ColorStorageType<ColorMode>>
491class Offscreen : public Rasterizable {
492 public:
495
496 /// Create an offscreen with the given geometry and buffer.
497 ///
498 /// The buffer must have capacity
499 /// $(width * height * ColorMode::bits_per_pixel + 7) / 8$ bytes. The buffer
500 /// is not modified on construction.
501 Offscreen(int16_t width, int16_t height, roo::byte* buffer,
502 ColorMode color_mode = ColorMode())
503 : Offscreen(Box(0, 0, width - 1, height - 1), buffer, color_mode) {}
504
505 // Convenience that accepts uint8_t* buffer.
507 ColorMode color_mode = ColorMode())
508 : Offscreen(width, height, (roo::byte*)buffer, std::move(color_mode)) {}
509
510 // Creates an offscreen device with specified geometry, using the
511 // designated buffer. The buffer must have sufficient capacity, determined as
512 // (width * height * ColorMode::bits_per_pixel + 7) / 8. The buffer is not
513 // modified; it can contain pre-existing content.
514 Offscreen(Box extents, roo::byte* buffer, ColorMode color_mode = ColorMode())
515 : device_(extents.width(), extents.height(), buffer, color_mode),
516 raster_(device_.raster(extents.xMin(), extents.yMin())),
517 extents_(extents),
518 anchor_extents_(extents),
519 owns_buffer_(false) {}
520
521 // Creates an offscreen with specified geometry, using an internally
522 // allocated buffer. The buffer is not pre-initialized; it contains random
523 // bytes.
524 Offscreen(int16_t width, int16_t height, ColorMode color_mode = ColorMode())
525 : Offscreen(Box(0, 0, width - 1, height - 1), color_mode) {}
526
527 // Creates an offscreen with specified geometry, using an internally allocated
528 // buffer. The buffer is not pre-initialized; it contains random bytes.
529 Offscreen(Box extents, ColorMode color_mode = ColorMode())
530 : device_(
531 extents.width(), extents.height(),
532 new roo::byte[(ColorMode::bits_per_pixel * extents.area() + 7) / 8],
533 color_mode),
534 raster_(device_.raster(extents.xMin(), extents.yMin())),
535 extents_(extents),
536 anchor_extents_(extents),
537 owns_buffer_(true) {
538#ifdef ROO_TESTING
539 // Fill contents with garbage, to make it more likely to come out in tests.
540 memset(this->buffer(), 0x66,
541 (ColorMode::bits_per_pixel * extents.area() + 7) / 8);
542#endif
543 }
544
545 // Creates an offscreen with specified geometry, using an internally allocated
546 // buffer. The buffer is pre-filled using the specified color.
548 ColorMode color_mode = ColorMode())
549 : Offscreen(Box(0, 0, width - 1, height - 1), fillColor, color_mode) {}
550
551 // Creates an offscreen with specified geometry, using an internally allocated
552 // buffer. The buffer is pre-filled using the specified color.
553 Offscreen(Box extents, Color fillColor, ColorMode color_mode = ColorMode())
555 device_.fillRect(0, 0, extents.width() - 1, extents.height() - 1,
556 fillColor);
557 }
558
559 // Convenience constructor that makes a RAM copy of the specified drawable.
560 Offscreen(const Drawable& d, ColorMode color_mode = ColorMode())
561 : Offscreen(d, color::Transparent, color_mode) {}
562
563 // Convenience constructor that makes a RAM copy of the specified drawable,
564 // using the specified background color. Useful when drawing translucent
565 // contents (e.g. text) to non-translucent offscreens.
567 ColorMode color_mode = ColorMode())
569 setAnchorExtents(d.anchorExtents());
570 Box extents = d.extents();
571 Surface s(device_, -extents.xMin(), -extents.yMin(),
572 Box(0, 0, extents.width(), extents.height()), false, bgColor,
574 s.drawObject(d);
575 }
576
577 virtual ~Offscreen() {
578 if (owns_buffer_) delete[] output().buffer();
579 }
580
582 : device_(std::move(other.device_)),
583 raster_(device_.raster(other.extents_.xMin(), other.extents_.yMin())),
584 extents_(other.extents_),
585 anchor_extents_(other.anchor_extents_),
586 owns_buffer_(other.owns_buffer_) {
587 other.owns_buffer_ = false;
588 }
589
590 const RasterType& raster() const { return raster_; }
591
592 Box extents() const override { return extents_; }
593 Box anchorExtents() const override { return anchor_extents_; }
594
596 anchor_extents_ = anchor_extents;
597 }
598
600 return raster().getTransparencyMode();
601 }
602
603 void readColors(const int16_t* x, const int16_t* y, uint32_t count,
604 Color* result) const override {
605 return raster().readColors(x, y, count, result);
606 }
607
608 const OffscreenDevice<ColorMode, pixel_order, byte_order, pixels_per_byte,
609 storage_type>&
610 output() const {
611 return device_;
612 }
613
614 OffscreenDevice<ColorMode, pixel_order, byte_order, pixels_per_byte,
615 storage_type>&
617 return device_;
618 }
619
620 roo::byte* buffer() { return output().buffer(); }
621 const roo::byte* buffer() const { return output().buffer(); }
622
623 const ColorMode& color_mode() const { return output().color_mode(); }
624
625 protected:
626 // Sets the default (maximum) clip box. Usually the same as raster extents,
627 // but may be smaller, e.g. if the underlying raster is byte-aligned and the
628 // extents aren't.
629 void set_extents(const Box& extents) { extents_ = extents; }
630
631 private:
632 friend class DrawingContext;
633
634 // Implements Drawable.
635 void drawTo(const Surface& s) const override { s.drawObject(raster()); }
636
637 // For DrawingContext.
638 void nest() const {}
639 void unnest() const {}
640 Color getBackgroundColor() const { return color::Transparent; }
641 const Rasterizable* getRasterizableBackground() const { return nullptr; }
642 int16_t dx() const { return -raster_.extents().xMin(); }
643 int16_t dy() const { return -raster_.extents().yMin(); }
644 bool is_write_once() const { return false; }
645 FillMode fill_mode() const { return FillMode::kVisible; }
647
648 OffscreenDevice<ColorMode, pixel_order, byte_order, pixels_per_byte,
649 storage_type>
650 device_;
651
652 const RasterType raster_;
653
654 Box extents_;
655 Box anchor_extents_;
656
657 bool owns_buffer_;
658};
659
660// Creates an offscreen whose color format matches the provided device.
661template <typename Device, typename... Args>
662auto OffscreenForDevice(const Device& device, Args&&... args)
663 -> Offscreen<typename Device::ColorMode, Device::pixel_order,
664 Device::byte_order> {
665 return Offscreen<typename Device::ColorMode, Device::pixel_order,
666 Device::byte_order>(std::forward<Args>(args)...,
667 device.color_mode());
668}
669
670// Convenience specialization for constructing bit maps, e.g. to set them
671// as bit masks. Uses Monochrome with transparent background. Writing anything
672// but full transparency causes the bit to be set. The data is aligned row-wise
673// to full bytes; that is, each row of pixels starts on a new byte.
674class BitMaskOffscreen : public Offscreen<Monochrome> {
675 public:
676 // Creates a bit map offscreen with the specified geometry, using the
677 // designated buffer. The buffer must have sufficient capacity, determined as
678 // ((width + 7) / 8) * height. The buffer is not modified; it can contain
679 // pre-existing content.
680 BitMaskOffscreen(int16_t width, int16_t height, roo::byte* buffer)
681 : BitMaskOffscreen(Box(0, 0, width - 1, height - 1), buffer) {}
682
683 // Convenience that accepts uint8_t* buffer.
685 : BitMaskOffscreen(width, height, (roo::byte*)buffer) {}
686
687 // Creates a bit map offscreen with the specified geometry, using the
688 // designated buffer. The buffer must have sufficient capacity, determined as
689 // ((width + 7) / 8) * height. The buffer is not modified; it can contain
690 // pre-existing content.
691 BitMaskOffscreen(Box extents, roo::byte* buffer);
692
693 // Convenience that accepts uint8_t* buffer.
696
697 // Creates an offscreen with specified geometry, using an internally
698 // allocated buffer. The buffer is not pre-initialized; it contains random
699 // bytes.
701 : BitMaskOffscreen(Box(0, 0, width - 1, height - 1)) {}
702
703 // Creates an offscreen with specified geometry, using an internally allocated
704 // buffer. The buffer is not pre-initialized; it contains random bytes.
706
707 // Creates an offscreen with specified geometry, using an internally allocated
708 // buffer. The buffer is pre-filled using the specified color.
710 : BitMaskOffscreen(Box(0, 0, width - 1, height - 1), fillColor) {}
711
712 // Creates an offscreen with specified geometry, using an internally allocated
713 // buffer. The buffer is pre-filled using the specified color.
715};
716
717// Implementation details follow.
718
719// Writer template contract specifies how to write pixel, or a sequence of
720// pixels, using a specified using a specified sequence of colors, into a buffer
721// with a given 'start' address, and a given pixel_offset. The writer does not
722// need to know the geometry (i.e. width and height) of the display; it treats
723// the buffer as a contiguous sequence of pixels, starting at the top-left
724// corner, and going left-to-right, and then top-to-bottom.
725
726namespace internal {
727
728// For sub-byte color modes.
729template <typename ColorMode, ColorPixelOrder pixel_order, ByteOrder byte_order,
731 uint8_t pixels_per_byte = ColorTraits<ColorMode>::pixels_per_byte,
732 typename storage_type = ColorStorageType<ColorMode>>
734 public:
735 BlendingWriterOperator(ColorMode& color_mode, const Color* color)
736 : color_mode_(color_mode), color_(color) {}
737
738 void operator()(roo::byte* p, uint32_t offset) {
740 int pixel_index = offset % pixels_per_byte;
741 roo::byte* target = p + offset / pixels_per_byte;
743 auto color =
744 blender(io.loadRaw(*target, pixel_index), *color_++, color_mode_);
745 io.storeRaw(color, target, pixel_index);
746 }
747
748 void operator()(roo::byte* p, uint32_t offset, uint32_t count) {
750 int pixel_index = offset % pixels_per_byte;
751 roo::byte* target = p + offset / pixels_per_byte;
752 while (count-- > 0) {
754 auto color =
755 blender(io.loadRaw(*target, pixel_index), *color_++, color_mode_);
756 io.storeRaw(color, target, pixel_index);
757 if (++pixel_index == pixels_per_byte) {
758 pixel_index = 0;
759 target++;
760 }
761 }
762 }
763
764 private:
765 ColorMode& color_mode_;
766 const Color* color_;
767};
768
769// For color modes in which a pixel takes up at least 1 byte.
770template <typename ColorMode, ColorPixelOrder pixel_order, ByteOrder byte_order,
771 BlendingMode blending_mode, typename storage_type>
772class BlendingWriterOperator<ColorMode, pixel_order, byte_order, blending_mode,
773 1, storage_type> {
774 public:
775 BlendingWriterOperator(const ColorMode& color_mode, const Color* color)
776 : color_mode_(color_mode), color_(color) {}
777
778 void operator()(roo::byte* p, uint32_t offset) {
779 constexpr uint32_t kBytesPerPixel = ColorTraits<ColorMode>::bytes_per_pixel;
781 blender(p + offset * kBytesPerPixel, *color_++, color_mode_);
782 }
783
784 void operator()(roo::byte* p, uint32_t offset, uint32_t count) {
785 constexpr uint32_t kBytesPerPixel = ColorTraits<ColorMode>::bytes_per_pixel;
786 roo::byte* cursor = p + offset * kBytesPerPixel;
788 while (count-- > 0) {
789 blender(cursor, *color_++, color_mode_);
790 cursor += kBytesPerPixel;
791 }
792 }
793
794 private:
795 const ColorMode& color_mode_;
796 const Color* color_;
797};
798
799template <typename ColorMode, ColorPixelOrder pixel_order, ByteOrder byte_order>
801 template <BlendingMode blending_mode>
802 using Operator =
804};
805
806// BlendingMode::kSource specialization of the writer.
807
808// // For sub-byte color modes.
809// template <typename ColorMode, ColorPixelOrder pixel_order, ByteOrder
810// byte_order,
811// uint8_t pixels_per_byte, typename storage_type>
812// class BlendingWriter<ColorMode, pixel_order, byte_order,
813// BlendingMode::kSource,
814// pixels_per_byte, storage_type> {
815// public:
816// BlendingWriter(ColorMode &color_mode, const Color *color)
817// : color_mode_(color_mode), color_(color) {}
818
819// void operator()(roo::byte *p, uint32_t offset) {
820// SubByteColorIo<ColorMode, pixel_order> io;
821// int pixel_index = offset % pixels_per_byte;
822// roo::byte *target = p + offset / pixels_per_byte;
823// io.storeRaw(color_mode_.fromArgbColor(*color_++), target,
824// pixel_index);
825// }
826
827// void operator()(roo::byte *p, uint32_t offset, uint32_t count) {
828// SubByteColorIo<ColorMode, pixel_order> io;
829// int pixel_index = offset % pixels_per_byte;
830// roo::byte *target = p + offset / pixels_per_byte;
831// while (count-- > 0) {
832// io.storeRaw(color_mode_.fromArgbColor(*color_++),
833// target,
834// pixel_index);
835// if (++pixel_index == pixels_per_byte) {
836// pixel_index = 0;
837// target++;
838// }
839// }
840// }
841
842// private:
843// ColorMode &color_mode_;
844// const Color *color_;
845// };
846
847// // For color modes in which a pixel takes up at least 1 byte.
848// template <typename ColorMode, ColorPixelOrder pixel_order, ByteOrder
849// byte_order,
850// typename storage_type>
851// class BlendingWriter<ColorMode, pixel_order, byte_order,
852// BlendingMode::kSource, 1,
853// storage_type> {
854// public:
855// BlendingWriter(const ColorMode &color_mode, const Color *color)
856// : color_mode_(color_mode), color_(color) {}
857
858// void operator()(roo::byte *p, uint32_t offset) {
859// internal::RawIterator<ColorMode::bits_per_pixel, byte_order> itr(p,
860// offset); itr.write(color_mode_.fromArgbColor(*color_++));
861// }
862
863// void operator()(roo::byte *p, uint32_t offset, uint32_t count) {
864// internal::RawIterator<ColorMode::bits_per_pixel, byte_order> itr(p,
865// offset); while (count-- > 0) {
866// itr.write(color_mode_.fromArgbColor(*color_++));
867// ++itr;
868// }
869// }
870
871// private:
872// const ColorMode &color_mode_;
873// const Color *color_;
874// };
875
876// GenericWriter is similar to BlendingWriter, but it resolves the blender at
877// run time. It might therefore be a bit slower, but it does not waste program
878// space.
879
880// For sub-byte color modes.
881template <typename ColorMode, ColorPixelOrder pixel_order, ByteOrder byte_order,
883 typename storage_type = ColorStorageType<ColorMode>>
885 public:
886 GenericWriter(ColorMode& color_mode, BlendingMode blending_mode, Color* color)
887 : color_mode_(color_mode), color_(color), blending_mode_(blending_mode) {}
888
889 void operator()(roo::byte* p, uint32_t offset) {
891 int pixel_index = offset % pixels_per_byte;
892 roo::byte* target = p + offset / pixels_per_byte;
893 auto color = ApplyRawSubByteBlending(blending_mode_,
894 io.loadRaw(*target, pixel_index),
895 *color_++, color_mode_);
896 io.storeRaw(color, target, pixel_index);
897 }
898
899 void operator()(roo::byte* p, uint32_t offset, uint32_t count) {
901 int pixel_index = offset % pixels_per_byte;
902 roo::byte* target = p + offset / pixels_per_byte;
903 // TODO: this loop can be optimized to work on an array of color at a time.
904 while (count-- > 0) {
905 auto color = ApplyRawSubByteBlending(blending_mode_,
906 io.loadRaw(*target, pixel_index),
907 *color_++, color_mode_);
908 io.storeRaw(color, target, pixel_index);
909 if (++pixel_index == pixels_per_byte) {
910 pixel_index = 0;
911 target++;
912 }
913 }
914 }
915
916 private:
917 ColorMode& color_mode_;
918 Color* color_;
919 BlendingMode blending_mode_;
920};
921
922// For color modes in which a pixel takes up at least 1 byte.
923template <typename ColorMode, ColorPixelOrder pixel_order, ByteOrder byte_order,
924 typename storage_type>
925class GenericWriter<ColorMode, pixel_order, byte_order, 1, storage_type> {
926 public:
927 GenericWriter(const ColorMode& color_mode, BlendingMode blending_mode,
928 Color* color)
929 : color_mode_(color_mode), color_(color), blending_mode_(blending_mode) {}
930
931 void operator()(roo::byte* p, uint32_t offset) {
932 constexpr uint32_t kBytesPerPixel = ColorTraits<ColorMode>::bytes_per_pixel;
934 blending_mode_, p + offset * kBytesPerPixel, *color_++, color_mode_);
935 }
936
937 void operator()(roo::byte* p, uint32_t offset, uint32_t count) {
938 constexpr uint32_t kBytesPerPixel = ColorTraits<ColorMode>::bytes_per_pixel;
939 roo::byte* cursor = p + offset * kBytesPerPixel;
940 while (count-- > 0) {
942 *color_++, color_mode_);
943 cursor += kBytesPerPixel;
944 }
945 }
946
947 private:
948 const ColorMode& color_mode_;
949 Color* color_;
950 BlendingMode blending_mode_;
951};
952
953// Filler template constract is similar to the writer template contract, except
954// that filler uses a single color.
955
956// BlendingFiller is a Filler that will blend the specified color over
957// previous content, templated on the specified blender.
958
959// For sub-byte color modes.
960template <typename ColorMode, ColorPixelOrder pixel_order, ByteOrder byte_order,
963 typename storage_type = ColorStorageType<ColorMode>>
965 public:
966 BlendingFillerOperator(ColorMode& color_mode, Color color)
967 : color_mode_(color_mode), color_(color) {}
968
969 void operator()(roo::byte* p, uint32_t offset) {
971 int pixel_index = offset % pixels_per_byte;
972 roo::byte* target = p + offset / pixels_per_byte;
974 auto color = blender(io.loadRaw(*target, pixel_index), color_, color_mode_);
975 io.storeRaw(color, target, pixel_index);
976 }
977
978 void operator()(roo::byte* p, uint32_t offset, uint32_t count) {
980 int pixel_index = offset % pixels_per_byte;
981 roo::byte* target = p + offset / pixels_per_byte;
983 while (count-- > 0) {
984 auto color =
985 blender(io.loadRaw(*target, pixel_index), color_, color_mode_);
986 io.storeRaw(color, target, pixel_index);
987 if (++pixel_index == pixels_per_byte) {
988 pixel_index = 0;
989 target++;
990 }
991 }
992 }
993
994 private:
995 ColorMode& color_mode_;
996 Color color_;
997};
998
999// For color modes in which a pixel takes up at least 1 byte.
1000template <typename ColorMode, ColorPixelOrder pixel_order, ByteOrder byte_order,
1001 BlendingMode blending_mode, typename storage_type>
1002class BlendingFillerOperator<ColorMode, pixel_order, byte_order, blending_mode,
1003 1, storage_type> {
1004 public:
1005 BlendingFillerOperator(const ColorMode& color_mode, Color color)
1006 : color_mode_(color_mode), color_(color) {}
1007
1008 void operator()(roo::byte* p, uint32_t offset) const {
1009 constexpr uint32_t kBytesPerPixel = ColorTraits<ColorMode>::bytes_per_pixel;
1011 blender(p + offset * kBytesPerPixel, color_, color_mode_);
1012 }
1013
1014 void operator()(roo::byte* p, uint32_t offset, uint32_t count) const {
1015 constexpr uint32_t kBytesPerPixel = ColorTraits<ColorMode>::bytes_per_pixel;
1016 roo::byte* cursor = p + offset * kBytesPerPixel;
1018 while (count-- > 0) {
1019 blender(cursor, color_, color_mode_);
1020 cursor += kBytesPerPixel;
1021 }
1022 }
1023
1024 private:
1025 const ColorMode& color_mode_;
1026 Color color_;
1027};
1028
1029// Optimized specialization for BlendingMode::kSource.
1030
1031// For sub-byte color modes.
1032template <typename ColorMode, ColorPixelOrder pixel_order, ByteOrder byte_order,
1033 uint8_t pixels_per_byte, typename storage_type>
1034class BlendingFillerOperator<ColorMode, pixel_order, byte_order,
1035 BlendingMode::kSource, pixels_per_byte,
1036 storage_type> {
1037 public:
1038 BlendingFillerOperator(ColorMode& color_mode, Color color)
1039 : color_mode_(color_mode),
1040 raw_color_(color_mode_.fromArgbColor(color)),
1041 raw_color_full_byte_(
1042 SubByteColorIo<ColorMode, pixel_order>().expandRaw(raw_color_)) {}
1043
1044 void operator()(roo::byte* p, uint32_t offset) const {
1046 io.storeRaw(raw_color_, p + offset / pixels_per_byte,
1047 offset % pixels_per_byte);
1048 }
1049
1050 void operator()(roo::byte* p, uint32_t offset, uint32_t count) const {
1052 int pixel_index = offset % pixels_per_byte;
1053 roo::byte* target = p + offset / pixels_per_byte;
1054 if (pixel_index > 0) {
1055 do {
1056 if (count-- == 0) return;
1057 io.storeRaw(raw_color_, target, pixel_index++);
1058 } while (pixel_index < pixels_per_byte);
1059 pixel_index = 0;
1060 ++target;
1061 }
1062 uint32_t contiguous_byte_count = count / pixels_per_byte;
1063 roo_io::PatternFill<1>(target, contiguous_byte_count,
1064 (const roo::byte*)&raw_color_full_byte_);
1065 count = count % pixels_per_byte;
1067 for (uint32_t i = 0; i < count; ++i) {
1068 io.storeRaw(raw_color_, target, i);
1069 }
1070 }
1071
1072 private:
1073 ColorMode& color_mode_;
1074 uint8_t raw_color_;
1075 roo::byte raw_color_full_byte_;
1076};
1077
1078// For color modes in which a pixel takes up at least 1 byte.
1079template <typename ColorMode, ColorPixelOrder pixel_order, ByteOrder byte_order,
1080 typename storage_type>
1081class BlendingFillerOperator<ColorMode, pixel_order, byte_order,
1082 BlendingMode::kSource, 1, storage_type> {
1083 public:
1084 BlendingFillerOperator(const ColorMode& color_mode, Color color)
1085 : color_mode_(color_mode) {
1086 ColorIo<ColorMode, byte_order>().store(color, raw_color_, color_mode_);
1087 }
1088
1089 void operator()(roo::byte* p, uint32_t offset) const {
1090 roo_io::PatternWrite<ColorMode::bits_per_pixel / 8>(
1091 p + offset * ColorMode::bits_per_pixel / 8, raw_color_);
1092 }
1093
1094 void operator()(roo::byte* p, uint32_t offset, uint32_t count) const {
1095 roo_io::PatternFill<ColorMode::bits_per_pixel / 8>(
1096 p + offset * ColorMode::bits_per_pixel / 8, count, raw_color_);
1097 }
1098
1099 private:
1100 const ColorMode& color_mode_;
1101 roo::byte raw_color_[ColorMode::bits_per_pixel / 8];
1102};
1103
1105 if (cursor_x_ < x1_) {
1106 ++cursor_x_;
1107 offset_ += advance_x_;
1108 } else {
1109 cursor_x_ = x0_;
1110 ++cursor_y_;
1111 offset_ += advance_x_;
1112 offset_ += advance_y_;
1113 }
1114}
1115
1117 uint16_t remaining_x = x1_ - cursor_x_ + 1;
1118 if (count < remaining_x) {
1119 cursor_x_ += count;
1120 offset_ += advance_x_ * count;
1121 return;
1122 }
1123 offset_ += advance_x_ * remaining_x;
1124 offset_ += advance_y_;
1125 count -= remaining_x;
1126 cursor_x_ = x0_;
1127 ++cursor_y_;
1128 int16_t full_lines = count / width();
1129 count = count % width();
1130 if (full_lines > 0) {
1131 offset_ += full_lines * (advance_x_ * width() + advance_y_);
1132 cursor_y_ += full_lines;
1133 }
1134 cursor_x_ += count;
1135 offset_ += advance_x_ * count;
1136}
1137
1138template <typename ColorMode, ColorPixelOrder pixel_order, ByteOrder byte_order>
1140 template <BlendingMode blending_mode>
1141 using Operator =
1143};
1144
1145// GenericFiller is similar to BlendingFiller, but it resolves the blender at
1146// run time. It might therefore be a bit slower, but it does not waste program
1147// space.
1148
1149// For sub-byte color modes.
1150template <typename ColorMode, ColorPixelOrder pixel_order, ByteOrder byte_order,
1152 typename storage_type = ColorStorageType<ColorMode>>
1154 public:
1155 GenericFiller(ColorMode& color_mode, BlendingMode blending_mode, Color color)
1156 : color_mode_(color_mode), color_(color), blending_mode_(blending_mode) {}
1157
1158 void operator()(roo::byte* p, uint32_t offset) {
1160 int pixel_index = offset % pixels_per_byte;
1161 roo::byte* target = p + offset / pixels_per_byte;
1163 blending_mode_, io.loadRaw(*target, pixel_index), color_, color_mode_);
1164 io.storeRaw(color, target, pixel_index);
1165 }
1166
1167 void operator()(roo::byte* p, uint32_t offset, uint32_t count) {
1169 int pixel_index = offset % pixels_per_byte;
1170 roo::byte* target = p + offset / pixels_per_byte;
1171 // TODO: this loop can be optimized to work on an array of color at a time.
1172 while (count-- > 0) {
1173 auto color = ApplyRawSubByteBlending(blending_mode_,
1174 io.loadRaw(*target, pixel_index),
1175 color_, color_mode_);
1176 io.storeRaw(color, target, pixel_index);
1177 if (++pixel_index == pixels_per_byte) {
1178 pixel_index = 0;
1179 target++;
1180 }
1181 }
1182 }
1183
1184 private:
1185 ColorMode& color_mode_;
1186 Color color_;
1187 BlendingMode blending_mode_;
1188};
1189
1190// For color modes in which a pixel takes up at least 1 byte.
1191template <typename ColorMode, ColorPixelOrder pixel_order, ByteOrder byte_order,
1192 typename storage_type>
1193class GenericFiller<ColorMode, pixel_order, byte_order, 1, storage_type> {
1194 public:
1195 GenericFiller(const ColorMode& color_mode, BlendingMode blending_mode,
1196 Color color)
1197 : color_mode_(color_mode), color_(color), blending_mode_(blending_mode) {}
1198
1199 void operator()(roo::byte* p, uint32_t offset) const {
1200 constexpr uint32_t kBytesPerPixel = ColorTraits<ColorMode>::bytes_per_pixel;
1202 blending_mode_, p + offset * kBytesPerPixel, color_, color_mode_);
1203 }
1204
1205 void operator()(roo::byte* p, uint32_t offset, uint32_t count) const {
1206 constexpr uint32_t kBytesPerPixel = ColorTraits<ColorMode>::bytes_per_pixel;
1207 roo::byte* cursor = p + offset * kBytesPerPixel;
1208 while (count-- > 0) {
1210 color_, color_mode_);
1211 cursor += kBytesPerPixel;
1212 }
1213 }
1214
1215 private:
1216 const ColorMode& color_mode_;
1217 Color color_;
1218 BlendingMode blending_mode_;
1219};
1220
1222 BlendingMode mode, TransparencyMode transparency_mode, Color color) {
1223 if (transparency_mode == TransparencyMode::kNone) {
1224 if (color.isOpaque()) {
1225 switch (mode) {
1230 return BlendingMode::kSource;
1231 }
1236 case BlendingMode::kXor: {
1238 }
1239 default: {
1240 return mode;
1241 }
1242 };
1243 } else if (color.a() == 0) {
1244 switch (mode) {
1255 case BlendingMode::kXor: {
1257 }
1258 default: {
1259 return mode;
1260 }
1261 }
1262 } else {
1263 switch (mode) {
1267 }
1269 return BlendingMode::kSource;
1270 }
1277 case BlendingMode::kXor: {
1279 }
1280 default: {
1281 return mode;
1282 }
1283 }
1284 }
1285 } else {
1286 if (color.isOpaque()) {
1287 switch (mode) {
1290 return BlendingMode::kSource;
1291 }
1294 }
1297 }
1299 return BlendingMode::kClear;
1300 }
1303 }
1304 case BlendingMode::kXor: {
1306 }
1307 default: {
1308 return mode;
1309 }
1310 };
1311 } else if (color.a() == 0) {
1312 switch (mode) {
1318 return BlendingMode::kClear;
1319 }
1325 case BlendingMode::kXor: {
1327 }
1328 default: {
1329 return mode;
1330 }
1331 }
1332 } else {
1333 return mode;
1334 }
1335 }
1336 return mode;
1337}
1338
1340 BlendingMode mode, TransparencyMode transparency_mode) {
1341 if (transparency_mode == TransparencyMode::kNone) {
1342 switch (mode) {
1346 }
1348 return BlendingMode::kSource;
1349 }
1356 case BlendingMode::kXor: {
1358 }
1359 default: {
1360 return mode;
1361 }
1362 }
1363 } else {
1364 return mode;
1365 }
1366}
1367
1368} // namespace internal
1369
1370template <typename ColorMode, ColorPixelOrder pixel_order, ByteOrder byte_order,
1371 int8_t pixels_per_byte, typename storage_type>
1372void OffscreenDevice<ColorMode, pixel_order, byte_order, pixels_per_byte,
1373 storage_type>::orientationUpdated() {
1374 awaitAsyncBlit();
1375 orienter_.setOrientation(orientation());
1376}
1377
1378template <typename ColorMode, ColorPixelOrder pixel_order, ByteOrder byte_order,
1379 int8_t pixels_per_byte, typename storage_type>
1380void OffscreenDevice<ColorMode, pixel_order, byte_order, pixels_per_byte,
1381 storage_type>::setAddress(uint16_t x0, uint16_t y0,
1382 uint16_t x1, uint16_t y1,
1384 awaitAsyncBlit();
1385 window_.setAddress(x0, y0, x1, y1, raw_width(), raw_height(),
1386 orienter_.orientation());
1389 blending_mode, color_mode_.transparency());
1390 }
1391 blending_mode_ = blending_mode;
1392}
1393
1394// template <typename Device, typename ColorMode, ColorPixelOrder pixel_order,
1395// ByteOrder byte_order>
1396// struct WriteOp {
1397// template <BlendingMode blending_mode>
1398// void operator()(Device &device, ColorMode &color_mode, Color *color,
1399// uint16_t pixel_count) const {
1400// internal::BlendingWriter<ColorMode, pixel_order, byte_order,
1401// blending_mode>
1402// writer(color_mode, color);
1403// device.writeToWindow(writer, pixel_count);
1404// }
1405// };
1406
1407template <typename ColorMode, ColorPixelOrder pixel_order, ByteOrder byte_order,
1408 int8_t pixels_per_byte, typename storage_type>
1409void OffscreenDevice<ColorMode, pixel_order, byte_order, pixels_per_byte,
1410 storage_type>::write(Color* color, uint32_t pixel_count) {
1411 if (blending_mode_ == BlendingMode::kSource) {
1414 writer(color_mode_, color);
1415 writeToWindow(writer, pixel_count);
1416 } else {
1417 if (blending_mode_ == BlendingMode::kDestination) return;
1418 if (blending_mode_ == BlendingMode::kSourceOverOpaque) {
1421 writer(color_mode_, color);
1422 writeToWindow(writer, pixel_count);
1423 } else if (blending_mode_ == BlendingMode::kSourceOver) {
1426 writer(color_mode_, color);
1427 writeToWindow(writer, pixel_count);
1428 } else {
1430 color_mode_, blending_mode_, color);
1431 writeToWindow(writer, pixel_count);
1432 }
1433 }
1434
1435 // internal::BlenderSpecialization<
1436 // WriteOp<OffscreenDevice<ColorMode, pixel_order, byte_order,
1437 // pixels_per_byte, storage_type>,
1438 // ColorMode, pixel_order, byte_order>>(
1439 // blending_mode_, *this, color_mode(), color, pixel_count);
1440}
1441
1442// template <typename ColorMode, ColorPixelOrder pixel_order, ByteOrder
1443// byte_order> struct WritePixelsOp {
1444// template <BlendingMode blending_mode>
1445// void operator()(ColorMode &color_mode, Color *color, roo::byte *buffer,
1446// int16_t w, int16_t *x, int16_t *y,
1447// uint16_t pixel_count) const {
1448// internal::BlendingWriter<ColorMode, pixel_order, byte_order,
1449// blending_mode>
1450// write(color_mode, color);
1451// while (pixel_count-- > 0) {
1452// write(buffer, *x++ + *y++ * w);
1453// }
1454// }
1455// };
1456
1457template <typename ColorMode, ColorPixelOrder pixel_order, ByteOrder byte_order,
1458 int8_t pixels_per_byte, typename storage_type>
1459void OffscreenDevice<ColorMode, pixel_order, byte_order, pixels_per_byte,
1460 storage_type>::writePixels(BlendingMode blending_mode,
1461 Color* color, int16_t* x,
1462 int16_t* y,
1464 awaitAsyncBlit();
1465 roo::byte* buffer = buffer_;
1466 int16_t w = raw_width();
1467 orienter_.orientPixels(x, y, pixel_count);
1471 write(color_mode_, color);
1472 while (pixel_count-- > 0) {
1473 write(buffer, *x++ + *y++ * w);
1474 }
1475 } else {
1477 blending_mode, color_mode_.transparency());
1482 write(color_mode_, color);
1483 while (pixel_count-- > 0) {
1484 write(buffer, *x++ + *y++ * w);
1485 }
1489 write(color_mode_, color);
1490 while (pixel_count-- > 0) {
1491 write(buffer, *x++ + *y++ * w);
1492 }
1493 } else {
1495 color_mode_, blending_mode, color);
1496 while (pixel_count-- > 0) {
1497 write(buffer, *x++ + *y++ * w);
1498 }
1499 }
1500 }
1501 // internal::BlenderSpecialization<
1502 // WritePixelsOp<ColorMode, pixel_order, byte_order>>(
1503 // blending_mode, color_mode(), color, buffer, w, x, y, pixel_count);
1504}
1505
1506// template <typename ColorMode, ColorPixelOrder pixel_order, ByteOrder
1507// byte_order> struct FillPixelsOp {
1508// template <BlendingMode blending_mode>
1509// void operator()(ColorMode &color_mode, Color color, roo::byte *buffer,
1510// int16_t w, int16_t *x, int16_t *y,
1511// uint16_t pixel_count) const {
1512// internal::BlendingFiller<ColorMode, pixel_order, byte_order,
1513// blending_mode>
1514// fill(color_mode, color);
1515// while (pixel_count-- > 0) {
1516// fill(buffer, *x++ + *y++ * w);
1517// }
1518// }
1519// };
1520
1521template <typename ColorMode, ColorPixelOrder pixel_order, ByteOrder byte_order,
1522 int8_t pixels_per_byte, typename storage_type>
1523void OffscreenDevice<ColorMode, pixel_order, byte_order, pixels_per_byte,
1524 storage_type>::fillPixels(BlendingMode blending_mode,
1525 Color color, int16_t* x,
1526 int16_t* y,
1528 awaitAsyncBlit();
1529 roo::byte* buffer = buffer_;
1530 int16_t w = raw_width();
1531 orienter_.orientPixels(x, y, pixel_count);
1534 blending_mode, color_mode_.transparency(), color);
1536 }
1541 fill(color_mode_, color);
1542 while (pixel_count-- > 0) {
1543 fill(buffer, *x++ + *y++ * w);
1544 }
1548 fill(color_mode_, color);
1549 while (pixel_count-- > 0) {
1550 fill(buffer, *x++ + *y++ * w);
1551 }
1552 } else {
1554 color_mode_, blending_mode, color);
1555 while (pixel_count-- > 0) {
1556 fill(buffer, *x++ + *y++ * w);
1557 }
1558 }
1559
1560 // internal::BlenderSpecialization<
1561 // FillPixelsOp<ColorMode, pixel_order, byte_order>>(
1562 // blending_mode, color_mode(), color, buffer, w, x, y, pixel_count);
1563}
1564
1565template <typename ColorMode, ColorPixelOrder pixel_order, ByteOrder byte_order,
1566 int8_t pixels_per_byte, typename storage_type>
1567void OffscreenDevice<ColorMode, pixel_order, byte_order, pixels_per_byte,
1568 storage_type>::writeRects(BlendingMode blending_mode,
1569 Color* color, int16_t* x0,
1570 int16_t* y0, int16_t* x1,
1571 int16_t* y1, uint16_t count) {
1572 awaitAsyncBlit();
1573 orienter_.orientRects(x0, y0, x1, y1, count);
1576 blending_mode, color_mode_.transparency());
1578 }
1579 while (count-- > 0) {
1580 fillRectsAbsolute(blending_mode, *color++, x0++, y0++, x1++, y1++, 1);
1581 }
1582}
1583
1584template <typename ColorMode, ColorPixelOrder pixel_order, ByteOrder byte_order,
1585 int8_t pixels_per_byte, typename storage_type>
1586void OffscreenDevice<ColorMode, pixel_order, byte_order, pixels_per_byte,
1587 storage_type>::fillRects(BlendingMode blending_mode,
1588 Color color, int16_t* x0,
1589 int16_t* y0, int16_t* x1,
1590 int16_t* y1, uint16_t count) {
1591 awaitAsyncBlit();
1592 orienter_.orientRects(x0, y0, x1, y1, count);
1595 blending_mode, color_mode_.transparency(), color);
1597 }
1598 if (y0 == y1) {
1599 fillHlinesAbsolute(blending_mode, color, x0, y0, x1, count);
1600 } else if (x0 == x1) {
1601 fillVlinesAbsolute(blending_mode, color, x0, y0, y1, count);
1602 } else {
1603 fillRectsAbsolute(blending_mode, color, x0, y0, x1, y1, count);
1604 }
1605}
1606
1607template <typename Filler>
1608void fillRectsAbsoluteImpl(Filler& fill, roo::byte* buffer, int16_t width,
1609 int16_t* x0, int16_t* y0, int16_t* x1, int16_t* y1,
1610 uint32_t count) {
1611 while (count-- > 0) {
1612 uint32_t offset = *x0 + *y0 * width;
1613 int16_t my_w = (*x1 - *x0 + 1);
1614 int16_t my_h = (*y1 - *y0 + 1);
1615 if (my_w == width) {
1616 fill(buffer, offset, my_w * my_h);
1617 } else {
1618 while (my_h-- > 0) {
1619 fill(buffer, offset, my_w);
1620 offset += width;
1621 }
1622 }
1623 x0++;
1624 y0++;
1625 x1++;
1626 y1++;
1627 }
1628}
1629
1630template <typename Filler>
1631void fillHlinesAbsoluteImpl(Filler& fill, roo::byte* buffer, int16_t width,
1632 int16_t* x0, int16_t* y0, int16_t* x1,
1633 uint16_t count) {
1634 while (count-- > 0) {
1635 int16_t n = *x1++ - *x0 + 1;
1636 fill(buffer, *x0++ + *y0++ * width, n);
1637 }
1638}
1639
1640template <typename Filler>
1641void fillVlinesAbsoluteImpl(Filler& fill, roo::byte* buffer, int16_t width,
1642 int16_t* x0, int16_t* y0, int16_t* y1,
1643 uint16_t count) {
1644 while (count-- > 0) {
1645 int16_t n = *y1++ - *y0 + 1;
1646 uint32_t offset = *x0++ + *y0++ * width;
1647 while (n-- > 0) {
1648 fill(buffer, offset);
1649 offset += width;
1650 }
1651 }
1652}
1653
1654// template <typename ColorMode, ColorPixelOrder pixel_order, ByteOrder
1655// byte_order> struct FillRectsOp {
1656// template <BlendingMode blending_mode>
1657// void operator()(ColorMode &color_mode, Color color, roo::byte *buffer,
1658// int16_t w, int16_t *x0, int16_t *y0, int16_t *x1, int16_t
1659// *y1, uint16_t count) const {
1660// internal::BlendingFiller<ColorMode, pixel_order, byte_order,
1661// blending_mode>
1662// fill(color_mode, color);
1663// fillRectsAbsoluteImpl(fill, buffer, w, x0, y0, x1, y1, count);
1664// }
1665// };
1666
1667template <typename ColorMode, ColorPixelOrder pixel_order, ByteOrder byte_order,
1668 int8_t pixels_per_byte, typename storage_type>
1669void OffscreenDevice<ColorMode, pixel_order, byte_order, pixels_per_byte,
1670 storage_type>::fillRectsAbsolute(BlendingMode
1672 Color color, int16_t* x0,
1673 int16_t* y0, int16_t* x1,
1674 int16_t* y1,
1675 uint16_t count) {
1676 if (y0 == y1) {
1677 fillHlinesAbsolute(blending_mode, color, x0, y0, x1, count);
1678 } else if (x0 == x1) {
1679 fillVlinesAbsolute(blending_mode, color, x0, y0, y1, count);
1680 } else {
1681 int16_t w = raw_width();
1682 roo::byte* buffer = buffer_;
1684 typename internal::BlendingFiller<ColorMode, pixel_order, byte_order>::
1685 template Operator<BlendingMode::kSource>
1686 fill(color_mode_, color);
1687 fillRectsAbsoluteImpl(fill, buffer, w, x0, y0, x1, y1, count);
1689 typename internal::BlendingFiller<ColorMode, pixel_order, byte_order>::
1690 template Operator<BlendingMode::kSourceOverOpaque>
1691 fill(color_mode_, color);
1692 fillRectsAbsoluteImpl(fill, buffer, w, x0, y0, x1, y1, count);
1694 typename internal::BlendingFiller<ColorMode, pixel_order, byte_order>::
1695 template Operator<BlendingMode::kSourceOver>
1696 fill(color_mode_, color);
1697 fillRectsAbsoluteImpl(fill, buffer, w, x0, y0, x1, y1, count);
1698 } else {
1699 internal::GenericFiller<ColorMode, pixel_order, byte_order> fill(
1700 color_mode_, blending_mode, color);
1701 fillRectsAbsoluteImpl(fill, buffer, w, x0, y0, x1, y1, count);
1702 }
1703 }
1704}
1705
1706// template <typename ColorMode, ColorPixelOrder pixel_order, ByteOrder
1707// byte_order> struct FillHLinesOp {
1708// template <BlendingMode blending_mode>
1709// void operator()(ColorMode &color_mode, Color color, roo::byte *buffer,
1710// int16_t w, int16_t *x0, int16_t *y0, int16_t *x1,
1711// uint16_t count) const {
1712// internal::BlendingFiller<ColorMode, pixel_order, byte_order,
1713// blending_mode>
1714// fill(color_mode, color);
1715// fillHlinesAbsoluteImpl(fill, buffer, w, x0, y0, x1, count);
1716// }
1717// };
1718
1719template <typename ColorMode, ColorPixelOrder pixel_order, ByteOrder byte_order,
1720 int8_t pixels_per_byte, typename storage_type>
1721void OffscreenDevice<ColorMode, pixel_order, byte_order, pixels_per_byte,
1722 storage_type>::fillHlinesAbsolute(BlendingMode
1724 Color color, int16_t* x0,
1725 int16_t* y0, int16_t* x1,
1726 uint16_t count) {
1727 roo::byte* buffer = buffer_;
1728 int16_t w = raw_width();
1730 typename internal::BlendingFiller<ColorMode, pixel_order, byte_order>::
1731 template Operator<BlendingMode::kSource>
1732 fill(color_mode_, color);
1733 fillHlinesAbsoluteImpl(fill, buffer, w, x0, y0, x1, count);
1735 typename internal::BlendingFiller<ColorMode, pixel_order, byte_order>::
1736 template Operator<BlendingMode::kSourceOverOpaque>
1737 fill(color_mode_, color);
1738 fillHlinesAbsoluteImpl(fill, buffer, w, x0, y0, x1, count);
1740 typename internal::BlendingFiller<ColorMode, pixel_order, byte_order>::
1741 template Operator<BlendingMode::kSourceOver>
1742 fill(color_mode_, color);
1743 fillHlinesAbsoluteImpl(fill, buffer, w, x0, y0, x1, count);
1744 } else {
1745 internal::GenericFiller<ColorMode, pixel_order, byte_order> fill(
1746 color_mode_, blending_mode, color);
1747 fillHlinesAbsoluteImpl(fill, buffer, w, x0, y0, x1, count);
1748 }
1749}
1750// internal::BlenderSpecialization<
1751// FillHLinesOp<ColorMode, pixel_order, byte_order>>(
1752// blending_mode, color_mode(), color, buffer_, raw_width(), x0, y0, x1,
1753// count);
1754// }
1755
1756// template <typename ColorMode, ColorPixelOrder pixel_order, ByteOrder
1757// byte_order> struct FillVLinesOp {
1758// template <BlendingMode blending_mode>
1759// void operator()(ColorMode &color_mode, Color color, roo::byte *buffer,
1760// int16_t w, int16_t *x0, int16_t *y0, int16_t *y1,
1761// uint16_t count) const {
1762// internal::BlendingFiller<ColorMode, pixel_order, byte_order,
1763// blending_mode>
1764// fill(color_mode, color);
1765// fillVlinesAbsoluteImpl(fill, buffer, w, x0, y0, y1, count);
1766// }
1767// };
1768
1769template <typename ColorMode, ColorPixelOrder pixel_order, ByteOrder byte_order,
1770 int8_t pixels_per_byte, typename storage_type>
1771void OffscreenDevice<ColorMode, pixel_order, byte_order, pixels_per_byte,
1772 storage_type>::fillVlinesAbsolute(BlendingMode
1774 Color color, int16_t* x0,
1775 int16_t* y0, int16_t* y1,
1776 uint16_t count) {
1777 roo::byte* buffer = buffer_;
1778 int16_t w = raw_width();
1780 typename internal::BlendingFiller<ColorMode, pixel_order, byte_order>::
1781 template Operator<BlendingMode::kSource>
1782 fill(color_mode_, color);
1783 fillVlinesAbsoluteImpl(fill, buffer, w, x0, y0, y1, count);
1785 typename internal::BlendingFiller<ColorMode, pixel_order, byte_order>::
1786 template Operator<BlendingMode::kSourceOverOpaque>
1787 fill(color_mode_, color);
1788 fillVlinesAbsoluteImpl(fill, buffer, w, x0, y0, y1, count);
1790 typename internal::BlendingFiller<ColorMode, pixel_order, byte_order>::
1791 template Operator<BlendingMode::kSourceOver>
1792 fill(color_mode_, color);
1793 fillVlinesAbsoluteImpl(fill, buffer, w, x0, y0, y1, count);
1794 } else {
1795 internal::GenericFiller<ColorMode, pixel_order, byte_order> fill(
1796 color_mode_, blending_mode, color);
1797 fillVlinesAbsoluteImpl(fill, buffer, w, x0, y0, y1, count);
1798 }
1799 // internal::BlenderSpecialization<
1800 // FillVLinesOp<ColorMode, pixel_order, byte_order>>(
1801 // blending_mode, color_mode(), color, buffer_, raw_width(), x0, y0, y1,
1802 // count);
1803}
1804
1805namespace internal {
1806
1807inline void Orienter::orientPixels(int16_t*& x, int16_t*& y, int16_t count) {
1808 DCHECK(x != y) << "orientPixels requires distinct x and y buffers";
1809 if (orientation_ != Orientation::Default()) {
1810 if (orientation_.isXYswapped()) {
1811 std::swap(x, y);
1812 }
1813 if (orientation_.isRightToLeft()) {
1814 revertX(x, count);
1815 }
1816 if (orientation_.isBottomToTop()) {
1817 revertY(y, count);
1818 }
1819 }
1820}
1821
1822inline void Orienter::orientRects(int16_t*& x0, int16_t*& y0, int16_t*& x1,
1823 int16_t*& y1, int16_t count) {
1824 DCHECK(x0 != y0 && x1 != y1 && x0 != y1 && x1 != y0)
1825 << "orientRects disallows cross-axis aliasing";
1826 if (orientation_ != Orientation::Default()) {
1827 if (orientation_.isXYswapped()) {
1828 std::swap(x0, y0);
1829 std::swap(x1, y1);
1830 }
1831 if (orientation_.isRightToLeft()) {
1832 revertX(x0, count);
1833 if (x0 != x1) {
1834 revertX(x1, count);
1835 std::swap(x0, x1);
1836 }
1837 }
1838 if (orientation_.isBottomToTop()) {
1839 revertY(y0, count);
1840 if (y0 != y1) {
1841 revertY(y1, count);
1842 std::swap(y0, y1);
1843 }
1844 }
1845 }
1846}
1847
1849 int16_t& y1) {
1850 DCHECK(&x0 != &y0 && &x1 != &y1 && &x0 != &y1 && &x1 != &y0)
1851 << "OrientRects disallows cross-axis aliasing";
1852 if (orientation_ != Orientation::Default()) {
1853 if (orientation_.isXYswapped()) {
1854 std::swap(x0, y0);
1855 std::swap(x1, y1);
1856 }
1857 if (orientation_.isRightToLeft()) {
1858 x0 = xMax_ - x0;
1859 if (&x0 != &x1) {
1860 x1 = xMax_ - x1;
1861 std::swap(x0, x1);
1862 }
1863 }
1864 if (orientation_.isBottomToTop()) {
1865 y0 = yMax_ - y0;
1866 if (&y0 != &y1) {
1867 y1 = yMax_ - y1;
1868 std::swap(y0, y1);
1869 }
1870 }
1871 }
1872}
1873
1874inline void Orienter::revertX(int16_t* x, uint16_t count) {
1875 int16_t xMax = xMax_;
1876 while (count-- > 0) {
1877 *x = xMax - *x;
1878 ++x;
1879 }
1880}
1881
1882inline void Orienter::revertY(int16_t* y, uint16_t count) {
1883 int16_t yMax = yMax_;
1884 while (count-- > 0) {
1885 *y = yMax - *y;
1886 ++y;
1887 }
1888}
1889
1890} // namespace internal
1891
1892} // namespace roo_display
BufferedRectWriter & writer
BitMaskOffscreen(Box extents, uint8_t *buffer)
Definition offscreen.h:694
BitMaskOffscreen(int16_t width, int16_t height, roo::byte *buffer)
Definition offscreen.h:680
BitMaskOffscreen(int16_t width, int16_t height, Color fillColor)
Definition offscreen.h:709
BitMaskOffscreen(int16_t width, int16_t height, uint8_t *buffer)
Definition offscreen.h:684
BitMaskOffscreen(int16_t width, int16_t height)
Definition offscreen.h:700
Axis-aligned integer rectangle.
Definition box.h:12
int16_t width() const
Width in pixels (inclusive coordinates).
Definition box.h:77
int16_t xMin() const
Minimum x (inclusive).
Definition box.h:65
int16_t height() const
Height in pixels (inclusive coordinates).
Definition box.h:80
int32_t area() const
Area in pixels.
Definition box.h:83
int16_t yMin() const
Minimum y (inclusive).
Definition box.h:68
ARGB8888 color stored as a 32-bit unsigned integer.
Definition color.h:16
Base class for display device drivers.
Definition device.h:223
int16_t raw_width() const
Return the width of the display in its native orientation.
Definition device.h:256
int16_t raw_height() const
Return the height of the display in its native orientation.
Definition device.h:262
Orientation orientation() const
Return the current orientation of the display.
Definition device.h:250
Interface for objects that can be drawn to an output device.
Definition drawable.h:229
Primary top-level interface for drawing to screens, off-screen buffers, or other devices.
In-memory DisplayDevice backed by a pixel buffer.
Definition offscreen.h:134
ColorMode & color_mode()
Access color mode.
Definition offscreen.h:394
void drawDirectRectAsync(const roo::byte *data, size_t row_width_bytes, int16_t src_x0, int16_t src_y0, int16_t src_x1, int16_t src_y1, int16_t dst_x0, int16_t dst_y0) override
Asynchronous variant of drawDirectRect().
Definition offscreen.h:335
int16_t window_x() const
Current address window x cursor.
Definition offscreen.h:438
void setAddress(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, BlendingMode mode) override
Set a rectangular window filled by subsequent calls to write().
Definition offscreen.h:1381
void writeRects(BlendingMode mode, Color *color, int16_t *x0, int16_t *y0, int16_t *x1, int16_t *y1, uint16_t count) override
Draw the specified rectangles (per-rectangle colors). Invalidates the address window.
Definition offscreen.h:1568
const ConstDramRaster< ColorMode, pixel_order, byte_order > raster(int16_t dx, int16_t dy) const
Return a raster view of the buffer with an offset.
Definition offscreen.h:412
void writePixels(BlendingMode mode, Color *color, int16_t *x, int16_t *y, uint16_t pixel_count) override
Draw the specified pixels (per-pixel colors). Invalidates the address window.
Definition offscreen.h:1460
const ColorFormat & getColorFormat() const override
Return the native color format used by this device for direct drawing.
Definition offscreen.h:398
const roo::byte * buffer() const
Direct access to the underlying buffer (const).
Definition offscreen.h:435
roo::byte * buffer()
Direct access to the underlying buffer.
Definition offscreen.h:433
OffscreenDevice(int16_t width, int16_t height, roo::byte *buffer, ColorMode color_mode)
Create an offscreen device with the given geometry and buffer.
Definition offscreen.h:141
void drawDirectRect(const roo::byte *data, size_t row_width_bytes, int16_t src_x0, int16_t src_y0, int16_t src_x1, int16_t src_y1, int16_t dst_x0, int16_t dst_y0) override
Draw a rectangle represented in the device's native color format.
Definition offscreen.h:185
const ColorMode & color_mode() const
Access color mode (const).
Definition offscreen.h:396
void fillRects(BlendingMode mode, Color color, int16_t *x0, int16_t *y0, int16_t *x1, int16_t *y1, uint16_t count) override
Draw the specified rectangles using the same color. Invalidates the address window.
Definition offscreen.h:1587
void orientationUpdated()
Update orientation-dependent state.
Definition offscreen.h:1373
void fillPixels(BlendingMode mode, Color color, int16_t *x, int16_t *y, uint16_t pixel_count) override
Draw the specified pixels using the same color. Invalidates the address window.
Definition offscreen.h:1524
void write(Color *color, uint32_t pixel_count) override
Write pixels into the current address window.
Definition offscreen.h:1410
const ConstDramRaster< ColorMode, pixel_order, byte_order > raster() const
Return a raster view of the full buffer.
Definition offscreen.h:407
OffscreenDevice(OffscreenDevice &&other) noexcept
Definition offscreen.h:151
int16_t window_y() const
Current address window y cursor.
Definition offscreen.h:440
void end() override
Finalize the previously entered write transaction, flushing any pending writes.
Definition offscreen.h:183
void flush() override
Wait until pending asynchronous drawing operations complete.
Definition offscreen.h:391
Offscreen rasterizable that writes into a pixel buffer.
Definition offscreen.h:491
void readColors(const int16_t *x, const int16_t *y, uint32_t count, Color *result) const override
Read colors for the given points.
Definition offscreen.h:603
const roo::byte * buffer() const
Definition offscreen.h:621
Offscreen(Box extents, Color fillColor, ColorMode color_mode=ColorMode())
Definition offscreen.h:553
Raster< const roo::byte *, ColorMode, pixel_order, byte_order > RasterType
Definition offscreen.h:494
Offscreen(const Drawable &d, Color bgColor, ColorMode color_mode=ColorMode())
Definition offscreen.h:566
Offscreen(Box extents, roo::byte *buffer, ColorMode color_mode=ColorMode())
Definition offscreen.h:514
void set_extents(const Box &extents)
Definition offscreen.h:629
Offscreen(Offscreen &&other) noexcept
Definition offscreen.h:581
OffscreenDevice< ColorMode, pixel_order, byte_order, pixels_per_byte, storage_type > & output()
Definition offscreen.h:616
roo::byte * buffer()
Definition offscreen.h:620
TransparencyMode getTransparencyMode() const override
Return the transparency mode for pixels in this stream.
Definition offscreen.h:599
const ColorMode & color_mode() const
Definition offscreen.h:623
void setAnchorExtents(Box anchor_extents)
Definition offscreen.h:595
Offscreen(Box extents, ColorMode color_mode=ColorMode())
Definition offscreen.h:529
Box anchorExtents() const override
Return the bounds used for alignment.
Definition offscreen.h:593
Offscreen(int16_t width, int16_t height, roo::byte *buffer, ColorMode color_mode=ColorMode())
Create an offscreen with the given geometry and buffer.
Definition offscreen.h:501
Box extents() const override
Return the bounding box encompassing all pixels that need to be drawn.
Definition offscreen.h:592
Offscreen(int16_t width, int16_t height, uint8_t *buffer, ColorMode color_mode=ColorMode())
Definition offscreen.h:506
Offscreen(const Drawable &d, ColorMode color_mode=ColorMode())
Definition offscreen.h:560
Offscreen(int16_t width, int16_t height, ColorMode color_mode=ColorMode())
Definition offscreen.h:524
const OffscreenDevice< ColorMode, pixel_order, byte_order, pixels_per_byte, storage_type > & output() const
Definition offscreen.h:610
const RasterType & raster() const
Definition offscreen.h:590
Offscreen(int16_t width, int16_t height, Color fillColor, ColorMode color_mode=ColorMode())
Definition offscreen.h:547
Represents the orientation of a display device.
Definition orientation.h:25
bool isRightToLeft() const
Return whether horizontal direction is right-to-left.
static constexpr Orientation Default()
Return the default orientation (RightDown).
Definition orientation.h:54
bool isBottomToTop() const
Return whether vertical direction is bottom-to-top.
bool isXYswapped() const
Return whether x maps to the vertical direction.
Definition orientation.h:90
Drawable that can provide a color for any point within its extents.
Low-level handle used to draw to an underlying device.
Definition drawable.h:60
void setAddress(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, int16_t raw_width, int16_t raw_height, Orientation orientation)
Definition offscreen.cpp:25
Orientation orientation() const
Definition offscreen.h:73
const uint32_t offset() const
Definition offscreen.h:72
void operator()(roo::byte *p, uint32_t offset, uint32_t count)
Definition offscreen.h:978
void operator()(roo::byte *p, uint32_t offset)
Definition offscreen.h:969
BlendingFillerOperator(ColorMode &color_mode, Color color)
Definition offscreen.h:966
BlendingWriterOperator(ColorMode &color_mode, const Color *color)
Definition offscreen.h:735
void operator()(roo::byte *p, uint32_t offset)
Definition offscreen.h:738
void operator()(roo::byte *p, uint32_t offset, uint32_t count)
Definition offscreen.h:748
GenericFiller(const ColorMode &color_mode, BlendingMode blending_mode, Color color)
Definition offscreen.h:1195
void operator()(roo::byte *p, uint32_t offset)
Definition offscreen.h:1158
void operator()(roo::byte *p, uint32_t offset, uint32_t count)
Definition offscreen.h:1167
GenericFiller(ColorMode &color_mode, BlendingMode blending_mode, Color color)
Definition offscreen.h:1155
GenericWriter(const ColorMode &color_mode, BlendingMode blending_mode, Color *color)
Definition offscreen.h:927
void operator()(roo::byte *p, uint32_t offset)
Definition offscreen.h:889
void operator()(roo::byte *p, uint32_t offset, uint32_t count)
Definition offscreen.h:899
GenericWriter(ColorMode &color_mode, BlendingMode blending_mode, Color *color)
Definition offscreen.h:886
void orientRects(int16_t *&x0, int16_t *&y0, int16_t *&x1, int16_t *&y1, int16_t count)
Definition offscreen.h:1822
void orientRect(int16_t &x0, int16_t &y0, int16_t &x1, int16_t &y1)
Definition offscreen.h:1848
Orientation orientation() const
Definition offscreen.h:36
Orienter(int16_t raster_width, int16_t raster_height, Orientation orientation=Orientation::Default())
Definition offscreen.h:30
void orientPixels(int16_t *&x, int16_t *&y, int16_t count)
Definition offscreen.h:1807
void setOrientation(Orientation orientation)
Definition offscreen.h:38
BlendingMode ResolveBlendingModeForWrite(BlendingMode mode, TransparencyMode transparency_mode)
Definition offscreen.h:1339
BlendingMode ResolveBlendingModeForFill(BlendingMode mode, TransparencyMode transparency_mode, Color color)
Definition offscreen.h:1221
Defines 140 opaque HTML named colors.
void async_blit_await()
ColorStorageType< ColorMode > ApplyRawSubByteBlending(BlendingMode blending_mode, uint8_t dst, Color src, const ColorMode &color_mode)
Definition blending.h:728
BlendingMode
Porter-Duff style blending modes.
Definition blending.h:17
@ kDestinationOver
Destination is placed over the source.
@ kDestinationIn
Destination which overlaps the source, replaces the source.
@ kDestinationOut
Destination is placed, where it falls outside of the source.
@ kSourceOverOpaque
Similar to kSourceOver, but assumes that the destination is opaque.
@ kXor
The non-overlapping regions of source and destination are combined.
@ kDestination
Only the destination will be present.
@ kSource
The new ARGB8888 value completely replaces the old one.
@ kDestinationAtop
Destination which overlaps the source replaces the source. Source is placed elsewhere.
@ kSourceIn
The source that overlaps the destination, replaces the destination.
@ kSourceAtop
Source which overlaps the destination, replaces the destination. Destination is placed elsewhere.
@ kClear
No regions are enabled.
@ kSourceOver
Source is placed (alpha-blended) over the destination. This is the default blending mode.
@ kSourceOut
Source is placed, where it falls outside of the destination.
void async_blit(const roo::byte *src_ptr, size_t src_stride, roo::byte *dst_ptr, size_t dst_stride, size_t width, size_t height)
TransparencyMode
Transparency information for a stream or color mode.
Definition blending.h:103
@ kNone
All colors are fully opaque.
auto OffscreenForDevice(const Device &device, Args &&... args) -> Offscreen< typename Device::ColorMode, Device::pixel_order, Device::byte_order >
Definition offscreen.h:662
void fillHlinesAbsoluteImpl(Filler &fill, roo::byte *buffer, int16_t width, int16_t *x0, int16_t *y0, int16_t *x1, uint16_t count)
Definition offscreen.h:1631
FillMode
Specifies whether a Drawable should fill its entire extents box, including fully transparent pixels.
Definition drawable.h:15
@ kVisible
Fully transparent pixels do not need to be filled.
@ kExtents
Fill the entire extents box (possibly with fully transparent pixels).
void fillRectsAbsoluteImpl(Filler &fill, roo::byte *buffer, int16_t width, int16_t *x0, int16_t *y0, int16_t *x1, int16_t *y1, uint32_t count)
Definition offscreen.h:1608
void fillVlinesAbsoluteImpl(Filler &fill, roo::byte *buffer, int16_t width, int16_t *x0, int16_t *y0, int16_t *y1, uint16_t count)
Definition offscreen.h:1641
roo_io::ByteOrder ByteOrder
Definition byte_order.h:7
void blit(const roo::byte *src_ptr, size_t src_stride, roo::byte *dst_ptr, size_t dst_stride, size_t width, size_t height)
Definition blit.cpp:15
FillMode fill_mode
Definition smooth.cpp:887
BlendingMode blending_mode
Definition smooth.cpp:888
uint16_t width_
Traits for a color mode's storage characteristics.
Definition traits.h:9